feat(i18n): language foundation with en and pt-BR

Nothing in the project was translatable — every string sat inline in English.

en.ts is the source dictionary and its type is derived from it, so a typo or a
missing key fails typecheck instead of rendering the raw key at runtime.
pt-BR.ts is deliberately Partial: translation proceeds one system per update
and anything absent falls back to English, so a half-migrated interface is
never broken, only partly English.

Locale is persisted, guessed from the browser on first run, and kept in sync
with <html lang> through a subscription — persisted state rehydrates after
first paint, so a one-off assignment would miss it.

Translates the voice input panel (including the mic test shipped earlier
today) and the profile card as this round's system. Language options are
labelled in the active language, so a wrong pick can always be undone.
This commit is contained in:
2026-08-31 12:24:50 -03:00
parent 89e13441c8
commit 688a1335cb
9 changed files with 298 additions and 33 deletions
+44
View File
@@ -0,0 +1,44 @@
import type { Dictionary } from './en';
/**
* Partial on purpose. Translation happens one system per update, and anything
* absent here falls back to English — so a half-migrated interface is never
* broken, just partly in English.
*/
export const ptBR: Partial<Dictionary> = {
// Configurações — navegação
'settings.tab.account': 'Conta',
'settings.tab.voice': 'Voz e Vídeo',
'settings.tab.privacy': 'Privacidade',
'settings.tab.connections': 'Conexões',
'settings.tab.keybinds': 'Atalhos',
'settings.tab.desktop': 'Desktop',
'settings.tab.instance': 'Instância',
'settings.tab.language': 'Idioma',
// Configurações — idioma
'settings.language.title': 'Idioma',
'settings.language.description': 'Escolha o idioma da interface. O que ainda não foi traduzido continua em inglês.',
'settings.language.en': 'Inglês',
'settings.language.ptBR': 'Português (Brasil)',
// Configurações — voz: entrada
'settings.voice.input.title': 'Dispositivo de entrada',
'settings.voice.input.volume': 'Volume de entrada',
'settings.voice.micTest.start': 'Testar microfone',
'settings.voice.micTest.stop': 'Parar teste',
'settings.voice.micTest.playing': 'Devolvendo seu microfone para você — fale alguma coisa.',
'settings.voice.micTest.inCall': 'O medidor fica ativo enquanto você está numa call.',
'settings.voice.micTest.idle': 'Teste seu microfone sem entrar numa call.',
'settings.voice.micTest.failed': 'Não foi possível abrir o microfone. Verifique o dispositivo e a permissão.',
// Cartão de perfil
'profile.aboutMe': 'Sobre mim',
'profile.memberSince': 'Membro desde',
'profile.sendMessage': 'Enviar mensagem',
'profile.activity.playing': 'Jogando',
'profile.activity.listening': 'Ouvindo',
'profile.activity.watching': 'Assistindo',
'profile.activity.streaming': 'Transmitindo',
'profile.activity.elapsed': '{time} decorrido',
};