Skip to content
On this page

国际化

3.0.0 起内置 vue-i18n@11,支持简体中文(zh-CN)与英文(en-US),顶栏可实时切换并持久化。

目录结构

bash
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 下的扩展组件保持原样,由使用方按需接入。

组件内使用

vue
<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():

ts
import { tr } from '@/locales';

const title = tr(route.meta.title);

tr() 与 t() 的区别:未命中语言包时 tr() 返回原始 key 字符串,适合标题类文案(后端菜单可能返回中文原文);t() 会走 vue-i18n 的缺失处理逻辑。

新增词条

在 zh-CN 对应命名空间添加词条,再在 en-US 中补齐:

ts
// 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:

ts
// src/router/modules/dashboard.ts
meta: {
  title: 'route.dashboard_console',
}

菜单、面包屑、多页签与浏览器标题在渲染时翻译,切换语言即时生效。详见 路由。

切换语言

顶栏的语言下拉会调用 useLocaleStore().setLocale():

ts
async setLocale(locale: LocaleType) {
  // 先加载语言包并切换 i18n,再更新响应式状态
  await setI18nLocale(locale);
  this.locale = locale;
}

顺序很重要:菜单等依赖 localeStore.locale 的 watcher 会在状态更新后触发,此时 i18n 必须已经切到新语言,否则首次切换会出现菜单不刷新的问题。

setI18nLocale 依次完成:

  1. 按需加载语言包(已加载则跳过)
  2. 更新 i18n.global.locale
  3. 写入 localStorage(LOCALE_KEY)
  4. 同步 <html lang>

语言持久化与初始值

  • 已保存的语言优先
  • 首次访问按浏览器语言推断(navigator.language),无法识别时回退 zh-CN
  • 语言包按需加载,不随语言数量增加首屏体积

Naive UI 语言同步

src/locales/naive.ts 导出 naiveLocales(locale + dateLocale)。src/App.vue 根据当前语言取对应语言包并传给 n-config-provider:

vue
<n-config-provider :locale="naiveLocale" :date-locale="naiveDateLocale">
ts
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,不需要一次性改完。

新增语言

  1. 新建 src/locales/lang/<locale>/ 并复制各命名空间文件
  2. 在 src/locales/types.ts 的 SUPPORT_LOCALES 中加入新语言,LocaleType 会自动推导
  3. 在 src/locales/types.ts 的 LOCALE_OPTIONS 中补充下拉选项(label 使用该语言的母语写法)
  4. 在 src/locales/index.ts 的 asyncLocaleLoaders 中注册异步加载器
  5. 在 src/locales/naive.ts 中补充 Naive UI 的 locale / dateLocale