feat(desktop): add 15-language i18n — hybrid JSON+TypeScript system - #38846
feat(desktop): add 15-language i18n — hybrid JSON+TypeScript system#38846iaendi wants to merge 188 commits into
Conversation
- Add React Context-based i18n system (store/i18n.tsx, hooks/use-translation.ts) - Support 7 languages: en, zh-CN, ja, ko, de, es, fr - Auto-detect system language, manual override with persistence - Complete Chinese (zh-CN) translations — 786/799 keys (98.4%) - Japanese and Korean partial translations (21 keys each) - German, Spanish, French as extensible English-stub locale files - Language selector in Settings → Appearance - Module-level _currentLocale for non-React code compatibility - localeLoaders map for easy new language registration - ~50 components updated: settings, shell, chat, overlays, sidebars, command center Closes NousResearch#37897, NousResearch#38064, NousResearch#37793, NousResearch#37562, NousResearch#37543, NousResearch#37503, NousResearch#37295, NousResearch#33749
…iptions - Translate color modes: Light→浅色, Dark→深色, System→跟随系统 - Translate theme labels: Midnight→午夜, Ember→余烬, Mono→单色, etc. - Add translateProviderDesc() for backend API key descriptions - 27 provider description mappings (DeepSeek, OpenAI, Anthropic, etc.) - Provider names preserved as-is (user request) - Add 45 new i18n keys to en.json and zh-CN.json
- Fix 53 provider description mappings to match exact backend config.py strings - Add missing providers: NVIDIA, LM Studio, StepFun, Arcee, GMI Cloud, Ollama Cloud, AWS Bedrock, Azure Foundry, Exa, Parallel, and more - Add base URL override translations - All descriptions now correctly matched and translated to zh-CN
- Previous approach used exported function in i18n.tsx — was tree-shaken by Vite - New approach: module-level PROVIDER_DESC_MAP + providerDesc() in keys-settings.tsx - Import t as providerT from @/store/i18n for standalone lookup - 38 provider descriptions mapped to i18n keys - No changes to i18n.tsx — keeps it clean - Build verified: tsc + vite pass, function present in bundle
To add a new language, just drop a {code}.json file into src/locales/.
No code changes needed — i18n.tsx auto-discovers all *.json files at build time.
- Replace hardcoded localeLoaders with import.meta.glob
- SUPPORTED_LOCALES now computed from available files
- LANGUAGE_LABELS centralized in i18n store
- Locale type simplified from union to string
- appearance-settings uses availableLocales from context
- Keys revert to raw description (API key translation deferred)
…anish, French All 7 languages now have full 857-key coverage: - en: 857/857 (source) - zh-CN: 843/857 (98%) - ja: 825/857 (96%) - ko: 832/857 (97%) - de: 804/857 (94%) - es: 822/857 (96%) - fr: 811/857 (95%) Remaining untranslated keys are intentional (language names, technical terms)
…globe icon - Add zh-TW locale with 857 keys (Simplified→Traditional conversion) - Add globe icon LanguageMenuButton to titlebar (right cluster) - Language switcher shows all 8 languages with native names - Active language highlighted with check mark - Default follows system language - Accidental escape fixes in titlebar-controls.tsx
…age icon - Fill remaining untranslated keys in ja, ko, de, es, fr (reaching 98-100% coverage) - Rename zh-TW.json to zh-Hant.json (neutral Traditional Chinese) - Update all 8 locale files with language.zh-Hant key - Replace Globe icon with Language icon (Tabler IconLanguage) - Add Language to icons.ts exports - Delete legacy zh-TW.json
…le sync - LanguageMenuButton: Globe 🌐 + Language 文A side-by-side, w-auto width - Titlebar gap: gap-x-1 → gap-x-1.5 for better spacing - useLocaleSync() hook: forces re-render of standalone t() consumers - I18nProvider: onLocaleChange listener system for non-Context components - TitlebarControls + useStatusbarItems now use useLocaleSync() - Eliminates the 30s+ delay for Gateway/Agents/Cron statusbar labels
- IconWorld has clear grid lines, doesn't look like a microphone - Added WorldGlobe to @/lib/icons.ts
- Replaced tabler IconWorld (tree-shaken in bundle) with inline SVG - SVG: circle + equator line + two meridian arcs - Same size and styling as other titlebar icons
…ale delay - Language button: focus-visible:outline-0 to remove orange ring - useLocaleSync() now returns version number for useMemo deps - useStatusbarItems: add localeVersion to all useMemo dep arrays - This ensures Gateway/Agents/Cron labels update instantly on locale change
Re-triage: the live PR scope is 522 files, including unrelated core agent, gateway, CLI, platform, tool, CI, and packaging deltas beyond the Desktop i18n feature. It also removes background-review cache-parity regression coverage while merged #64379 retains the production repair. Please rebase and split before review; related work is #38083, #38183, and #64379. |
|
Thanks for the re-triage, @alt-glitch. A few notes:
Will update once the clean PR is ready. Appreciate the detailed triage. |
Re-triage on current head |
…ey alignment, [skip ci]
- sync-locales.py: add TS type annotations (count:number, label:string etc)
- sync-locales.py: fix single-param arrow fn parentheses in object literal
- JSON locales: remove keys not in upstream Translations type
- JSON locales: add {provider}/{count} placeholders for function-typed keys
- JSON locales: rename mismatched keys (noProfilesYet→noProfiles etc)
- submit.ts: fix 6 merge artifact syntax errors
- upstream sync: resolve merge conflicts, push behind_by→0
|
Thanks for the re-triage @alt-glitch. Done: -> Split to i18n-only PR: #69819 — 35 files, Desktop-i18n-only scope (down from 522) The old branch (feat/i18n-desktop-multilingual) accumulated cruft from repeated upstream merges. The new clean branch contains only:
|
|
Superseded by #69819 — clean i18n-only split as requested. All 15 languages ported, 0 type errors, 35 files (down from 522). |
Hybrid JSON + TypeScript i18n — 15 Desktop locales
Adds 11 new Desktop UI locales to the framework that landed in #38241, expanding from 4 to 15 languages. Uses a hybrid workflow that combines the translator-friendliness of JSON with the type safety of upstream's TypeScript framework.
New locales (11):
ko (한국어), de (Deutsch), es (Español), fr (Français), pt-BR (Português Brasil), ar (العربية), hi (हिन्दी), th (ภาษาไทย), vi (Tiếng Việt), it (Italiano), ru (Русский)
Architecture
How it works
apps/desktop/src/locales/): flat key-value, ~850 Desktop UI strings each. Translators only edit JSON.apps/desktop/src/i18n/): uses upstream'sdefineLocale()pattern. Missing keys fall back to English. TypeScript validates against the Translations interface.apps/desktop/scripts/sync-locales.py): validates JSON keys against en.json, generates .ts files, updates catalog.ts/types.ts/languages.ts.{code}.jsoninto locales/ → add to KNOWN_LOCALES → runsync-locales.py.Why hybrid
Files
Closes the Russian Desktop locale gap in #40347.