Files
BYW-VoiceHub/app/plugins/locale.ts
T

60 lines
2.2 KiB
TypeScript

import {
LOCALE_COOKIE_KEY,
LOCALE_PREFERENCE_KEY,
isSupportedLocale,
loadLocaleMessages,
resolveClientInitialLocale,
resolveLocaleFromAcceptLanguage,
setLocale,
useLocale,
type Locale,
type LocalePreference
} from '~/utils/locale'
// 语言初始化插件(服务端 + 客户端通用)。
// - 仅当用户手动选择过语言(偏好为 manual)时信任 cookie 中保存的语言;
// 否则每次进入都按 Accept-Language / 浏览器语言跟随系统语言,系统语言变化后自动切换。
// - 客户端沿用服务端解析结果(cookie)以保证水合一致,cookie 缺失时才按浏览器语言解析。
// 在渲染前 await 目标语言词典,避免懒加载导致的水合不匹配。
export default defineNuxtPlugin(async () => {
const { currentLocale } = useLocale()
const localeCookie = useCookie<Locale | undefined>(LOCALE_COOKIE_KEY, {
maxAge: 60 * 60 * 24 * 365,
sameSite: 'lax',
path: '/'
})
const preferenceCookie = useCookie<LocalePreference | undefined>(LOCALE_PREFERENCE_KEY, {
maxAge: 60 * 60 * 24 * 365,
sameSite: 'lax',
path: '/'
})
let resolved: Locale
let isManualPreference = false
if (preferenceCookie.value === 'manual' && isSupportedLocale(localeCookie.value)) {
isManualPreference = true
resolved = localeCookie.value
} else if (import.meta.server) {
const headers = useRequestHeaders(['accept-language'])
resolved = resolveLocaleFromAcceptLanguage(headers['accept-language'])
} else if (isSupportedLocale(localeCookie.value)) {
// 沿用服务端解析结果(本次会话跟随系统得到),避免水合不一致
resolved = localeCookie.value
} else {
resolved = resolveClientInitialLocale()
}
// 渲染前确保词典就绪:中文为静态内置;非兜底语言在此 await 其动态 chunk。
await loadLocaleMessages(resolved)
setLocale(resolved, isManualPreference)
// 由当前语言驱动 <html lang>,服务端渲染即写入,客户端切换语言时响应式更新。
useHead({ htmlAttrs: { lang: currentLocale } })
if (import.meta.client) {
watch(currentLocale, (value) => {
localeCookie.value = value
})
}
})