/** * 按路由加载页面级翻译到 page 命名空间 * 路由 /dice/lottery_pool_config/index -> 加载 langs/{locale}/dice/lottery_pool_config.json */ import i18n from '@/locales' import { LanguageEnum } from '@/enums/appEnum' /** 路由 path 到 locale 文件路径的映射(无前导斜杠、无 /index) */ export function getPageLocalePath(routePath: string): string | null { if (!routePath || routePath === '/') return null const normalized = routePath.replace(/\?.*$/, '').replace(/#.*$/, '').replace(/\/$/, '') const withoutIndex = normalized.replace(/\/index$/i, '') || '/' const path = withoutIndex.replace(/^\//, '') || '' if (!path) return null return path } type PageLocaleModule = { default: Record } const enModules = import.meta.glob('./langs/en/**/*.json') const zhModules = import.meta.glob('./langs/zh/**/*.json') function getModuleKey(locale: string, path: string): string { return `./langs/${locale}/${path}.json` } let lastLoadedPath: string | null = null let lastLoadedLocale: string | null = null /** 获取当前语言(locale 可能是 string 或 Ref) */ function getCurrentLocale(): string { const loc = i18n.global.locale return typeof loc === 'string' ? loc : (loc as { value: string }).value } /** * 加载并合并页面翻译到 i18n 的 page 命名空间 */ export async function loadPageLocale(routePath: string): Promise { const path = getPageLocalePath(routePath) if (!path) { clearPageLocale() return } const locale = getCurrentLocale() const modules = locale === LanguageEnum.EN ? enModules : zhModules const tryPaths: string[] = [path] // 兼容别名路由:菜单 path 为短名但 locale 文件位于模块子目录 // 例如:/user -> system/user,/game -> dice/game if (!path.includes('/')) { tryPaths.push(`system/${path}`) // 兜底:在任意一级子目录下查找同名文件 const suffix = `/${path}.json` const localePrefix = `./langs/${locale}/` for (const key of Object.keys(modules)) { if (key.startsWith(localePrefix) && key.endsWith(suffix)) { const candidate = key.slice(localePrefix.length, -'.json'.length) if (!tryPaths.includes(candidate)) { tryPaths.push(candidate) } } } } let matchedPath: string | null = null let loader: (() => Promise) | undefined for (const p of tryPaths) { const key = getModuleKey(locale, p) const l = modules[key] if (l) { matchedPath = p loader = l break } } if (!loader) { clearPageLocale() return } if (lastLoadedPath === matchedPath && lastLoadedLocale === locale) { return } try { const mod = await loader() const message = mod?.default if (message && typeof message === 'object') { i18n.global.mergeLocaleMessage(locale, { page: message }) lastLoadedPath = matchedPath lastLoadedLocale = locale } } catch { clearPageLocale() } } /** * 清除 page 命名空间(进入无页面翻译的路由时调用) */ export function clearPageLocale(): void { const locale = getCurrentLocale() const messages = i18n.global.getLocaleMessage(locale) as Record if (messages && 'page' in messages) { const next = { ...messages } delete next.page i18n.global.setLocaleMessage(locale, next) } lastLoadedPath = null lastLoadedLocale = null } /** * 语言切换时清空缓存,下次进入页面会重新加载 */ export function invalidatePageLocaleCache(): void { lastLoadedPath = null lastLoadedLocale = null }