背景
多语言,也称国际化,前端多语言配置一般用于切换网页上静态内容的语种。社区内已有不少多语言配置的工具,我用过vue-i18n和formatJS,使用前都需要先配置各个语种的文案,再通过格式化工具生成指定的语言。这类方案没问题,但配置和维护多语言内容却成为了开发人员的负担。
本文从项目和技术两个角度来阐述关于前端分离多语言配置整个分离工作的背景、思考、结果及未来。
多语言配置为什么成为负担?
额外工作量
敏捷开发一大特点就是迭代周期较短,开发人员需要高效的完成功能开发及缺陷修复。多语言配置往往并非第一优先级工作,且在开发的初期多语言内容并非是确定的,因此不会得到开发人员足够的重视。我们可以要求开发人员开发时加上多语言配置,但这无疑会增加额外的时间成本。
后续的迭代中可能随时会增删部分内容,那意味开发人员除了要维护代码,还需要维护多语言配置文件。
以umi项目(@umijs/plugin-locale 基于 react-intl 封装,功能由formatJS提供)为例,有如下目录结构
在下面一段代码中我想用简体中文、英文、葡文三种语言显示你好:
import React from 'react';
import { useIntl } from 'react-intl';
const App = () => {
const intl = useIntl();
return <div>{intl.formatMessage({ id: '你好' })}</div>
}
export default App;
然后我还需要在项目的locales目录下,创建zh-CN.json、en-US.json、pt-PT.json三个语言包文件,分别配置三种语言的内容:
zh-CN.json
{
"你好": "你好"
}
en-US.json
{
"你好": "Hello"
}
pt-PT.json
{
"你好": "Olá"
}
显然这个过程较为繁琐。一旦你删除了页面代码或者产品经理要求修改文案时,你需要花费更多的时间来清理json文件中的配置(当然也可以不清理,只要你项目中可以接受这些无用的冗余内容)。
代码维护地狱
也许你可以对自己严格要求一点,编写代码足够规范,配置多语言内容也足够细心,但你总会遇到需要维护其他开发者代码的时候,你无法保证其他人的也像你一样编写规范且细心。
很多时候接手一个项目,其中多语言配置存在各种各样的遗漏情况,而你需要根据产品经理提供的文件(一般是Excel文件,下面全部简称Excel文件),对多语言配置补充或修改。
如何减轻开发者的负担
自动化管理多语言配置
通过一些约定,编写程序自动化管理多语言配置,解放开发者双手。
一月份的时候我发布了多语言配置自动化工具Zuoy的v1.0版本,引入Z函数概念,本质是约定多语言配置的函数命名,再通过AST(抽象语法树分析)收集到需要配置多语言的文案,然后生成不同语种的json文件。
修改上面umi项目的例子:
安装Zuoy
npm install zuoy --global # or `npm i zuoy -g` for short
在根目录下执行zy init,zuoy会为你添加默认的配置文件zuoy.config.js。
提供简体中文、英文、葡文三种语言,简体中文为输入的默认语言,修改配置文件的languages如下:
languages: [
{
code: 'zh',
file: 'src/locales/zh-CN.json',
},
{
code: 'en',
file: 'src/locales/en-US.json',
},
{
code: 'pt',
file: 'src/locales/pt-PT.json',
},
],
暂时没有接入机器翻译功能,为了区分不同语言的内容,通过defaultContent来给英文和葡文加上语言代码前缀。
defaultContent: (value, code) => {
return `${code}-${value}`;
}
我们需要对build进行配置。在上述的umi项目中,页面开发使用typescript,我们需要扫描.tsx文件,同时.umi文件夹是umi临时文件,不需要扫描。因此增加如下配置:
// build配置
build: {
include: [/\.tsx/],
exclude: [/\.umi/],
}
在页面文件index.tsx写出如下代码:
import { useState, useEffect } from 'react';
import { Select } from 'antd';
import { useZuoyIntl } from '@/utils/zuoy';
import { setLocale } from 'umi';
export default function IndexPage() {
const [lang, setLang] = useState('zh-CN');
const z = useZuoyIntl();
useEffect(() => {
setLocale(lang, false);
}, [lang]);
return (
<div style={{ margin: 24 }}>
<Select
value={lang}
onChange={(val) => setLang(val)}
options={[
{ label: '简体中文', value: 'zh-CN' },
{ label: '英文', value: 'en-US' },
{ label: '葡文', value: 'pt-PT' },
]}
/>
<br />
{z('你好, {name}', { name: 'zuoy' })}
<br />
{z('世界和平')}
</div>
);
}
执行zy build,zuoy会扫描项目根目录下的.tsx文件并过滤掉.umi文件夹中的内容。
在src/locales下,创建三个文件:
// zh-CN.json
{
"你好, {name}": "你好, {name}",
"世界和平": "世界和平"
}
// en-US.json
{
"你好, {name}": "en-你好, {name}",
"世界和平": "en-世界和平"
}
// pt-PT.json
{
"你好, {name}": "pt-你好, {name}",
"世界和平": "pt-世界和平"
}
人工配置多语言不仅费时费力,而且容易出错,使用程序来处理这个问题会好得多。通过自动化配置工具,开发人员维护多语言配置的工作量大幅降低,不再担忧多语言配置的遗漏情况,编写代码时也更加简洁。
让自动化配置更进一步
做到这一步,多语言配置的核心工作便是维护上述的JSON文件了。我们需要把Excel文件中对应语种的翻译内容取出,粘贴到JSON文件,同样费时费力,而且很容易出错。
使用nodeJS我们可以解析excel单元格的内容,但想要足够准确,就需要明确Excel文件的编排方式,但是产品经理们大概率不会坐到一起开会统一编排方式,那么程序如何处理?
换一个角度思考,不如合并JSON文件的数据生成Excel文件,这样由我们提供固定排版的原始Excel,再让产品经理修改,然后再读取已修改的Excel文件重新生成JSON文件。如下图所示:
做到这一步,可以发现,我们已经逐渐将多语言配置工作与项目工程必要的文件分离了。Excel文件的维护可以交给专业的翻译人员维护,产品经理也只需要监督翻译文件的落实即可,无需再花时间整理页面上的文案了。
多语言配置工作分离的完全体
我们理想的多语言配置工作应该是与项目开发解耦的,即多语言配置的维护人员(可能是翻译者,也可能产品经理等其他角色)完成翻译后应当自动更新到项目中,而不需要把Excel文件传来传去,我们希望参与多语言配置工作的任务角色拿到的Excel文件都是最新的。
因此我们想到了云文档。
开发时增加了新的文案,结合已有的JSON文件数据重新整理再更新到云文档,由专业的翻译人员翻译并修改云文档,项目中再从云端更新最新多语言数据。
总结
综上所述,从配置多语言自动化到分离,我们的方案的核心优势:
- 显著提升开发效率,开发者不用关注国际化的文案处理,注重代码编写即可。
- 国际化配置文案更精准,避免了冗余、遗漏等问题
- 多语言文档可轻松转交给专业的翻译人员,产品经理无需再自行整理。
参照此方案,我在上个月发布了Zuoy v1.2.0,结合语雀云文档API,实现多语言配置的自动化与分离。关于Zuoy的使用,请参考如下资料:
未来寄望
Zuoy这个工具,并非是多语言配置的竞争品,它是一个如同脚手架一般的效率工具。Zuoy的未来是不确定的,当你需要它时,它便会变成你想要的样子,当你不需要它时,它便会止步不前。因此我将Zuoy的代码开源了(gitee.com/ttf-zuoy/zu…
关于我
我是听风,目前在浩鲸智能大政务开发部前端二团队,一个开源爱好者。
擅长Vue和React,对nodeJS也比较熟悉。始于前端,而不止于前端,对服务端开发也很感兴趣,了解EggJs、NestJs、MongoDB、Mysql、Docker。现在是Vite+React+NestJs+MongoDB+Docker全栈开发和部署的忠粉,试图用JS衔接微前端和微服务。
非常介意开发效率(代码运行速度与构建速度),讨厌重复性工作。
喜欢钻研一些有趣的东西,比如Rust和webassembly。
请让我的程序跑的更快的一点。