From d8552b2e6fea542bcf036d16489a4ae16777038a Mon Sep 17 00:00:00 2001 From: Celia Smitham Date: Tue, 6 Jan 2026 07:19:56 +0000 Subject: [PATCH 1/3] Choose best language from the user browser --- ui/i18n/locale_service.ts | 43 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/ui/i18n/locale_service.ts b/ui/i18n/locale_service.ts index 7be1464c21..237ad016e4 100644 --- a/ui/i18n/locale_service.ts +++ b/ui/i18n/locale_service.ts @@ -13,7 +13,7 @@ export const getLang = (): string => { if (storedLang && storedLang in supportedLanguages) { return storedLang; } - return setLang('en'); + return setLang(detectUserLanguage()); }; export const setLang = (lang: string): string => { @@ -27,6 +27,47 @@ export const setLang = (lang: string): string => { return lang; }; +const languageAliases: Record = { + 'zh-CN': 'cn', + 'zh': 'cn', + 'en-US': 'en', + 'en-GB': 'en', + 'fr-FR': 'fr', + 'fr-CA': 'fr', +}; + +function getBrowserLanguages(): string[] { + if (typeof navigator === 'undefined') { + return []; + } + return 'languages' in navigator && Array.isArray((navigator as any).languages) + ? [...navigator.languages] + : [(navigator as any).language || 'en']; +} + +function detectUserLanguage(defaultLang: string = 'en'): string { + const browserLangs = getBrowserLanguages(); + if (browserLangs.length === 0) { + return defaultLang; + } + for (const lang of browserLangs) { + if (supportedLanguages.hasOwnProperty(lang)) { + return lang; + } + const shortLang = lang.split('-')[0].toLowerCase(); + if (supportedLanguages.hasOwnProperty(shortLang)) { + return shortLang; + } + if (languageAliases.hasOwnProperty(lang) && supportedLanguages.hasOwnProperty(languageAliases[lang])) { + return languageAliases[lang]; + } + if (languageAliases.hasOwnProperty(shortLang) && supportedLanguages.hasOwnProperty(languageAliases[shortLang])) { + return languageAliases[shortLang]; + } + } + return defaultLang; +} + // Add TypeScript interface for i18next on window declare global { interface Window { From 80f50c534083c5530109755f423a440087addacb Mon Sep 17 00:00:00 2001 From: Celia Smitham Date: Tue, 6 Jan 2026 07:44:40 +0000 Subject: [PATCH 2/3] Refactor to get the best language for user --- ui/i18n/locale_service.ts | 50 ++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/ui/i18n/locale_service.ts b/ui/i18n/locale_service.ts index 237ad016e4..735aa70173 100644 --- a/ui/i18n/locale_service.ts +++ b/ui/i18n/locale_service.ts @@ -27,45 +27,47 @@ export const setLang = (lang: string): string => { return lang; }; -const languageAliases: Record = { - 'zh-CN': 'cn', - 'zh': 'cn', - 'en-US': 'en', - 'en-GB': 'en', - 'fr-FR': 'fr', - 'fr-CA': 'fr', -}; +const languageMap = new Map([ + ['en-US', 'en'], + ['en-GB', 'en'], + ['en-AU', 'en'], + ['en', 'en'], + ['fr-FR', 'fr'], + ['fr-CA', 'fr'], + ['fr', 'fr'], + ['zh-CN', 'cn'], + ['zh-Hans', 'cn'], + ['zh', 'cn'], +]); function getBrowserLanguages(): string[] { if (typeof navigator === 'undefined') { return []; } - return 'languages' in navigator && Array.isArray((navigator as any).languages) - ? [...navigator.languages] - : [(navigator as any).language || 'en']; + if (Array.isArray(navigator.languages)) { + return navigator.languages; + } + const lang = (navigator as any).language || (navigator as any).browserLanguage || (navigator as any).userLanguage; + return lang ? [lang] : []; } function detectUserLanguage(defaultLang: string = 'en'): string { const browserLangs = getBrowserLanguages(); - if (browserLangs.length === 0) { - return defaultLang; - } for (const lang of browserLangs) { - if (supportedLanguages.hasOwnProperty(lang)) { - return lang; + const normalized = lang.toLowerCase(); + if (normalized in supportedLanguages) { + return normalized; } - const shortLang = lang.split('-')[0].toLowerCase(); - if (supportedLanguages.hasOwnProperty(shortLang)) { + const shortLang = normalized.split('-')[0]; + if (shortLang in supportedLanguages) { return shortLang; } - if (languageAliases.hasOwnProperty(lang) && supportedLanguages.hasOwnProperty(languageAliases[lang])) { - return languageAliases[lang]; - } - if (languageAliases.hasOwnProperty(shortLang) && supportedLanguages.hasOwnProperty(languageAliases[shortLang])) { - return languageAliases[shortLang]; + const mapped = languageMap.get(normalized) || languageMap.get(shortLang); + if (mapped && mapped in supportedLanguages) { + return mapped; } } - return defaultLang; + return defaultLang in supportedLanguages ? defaultLang : 'en'; } // Add TypeScript interface for i18next on window From c4aadfc1bbf934985add517815d65944361fd71e Mon Sep 17 00:00:00 2001 From: Celia Smitham Date: Tue, 6 Jan 2026 09:05:07 +0000 Subject: [PATCH 3/3] Refactor the function to get the browser language --- ui/i18n/locale_service.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/ui/i18n/locale_service.ts b/ui/i18n/locale_service.ts index 735aa70173..77b7545638 100644 --- a/ui/i18n/locale_service.ts +++ b/ui/i18n/locale_service.ts @@ -40,19 +40,8 @@ const languageMap = new Map([ ['zh', 'cn'], ]); -function getBrowserLanguages(): string[] { - if (typeof navigator === 'undefined') { - return []; - } - if (Array.isArray(navigator.languages)) { - return navigator.languages; - } - const lang = (navigator as any).language || (navigator as any).browserLanguage || (navigator as any).userLanguage; - return lang ? [lang] : []; -} - function detectUserLanguage(defaultLang: string = 'en'): string { - const browserLangs = getBrowserLanguages(); + const browserLangs = typeof navigator !== 'undefined' && navigator.language ? [navigator.language] : []; for (const lang of browserLangs) { const normalized = lang.toLowerCase(); if (normalized in supportedLanguages) {