Skip to content

国际化 ​

概述 ​

前端基于 vue-i18n(v9,组合式 API 模式)实现多语言,并配套切换了 Element Plus 与 dayjs 的语言包,使界面、组件库、日期格式随用户选择的语言保持一致。默认语言为简体中文(zh-CN),当前内置 zh-CN 与 en-US 两种语言。

整体架构 ​

语言包按职责分为两层:框架/通用层与业务层。两者在运行时被合并为同一份 vue-i18n 消息,按命名空间(JSON 顶层 key)区分归属。

  • 框架/通用层 packages/locales/src/langs/:由 @vben/locales 提供,包含 common、ui、authentication、preferences、profile 等通用命名空间,所有基于 Vben 的 App 共享。
  • 业务层 apps/web-ele/src/locales/langs/:仅 web-ele 业务使用,包含 page、utils 等业务命名空间,通过 setupI18n 的 loadMessages 钩子注入并合并。

语言包目录结构 ​

语言包以 JSON 文件存储,目录即语言、文件名即命名空间:

text
packages/locales/src/langs/
├── zh-CN/
│   ├── authentication.json   # 登录/注册相关
│   ├── common.json           # 通用按钮、提示
│   ├── preferences.json      # 偏好设置面板
│   ├── profile.json          # 个人中心
│   └── ui.json               # 表单校验、动作提示、上传等 UI 文案
└── en-US/
    └── ...(与 zh-CN 同名文件一一对应)

apps/web-ele/src/locales/langs/
├── zh-CN/
│   ├── page.json             # 业务页面文案(如 dashboard、auth、action)
│   └── utils.json            # 工具类文案(如时间范围选择器)
└── en-US/
    └── ...(同上)

每新增/修改一种语言,需同时维护 zh-CN 与 en-US 两个目录下同名 JSON,保证 key 一致。

加载与合并机制 ​

语言包通过 Vite 的 import.meta.glob 在编译期自动收集(见 frontend/packages/locales/src/i18n.ts),无需手动 import 每个 JSON:

ts
const modules = import.meta.glob('./langs/**/*.json');

const localesMap = loadLocalesMapFromDir(
  /\.\/langs\/([^/]+)\/(.*)\.json$/,
  modules,
);

loadLocalesMapFromDir 用正则把路径拆解为「语言 / 文件名」,运行时按语言懒加载并拼装成 { <命名空间>: <内容> } 的消息对象。web-ele 在 src/locales/index.ts 中通过 setupI18n 的 loadMessages 钩子,把业务语言包与框架语言包合并:

ts
async function loadMessages(lang: SupportedLanguagesType) {
  const [appLocaleMessages] = await Promise.all([
    localesMap[lang]?.(),
    loadThirdPartyMessage(lang),
  ]);
  return appLocaleMessages?.default;
}

框架默认语言来自 packages/@core/preferences/src/config.ts:

ts
    locale: 'zh-CN',

受支持的语言类型由 packages/locales/src/typing.ts 定义:

ts
export type SupportedLanguagesType = 'en-US' | 'zh-CN';

语言切换 ​

切换入口是顶栏的 LanguageToggle 组件(可在偏好设置面板的「小组件」中开启/关闭)。其切换逻辑:

ts
async function handleUpdate(value: string | undefined) {
  if (!value) return;
  const locale = value as SupportedLanguagesType;
  updatePreferences({
    app: {
      locale,
    },
  });
  await loadLocaleMessages(locale);
}

切换时做了两件事:

  1. updatePreferences({ app: { locale } }):将语言写入偏好设置,默认持久化到 localStorage,刷新/下次启动自动应用。
  2. loadLocaleMessages(locale):加载并 merge 对应语言包,同时切换 Element Plus 与 dayjs 的语言包(见 loadThirdPartyMessage)。

可选项 SUPPORT_LANGUAGES 定义在 packages/constants/src/core.ts,控制下拉菜单的可选项与展示文案:

ts
export const SUPPORT_LANGUAGES: LanguageOption[] = [
  { label: '简体中文', value: 'zh-CN' },
  { label: 'English', value: 'en-US' },
];

在代码中使用 ​

全局 $t ​

vue-i18n 开启了 globalInjection,在模板与 <script setup> 中均可直接使用 $t:

vue
<template>
  <span>{{ $t('common.delete') }}</span>
</template>

<script setup lang="ts">
import { $t } from '#/locales';

ElMessage.success($t('ui.actionMessage.operationSuccess'));
</script>

使用 useI18n ​

在需要 t、te、tm 等完整能力的组合式函数中,也可显式调用:

ts
import { useI18n } from 'vue-i18n';

const { t } = useI18n();
console.log(t('common.noData'));

带参数的文案 ​

JSON 中用 {0}、{1} 占位,调用时传入数组:

json
"deleteConfirm": "确定删除 {0} 吗?"
ts
$t('ui.actionMessage.deleteConfirm', [row.username]);

路由标题翻译 ​

路由 meta.title 使用 i18n key,由 bootstrap.ts 在动态标题中翻译,菜单与浏览器标签同步多语言:

ts
  watchEffect(() => {
    if (preferences.app.dynamicTitle) {
      const routeTitle = router.currentRoute.value.meta?.title;
      const pageTitle =
        (routeTitle ? `${$t(routeTitle)} - ` : '') + preferences.app.name;
      useTitle(pageTitle);
    }
  });

命名空间约定 ​

建议按语义划分子树,避免扁平命名导致冲突:

命名空间用途所在层
common通用按钮、确认、必填等框架
ui表单校验、动作提示、上传、组件文案框架
authentication登录/注册/找回密码框架
preferences偏好设置面板框架
profile个人中心框架
page业务页面文案(dashboard、auth、action、tenant…)业务
utils工具类文案(如时间范围)业务

业务页面优先复用 common、ui、action 等通用 key,仅在确有业务专属文案时新增 page 命名空间下的 key。

新增或修改文案 ​

  1. 在 apps/web-ele/src/locales/langs/zh-CN/page.json(或对应文件)新增 key,如 "user": { "title": "用户管理" }。
  2. 在 apps/web-ele/src/locales/langs/en-US/page.json 同路径新增 "user": { "title": "User Management" },保证 key 完全一致。
  3. 在代码中使用 $t('page.user.title')。

若文案属于框架通用能力(如新增一类 UI 提示),则改 packages/locales/src/langs/。

扩展更多语言 ​

  1. 在 packages/locales/src/typing.ts 的 SupportedLanguagesType 增加语言类型,如 'ja-JP'。
  2. 在 packages/constants/src/core.ts 的 SUPPORT_LANGUAGES 增加可选项。
  3. 在 packages/locales/src/langs/ 与 apps/web-ele/src/locales/langs/ 下新建对应的语言目录(如 ja-JP/),并完整翻译 zh-CN 目录下所有 key。
  4. 若需切换该语言的 Element Plus / dayjs 包,在 apps/web-ele/src/locales/index.ts 的 loadElementLocale / loadDayjsLocale 中补充分支。

缺失 key 在非生产环境(!import.meta.env.PROD)会在控制台打印 [intlify] Not found ... 警告,便于及时发现漏翻。