1.1 前言
关于最近项目实现国际化改造的一些记录,针对 vue 项目,使用 vue-i18n 库。
1.2 对工作量的清晰认识
- 词条提取翻译:文本要用翻译函数 $t 包裹、词条写入 json、json 和 excel 转换
- 布局样式修改:文本翻译后可能溢出、排版错乱等,需要针对不同语言分别处理
- 功能修正:用中文做判断的地方、后端返回的中文等,需要修改原来逻辑
- 第三方库的国际化:组件库一般都有提供不同语言,但有些库是没有的,那就很麻烦
- 有些图片或文件包含中文,就需要提供不同语言的版本
从以上 5 点和页面复杂度来正确评估工作量,避免过于乐观!
(可以先拿一个简单页面和一个复杂页面进行国际化整改,记录花费的时间)
1.2 vue-i18n 使用
官网文档:vue-i18n.intlify.dev/guide/advan...
使用总结:
js
// main.ts
import i18n from './i18n/create';
app.use(i18n);
// create.ts
import { createI18n } from 'vue-i18n';
import zh-CN from './zh-CN.json';
import en-US from './en-US.json';
const currentLang = localStorage.getItem('lang') || 'zh-CN'; // 从本地存储中获取当前语言
const i18n = createI18n({
legacy: false, // 使用Composition API模式
globalInjection: true, // 在组件注入全局Composer实例的属性和方法,这样即使是Composition API模式,也能在模板上直接使用 $t、$i18n等
locale: currentLang, // 主语言
fallbackLocale: currentLang, // 备用
messages: {
'zh-CN': zh-CN,
'en-US': en-US,
},
});
export default i18n;
// zh-CN.json
// 将词条分成【global】和【页面】两大类来维护:能复用的就放在global,页面特有的就放在页面路由名称下
{
"global": {
"confirm": "确认",
"cancel": "取消",
"enter": "请输入"
},
"页面路由名称": {
"639423-0": "全部阶段"
}
}
// 组件内使用
$t('orderNew.799657-1') // 引用词条
$t('orderNew.799657-273', [used, total] // 动态拼接词条
:width="{ 'en-US': '150px' }[locale] || '100px'" // 动态设置不同语言样式
import { useI18n } from 'vue-i18n'
// global使用全局Composer实例,也是默认值
// local使用本地Composer实例,只在本地需要语言特殊化处理时使用
const { t: $t, locale } = useI18n({ useScope: 'global' });
const isZhCN = computed(() => locale.value === 'zh-CN')
const isEnUS = computed(() => locale.value === 'en-US')
locale.value = 'en-US'; // 直接修改 locale 就能切换语言
[lang="en-US"] & {
// 针对en-US做样式调整
}
1.3 维护词条
使用 Excel 管理词条:
- 前端先将不同语言 json 合并转换成 excel
- 然后产品或测试修改词条翻译(或交给专业的翻译人员处理)
- 等翻译改好后,前端再将 excel 转换成不同语言 json
需要实现两个脚本:json 合并转换 excel、excel 导出不同语言 json
假设维护词条的 excel 表格如下:
key | zh | en |
---|---|---|
common.ok | 确定 | OK |
common.cancel | 取消 | Cancel |
login.username | 用户名 | Username |
login.password | 密码 | Password |
excel 导出 json 脚本:
js
const xlsx = require('xlsx');
const fs = require('fs');
const path = require('path');
const { set } = require('lodash');
const workbook = xlsx.readFile('./i18n.xlsx');
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const data = xlsx.utils.sheet_to_json(sheet);
const langs = ['zh', 'en'];
const result = { zh: {}, en: {} };
data.forEach((row) => {
const key = row['key'];
if (!key) return;
langs.forEach((lang) => {
set(result[lang], key, row[lang] || '');
});
});
langs.forEach((lang) => {
const filePath = path.resolve(__dirname, `./${lang}.json`);
fs.writeFileSync(filePath, JSON.stringify(result[lang], null, 2), 'utf-8');
console.log(`输出 ${lang}.json 成功!`);
});
1.3 切换全局语言
关键点:
- 切换后当前语言存储在 localStorage,在非 vue 场景使用(比如:初始化 createI18n 时)
- 切换后改变 html 的 lang 属性,用于针对改某一语言的样式
- 切换后刷新当前页面,使组件重新渲染,接口重新调用
- 在请求拦截器的 header 增加 lang 字段,表示当前使用的语言
参考代码:
js
const { locale } = useI18n({ useScope: 'global' });
const langStorage = useStorage('lang', locale.value);
const html = document.querySelector('html');
html.setAttribute('lang', locale.value);
function toggleGlobalLocale() {
locale.value = locale.value === 'zh-CN' ? 'en-US' : 'zh-CN';
langStorage.value = locale.value;
const html = document.querySelector('html');
html.setAttribute('lang', locale.value);
window.location.reload();
}
1.4 我的国际化处理套路(半自动)
主要依赖的 vscode 插件:Du I18N(感谢作者,抽离中文的功能很好用)
流程:
- 打开要国际化的页面,右键选择国际化-扫描中文(Du I18N)
- 修复扫描后自动包裹 $t 的大量报错,包括:模板字符串错误、恢复注释和 log 等
- 将抽离出的词条用 LLM 翻译,然后复制到对应的 json 中
- 代码从头看到尾,收集要处理的情况,打上 TODO
- 最后一个个解决,然后自测所有功能
PS:不要想着能有那种完全自动化的插件或库,能给你一次性处理到位。我觉得这是不存在的,即使真的存在,也不一定适用于你的项目。并且生产项目它改了哪些我也得一个个审核自测,否则不放心。
最后推荐一下我的 vscode 插件:vue-i18n 中文搜索定位
这个插件主要解决的问题是:当文件中都是用 $t('key') 引用词条时,能快速通过词条中文搜索定位到使用位置
1.8 结束
更新记录
2025/08/10:发布文章