作者简介
蒋琦 云极星创联合创始人兼产品开发部总监,有超过十年的前端开发经验以及超过三年的云计算相关产品的前端开发经验。长期关注前端社区的开发,自动化测试以及自动化流程的管理。
责编:孙浩峰,欢迎云计算、大数据、运维等技术文章投稿,投稿信箱:[email protected]。
Webpack是目前非常流行的前端工程化解决方案。通过Webpack,可以非常方便的将前端的组件整合成尽可能少的文件,并且进行混淆压缩,达到上线的要求。也可以用Webpack对LESS等CSS类语言进行编译。在ES6/ES7流行的今日,也可以通过Babel等Loader,将ES6的语法转换为ES5,提前让前端工程师们感受到语法糖的美妙。
i18n(Internationalization,即国际化)是前端工程师非常容易遇到的问题。在传统的页面渲染中,一般是由后端的框架中,调用i18n模块直接渲染生成页面,这一部分内容基本上不需要前端工程师来考虑。但是在当下的诸多MVVM的框架构建的前端工程中,页面模版是由前端生成的,在这个情况下,多语言,也成为了前端工程师面对的一个问题。
在云极星创的云平台产品上,我们从一开始架构的时候,就把多语言作为我们平台的标配,因此i18n也成为云极星创前端开发过程中必须直面和解决的问题。我们的前端开发团队在经历了几轮的方案测试推翻再测试后,最终用Webpack的方式解决了多语言的问题。
一般来说,i18n文件都是以key/value的JSON格式存储。
在我们的项目构建的第一天,就在项目中引入了i18n。当时项目中采用的是requirejs来加载js代码,并且在项目发布的时候,通过r.js打包成一个单独的文件(其实当时并没有涉及到Webpack)。
当时的代码,看起来,大致是这样的:
define([‘lang.json’],function(__) {
var language = getLanguage(); //获取当前的语言选项。
var label = __[language][‘label’];
/* 然后将该文案应用于程序中。*/
});
其中lang.json大致长这样:
{
“en”: {
“label”: “Label”
},
“zh-CN”: {
“label”: “文案”
}
这个方案从当时看来还是比较不错的方案,把i18n和代码完全剥离,方便文案的修改。这个方案最大的问题是,多种语言同时被require。在用r.js打包时,所有的文案会被打包进入一个文件。
想象一下,如果需要支持五种语言,那需要到js里的多语言的数量。随着时间的推移,代码量的增长,这个问题越来越突出。
方案一 OUT
然后,我们对代码做了一次重构,用上了Webpack来打包。淘汰了requirejs。在重构的过程中,我们使用了另外一种方法来处理i18n。
这个方案的大致的思路如下:
1.将所有的i18n的配置分别存到不同的文件里。
比如zh-CN.lang.json的内容大致如下:
{
“label”: “文案”
}
然后每次编译只打包一个语言并生成js文件。
在开始编译之前,将1中的zh-CN.lang.json复制生成lang.json。
在代码中,统一require生成的lang.json文件。
const __ =require(‘./lang.json’);
constlabel = __.label;
由于在开始编译之前,lang.json已经变成我们需要的语言文件,因此4中可以直接require到我们需要的i18n文件。
这样,每个语言会通过打包生成一个js文件。在客户端加载的时候,不需要加载没有用到的多语言文件,从而实现了瘦身。
然而,这个方案很快又暴露了问题。
首先,这个文件是一个全局的文件,在写组件的时候,不能基于组件级别去定制一个i18n文件。
其次,这个文件是全局的,在具体的开发过程中,会遇到key值冲突的情况。
为了解决key值冲突的情况,我们进行了很多的调研,当时使用了namespace来临时性的解决了这个问题。
最后,这个方案还需要在正式开始打包前,先复制语言文件,导致多种语言的打包不能同时开始。
方案二OUT
我们又进行了一轮探讨和思考。终于,找到了相对完美的一种解决方案—— Loader。
相信很多朋友看到这个标题就已经明白我们的解决方案了。
在Webpack中,Loader是用来对require的代码进行预处理的,Loader可以在加载代码过程中做很多预处理,比如可以把CoffeScript编译成JavaScript,把ES6的代码编译成ES5。这些都是非常典型的Loader的作用。
首先,我们还原了JSON文件为一开始的模样:
{
“en”: {
“label”: “Label”
},
“zh-CN”: {
“label”: “文案”
}
并且将lang.json文件拆分开和各个组件存放在一起,这样修改i18n的时候,思路就会比较清晰,也不需要考虑Key重名的问题了。
然后在代码中,直接require:
const __ =require(‘lang.json’);
constlabel = __.label;
…
在Webpack的配置文件中,直接启用我们为此写的Loader。
最后,只需要每次打包编译的时候,直接在环境中制定语言信息,Loader会读整个JSON文件,只留下当前语言的内容,将这些内容打包进入代码中。
通过这种方法,优雅的解决了所有的i18n中遇到的大大小小的问题。
方案三 PASS
Tips
现在我们已经将该Loader开源,在npm上提供下载,欢迎大家下载使用:
https://www.npmjs.com/package/lang-loader