背景
最近有一个我负责的项目需要开源,彻彻底底地支持国际化。项目本身的业务代码有做国际化配置,但是引入的组件库不支持国际化,会出现如图所示的情况。
在业务站点切换成英文后,业务站点自身的文案会替换成英文,但是“请选择筛选条件并搜索”这个输入框就没有展示英文。原先这个英文版只有美国同事内部使用,比较随意没有做处理。但现在作为开源的问题点提出来,就必须要做处理。需要达到下面的效果。
思考
组件库现状分析
- 组件库有8人协同维护,已经有几十个组件,新增的逻辑需要考虑到对原有代码的影响。
- 如果要对所有组件进行国际化需要自动化方案,不然维护不动。
- 组件库是基于ArcoDesign提供的脚手架创建的,需要考虑到Arco的一些规则。
最简单,但意义最小的方案
业务方指对这个搜索框提出了问题,希望我能修改。最简单的方案就是我给搜索框组件增加一组参数customTips: {inputTip?:string; guideTip?:string},如果业务代码内想要国际化那么重新给组件赋值就行。但问题在于后续持续维护,如果用到了更多组件,需要给所有组件新增一组参数。如果customTips参数并没有形成一个规范,那后续所有组件自己维护自己的国际化,也会带来混乱。
相对复杂,但更健康的方案
参考Arco官方,其实已经给出了答案。通过一个组件ConfigProvider来统一控制组件库的国际化。在根组件使用ConfigProvider把实际业务代码以及组件包裹起来,组件就可以获取ConfigProvider的参数。
Arco支持多种语言国际化,所以也做了按需引入,需要手动引入所需的语言包。不过因为考虑到我的文案可能也就几十条,并且只支持英语这个国际化语言,暂时就没什么必要做按需引入了。
import { useState } from 'react';
import {
ConfigProvider,
} from '@arco-design/web-react';
import zhCN from '@arco-design/web-react/es/locale/zh-CN';
import enUS from '@arco-design/web-react/es/locale/en-US';
function App() {
const [locale, setLocale] = useState('zh-CN');
function getLocale() {
switch (locale) {
case 'zh-CN':
return zhCN;
case 'en-US':
return enUS;
default:
return zhCN;
}
}
return (
<ConfigProvider locale={getLocale()}>
// 你的代码
</ConfigProvider>
);
}
export default App;
参考Arco的ConfigProvider,我设计了TobConfigProvider。
踩坑记录
别名坑
ArcoDesign的组件库会将/components目录打包成dist、es、lib三个文件夹,分别对应了umd、es、commonjs三种产物。除dist是使用webpack进行打包,es与lib是直接用tsc进行打包。
一开始我在项目里创建了一个文件夹/locales,里面放了与国际化有关的内容。为了让组件库的每个文件都能以相同的名字引入/locales/i18n.tsx,我设置了别名。最后实现的效果是import useTrans from '@locales/i18'。
还有一个考虑就是用到了批量替换代码的脚本。这个脚本会将代码中的中文替换成trans(中文内容),并自动插入import useTrans from '@locales/i18'到代码里。目前这个脚本自动插入固定字符串,没有办法根据ts文件的路径去动态生成一个相对路径。
一般来说你用webpack打包一个东西,打包的产物直接放浏览器里跑完全没问题,因为webpack帮你处理好了依赖关系,不管是通过别名还是相对路径引入的,最后都会得到一个moduleID。然而组件库不同,它的打包产物不是直接放在浏览器运行,而是要经过使用者的二次打包。
从上面的两张图可以看出来,第一张图是ts文件,导入了别名路径@code2/test。图2是tsc的打包产物,导入的内容依旧是别名。最后发包的时候只会上传dist/code/index.js,而保留了别名映射关系的tsconfig.js是不会被上传的。所以业务代码其实不知道你这个@code2/test对应的原来是./src/code2/test,就会报错。
其实也蛮奇怪的,找了半天,没有找到让TypeScript把打包产物的别名更正为相对路径的配置。所以这边ArcoDesign用tsc来打包是否合理呢?如果用rollup打包就还能用插件把路径处理一下,否则这在组件库的开发中就没有办法使用别名。
tsc打包坑
一开始我把/locales放到根目录,和/components同级,结果打包出来的东西使用者找不到模块。原先tsc会将/components目录内的东西直接输出到/es目录中。但是如果/components目录内的文件引用了/locales则会导致/es的目录下变更为/components+/locales,那使用者自然是无法引入组件了。
正常的
/es
/TagInput
/Ellipsis
……
异常的
/es
/components
/locales
webpack配置坑
ArcoDesign的组件库可以将我们编写的组件库直接在一个网站预览。里面就有一个./arco-team-site/.config/webpack.config.js来配置预览站点的打包配置。还有一个输出UMD产物的配置文件.config/webpack.config.js。印象中会影响到webpack配置的地方有4处,可能都得改改,这边也有点麻烦。