提到 Vue 项目实现国际化,一般会想到使用 vue-i18n 国际化插件来实现。思路是在项目本地定义并管理语言包 json 文件,在 json 文件下进行翻译条目的新增,修改和删除。
一.背景
目前在公司参与的一个前端项目,支持 3 种语言。由于是体量较大的 monorepo 项目,每种语言就有四千多个翻译条目,使得管理上会出现一些问题。
1.顺序错乱
项目依赖编辑器的 i18n Ally 插件,其中配置了每个词条自动按照 a-z 排序。但存在部分同事漏装插件的情况,导致 json 文件的词条顺序经常错乱;
2.代码容易冲突
插件安装问题其实容易解决,但是…在多人协作开发的场景下,词条 json 文件极易冲突,即使花费时间解决了冲突,也可能会无意间再次打乱 a-z 排序,导致 git diff 持续混乱;
3.词条表述需要反复调整
词条翻译质量参差,为了调整词条表述,开发测试阶段需要反复提交代码构建
二.解决方式
出现这 3 个问题,是因为语言包 json 文件都放在了项目本地进行管理,导致开发阶段(特别是代码合并的时候)需要花费精力处理。
和同事讨论后,决定给前端项目接入 tolgee 词条管理平台。
主要思路是,项目还是使用 vue-i18n 插件实现国际化,而所有的翻译条目在 tolgee 平台进行线上管理。在本地开发阶段,网页刷新时请求最新的语言包,传入 i18n 实例进行使用。线上包 build 时,会先下载 tolgee 平台的语言包到项目,再进行构建。
三.实现步骤
今天已经从零再次实现了一个简单的项目 demo:tolgee-i18n-project
1.本地开发:网页加载时先请求语言包数据,存在浏览器 localStorage 里,在 createI18n 时获取 localStorage 的语言包传入
(1)新增公共环境变量文件.env
1 | # tolgee URL |
(2)创建自定义 Vite 插件 htmlGetLocales
新建 vite.base.ts
在开发环境,赋值 localesPromise 一个加载语言包的 Promise,加载后存入 localStorage;在生产环境,赋值 localesPromise 一个已成功的 Promise
1 | import { loadEnv } from "vite"; |
在 vite.config.ts 中引入并使用
1 | import { defineConfig } from "vite"; |
(3)index.html 中引入 main.ts 的逻辑调整
先执行 localesPromise()再引入 main.ts
1 | <script type="module"> |
(4)src 下新增 i8n.ts 文件
在开发环境,获取的是本地存储的语言包;在生产环境,使用的是 src/locales 文件夹下的语言包
1 | import { createI18n } from "vue-i18n"; |
2.生产环境:pnpm build 时先下载语言包文件
(1)编写 node 脚本,实现语言包下载功能
先安装 axios、dotenv、unzipper。
1 | pnpm i axios |
1 | pnpm i --save-dev dotenv |
1 | pnpm i --save-dev unzipper |
新增脚本文件 getDataExport.mjs
使用 axios 下载语言包 zip 文件,并解压到 src/locales
1 | import axios from "axios"; |
(2)新增自定义 Vite 插件 downloadLocales
在 vite.base.ts 文件添加自定义插件
1 | import { execSync } from "child_process"; |
这个插件会在 build 时先执行 getDataExport.mjs 脚本
最后将写好的插件引入 vite.config.ts 中使用
1 | plugins: [..., downloadLocales()] |
3.补充
在 package.json 加入 scripts 命令,使得开发过程中随时可以通过 pnpm getLocales 下载语言包(主要是方便 vscode 的 i18n Ally 插件,有翻译条目的预览效果)
1 | "scripts": { |