You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
865 lines
29 KiB
865 lines
29 KiB
'use strict';
|
|
|
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
|
var tslib = require('tslib');
|
|
var http = require('http');
|
|
var https = require('https');
|
|
var url = require('url');
|
|
var querystring = require('querystring');
|
|
var crypto = require('crypto');
|
|
|
|
/** 反转对象 */
|
|
function invert (obj) {
|
|
var result = {};
|
|
for (var key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
result[obj[key]] = key;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
var root = 'https://fanyi.baidu.com';
|
|
// 写死一个 Cookie 供 Node.js 端使用;浏览器端自带这个 Cookie 所以无需处理
|
|
var Cookie = 'BAIDUID=0F8E1A72A51EE47B7CA0A81711749C00:FG=1;';
|
|
/**
|
|
* 百度支持的语种到百度自定义的语种名的映射,去掉了文言文。
|
|
* @see http://api.fanyi.baidu.com/api/trans/product/apidoc#languageList
|
|
*/
|
|
var standard2custom = {
|
|
en: 'en',
|
|
th: 'th',
|
|
ru: 'ru',
|
|
pt: 'pt',
|
|
el: 'el',
|
|
nl: 'nl',
|
|
pl: 'pl',
|
|
bg: 'bul',
|
|
et: 'est',
|
|
da: 'dan',
|
|
fi: 'fin',
|
|
cs: 'cs',
|
|
ro: 'rom',
|
|
sl: 'slo',
|
|
sv: 'swe',
|
|
hu: 'hu',
|
|
de: 'de',
|
|
it: 'it',
|
|
'zh-CN': 'zh',
|
|
'zh-TW': 'cht',
|
|
// 'zh-HK': 'yue',
|
|
ja: 'jp',
|
|
ko: 'kor',
|
|
es: 'spa',
|
|
fr: 'fra',
|
|
ar: 'ara'
|
|
};
|
|
/** 百度自定义的语种名到标准语种名的映射 */
|
|
var custom2standard = invert(standard2custom);
|
|
|
|
/**
|
|
* 安全的获取一个变量上指定路径的值。
|
|
* TODO: 使用 noshjs 代替
|
|
*/
|
|
function getValue (obj, pathArray, defaultValue) {
|
|
if (obj == null)
|
|
return defaultValue;
|
|
if (typeof pathArray === 'string') {
|
|
pathArray = [pathArray];
|
|
}
|
|
var value = obj;
|
|
for (var i = 0; i < pathArray.length; i += 1) {
|
|
var key = pathArray[i];
|
|
value = value[key];
|
|
if (value == null) {
|
|
return defaultValue;
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function getError (code, msg) {
|
|
var e = new Error(msg);
|
|
e.code = code;
|
|
return e;
|
|
}
|
|
|
|
function request (options) {
|
|
var _a = options.method, method = _a === void 0 ? 'get' : _a;
|
|
var urlObj = url.parse(options.url, true);
|
|
var qs = querystring.stringify(Object.assign(urlObj.query, options.query));
|
|
var headers = {
|
|
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
|
|
};
|
|
var body;
|
|
if (method === 'post') {
|
|
switch (options.type) {
|
|
case 'form':
|
|
headers['Content-Type'] =
|
|
'application/x-www-form-urlencoded; charset=UTF-8';
|
|
body = querystring.stringify(options.body);
|
|
break;
|
|
case 'json':
|
|
default:
|
|
headers['Content-Type'] = 'application/json; charset=UTF-8';
|
|
body = JSON.stringify(options.body);
|
|
break;
|
|
}
|
|
headers['Content-Length'] = String(Buffer.byteLength(body));
|
|
}
|
|
Object.assign(headers, options.headers);
|
|
var httpOptions = {
|
|
hostname: urlObj.hostname,
|
|
method: method,
|
|
path: urlObj.pathname + '?' + qs,
|
|
headers: headers,
|
|
auth: urlObj.auth,
|
|
timeout: options.timeout || 5000
|
|
};
|
|
var responseType = options.responseType || 'json';
|
|
return new Promise(function (resolve, reject) {
|
|
var req = (urlObj.protocol === 'https:' ? https.request : http.request)(httpOptions, function (res) {
|
|
// 内置的翻译接口都以 200 作为响应码,所以不是 200 的一律视为错误
|
|
if (res.statusCode !== 200) {
|
|
reject(getError("API_SERVER_ERROR" /* API_SERVER_ERROR */));
|
|
return;
|
|
}
|
|
res.setEncoding('utf8');
|
|
var rawData = '';
|
|
res.on('data', function (chunk) {
|
|
rawData += chunk;
|
|
});
|
|
res.on('end', function () {
|
|
// Node.js 端只支持 json,其余都作为 text 处理
|
|
if (responseType === 'json') {
|
|
try {
|
|
resolve(JSON.parse(rawData));
|
|
}
|
|
catch (e) {
|
|
// 与浏览器端保持一致,在无法解析成 json 时报错
|
|
reject(getError("API_SERVER_ERROR" /* API_SERVER_ERROR */));
|
|
}
|
|
}
|
|
else {
|
|
resolve(rawData);
|
|
}
|
|
});
|
|
});
|
|
req.on('timeout', function () {
|
|
req.abort();
|
|
reject(getError("NETWORK_TIMEOUT" /* NETWORK_TIMEOUT */, '查询超时'));
|
|
});
|
|
req.on('error', function (e) {
|
|
reject(getError("NETWORK_ERROR" /* NETWORK_ERROR */, e.message));
|
|
});
|
|
req.end(body);
|
|
});
|
|
}
|
|
|
|
// tslint:disable
|
|
var C = null;
|
|
/**
|
|
* 从百度网页翻译中复制过来的计算签名的代码
|
|
* @param text 要查询的文本
|
|
* @param seed 从 ./seed.ts 获取到的 seed
|
|
*/
|
|
function sign (text, seed) {
|
|
var o = text.length;
|
|
o > 30 &&
|
|
(text =
|
|
'' +
|
|
text.substr(0, 10) +
|
|
text.substr(Math.floor(o / 2) - 5, 10) +
|
|
text.substr(-10, 10));
|
|
var t = null !== C ? C : (C = seed || '') || '';
|
|
for (var e = t.split('.'), h = Number(e[0]) || 0, i = Number(e[1]) || 0, d = [], f = 0, g = 0; g < text.length; g++) {
|
|
var m = text.charCodeAt(g);
|
|
128 > m
|
|
? (d[f++] = m)
|
|
: (2048 > m
|
|
? (d[f++] = (m >> 6) | 192)
|
|
: (55296 === (64512 & m) &&
|
|
g + 1 < text.length &&
|
|
56320 === (64512 & text.charCodeAt(g + 1))
|
|
? ((m =
|
|
65536 + ((1023 & m) << 10) + (1023 & text.charCodeAt(++g))),
|
|
(d[f++] = (m >> 18) | 240),
|
|
(d[f++] = ((m >> 12) & 63) | 128))
|
|
: (d[f++] = (m >> 12) | 224),
|
|
(d[f++] = ((m >> 6) & 63) | 128)),
|
|
(d[f++] = (63 & m) | 128));
|
|
}
|
|
for (var S = h, u = '+-a^+6', l = '+-3^+b+-f', s = 0; s < d.length; s++)
|
|
(S += d[s]), (S = a(S, u));
|
|
return ((S = a(S, l)),
|
|
(S ^= i),
|
|
0 > S && (S = (2147483647 & S) + 2147483648),
|
|
(S %= 1e6),
|
|
S.toString() + '.' + (S ^ h));
|
|
}
|
|
function a(r, o) {
|
|
for (var t = 0; t < o.length - 2; t += 3) {
|
|
var a = o.charAt(t + 2);
|
|
(a = a >= 'a' ? a.charCodeAt(0) - 87 : Number(a)),
|
|
(a = '+' === o.charAt(t + 1) ? r >>> a : r << a),
|
|
(r = '+' === o.charAt(t) ? (r + a) & 4294967295 : r ^ a);
|
|
}
|
|
return r;
|
|
}
|
|
|
|
var seedReg = /window\.gtk\s=\s'([^']+)';/;
|
|
var tokenReg = /token:\s'([^']+)'/;
|
|
var headers = {
|
|
// 鸡贼的百度,需要带上 BAIDUUID 才会返回正确的 token;请求接口时也需要带上相同的 Cookie。
|
|
// 在浏览器端应该不需要做额外设置,因为浏览器会自动保存 cookie,然后请求接口时自动带上。
|
|
// 换了一个 IP 地址后也能用相同的 Cookie 请求,不过不清楚过期了是否还能继续用。
|
|
Cookie: Cookie
|
|
}
|
|
;
|
|
function getSeed () {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var html, seed, token;
|
|
return tslib.__generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, request({
|
|
url: 'https://fanyi.baidu.com',
|
|
headers: headers,
|
|
responseType: 'text'
|
|
})];
|
|
case 1:
|
|
html = _a.sent();
|
|
seed = html.match(seedReg);
|
|
if (seed) {
|
|
token = html.match(tokenReg);
|
|
if (token) {
|
|
return [2 /*return*/, {
|
|
seed: seed[1],
|
|
token: token[1]
|
|
}];
|
|
}
|
|
}
|
|
// 如果不能正确解析出 seed 和 token,则视为服务器错误
|
|
throw getError("API_SERVER_ERROR" /* API_SERVER_ERROR */);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 获取查询百度网页翻译接口所需的 token 和 sign
|
|
* @param text 要查询的文本
|
|
*/
|
|
function sign$1 (text) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var _a, seed, token;
|
|
return tslib.__generator(this, function (_b) {
|
|
switch (_b.label) {
|
|
case 0: return [4 /*yield*/, getSeed()];
|
|
case 1:
|
|
_a = _b.sent(), seed = _a.seed, token = _a.token;
|
|
return [2 /*return*/, {
|
|
token: token,
|
|
sign: sign(text, seed)
|
|
}];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function detect (options) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var query, body, iso689lang;
|
|
return tslib.__generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0:
|
|
query = (typeof options === 'string' ? options : options.text).slice(0, 73);
|
|
return [4 /*yield*/, request({
|
|
method: 'post',
|
|
url: root + '/langdetect',
|
|
body: {
|
|
query: query
|
|
},
|
|
type: 'form'
|
|
})];
|
|
case 1:
|
|
body = _a.sent();
|
|
if (body.error === 0) {
|
|
iso689lang = custom2standard[body.lan];
|
|
if (iso689lang)
|
|
return [2 /*return*/, iso689lang];
|
|
}
|
|
throw getError("UNSUPPORTED_LANG" /* UNSUPPORTED_LANG */);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 生成百度语音地址
|
|
* @param text 要朗读的文本
|
|
* @param lang 文本的语种,使用百度自定义的语种名称
|
|
*/
|
|
function getAudioURI(text, lang) {
|
|
return (root +
|
|
("/gettts?lan=" + lang + "&text=" + encodeURIComponent(text) + "&spd=3&source=web"));
|
|
}
|
|
/**
|
|
* 获取指定文本的网络语音地址
|
|
*/
|
|
function audio (options) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var _a, text, _b, from, lang;
|
|
return tslib.__generator(this, function (_c) {
|
|
switch (_c.label) {
|
|
case 0:
|
|
_a = typeof options === 'string' ? { text: options } : options, text = _a.text, _b = _a.from, from = _b === void 0 ? undefined : _b;
|
|
if (!!from) return [3 /*break*/, 2];
|
|
return [4 /*yield*/, detect(text)];
|
|
case 1:
|
|
from = _c.sent();
|
|
_c.label = 2;
|
|
case 2:
|
|
if (from === 'en-GB') {
|
|
lang = 'uk';
|
|
}
|
|
else {
|
|
lang = standard2custom[from];
|
|
if (!lang)
|
|
throw getError("UNSUPPORTED_LANG" /* UNSUPPORTED_LANG */);
|
|
}
|
|
return [2 /*return*/, getAudioURI(text, lang)];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
var headers$1 = {
|
|
'X-Requested-With': 'XMLHttpRequest',
|
|
Cookie: Cookie
|
|
}
|
|
;
|
|
function translate (options) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var _a, _b, from, _c, to, text, customFromLang, customToLang, _d, _e, _f, _g, _h, _j, _k;
|
|
return tslib.__generator(this, function (_l) {
|
|
switch (_l.label) {
|
|
case 0:
|
|
_a = typeof options === 'string' ? { text: options } : options, _b = _a.from, from = _b === void 0 ? undefined : _b, _c = _a.to, to = _c === void 0 ? undefined : _c, text = _a.text;
|
|
if (!!from) return [3 /*break*/, 2];
|
|
return [4 /*yield*/, detect(text)];
|
|
case 1:
|
|
from = _l.sent();
|
|
_l.label = 2;
|
|
case 2:
|
|
if (!to) {
|
|
to = from.startsWith('zh') ? 'en' : 'zh-CN';
|
|
}
|
|
customFromLang = standard2custom[from];
|
|
customToLang = standard2custom[to];
|
|
if (!customFromLang || !customToLang) {
|
|
throw getError("UNSUPPORTED_LANG" /* UNSUPPORTED_LANG */);
|
|
}
|
|
_d = transformRaw;
|
|
_e = [text];
|
|
_f = request;
|
|
_g = {
|
|
url: root + '/v2transapi',
|
|
type: 'form',
|
|
method: 'post'
|
|
};
|
|
_j = (_h = Object).assign;
|
|
_k = [{
|
|
from: customFromLang,
|
|
to: customToLang,
|
|
query: text,
|
|
transtype: 'translang',
|
|
simple_means_flag: 3
|
|
}];
|
|
return [4 /*yield*/, sign$1(text)];
|
|
case 3: return [4 /*yield*/, _f.apply(void 0, [(_g.body = _j.apply(_h, _k.concat([_l.sent()])),
|
|
_g.headers = headers$1,
|
|
_g)])];
|
|
case 4: return [2 /*return*/, _d.apply(void 0, _e.concat([_l.sent()]))];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function transformRaw(text, body) {
|
|
var transResult = body.trans_result;
|
|
var customFrom = getValue(transResult, 'from');
|
|
var customTo = getValue(transResult, 'to');
|
|
var result = {
|
|
text: text,
|
|
raw: body,
|
|
link: root + ("/#" + customFrom + "/" + customTo + "/" + encodeURIComponent(text)),
|
|
from: custom2standard[customFrom],
|
|
to: custom2standard[customTo]
|
|
};
|
|
var symbols = getValue(body, [
|
|
'dict_result',
|
|
'simple_means',
|
|
'symbols',
|
|
'0'
|
|
]);
|
|
if (symbols) {
|
|
// 解析音标
|
|
var phonetic = [];
|
|
var ph_am = symbols.ph_am, ph_en = symbols.ph_en;
|
|
if (ph_am) {
|
|
phonetic.push({
|
|
name: '美',
|
|
ttsURI: getAudioURI(text, 'en'),
|
|
value: ph_am
|
|
});
|
|
}
|
|
if (ph_en) {
|
|
phonetic.push({
|
|
name: '英',
|
|
ttsURI: getAudioURI(text, 'en-GB'),
|
|
value: ph_en
|
|
});
|
|
}
|
|
if (phonetic.length) {
|
|
result.phonetic = phonetic;
|
|
}
|
|
// 解析词典数据
|
|
try {
|
|
result.dict = symbols.parts.map(function (part) {
|
|
return (part.part ? part.part + ' ' : '') + part.means.join(';');
|
|
});
|
|
}
|
|
catch (e) { }
|
|
}
|
|
// 解析普通的翻译结果
|
|
try {
|
|
result.result = transResult.data.map(function (d) { return d.dst; });
|
|
}
|
|
catch (e) { }
|
|
if (!result.dict && !result.result) {
|
|
throw getError("API_SERVER_ERROR" /* API_SERVER_ERROR */);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
var index = /*#__PURE__*/Object.freeze({
|
|
__proto__: null,
|
|
translate: translate,
|
|
detect: detect,
|
|
audio: audio
|
|
});
|
|
|
|
function getRoot(com) {
|
|
return 'https://translate.google.c' + (com ? 'om' : 'n');
|
|
}
|
|
|
|
var window = {
|
|
TKK: '0'
|
|
};
|
|
|
|
var yr = null;
|
|
var xr = function(a, b) {
|
|
for (var c = 0; c < b.length - 2; c += 3) {
|
|
var d = b.charAt(c + 2),
|
|
d = 'a' <= d ? d.charCodeAt(0) - 87 : Number(d),
|
|
d = '+' == b.charAt(c + 1) ? a >>> d : a << d;
|
|
a = '+' == b.charAt(c) ? (a + d) & 4294967295 : a ^ d;
|
|
}
|
|
return a
|
|
};
|
|
|
|
function sM(a) {
|
|
var b;
|
|
if (null !== yr) {
|
|
b = yr;
|
|
} else {
|
|
b = (yr = window.TKK || '') || '';
|
|
}
|
|
var d = b.split('.');
|
|
b = Number(d[0]) || 0;
|
|
for (var e = [], f = 0, g = 0; g < a.length; g++) {
|
|
var l = a.charCodeAt(g);
|
|
128 > l
|
|
? (e[f++] = l)
|
|
: (2048 > l
|
|
? (e[f++] = (l >> 6) | 192)
|
|
: (55296 == (l & 64512) &&
|
|
g + 1 < a.length &&
|
|
56320 == (a.charCodeAt(g + 1) & 64512)
|
|
? ((l = 65536 + ((l & 1023) << 10) + (a.charCodeAt(++g) & 1023)),
|
|
(e[f++] = (l >> 18) | 240),
|
|
(e[f++] = ((l >> 12) & 63) | 128))
|
|
: (e[f++] = (l >> 12) | 224),
|
|
(e[f++] = ((l >> 6) & 63) | 128)),
|
|
(e[f++] = (l & 63) | 128));
|
|
}
|
|
a = b;
|
|
for (f = 0; f < e.length; f++) (a += e[f]), (a = xr(a, '+-a^+6'));
|
|
a = xr(a, '+-3^+b+-f');
|
|
a ^= Number(d[1]) || 0;
|
|
0 > a && (a = (a & 2147483647) + 2147483648);
|
|
a %= 1e6;
|
|
return a.toString() + '.' + (a ^ b)
|
|
}
|
|
|
|
/**
|
|
* 代码来自 https://github.com/matheuss/google-translate-token
|
|
* 做了一些修改以适应本项目
|
|
*/
|
|
function updateTKK(com) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var now, html, code;
|
|
return tslib.__generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0:
|
|
now = Math.floor(Date.now() / 3600000);
|
|
if (Number(window.TKK.split('.')[0]) === now) {
|
|
return [2 /*return*/];
|
|
}
|
|
return [4 /*yield*/, request({
|
|
url: getRoot(com),
|
|
responseType: 'text'
|
|
})];
|
|
case 1:
|
|
html = _a.sent();
|
|
code = html.match(/tkk:'(\d+\.\d+)'/);
|
|
if (code) {
|
|
window.TKK = code[1];
|
|
}
|
|
return [2 /*return*/];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function sign$2 (text, com) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
return tslib.__generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, updateTKK(com)];
|
|
case 1:
|
|
_a.sent();
|
|
return [2 /*return*/, sM(text)];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function detect$1 (options) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var _a, text, _b, com, result, _c, _d, _e, src;
|
|
return tslib.__generator(this, function (_f) {
|
|
switch (_f.label) {
|
|
case 0:
|
|
_a = typeof options === 'string' ? { text: options } : options, text = _a.text, _b = _a.com, com = _b === void 0 ? false : _b;
|
|
_c = request;
|
|
_d = {
|
|
url: getRoot(com) + '/translate_a/single'
|
|
};
|
|
_e = {
|
|
client: 'webapp',
|
|
sl: 'auto',
|
|
tl: 'zh-CN',
|
|
hl: 'zh-CN',
|
|
ssel: '3',
|
|
tsel: '0',
|
|
kc: '0'
|
|
};
|
|
return [4 /*yield*/, sign$2(text, com)];
|
|
case 1: return [4 /*yield*/, _c.apply(void 0, [(_d.query = (_e.tk = _f.sent(),
|
|
_e.q = text,
|
|
_e),
|
|
_d)])];
|
|
case 2:
|
|
result = _f.sent();
|
|
src = result && result[2];
|
|
if (src)
|
|
return [2 /*return*/, src];
|
|
throw getError("UNSUPPORTED_LANG" /* UNSUPPORTED_LANG */);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function audio$1 (options) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var _a, text, _b, from, _c, com, _d;
|
|
return tslib.__generator(this, function (_e) {
|
|
switch (_e.label) {
|
|
case 0:
|
|
_a = typeof options === 'string' ? { text: options } : options, text = _a.text, _b = _a.from, from = _b === void 0 ? '' : _b, _c = _a.com, com = _c === void 0 ? false : _c;
|
|
if (!!from) return [3 /*break*/, 2];
|
|
return [4 /*yield*/, detect$1(text)];
|
|
case 1:
|
|
from = _e.sent();
|
|
_e.label = 2;
|
|
case 2:
|
|
_d = getRoot(com) + "/translate_tts?ie=UTF-8&q=" + encodeURIComponent(text) + "&tl=" + from + "&total=1&idx=0&textlen=" + text.length + "&tk=";
|
|
return [4 /*yield*/, sign$2(text, com)];
|
|
case 3: return [2 /*return*/, _d + (_e.sent()) + "&client=webapp&prev=input"];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
function translate$1 (options) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var _a, text, _b, com, _c, from, _d, to, _e, _f, _g, _h;
|
|
return tslib.__generator(this, function (_j) {
|
|
switch (_j.label) {
|
|
case 0:
|
|
_a = typeof options === 'string' ? { text: options } : options, text = _a.text, _b = _a.com, com = _b === void 0 ? false : _b, _c = _a.from, from = _c === void 0 ? '' : _c, _d = _a.to, to = _d === void 0 ? '' : _d;
|
|
if (!!from) return [3 /*break*/, 2];
|
|
return [4 /*yield*/, detect$1(options)];
|
|
case 1:
|
|
from = _j.sent();
|
|
_j.label = 2;
|
|
case 2:
|
|
if (!to) {
|
|
to = from.startsWith('zh') ? 'en' : 'zh-CN';
|
|
}
|
|
_e = transformRaw$1;
|
|
_f = request;
|
|
_g = {
|
|
url: getRoot(com) + '/translate_a/single'
|
|
};
|
|
_h = {
|
|
client: 'webapp',
|
|
sl: from,
|
|
tl: to,
|
|
hl: 'zh-CN',
|
|
dt: ['at', 'bd', 'ex', 'ld', 'md', 'qca', 'rw', 'rm', 'ss', 't'],
|
|
otf: '2',
|
|
ssel: '3',
|
|
tsel: '0',
|
|
kc: '6'
|
|
};
|
|
return [4 /*yield*/, sign$2(text, com)];
|
|
case 3: return [4 /*yield*/, _f.apply(void 0, [(_g.query = (_h.tk = _j.sent(),
|
|
_h.q = text,
|
|
_h),
|
|
_g)])];
|
|
case 4: return [2 /*return*/, _e.apply(void 0, [_j.sent(),
|
|
{
|
|
from: from,
|
|
to: to,
|
|
com: com,
|
|
text: text
|
|
}])];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function transformRaw$1(body, queryObj) {
|
|
var text = queryObj.text, com = queryObj.com, to = queryObj.to;
|
|
var googleFrom = body[2];
|
|
var result = {
|
|
text: text,
|
|
raw: body,
|
|
from: googleFrom,
|
|
to: to,
|
|
link: getRoot(com) + "/#view=home&op=translate&sl=" + googleFrom + "&tl=" + to + "&text=" + encodeURIComponent(text)
|
|
};
|
|
try {
|
|
result.dict = body[1].map(function (arr) {
|
|
return arr[0] + ':' + arr[1].join(',');
|
|
});
|
|
}
|
|
catch (e) { }
|
|
try {
|
|
result.result = body[0]
|
|
.map(function (arr) { return arr[0]; })
|
|
.filter(function (x) { return x; })
|
|
.map(function (x) { return x.trim(); });
|
|
}
|
|
catch (e) { }
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
var index$1 = /*#__PURE__*/Object.freeze({
|
|
__proto__: null,
|
|
detect: detect$1,
|
|
audio: audio$1,
|
|
translate: translate$1
|
|
});
|
|
|
|
function md5 (text) {
|
|
return crypto.createHash('md5')
|
|
.update(text)
|
|
.digest('hex');
|
|
}
|
|
|
|
var client = 'fanyideskweb';
|
|
var navigatorAppVersion = '5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
|
|
;
|
|
var bv = md5(navigatorAppVersion);
|
|
/**
|
|
* 有道翻译接口的签名算法
|
|
* @param text
|
|
*/
|
|
function sign$3 (text) {
|
|
var ts = Date.now() + '';
|
|
var salt = ts + parseInt(10 * Math.random() + '', 10);
|
|
return {
|
|
client: client,
|
|
ts: ts,
|
|
bv: bv,
|
|
salt: salt,
|
|
sign: md5(client + text + salt + 'mmbP%A-r6U3Nw(n]BjuEU')
|
|
};
|
|
}
|
|
|
|
var standard2custom$1 = {
|
|
en: 'en',
|
|
ru: 'ru',
|
|
pt: 'pt',
|
|
es: 'es',
|
|
'zh-CN': 'zh-CHS',
|
|
ja: 'ja',
|
|
ko: 'ko',
|
|
fr: 'fr'
|
|
};
|
|
var custom2standard$1 = invert(standard2custom$1);
|
|
var link = 'http://fanyi.youdao.com';
|
|
var translateAPI = link + '/translate_o?smartresult=dict&smartresult=rule';
|
|
// 有道跟百度一样,通过添加一个 Cookie 鉴别请求是否来自网页
|
|
var headers$2 = { Referer: link, Cookie: 'OUTFOX_SEARCH_USER_ID=-1799202939@10.168.8.64' }
|
|
;
|
|
function webAPI (options) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var _a, text, _b, from, _c, to, _d;
|
|
return tslib.__generator(this, function (_e) {
|
|
switch (_e.label) {
|
|
case 0:
|
|
_a = typeof options === 'string' ? { text: options } : options, text = _a.text, _b = _a.from, from = _b === void 0 ? '' : _b, _c = _a.to, to = _c === void 0 ? '' : _c;
|
|
text = text.slice(0, 5000);
|
|
if (from) {
|
|
from = standard2custom$1[from];
|
|
}
|
|
else {
|
|
from = 'AUTO';
|
|
}
|
|
if (to) {
|
|
to = standard2custom$1[to];
|
|
}
|
|
else {
|
|
to = 'AUTO';
|
|
}
|
|
// 有道网页翻译的接口的语种与目标语种中必须有一个是中文,或者两个都是 AUTO
|
|
if (!((from === 'AUTO' && to === 'AUTO') ||
|
|
(from === 'zh-CHS' || to === 'zh-CHS'))) {
|
|
throw getError("UNSUPPORTED_LANG" /* UNSUPPORTED_LANG */);
|
|
}
|
|
_d = transformRaw$2;
|
|
return [4 /*yield*/, request({
|
|
method: 'post',
|
|
url: translateAPI,
|
|
type: 'form',
|
|
body: Object.assign({
|
|
i: text,
|
|
from: from,
|
|
to: to,
|
|
smartresult: 'dict',
|
|
doctype: 'json',
|
|
version: '2.1',
|
|
keyfrom: 'fanyi.web',
|
|
action: 'FY_BY_REALTIME',
|
|
typoResult: 'false'
|
|
}, sign$3(text)),
|
|
headers: headers$2
|
|
})];
|
|
case 1: return [2 /*return*/, _d.apply(void 0, [_e.sent(),
|
|
text])];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function transformRaw$2(body, text) {
|
|
if (body.errorCode !== 0) {
|
|
throw getError("API_SERVER_ERROR" /* API_SERVER_ERROR */);
|
|
}
|
|
var _a = body.type.split('2'), from = _a[0], to = _a[1];
|
|
from = custom2standard$1[from];
|
|
to = custom2standard$1[to];
|
|
var smartResult = body.smartResult;
|
|
var result = {
|
|
raw: body,
|
|
text: text,
|
|
from: from,
|
|
to: to,
|
|
link: smartResult
|
|
? "https://dict.youdao.com/search?q=" + encodeURIComponent(text) + "&keyfrom=fanyi.smartResult"
|
|
: "http://fanyi.youdao.com/translate?i=" + encodeURIComponent(text)
|
|
};
|
|
if (smartResult) {
|
|
try {
|
|
result.dict = smartResult.entries.filter(function (s) { return s; }).map(function (s) { return s.trim(); });
|
|
}
|
|
catch (e) { }
|
|
}
|
|
try {
|
|
result.result = body.translateResult.map(function (part) {
|
|
return part.map(function (o) { return o.tgt.trim(); }).join('');
|
|
});
|
|
}
|
|
catch (e) { }
|
|
return result;
|
|
}
|
|
|
|
function detect$2 (options) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var result;
|
|
return tslib.__generator(this, function (_a) {
|
|
switch (_a.label) {
|
|
case 0: return [4 /*yield*/, webAPI(typeof options === 'string' ? options : options.text)];
|
|
case 1:
|
|
result = _a.sent();
|
|
return [2 /*return*/, result.from];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
var standard2custom$2 = {
|
|
en: 'eng',
|
|
ja: 'jap',
|
|
ko: 'ko',
|
|
fr: 'fr'
|
|
};
|
|
function audio$2 (options) {
|
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
var _a, text, _b, from, voiceLang;
|
|
return tslib.__generator(this, function (_c) {
|
|
switch (_c.label) {
|
|
case 0:
|
|
_a = typeof options === 'string' ? { text: options } : options, text = _a.text, _b = _a.from, from = _b === void 0 ? '' : _b;
|
|
if (!!from) return [3 /*break*/, 2];
|
|
return [4 /*yield*/, detect$2(text)];
|
|
case 1:
|
|
from = _c.sent();
|
|
_c.label = 2;
|
|
case 2:
|
|
voiceLang = standard2custom$2[from];
|
|
if (!voiceLang)
|
|
throw getError("UNSUPPORTED_LANG" /* UNSUPPORTED_LANG */);
|
|
return [2 /*return*/, "http://tts.youdao.com/fanyivoice?word=" + encodeURIComponent(text) + "&le=" + voiceLang + "&keyfrom=speaker-target"];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
|
|
var index$2 = /*#__PURE__*/Object.freeze({
|
|
__proto__: null,
|
|
detect: detect$2,
|
|
audio: audio$2,
|
|
translate: webAPI
|
|
});
|
|
|
|
exports.baidu = index;
|
|
exports.google = index$1;
|
|
exports.youdao = index$2;
|
|
|