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:
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* Source dictionary. Every key the app can translate is declared here, and its
|
||||
* type is derived from this object — a typo or a missing key fails typecheck
|
||||
* rather than silently rendering the raw key at runtime.
|
||||
*
|
||||
* Keys are flat and dot-namespaced by system (`settings.voice.*`), so a
|
||||
* translation pass can take one system at a time.
|
||||
*/
|
||||
export const en = {
|
||||
// Settings — navigation
|
||||
'settings.tab.account': 'Account',
|
||||
'settings.tab.voice': 'Voice & Video',
|
||||
'settings.tab.privacy': 'Privacy',
|
||||
'settings.tab.connections': 'Connections',
|
||||
'settings.tab.keybinds': 'Keybinds',
|
||||
'settings.tab.desktop': 'Desktop',
|
||||
'settings.tab.instance': 'Instance',
|
||||
'settings.tab.language': 'Language',
|
||||
|
||||
// Settings — language
|
||||
'settings.language.title': 'Language',
|
||||
'settings.language.description': 'Choose the language for the interface. Anything not yet translated stays in English.',
|
||||
'settings.language.en': 'English',
|
||||
'settings.language.ptBR': 'Portuguese (Brazil)',
|
||||
|
||||
// Settings — voice: input
|
||||
'settings.voice.input.title': 'Input Device',
|
||||
'settings.voice.input.volume': 'Input Volume',
|
||||
'settings.voice.micTest.start': "Let's Check",
|
||||
'settings.voice.micTest.stop': 'Stop Testing',
|
||||
'settings.voice.micTest.playing': 'Playing your mic back to you — say something.',
|
||||
'settings.voice.micTest.inCall': 'The level meter is live while you are in a call.',
|
||||
'settings.voice.micTest.idle': 'Test your mic without joining a call.',
|
||||
'settings.voice.micTest.failed': 'Could not open the microphone. Check the device and its permission.',
|
||||
|
||||
// Profile card
|
||||
'profile.aboutMe': 'About Me',
|
||||
'profile.memberSince': 'Member Since',
|
||||
'profile.sendMessage': 'Send Message',
|
||||
'profile.activity.playing': 'Playing',
|
||||
'profile.activity.listening': 'Listening to',
|
||||
'profile.activity.watching': 'Watching',
|
||||
'profile.activity.streaming': 'Streaming',
|
||||
'profile.activity.elapsed': '{time} elapsed',
|
||||
} as const;
|
||||
|
||||
export type TranslationKey = keyof typeof en;
|
||||
export type Dictionary = Record<TranslationKey, string>;
|
||||
Reference in New Issue
Block a user