技术标签: node 谷歌翻译 翻译 国家化 javascript i18n
原因:
项目国际化过程繁琐,每次都需要人工去google翻译,导致工作效率不高。
需求:
1.减少人工的重复劳动,提高工作效率。
2.使用脚本调用谷歌翻译接口自动化翻译。
3.free,作为程序员肯定接受不了付费服务,找方法解决限制。
前期准备:
1.谷歌翻译api:https://translate.google.cn/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:用来操作命令行参数
实现:
https://translate.google.cn/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}
;${val}\n
, ‘utf8’, function (err) {
数据写入 ${path} 文件成功!
)${getDate()}${error}
4.获取当前时间
function getDate() {
var timer = moment(Date.now()).format(‘YYYY-MM-DD HH:mm:ss’)
console.log(timer)
return [${timer}]:
;
}
./src/languages/${language}.locale.json
;没有 ${key} 这个字段
);${language}语言,写入成功:*** ${key}: ${res} *** 数据。
);}
到这里基本上就已经差不多可以正常使用了
但又觉得每次修改 翻译语言很麻烦 就使用了命令行参数来进一步修改整体代码;
这里我们就需要 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 = https://translate.google.cn/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’ // 将中文翻译为英文
截图:
不足之处,还请大佬指点一下。
文章浏览阅读1.2k次。一个小小的录像功能,如果做的更加通用兼容性好的话,需要注意的点还很多,本文抛砖引玉,感兴趣的开发者可酌情参考。_windows rtsp播放器
文章浏览阅读360次。场景一. 分析农业大棚监控系统的数据表设计1. 设备描述表2. 设备类型表3. 设备状态表4. 大棚表5. 。。。。。二. 分析农业大棚监控系统功能设计1. 设备管理2. 监控中心2.1 实时:每隔10分钟动态刷新..._农业监控系统数据项描述表
文章浏览阅读260次。这个教程不赖,以前学的时候咋就没这种教程,近段时间学paddlepaddle。教程:https://www.paddlepaddle.org.cn/tutorials/projectdetail/1516091数据:https://archive.ics.uci.edu/ml/machine-learning-databases/housing/housing.data# 导入需要用到的packageimport numpy as npimport jsonfrom matplotlib _housing.data 飞桨 没有
文章浏览阅读6.7k次。出现问题:url :localhost/public/index.php/能用,而index.php不能用。也就是public隐藏的问题。(项目放在了www根目录下)看了下官方文档的解释点击打开链接,但是完全没有看懂。就百度看了下。找到了如何修改Apaceh配置localhost虚拟主机1:首先找到vhost所在的位置 (E:\wamp\bin\apache\apache2.4.9\conf),打..._工具类应隐藏 public 构造器
文章浏览阅读1.7k次。js 定时器(setTimeout/setInterval)出现变量未定义(xxx is not defined) 的解决方法_setinterval is not defined
文章浏览阅读481次。为此,请使用CASE语句。即使不使用临时表也可以使用。让我们首先创建一个表-mysql>createtableDemoTable->(->UserNamevarchar(100),->UserStatusvarchar(100)->);QueryOK,0rowsaffected(0.74sec)使用插入命令在表中插入一些记录-mysql&..._mysql临时表更新语句
文章浏览阅读894次。Pytorch 属性统计. norm. mean sum. prod. max, min, argmin, argmax. kthvalue, topknorm - p :范数import torcha = torch.full([8], 1)b = a.view(2, 4)c = a.view(2, 2, 2)# 所有元素的1范数print("a.norm(1):\t", a.norm(1))print("a.norm(1):\t", a.norm(1))print("c
文章浏览阅读242次。解压tar -xvf mysql-5.7.20-1.el6.x86_64.rpm-bundle.tar安装yum -y localinstall mysql-community-common-5.7.20-1.el6.x86_64.rpmyum -y localinstall mysql-community-libs-5.7.20-1.el6.x86_64.rpmyum -y local...
文章浏览阅读1.2k次。1,一服务器/dev/sdb文件系统损坏,重启后系统启不来,进入单用户模式fsck无法修复,把/etc/fstab中的/dev/sdb注释掉后,系统成功起来。2,mount挂载/dev/sdb提示bad superblock错误,无法正常挂载:[root@localhost ~]# mount /dev/sdb /testmount: wrong fs type, bad option, bad ..._group descriptors look bad
文章浏览阅读946次。这不是最优雅的解决方案,但如果您无法更改表结构,则可以取消数据的转换,然后应用用户定义的变量来获取每个student_id的行号.代码将类似于以下内容:select student_id, name, col, datafrom(SELECT student_id, name, col,data,@rn:=case when student_id = @prev then @rn else 0 e..._数据库 取出相同最大的2个值
文章浏览阅读255次。StarUML for Mac是一款UML软件建模器,自动更新StarUML会自动检查最新更新,支持快速编辑中的许多缩写,一次创建元素和关系是一款强大且易用的工具。staruml下载使用这款UML软件建模器吧!软件功能UML 2兼容UML 2.x标准元模型和图表:类,对象,用例,组件,部署,复合结构,序列,通信,状态图,活动和配置文件图。附加图表支持创建实体 - 关系图(ERD),数据流图(DFD..._idea mac 子类
文章浏览阅读959次。为了保证每个组件的css唯一性,避免污染全局或者被全局污染,vue提供了scoped作用域。当 标签有 scoped 属性时,它的 CSS 只作用于当前组件中的元素。如果你希望scoped样式中的一个选择器能够作用得“更深”,例如影响子组件,可以用深度作用选择器(样式穿透)来实现。_vue /deep/