原因:
项目国际化过程繁琐,每次都需要人工去google翻译,导致工作效率不高。
需求:
1.减少人工的重复劳动,提高工作效率。
2.使用脚本调用谷歌翻译接口自动化翻译。
3.free,作为程序员肯定接受不了付费服务,找方法解决限制。
前期准备:
1.谷歌翻译api:/translate_a/single
2.一系列参数,
我们需要找到 tk 这个参数;这个参数决定着是否能调通翻译api;
大佬提供的代码:(非常感谢)
/**
获取 google token
@param {*} a
*/
function token(a) {
var k = “”;
var b = 406644;
var b1 = 3293161072;
var jd = “.”;
var sb = “±a^+6”;
var Zb = “±3^+b±f”;
for (var e = [], f = 0, g = 0; g < a.length; g++) {
var m = a.charCodeAt(g);
128 > m ? e[f++] = m : (2048 > m ? e[f++] = m >> 6 | 192 : (55296 == (m & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (m = 65536 + ((m & 1023) << 10) + (a.charCodeAt(++g) & 1023),
e[f++] = m >> 18 | 240,
e[f++] = m >> 12 & 63 | 128) : e[f++] = m >> 12 | 224,
e[f++] = m >> 6 & 63 | 128),
e[f++] = m & 63 | 128)
}
a = b;
for (f = 0; f < e.length; f++)
a += e[f],
a = RL(a, sb);
a = RL(a, Zb);
a ^= b1 || 0;
0 > a && (a = (a & 2147483647) + 2147483648);
a %= 1E6;
return a.toString() + jd + (a ^ b)
};
function RL(a, b) {
var t = “a”;
var Yb = “+”;
for (var c = 0; c < b.length - 2; c += 3) {
var d = b.charAt(c + 2),
d = d >= t ? d.charCodeAt(0) - 87 : Number(d),
d = b.charAt(c + 1) == Yb ? a >>> d : a << d;
a = b.charAt© == Yb ? a + d & 4294967295 : a ^ d
}
return a
}
(我们这里就可以直接使用这段代码,可以解决我们80%的问题了,接下来我们需要针对自己的项目做进一步细化);
3.在这里我使用的是 node 去做这件事
需要用到 fs,moment,commander,https;这几个模块;
fs: 读、写文件;
https:发送请求到Google 翻译 Api;
moment:格式化时间,我是用来添加日志时用到的;
commander:用来操作命令行参数
实现:
翻译主函数:
/** 翻译方法@param {*} language 语言@param {*} txt 需翻译的文本
*/
function translate_google(language, txt, callback) {
var url =/translate_a/single?client=t&sl=zh-CN&tl=${language}&hl=${language}&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&ie=UTF-8&oe=UTF-8&source=btn&ssel=0&tsel=1&kc=1&tk=${token(txt)}&q=${txt}
;
var options = new URL(url);
var req = https.request(options, function (res) {
console.log('STATUS: ’ + res.statusCode);
res.setEncoding(‘utf8’);
var val = ‘’;
res.on(‘data’, function (chunk) {
val += chunk;
// 数据流,读取的时候会分布读取下来,我们需要在读取完毕的时候操作数据。
//(一开始我在这里操作数据,会致使代码报错,是因为数据的不完整性导致)
});
res.on(‘end’, () => {
callback(JSON.parse(val)[0][0][0]) // 拿去返回的参数,得到翻译值
});
});
req.on(‘error’, function (e) {
errorLog(e.message);
});
req.end();
} 向文件中写入数据
/** 向文件中写入数据@param {*} path 文件路径@param {*} val 文本
*/
function appendFile(path, val) {
fs.appendFile(path,${val}\n
, ‘utf8’, function (err) {
if (err) {
errorLog(err);
return false;
}
errorLog(数据写入 ${path} 文件成功!
)
})
} 错误日志
/** 错误日志@param {*} error 错误信息
*/
function errorLog(error) {
var path = ‘./translate_google_error_log.txt’;
var val =${getDate()}${error}
appendFile(path, val);
}
4.获取当前时间
function getDate() {
var timer = moment(Date.now()).format(‘YYYY-MM-DD HH:mm:ss’)
console.log(timer)
return[${timer}]:
;
}
处理翻译
function creteTranlate(language) {
var path =./src/languages/${language}.locale.json
;
var datas_one = {};
var datas_two = {};
var dataObj;
var i = 1;
fs.readFile(’./src/languages/zh.locale.json’, ‘utf8’, (err, dataOne) => {
if (err) {
errorLog(err);
return false;
}
datas_one = JSON.parse(dataOne);
fs.readFile(path, ‘utf8’, (err, dataTwo) => {
if (err) {
errorLog(err);
return false;
}
datas_two = JSON.parse(dataTwo);
for (let key in datas_one) {
if (!datas_two[key]) {
i++;
errorLog(没有 ${key} 这个字段
);
setTimeout(() => {
translate_google(language, datas_one[key], (res) => {
var a = {};
a[key] = res;
dataObj = Object.assign(datas_two, a);
fs.writeFile(path, JSON.stringify(dataObj), (err) => {
if (err) {
errorLog(err);
return false;
}
errorLog(${language}语言,写入成功:*** ${key}: ${res} *** 数据。
);
})
})
}, i * 500) // 加上延时,降低被封ip的概率,(测试的时候,被封了好几个ip)
// 最后是通过联手机热点完成项目改造
}
}
})
})
}
到这里基本上就已经差不多可以正常使用了
但又觉得每次修改 翻译语言很麻烦 就使用了命令行参数来进一步修改整体代码;
这里我们就需要 commander 这个模块来处理 我们的命令参数了
var program = require(‘commander’);
//定义参数,以及参数内容的描述
program
.version(‘0.0.1’)
.usage(’[option][value …]’)
.option(’-p, -path ', ‘a string argument’)
//解析commandline arguments
program.parse(process.argv)
到这里,我们就基本上可以上测试了。
附上整个代码及使用方法:
代码:
var fs = require(‘fs’);
var moment = require(‘moment’);
var program = require(‘commander’);
var https = require(‘https’);
//定义参数,以及参数内容的描述
program
.version(‘0.0.1’)
.usage(’[option][value …]’)
.option(’-p, -path ', ‘a string argument’)
//解析commandline arguments
program.parse(process.argv)
function getDate() {
var timer = moment(Date.now()).format(‘YYYY-MM-DD HH:mm:ss’)
console.log(timer)
return[${timer}]:
;
}
/**
获取 google token
@param {*} a
*/
function token(a) {
var k = “”;
var b = 406644;
var b1 = 3293161072;
var jd = “.”;
var sb = “±a^+6”;
var Zb = “±3^+b±f”;
for (var e = [], f = 0, g = 0; g < a.length; g++) {
var m = a.charCodeAt(g);
128 > m ? e[f++] = m : (2048 > m ? e[f++] = m >> 6 | 192 : (55296 == (m & 64512) && g + 1 < a.length && 56320 == (a.charCodeAt(g + 1) & 64512) ? (m = 65536 + ((m & 1023) << 10) + (a.charCodeAt(++g) & 1023),
e[f++] = m >> 18 | 240,
e[f++] = m >> 12 & 63 | 128) : e[f++] = m >> 12 | 224,
e[f++] = m >> 6 & 63 | 128),
e[f++] = m & 63 | 128)
}
a = b;
for (f = 0; f < e.length; f++)
a += e[f],
a = RL(a, sb);
a = RL(a, Zb);
a ^= b1 || 0;
0 > a && (a = (a & 2147483647) + 2147483648);
a %= 1E6;
return a.toString() + jd + (a ^ b)
};
function RL(a, b) {
var t = “a”;
var Yb = “+”;
for (var c = 0; c < b.length - 2; c += 3) {
var d = b.charAt(c + 2),
d = d >= t ? d.charCodeAt(0) - 87 : Number(d),
d = b.charAt(c + 1) == Yb ? a >>> d : a << d;
a = b.charAt© == Yb ? a + d & 4294967295 : a ^ d
}
return a
}
/**
翻译方法
@param {*} language 语言
@param {*} txt 需翻译的文本
/
function translate_google(language, txt, callback) {
var url =/translate_a/single?client=t&sl=zh-CN&tl=${language}&hl=${language}&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=ss&dt=t&ie=UTF-8&oe=UTF-8&source=btn&ssel=0&tsel=1&kc=1&tk=${token(txt)}&q=${txt}
;
var options = new URL(url);
var req = https.request(options, function (res) {
console.log('STATUS: ’ + res.statusCode);
res.setEncoding(‘utf8’);
var val = ‘’;
res.on(‘data’, function (chunk) {
val += chunk;
});
res.on(‘end’, () => {
callback(JSON.parse(val)[0][0][0])
});
});
req.on(‘error’, function (e) {
errorLog(e.message);
});
req.end();
}
/*
错误日志
@param {*} error 错误信息
/
function errorLog(error) {
var path = ‘./translate_google_error_log.txt’;
var val =${getDate()}${error}
appendFile(path, val);
}
/*
向文件中写入数据
@param {*} path 文件路径
@param {*} val 文本
*/
function appendFile(path, val) {
fs.appendFile(path,${val}\n
, ‘utf8’, function (err) {
if (err) {
errorLog(err);
return false;
}
console.log(数据写入 ${path} 文件成功!
)
})
}
function creteTranlate(language) {
var path =./src/languages/${program.Path}.locale.json
;
var datas_one = {}; // 翻译源文件
var datas_two = {}; // 翻译目标文件
var dataObj;
var i = 1;
fs.readFile(’./src/languages/zh.locale.json’, ‘utf8’, (err, dataOne) => {
if (err) {
errorLog(err);
return false;
}
datas_one = JSON.parse(dataOne);
fs.readFile(path, ‘utf8’, (err, dataTwo) => {
if (err) {
errorLog(err);
return false;
}
datas_two = JSON.parse(dataTwo);
for (let key in datas_one) {
if (!datas_two[key]) { // 若已存在,则不去翻译
i++;
errorLog(没有 ${key} 这个字段
);
setTimeout(() => {
translate_google(language, datas_one[key], (res) => {
var a = {};
a[key] = res;
dataObj = Object.assign(datas_two, a);
fs.writeFile(path, JSON.stringify(dataObj), (err) => {
if (err) {
errorLog(err);
return false;
}
errorLog(${language}语言,写入成功:*** ${key}: ${res} *** 数据。
);
})
})
}, i * 500)
}
}
})
})
}
let language = program.Path === ‘ba’ ? ‘id’ : program.Path; // 这里是因为 谷歌翻译印尼文使用的是‘id’这个参数,我们项目中使用的是“ba”来命名印尼语文件的,做了个转换
creteTranlate(language);
使用方法:
node node_translate.js -p ‘ba’ // 将中文翻译为印尼文
node node_translate.js -p ‘vi’ // 将中文翻译为越南文
node node_translate.js -p ‘en’ // 将中文翻译为英文
截图:
不足之处,还请大佬指点一下。