外观
国际化
概述
前端基于 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);
}切换时做了两件事:
updatePreferences({ app: { locale } }):将语言写入偏好设置,默认持久化到localStorage,刷新/下次启动自动应用。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。
新增或修改文案
- 在
apps/web-ele/src/locales/langs/zh-CN/page.json(或对应文件)新增 key,如"user": { "title": "用户管理" }。 - 在
apps/web-ele/src/locales/langs/en-US/page.json同路径新增"user": { "title": "User Management" },保证 key 完全一致。 - 在代码中使用
$t('page.user.title')。
若文案属于框架通用能力(如新增一类 UI 提示),则改 packages/locales/src/langs/。
扩展更多语言
- 在
packages/locales/src/typing.ts的SupportedLanguagesType增加语言类型,如'ja-JP'。 - 在
packages/constants/src/core.ts的SUPPORT_LANGUAGES增加可选项。 - 在
packages/locales/src/langs/与apps/web-ele/src/locales/langs/下新建对应的语言目录(如ja-JP/),并完整翻译zh-CN目录下所有 key。 - 若需切换该语言的
Element Plus/dayjs包,在apps/web-ele/src/locales/index.ts的loadElementLocale/loadDayjsLocale中补充分支。
缺失 key 在非生产环境(
!import.meta.env.PROD)会在控制台打印[intlify] Not found ...警告,便于及时发现漏翻。