基于百度翻译API的node插件
基于百度翻译API的node插件背景做过国际化的项目就明白要把每处的文案翻译成不同的语言版本,如果只是一点点,自己去百度上翻译成对应语言版本,copy过来就ok了,但是如果这个项目文案特别多的话,自己去翻译,可能会烦死umijs如果构建国际化,会有一个locals的目录,里面存放前端项目中不需要存进数据库的各种语言版本文件,我就想实现只写中文的,其他版本通过nodejs+百度翻译api直接生成一、
基于百度翻译API的node插件
背景
做过国际化的项目就明白要把每处的文案翻译成不同的语言版本,如果只是一点点,自己去百度上翻译成对应语言版本,copy过来就ok了,但是如果这个项目文案特别多的话,自己去翻译,可能会烦死
umijs如果构建国际化,会有一个locals的目录,里面存放前端项目中不需要存进数据库的各种语言版本文件,我就想实现只写中文的,其他版本通过nodejs+百度翻译api
直接生成
一、百度API
需要注册开发者(使用时需要开发者的appid+密钥
),并开通通用翻译API
,每个月有200万个免费字符翻译,所以不用太担心会出现费用
我本來想使用google翻译api的,但是貌似需要翻墙,还是做个好公民,对比了有道和百度,百度翻译api更稳定和准确些,最终决定使用百度翻译API,下面分享一些坑:
- 1、直接使用百度翻译的api很坑,首先传参很多,最终要的还是无法并发,如果你频繁调用的话就是返回 54003
- 2、sign生成,需要md5加密多个字段的拼接
然后我写了这个插件,解决下这些问题,让使用更加方面!
二、该插件优点
- 1、默认中转英
translate('密钥').then((res) => {
console.log('res', res); // res secret key
});
- 2、能直接传入复杂对象值来进行翻译,例如:
{ key: value }
,只翻译value,不翻译key
translate({ name: 'faker' }, { from: "en", to: 'zh' }).then((res) => {
console.log('res', res); // res { name: '冒牌货' }
});
- 3、支持嵌套对象
translate({
name: "小明",
info: { father: "小明爸爸", mather: "小明妈妈" },
}).then((res) => {
console.log("res", res);
/*
res {
name: 'Xiao Ming',
info: { father: "Xiao Ming's father", mather: "Xiao Ming's mother" }
}
*/
});
// 各种对象嵌套都行,数组嵌套对象,对象嵌套数组
translate([
{
name: "小明",
info: { father: "小明爸爸", mather: "小明妈妈" },
},
{
name: "小红",
info: { father: "小红爸爸", mather: "小红妈妈" },
},
]).then((res) => {
console.log("res", res);
/*
res [
{
name: 'Xiao Ming',
info: { father: "Xiao Ming's father", mather: "Xiao Ming's mother" }
},
{
name: 'Xiaohong',
info: { father: 'Little red Dad', mather: 'Little red mother' }
}
]
*/
});
- 4、解决了百度api的并发问题
translate('密钥', { from: "zh", to: 'en' }).then((res) => {
console.log('res', res);
});
translate({ name: 'faker' }, { from: "en", to: 'zh' }).then((res) => {
console.log('res', res);
});
直接用百度api,同时翻译,那么就会导致前面的请求失败,当然我不是vip,看说明文档上可能是没买vip,就不支持并发,但是我就是不想花钱,毕竟穷!
实现解决并发原理:其实就是上次请求没有完成,我就将这次请求排入队列
if (this.isRequesting) {
return new Promise((resolve) => {
setTimeout(() => {
this.requestApi(value, parames).then((res) => {
resolve(res);
});
}, 1000);
});
}
- 5、对于复杂对象直接传入翻译的优化
不用担心直接传入一个对象,有很多数据,因为我将对象的数据合并之后,只发送了一个请求到百度翻译,然后我再对应解析出来数据,其实传入对象,数组对翻译性能更高
translate([
{
name: "小明",
info: { father: "小明爸爸", mather: "小明妈妈" },
},
{
name: "小红",
info: { father: "小红爸爸", mather: "小红妈妈" },
},
]).then((res) => {
console.log("res", res);
/*
res [
{
name: 'Xiao Ming',
info: { father: "Xiao Ming's father", mather: "Xiao Ming's mother" }
},
{
name: 'Xiaohong',
info: { father: 'Little red Dad', mather: 'Little red mother' }
}
]
*/
});
这个翻译流程我把图放出来,明显值请求了4次api,每个对象如果当前层级都是string,自然会被我合并,就能一次翻译完成:
三、插件源码
const md5 = require("md5-node");
const axios = require("axios");
function MysKeyTranslate(config) {
this.requestNumber = 0;
this.config = {
showProgress: true,
requestNumber: 1,
agreement: 'http',
...config,
};
this.baiduApi = `${this.config.agreement}://api.fanyi.baidu.com/api/trans/vip/translate`
this.createUrl = (domain, form) => {
let result = domain + "?";
for (let key in form) {
result += `${key}=${form[key]}&`;
}
return result.slice(0, result.length - 1);
};
this.requestApi = (value, parames) => {
if (this.requestNumber >= this.config.requestNumber) {
return new Promise((resolve) => {
setTimeout(() => {
this.requestApi(value, parames).then((res) => {
resolve(res);
});
}, 1000);
});
}
this.requestNumber++;
const { appid, secret } = this.config;
const q = value;
const salt = Math.random();
const sign = md5(`${appid}${q}${salt}${secret}`);
const fromData = {
...parames,
q: encodeURIComponent(q),
sign,
appid,
salt,
};
const fanyiApi = this.createUrl(this.baiduApi, fromData);
// console.log("fanyiApi", fanyiApi);
return new Promise((resolve) => {
axios
.get(fanyiApi)
.then(({ data: res }) => {
if (this.config.showProgress) console.log("翻译结果:", res);
if (!res.error_code) {
const resList = res.trans_result;
resolve(resList);
}
})
.finally(() => {
setTimeout(() => {
this.requestNumber--;
}, 1000);
});
});
};
this.translate = async (value, parames = { from: "zh", to: "en" }) => {
let result = "";
if (typeof value === "string") {
const res = await this.requestApi(value, parames);
result = res[0]["dst"];
}
if (
Array.isArray(value) ||
Object.prototype.toString.call(value) === "[object Object]"
) {
result = await this._createObjValue(value, parames);
}
return result;
};
this._createObjValue = async (value, parames) => {
let index = 0;
const obj = Array.isArray(value) ? [] : {};
const strDatas = Array.isArray(value) ? value : Object.values(value);
const reqData = strDatas
.filter((item) => typeof item === "string")
.join("\n");
const res = reqData ? await this.requestApi(reqData, parames) : [];
for (let key in value) {
if (typeof value[key] === "string") {
obj[key] = res[index]["dst"];
index++;
}
if (
Array.isArray(value[key]) ||
Object.prototype.toString.call(value[key]) === "[object Object]"
) {
obj[key] = await this.translate(value[key], parames);
}
}
return obj;
};
return this.translate;
}
export default MysKeyTranslate;
四、使用方法
- 1、安装 md5-node ,使用百度翻译api需要md5
npm i --save md5-node
- 2、保存上面的源码到一个文件
- 3、使用
const MysKeyTranslate = require("./MysKeyTranslate.js"); // 引入刚才保存的文件
const translate = new MysKeyTranslate({
appid: "", // 你的appid 去百度开发者平台查看 http://api.fanyi.baidu.com/doc/21
secret: "", // 你的密钥
});
// 下面就可以直接使用了
translate('密钥', { from: "zh", to: 'en' }).then((res) => {
console.log('res', res);
});
- 4、如果想读取中文文件,然后生成其他版本内容,可以参考下面
const MysKeyTranslate = require("./MysKeyTranslate.js"); // 引入刚才保存的文件
const data = require("./ZH_CN.ts"); // 引入中文文件
const translate = new MysKeyTranslate({
appid: "", // 你的appid 去百度开发者平台查看 http://api.fanyi.baidu.com/doc/21
secret: "", // 你的密钥
});
["en", "jp"].forEach((item) => {
translate(data, { from: "zh", to: item }).then((res) => {
createFile(item, res);
});
});
function createFile(fileName, fileContent) {
fs.writeFileSync(
`ZH_${fileName.toUpperCase()}.ts`,
`export default ${JSON.stringify(fileContent)}`
);
}
ZH_CN.ts文件内容如下:
module.exports = [
{
'home.title': '首页',
'home.name': '首页名称',
'book': {
'name': '时间简史',
'date': '公元前203年'
}
}
]
五、语言对应表
常用语言:
中文 zh
英语 en
韩语 kor
日语 jp
法语 fra
俄语 ru
完整版请参考百度翻译文档: http://api.fanyi.baidu.com/doc/21
六、后续
后面有时间的话我可以让这个不止在代码层面,还是上传到npm,完善一些功能,增加能命令直接生成其他语言版本的文件…
更多推荐
所有评论(0)