国际化
3.0.0 起内置 vue-i18n@11,支持简体中文(zh-CN)与英文(en-US),顶栏可实时切换并持久化。
目录结构
src/locales
├── index.ts # createI18n、语言包加载、tr()、切换语言
├── naive.ts # Naive UI locale / dateLocale 映射
├── helper.ts # 浏览器语言推断、<html lang> 同步
├── types.ts # LocaleType、LOCALE_KEY、DEFAULT_LOCALE
└── lang
├── zh-CN # 默认语言,随首屏加载
│ ├── index.ts # 汇总并导出各命名空间
│ ├── common.ts
│ ├── route.ts
│ ├── layout.ts
│ ├── login.ts
│ └── about.ts
└── en-US # 按需异步加载
└── ...
已翻译范围
- 路由菜单、面包屑、多页签、浏览器标签页标题
- 顶栏、项目配置面板
- 登录页、关于页
- Naive UI 组件文案(
locale/date-locale跟随切换)
业务页面与 src/components 下的扩展组件保持原样,由使用方按需接入。
组件内使用
<script setup lang="ts">
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
</script>
<template>
<n-button>{{ t('common.refresh') }}</n-button>
</template>
组件外使用
路由生成、菜单转换、document.title 等非组件场景使用 tr():
import { tr } from '@/locales';
const title = tr(route.meta.title);
tr() 与 t() 的区别:未命中语言包时 tr() 返回原始 key 字符串,适合标题类文案(后端菜单可能返回中文原文);t() 会走 vue-i18n 的缺失处理逻辑。
新增词条
在 zh-CN 对应命名空间添加词条,再在 en-US 中补齐:
// src/locales/lang/zh-CN/common.ts
export default {
refresh: '刷新',
};
// src/locales/lang/en-US/common.ts
export default {
refresh: 'Refresh',
};
英文语言包通过 satisfies typeof zhMessages 约束:键名缺失或多余都会在 pnpm type-check 阶段报错。
新增命名空间时,还需要在 zh-CN/index.ts 与 en-US/index.ts 中同时导入并注册。
路由标题
meta.title 使用 i18n key(如 route.dashboard_console),词条放在 src/locales/lang/<locale>/route.ts:
// src/router/modules/dashboard.ts
meta: {
title: 'route.dashboard_console',
}
菜单、面包屑、多页签与浏览器标题在渲染时翻译,切换语言即时生效。详见 路由。
切换语言
顶栏的语言下拉会调用 useLocaleStore().setLocale():
async setLocale(locale: LocaleType) {
// 先加载语言包并切换 i18n,再更新响应式状态
await setI18nLocale(locale);
this.locale = locale;
}
顺序很重要:菜单等依赖 localeStore.locale 的 watcher 会在状态更新后触发,此时 i18n 必须已经切到新语言,否则首次切换会出现菜单不刷新的问题。
setI18nLocale 依次完成:
- 按需加载语言包(已加载则跳过)
- 更新
i18n.global.locale - 写入
localStorage(LOCALE_KEY) - 同步
<html lang>
语言持久化与初始值
- 已保存的语言优先
- 首次访问按浏览器语言推断(
navigator.language),无法识别时回退zh-CN - 语言包按需加载,不随语言数量增加首屏体积
Naive UI 语言同步
src/locales/naive.ts 导出 naiveLocales(locale + dateLocale)。src/App.vue 根据当前语言取对应语言包并传给 n-config-provider:
<n-config-provider :locale="naiveLocale" :date-locale="naiveDateLocale">
const naiveLocale = computed(() => naiveLocales[localeStore.locale ?? DEFAULT_LOCALE].locale);
const naiveDateLocale = computed(() => naiveLocales[localeStore.locale ?? DEFAULT_LOCALE].dateLocale);
这样日期选择器、空状态、分页等组件文案会跟随切换。
后端动态菜单
BACK 模式下,src/router/generator.ts 保留后端返回的原始 meta.title,不做预翻译:
- 返回 i18n key(如
route.dashboard_console)→ 跟随语言切换 - 返回纯中文标题(如
主控台)→ 未命中语言包,原样显示
因此后端可以渐进式迁移到 key,不需要一次性改完。
新增语言
- 新建
src/locales/lang/<locale>/并复制各命名空间文件 - 在
src/locales/types.ts的SUPPORT_LOCALES中加入新语言,LocaleType会自动推导 - 在
src/locales/types.ts的LOCALE_OPTIONS中补充下拉选项(label 使用该语言的母语写法) - 在
src/locales/index.ts的asyncLocaleLoaders中注册异步加载器 - 在
src/locales/naive.ts中补充 Naive UI 的locale/dateLocale
Naive Ui Admin