记一个国际化语言包生成器

由于在项目中多次涉及到国际化的支持(技术栈中国际化使用 Vuex-i18n,然而针对于开发人员来说,做国际化支持的难度就不言而喻。如若仅仅是一个简繁体中文,那也还是难不倒在下,输入法一个Ctrl + Shift + F ,就自动转换了。但是针对于,英语,德语,法语 … 这些就是懵逼了。 然后就把中文语言包给翻译小伙伴儿翻译,然后,问题就来了,协助效率极低,错误率极高,开发人员对应解析最低,维护成本高。
下面给大家分享一波我的开发环境及工具。

目的:通过一个基础语言文档,生成多语言的json文件(eg:zh_CN.json, en.json, de.json)。

开发环境

1
2
node v8.11.1
npm 6.2.0

引用的工具包

jsonfile, lodash.set

建立项目,初始化项目

1
2
3
4
5
mkdir local-lang
cd local-lang
npm init // 一路回车,完成
npm install jsonfile lodash.net prompt colors
touch app.js

上手开撸

编辑app.js

引入依赖包 并定义初始化数据
1
2
3
4
5
6
7
8
var fs = require('fs')
var jsonfile = require('jsonfile')
var set = require('lodash.set')
var prompt = require('prompt');
var colors = require('colors');
var odata; // 读取的原始数据结构
var data; // 经过处理为分行的数据
var current = "" // 写入的当前文件地址
定义初始化函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* @params result:通过terminl 询问框提示用户输入的源文件地址(url), 生成的语言包(lang)
**/
async function init(result) {
console.log(' 读取数据源文件…'.green)
odata = fs.readFileSync(`./${result.url}`)
data = String(odata).split(/\r?\n/ig)
console.log('√ 数据源文件读取成功'.green)
console.log(' 删除已生成文件…'.green)
let langFlolder = './lang'
deleteFolderRecursive(langFlolder)
console.log('√ 原文件删除成功'.green)
let exist = await isExist(langFlolder)
if(!exist) {
fs.mkdirSync(langFlolder)
}
console.log('√ 初始化文件目录成功'.green)
let files = result.lang.split(',')
let nfiles = files.map(item => {
return `${langFlolder}/${item}.json`
})
deal(nfiles, files)
}
定义用户输入提示(程序入口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function getInput() {
prompt.start();
prompt.get([{
name: 'lang',
default: 'en,zh_CN',
description: '请输入需要生成的语言类型,多语言以英文逗号隔开',
required: true
},
{
name: 'url',
default: 'lang.txt',
description: '请输入源文件名(当前目录下)',
required: true
}], function(err, result) {
init(result)
console.time('useTime')
})
}
定义辅助方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* @params url :判断此路径的文件是否存在
**/
function isExist(url) {
return new Promise((resolve, reject) => {
fs.exists(url, function(exists){
if(exists) {
resolve(true)
} else {
resolve(false)
}
})
})
}

/**
* @params path :深度删除此路径的文件及文件夹
**/
function deleteFolderRecursive(path) {
if( fs.existsSync(path) ) {
fs.readdirSync(path).forEach(function(file) {
var curPath = path + "/" + file;
if(fs.statSync(curPath).isDirectory()) { // recurse
deleteFolderRecursive(curPath);
} else { // delete file
fs.unlinkSync(curPath);
}
});
fs.rmdirSync(path);
}
};
逻辑处理方法

根据传入的文件生成路径数组进行遍历, 对对应的路径的文件挨个调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
```
/**
* @params files : 存放生成文件的路径
* @params langname :当前的国际化语言类型(如:zh_CN)
**/
async function deal(files, langname){
let filelen = files.length
for(var i = 0,len = data.length;i<len;i++){
if(i%(filelen+2) == 0) {
current = data[i]
console.log(` ${data[i]}`.cyan)
} else if(i%(filelen+2) < (filelen+1)) {
try{
await writeTranslationsToDisk(current, data[i], files[(i+1)%filelen]);
let lang = langname[(i+1)%filelen];
console.log(`√ ${lang}:${data[i]}`.green)
}catch(e){
console.log(e.message.red)
}
}
}

写入磁盘文件

通过lodash.set 可以直接传入(object,key, value),也就是类似于 object[key] = value 进行设置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* @params key : 要写入的key
* @params translation :要写入的value值
* @params translationFile :写入文件的目标地址
**/
function writeTranslationsToDisk (key, translation,translationFile) {
return new Promise((resolve, reject) => {
jsonfile.readFile(translationFile, (e, obj) => {
obj = obj || {}
set(obj, key, translation)
jsonfile.writeFile(translationFile, obj, { spaces: 2 }, err => { reject(err) })
resolve()
})
})
}

效果验证

通过实际的一个效果看一下,先准备一个lang.txt文件。格式如下

1
2
3
4
#1:page.title
#2:主页
#3:Home
#4:

第一行: 生成的json文件的key值。多层将生成对应的树状结构
第二行: 第一种语言
第三行: 第二种语言
第N行: 第N-1种语言
第N+1行: 空行做间隔

说明: 语言至少为一种(其实也就没什么意义了),每一个块数据块以空行隔开。

输入语言

输入语言类型

选择源文件地址

输入源数据地址

生成文件

输出文件
输出文件成功

生成的json文件

生成的json文件

大功告成!

此项目 GitHub 地址。

文章作者: liming liu
文章链接: http://unkonws.info/2018/08/24/local-lang/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 黎明