前言
在当前公司,许多内部系统之前是没有国际化需求的。然而随着公司业务的发展,现在需要给所有内部系统提供多语言能力。这个需求听起来就非常费时费力,且完全是机械重复的劳动。身为程序员,对于机械重复的劳动是非常讨厌的,因此想尝试有没有更简单的办法完成这个需求。
思考
国际化流程
在正常的开发过程中,国际化流程如下:
我们的国际化流程经历了以下几个阶段:
人力阶段
研发需要将项目中涉及到的文案挨个人工提取以文件的形式记录下来 (通常为json/js文件),然后使用翻译软件机翻成对应的语言。此阶段涉及到每个需求都要人工介入收集、等待翻译结果、回填到项目中。如果有文案变动需要更新代码并重新上线。 其中机翻的质量不能够保证完美的表达文案本意,当然最大的痛点是需要人工提取记录,并需要维护对应其他语言的配置文件。
缺陷
- 项目中需要进行多语言的文案,开发者都需手动去用 translate 函数替换。
- 开发者需要手动维护 en.json,ja.json 等多种语言的翻译文案。
- 开发者需要保证 lang.json 中的 key 和 intl.get(key)中的 key 是正确对应的,一旦需要多语言的文案有成百上千条,很容易造成 intl.get(key)中对应的翻译错误。这无形中也给开发者带来心智负担。
- 翻译资源文件维护在项目内,如果需要修改翻译,就需要修改代码发布版本。这也增大了翻译的维护成本。
动态下发
针对以上问题,我们搭建了一个简易翻译平台来存储翻译资源,提供以下能力:
- 上传json多语言资源文件;
- 解析资源文件并展示为页面表格形式,支持用户修改翻译条目;
- 支持导入导出excel功能,方便用户批量翻译;
- 提供获取资源文件接口。
在此时期,研发仍需要挨个提取文案,然后将资源文件上传至翻译平台中,在用户进入页面时通过接口拉取平台下发的文案。此时研发和翻译的动作就开始解耦。此阶段仍然存在人工介入收集、手动上传等机械重复劳动过程。
基于AST的国际化方案
核心思路是在编译时替换,带来的好处有以下几点:
- 之前的方案都是在代码中进行永久性的替换,下次阅读时只会看到一串编码,开发者注重key的质量的话,可能是语义化的key,否则很可能不能够直观知晓该文案的意思。当然有插件可以做到展示对应的翻译,这样仍然存在问题2。在编译时替换的话,不会破坏源代码结构,即维持了原有代码的可阅读性;
- 在开发过程中可以很快速的定位文案位置,永久性替换的话如果需要修改文案,最好是同步修改语义化key,那么就需要同时修改语言配置文件中的key,给开发带来严重的心智负担;
- 保持原来的开发风格和习惯,在原有开发国际化项目过程中必须时刻提醒自己文案需要用 translate 函数,在开发过程中可能会遗忘。
AST
关于AST的解释以及运用,已有许多文章介绍,这里就不过多赘述,感兴趣的同学可以自行了解。
目前使用的打包工具对于项目源代码的处理过程主要为以下三个步骤:
我们要做的就是第二第三步,将源代码中的中文转换为翻译函数并生成最终代码。
有许多工具支持AST操作,这里选用了比较熟悉、常用的 Babel,几个核心包如下:
@babel/parser解析源码得到AST;@babel/traverse接受AST,并遍历其节点,根据规则进行处理;@babel/types用于构建AST节点和判断AST节点类型;@babel/generate接受AST,生成目标代码和 sorucemap(即将ast转换成js代码)。
在开发过程中可以借助 ast explorer 帮助查看理解AST。
国际化流程
- 通过打包工具在打包的过程中读取项目中的代码,将代码中的中文扫描出来;
- 通过特定生成规则生成一个多语言key,并存储为
key-value的形式(默认规则为将中文md5生成一串哈希值)。 - 在打包结束后生成对应的多语言资源文件并上传至翻译平台;
- 由专业人员在平台更新翻译;
- 在用户进入页面后拉取多语言资源文件。
核心库
针对 webpack 和 vite 提供了不同的包做处理,具体使用可参考仓库中的实例。