c6fb449a19
* feat(client): add Traditional Chinese (zh-TW) language support Update language switcher and i18n configuration to include Traditional Chinese. Modify locale resolution to prioritize exact matches (zh-TW) over base codes (zh), ensuring accurate browser language detection. Add complete translation set. Co-authored-by: Copilot <copilot@github.com> * feat(i18n): improve BCP-47 locale resolution and browser languages Refactor resolveLocale to use a normalize helper that correctly maps BCP-47 tags to supported locale keys, properly distinguishing Traditional vs Simplified Chinese variants. Additionally, iterate over navigator.languages instead of relying solely on navigator.language to respect the browser's full language preference list. Co-authored-by: Copilot <copilot@github.com> --------- Co-authored-by: Copilot <copilot@github.com>
53 lines
1.3 KiB
TypeScript
53 lines
1.3 KiB
TypeScript
import de from './locales/de'
|
|
import en from './locales/en'
|
|
import es from './locales/es'
|
|
import fr from './locales/fr'
|
|
import ja from './locales/ja'
|
|
import ko from './locales/ko'
|
|
import pt from './locales/pt'
|
|
import zh from './locales/zh'
|
|
import zhTW from './locales/zh-TW'
|
|
|
|
export type LocaleMessages = Record<string, unknown>
|
|
|
|
export const rawMessages = {
|
|
'en': en,
|
|
'zh': zh,
|
|
'zh-TW': zhTW,
|
|
'ja': ja,
|
|
'ko': ko,
|
|
'fr': fr,
|
|
'es': es,
|
|
'de': de,
|
|
'pt': pt,
|
|
} satisfies Record<string, LocaleMessages>
|
|
|
|
function isPlainObject(value: unknown): value is LocaleMessages {
|
|
return !!value && typeof value === 'object' && !Array.isArray(value)
|
|
}
|
|
|
|
export function mergeMessagesWithFallback(
|
|
fallback: LocaleMessages,
|
|
locale: LocaleMessages,
|
|
): LocaleMessages {
|
|
const merged: LocaleMessages = { ...fallback }
|
|
|
|
for (const [key, value] of Object.entries(locale)) {
|
|
const fallbackValue = fallback[key]
|
|
merged[key] = isPlainObject(fallbackValue) && isPlainObject(value)
|
|
? mergeMessagesWithFallback(fallbackValue, value)
|
|
: value
|
|
}
|
|
|
|
return merged
|
|
}
|
|
|
|
export const messages = Object.fromEntries(
|
|
Object.entries(rawMessages).map(([locale, localeMessages]) => [
|
|
locale,
|
|
locale === 'en'
|
|
? localeMessages
|
|
: mergeMessagesWithFallback(en, localeMessages),
|
|
]),
|
|
) as typeof rawMessages
|