Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/client/src/components/layout/LanguageSwitch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { NSelect } from 'naive-ui'
const { locale } = useI18n()

const options = [
{ label: '中文', value: 'zh' },
{ label: '简体中文', value: 'zh' },
{ label: '繁體中文', value: 'zh-TW' },
{ label: 'English', value: 'en' },
{ label: '日本語', value: 'ja' },
{ label: '한국어', value: 'ko' },
Expand Down
33 changes: 27 additions & 6 deletions packages/client/src/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,45 @@ import { createI18n } from 'vue-i18n'
import { messages } from './messages'

const saved = localStorage.getItem('hermes_locale')
const detected = navigator.language.slice(0, 2)

const supportedLocales = ['en', 'zh', 'ja', 'ko', 'fr', 'es', 'de', 'pt'] as const
const supportedLocales = ['en', 'zh', 'zh-TW', 'ja', 'ko', 'fr', 'es', 'de', 'pt'] as const
type SupportedLocale = (typeof supportedLocales)[number]

function resolveLocale(saved: string | null, detected: string): SupportedLocale {
function resolveLocale(saved: string | null): SupportedLocale {
if (saved && (supportedLocales as readonly string[]).includes(saved)) {
return saved as SupportedLocale
}
if ((supportedLocales as readonly string[]).includes(detected)) {
return detected as SupportedLocale

// Normalize a single BCP-47 tag to a supported locale key.
// Covers zh-Hant-TW, zh-TW, zh-HK, zh-MO, zh-Hant → zh-TW
// zh-Hans-*, zh-CN, zh-SG, zh → zh
function normalize(tag: string): SupportedLocale | null {
const lower = tag.toLowerCase()
if (lower.startsWith('zh')) {
const isTraditional =
lower.includes('hant') ||
lower.includes('-tw') ||
lower.includes('-hk') ||
lower.includes('-mo')
return isTraditional ? 'zh-TW' : 'zh'
}
const short = tag.slice(0, 2)
if ((supportedLocales as readonly string[]).includes(tag)) return tag as SupportedLocale
if ((supportedLocales as readonly string[]).includes(short)) return short as SupportedLocale
return null
}

for (const lang of navigator.languages) {
const resolved = normalize(lang)
if (resolved) return resolved
}

return 'en'
}

export const i18n = createI18n({
legacy: false,
locale: resolveLocale(saved, detected),
locale: resolveLocale(saved),
fallbackLocale: 'en',
messages,
})
Loading
Loading