add more translators: baidu/tencent/deeplfree
This commit is contained in:
@@ -95,6 +95,7 @@ const userscriptWebpack = (config, env) => {
|
|||||||
// @connect edge.microsoft.com
|
// @connect edge.microsoft.com
|
||||||
// @connect api-free.deepl.com
|
// @connect api-free.deepl.com
|
||||||
// @connect api.deepl.com
|
// @connect api.deepl.com
|
||||||
|
// @connect www2.deepl.com
|
||||||
// @connect api.openai.com
|
// @connect api.openai.com
|
||||||
// @connect openai.azure.com
|
// @connect openai.azure.com
|
||||||
// @connect workers.dev
|
// @connect workers.dev
|
||||||
@@ -104,6 +105,7 @@ const userscriptWebpack = (config, env) => {
|
|||||||
// @connect ghproxy.com
|
// @connect ghproxy.com
|
||||||
// @connect dav.jianguoyun.com
|
// @connect dav.jianguoyun.com
|
||||||
// @connect fanyi.baidu.com
|
// @connect fanyi.baidu.com
|
||||||
|
// @connect transmart.qq.com
|
||||||
// @connect localhost:3000
|
// @connect localhost:3000
|
||||||
// @connect 127.0.0.1:3000
|
// @connect 127.0.0.1:3000
|
||||||
// @connect localhost:1188
|
// @connect localhost:1188
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import { fetchPolyfill } from "../libs/fetch";
|
|
||||||
import { getBdauth, setBdauth } from "../libs/storage";
|
import { getBdauth, setBdauth } from "../libs/storage";
|
||||||
import { URL_BAIDU_WEB, URL_BAIDU_TRAN } from "../config";
|
import { URL_BAIDU_WEB, URL_BAIDU_TRAN } from "../config";
|
||||||
|
import { fetchApi } from "../libs/fetch";
|
||||||
|
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
function n(t, e) {
|
function n(t, e) {
|
||||||
@@ -147,26 +147,13 @@ function getSign(t, gtk, r = null) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCookie = async () => {
|
const getToken = async () => {
|
||||||
const res = await fetch(URL_BAIDU_WEB, {
|
const res = await fetchApi({
|
||||||
|
input: URL_BAIDU_WEB,
|
||||||
|
init: {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "text/html; charset=utf-8",
|
"Content-type": "text/html; charset=utf-8",
|
||||||
},
|
},
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
throw new Error(res.statusText);
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.headers.get("set-cookie");
|
|
||||||
};
|
|
||||||
|
|
||||||
const getToken = async () => {
|
|
||||||
const cookie = await getCookie();
|
|
||||||
const res = await fetch(URL_BAIDU_WEB, {
|
|
||||||
headers: {
|
|
||||||
"Content-type": "text/html; charset=utf-8",
|
|
||||||
cookie,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -179,7 +166,11 @@ const getToken = async () => {
|
|||||||
const gtk = text.match(/gtk = "(.*)";/)[1];
|
const gtk = text.match(/gtk = "(.*)";/)[1];
|
||||||
const exp = Date.now() + 8 * 60 * 60 * 1000;
|
const exp = Date.now() + 8 * 60 * 60 * 1000;
|
||||||
|
|
||||||
return { cookie, token, gtk, exp };
|
if (!token || !gtk) {
|
||||||
|
throw new Error("[baidu] get token error");
|
||||||
|
}
|
||||||
|
|
||||||
|
return { token, gtk, exp };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -212,21 +203,8 @@ const _bdAuth = () => {
|
|||||||
|
|
||||||
const bdAuth = _bdAuth();
|
const bdAuth = _bdAuth();
|
||||||
|
|
||||||
/**
|
export const genBaidu = async ({ text, from, to }) => {
|
||||||
* 腾讯翻译
|
const { token, gtk } = await bdAuth();
|
||||||
* @param {*} text
|
|
||||||
* @param {*} to
|
|
||||||
* @param {*} from
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const apiBaiduTranslate = async (
|
|
||||||
translator,
|
|
||||||
text,
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
{ useCache = true }
|
|
||||||
) => {
|
|
||||||
const { cookie, token, gtk } = await bdAuth();
|
|
||||||
const sign = getSign(text, gtk);
|
const sign = getSign(text, gtk);
|
||||||
const data = {
|
const data = {
|
||||||
from,
|
from,
|
||||||
@@ -239,19 +217,14 @@ export const apiBaiduTranslate = async (
|
|||||||
ts: Date.now(),
|
ts: Date.now(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const res = await fetchPolyfill(`${URL_BAIDU_TRAN}?from=${from}&to=${to}`, {
|
const input = `${URL_BAIDU_TRAN}?from=${from}&to=${to}`;
|
||||||
|
const init = {
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
|
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||||
cookie,
|
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: queryString.stringify(data),
|
body: queryString.stringify(data),
|
||||||
useCache,
|
};
|
||||||
usePool: true,
|
|
||||||
translator,
|
return [input, init];
|
||||||
});
|
|
||||||
const trText = res.trans_result?.data.map((item) => item.dst).join(" ");
|
|
||||||
const isSame = res.trans_result?.to === res.trans_result?.from;
|
|
||||||
|
|
||||||
return [trText, isSame, res];
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,22 +1,8 @@
|
|||||||
import { fetchPolyfill } from "../libs/fetch";
|
|
||||||
import { URL_DEEPLFREE_TRAN } from "../config";
|
import { URL_DEEPLFREE_TRAN } from "../config";
|
||||||
|
|
||||||
let id = 1e4 * Math.round(1e4 * Math.random());
|
let id = 1e4 * Math.round(1e4 * Math.random());
|
||||||
|
|
||||||
/**
|
export const genDeeplFree = ({ text, from, to }) => {
|
||||||
* DeepL翻译
|
|
||||||
* @param {*} text
|
|
||||||
* @param {*} to
|
|
||||||
* @param {*} from
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const apiDeepLFreeTranslate = async (
|
|
||||||
translator,
|
|
||||||
text,
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
{ useCache = true }
|
|
||||||
) => {
|
|
||||||
const iCount = (text.match(/[i]/g) || []).length + 1;
|
const iCount = (text.match(/[i]/g) || []).length + 1;
|
||||||
let timestamp = Date.now();
|
let timestamp = Date.now();
|
||||||
timestamp = timestamp + (iCount - (timestamp % iCount));
|
timestamp = timestamp + (iCount - (timestamp % iCount));
|
||||||
@@ -51,7 +37,7 @@ export const apiDeepLFreeTranslate = async (
|
|||||||
(id + 3) % 13 === 0 || (id + 5) % 29 === 0 ? 'method" : "' : 'method": "'
|
(id + 3) % 13 === 0 || (id + 5) % 29 === 0 ? 'method" : "' : 'method": "'
|
||||||
);
|
);
|
||||||
|
|
||||||
const res = await fetchPolyfill(URL_DEEPLFREE_TRAN, {
|
const init = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Accept: "*/*",
|
Accept: "*/*",
|
||||||
@@ -66,12 +52,7 @@ export const apiDeepLFreeTranslate = async (
|
|||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body,
|
body,
|
||||||
useCache,
|
};
|
||||||
usePool: true,
|
|
||||||
translator,
|
return [URL_DEEPLFREE_TRAN, init];
|
||||||
});
|
|
||||||
const trText = res.result?.texts.map((item) => item.text).join(" ");
|
|
||||||
const isSame = to === res.result?.lang;
|
|
||||||
|
|
||||||
return [trText, isSame];
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,19 +11,14 @@ import {
|
|||||||
OPT_TRANS_OPENAI,
|
OPT_TRANS_OPENAI,
|
||||||
OPT_TRANS_CUSTOMIZE,
|
OPT_TRANS_CUSTOMIZE,
|
||||||
URL_CACHE_TRAN,
|
URL_CACHE_TRAN,
|
||||||
OPT_LANGS_SPECIAL,
|
|
||||||
PROMPT_PLACE_FROM,
|
|
||||||
PROMPT_PLACE_TO,
|
|
||||||
KV_SALT_SYNC,
|
KV_SALT_SYNC,
|
||||||
URL_BAIDU_LANGDETECT,
|
URL_BAIDU_LANGDETECT,
|
||||||
URL_MICROSOFT_TRAN,
|
|
||||||
OPT_LANGS_BAIDU,
|
OPT_LANGS_BAIDU,
|
||||||
|
URL_TENCENT_TRANSMART,
|
||||||
|
OPT_LANGS_TENCENT,
|
||||||
|
OPT_LANGS_SPECIAL,
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import { tryDetectLang } from "../libs";
|
|
||||||
import { sha256 } from "../libs/utils";
|
import { sha256 } from "../libs/utils";
|
||||||
import { apiDeepLFreeTranslate } from "./deepl";
|
|
||||||
import { apiBaiduTranslate } from "./baidu";
|
|
||||||
import { apiTencentTranslate } from "./tencent";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步数据
|
* 同步数据
|
||||||
@@ -49,244 +44,6 @@ export const apiSyncData = async (url, key, data) =>
|
|||||||
*/
|
*/
|
||||||
export const apiFetch = (url) => fetchPolyfill(url);
|
export const apiFetch = (url) => fetchPolyfill(url);
|
||||||
|
|
||||||
/**
|
|
||||||
* 谷歌翻译
|
|
||||||
* @param {*} text
|
|
||||||
* @param {*} to
|
|
||||||
* @param {*} from
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const apiGoogleTranslate = async (
|
|
||||||
translator,
|
|
||||||
text,
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
{ url, key, useCache = true }
|
|
||||||
) => {
|
|
||||||
const params = {
|
|
||||||
client: "gtx",
|
|
||||||
dt: "t",
|
|
||||||
dj: 1,
|
|
||||||
ie: "UTF-8",
|
|
||||||
sl: from,
|
|
||||||
tl: to,
|
|
||||||
q: text,
|
|
||||||
};
|
|
||||||
const input = `${url}?${queryString.stringify(params)}`;
|
|
||||||
const res = await fetchPolyfill(input, {
|
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
useCache,
|
|
||||||
usePool: true,
|
|
||||||
translator,
|
|
||||||
token: key,
|
|
||||||
});
|
|
||||||
const trText = res.sentences.map((item) => item.trans).join(" ");
|
|
||||||
const isSame = to === res.src;
|
|
||||||
|
|
||||||
return [trText, isSame];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 微软翻译
|
|
||||||
* @param {*} text
|
|
||||||
* @param {*} to
|
|
||||||
* @param {*} from
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const apiMicrosoftTranslate = async (
|
|
||||||
translator,
|
|
||||||
text,
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
{ useCache = true }
|
|
||||||
) => {
|
|
||||||
const params = {
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
"api-version": "3.0",
|
|
||||||
};
|
|
||||||
const input = `${URL_MICROSOFT_TRAN}?${queryString.stringify(params)}`;
|
|
||||||
const res = await fetchPolyfill(input, {
|
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify([{ Text: text }]),
|
|
||||||
useCache,
|
|
||||||
usePool: true,
|
|
||||||
translator,
|
|
||||||
});
|
|
||||||
const trText = res[0].translations[0].text;
|
|
||||||
const isSame = to === res[0].detectedLanguage?.language;
|
|
||||||
|
|
||||||
return [trText, isSame];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DeepL翻译
|
|
||||||
* @param {*} text
|
|
||||||
* @param {*} to
|
|
||||||
* @param {*} from
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const apiDeepLTranslate = async (
|
|
||||||
translator,
|
|
||||||
text,
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
{ url, key, useCache = true }
|
|
||||||
) => {
|
|
||||||
const data = {
|
|
||||||
text: [text],
|
|
||||||
target_lang: to,
|
|
||||||
// split_sentences: "0",
|
|
||||||
};
|
|
||||||
if (from) {
|
|
||||||
data.source_lang = from;
|
|
||||||
}
|
|
||||||
const res = await fetchPolyfill(url, {
|
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
useCache,
|
|
||||||
usePool: true,
|
|
||||||
translator,
|
|
||||||
token: key,
|
|
||||||
});
|
|
||||||
const trText = res.translations.map((item) => item.text).join(" ");
|
|
||||||
const isSame = to === res.translations[0].detected_source_language;
|
|
||||||
|
|
||||||
return [trText, isSame];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DeepLX翻译
|
|
||||||
* https://github.com/OwO-Network/DeepLX
|
|
||||||
* @param {*} text
|
|
||||||
* @param {*} to
|
|
||||||
* @param {*} from
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const apiDeepLXTranslate = async (
|
|
||||||
translator,
|
|
||||||
text,
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
{ url, key, useCache = true }
|
|
||||||
) => {
|
|
||||||
const data = {
|
|
||||||
text,
|
|
||||||
target_lang: to,
|
|
||||||
};
|
|
||||||
if (from) {
|
|
||||||
data.source_lang = from;
|
|
||||||
}
|
|
||||||
const res = await fetchPolyfill(url, {
|
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
useCache,
|
|
||||||
usePool: true,
|
|
||||||
translator,
|
|
||||||
token: key,
|
|
||||||
});
|
|
||||||
const trText = res.data;
|
|
||||||
const isSame = to === res.source_lang;
|
|
||||||
|
|
||||||
return [trText, isSame];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OpenAI 翻译
|
|
||||||
* @param {*} text
|
|
||||||
* @param {*} to
|
|
||||||
* @param {*} from
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const apiOpenaiTranslate = async (
|
|
||||||
translator,
|
|
||||||
text,
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
{ url, key, model, prompt, useCache = true }
|
|
||||||
) => {
|
|
||||||
prompt = prompt
|
|
||||||
.replaceAll(PROMPT_PLACE_FROM, from)
|
|
||||||
.replaceAll(PROMPT_PLACE_TO, to);
|
|
||||||
const res = await fetchPolyfill(url, {
|
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({
|
|
||||||
model: model,
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: "system",
|
|
||||||
content: prompt,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: text,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
temperature: 0,
|
|
||||||
max_tokens: 256,
|
|
||||||
}),
|
|
||||||
useCache,
|
|
||||||
usePool: true,
|
|
||||||
translator,
|
|
||||||
token: key,
|
|
||||||
});
|
|
||||||
const trText = res?.choices?.[0].message.content;
|
|
||||||
const sLang = await tryDetectLang(text);
|
|
||||||
const tLang = await tryDetectLang(trText);
|
|
||||||
const isSame = text === trText || (sLang && tLang && sLang === tLang);
|
|
||||||
|
|
||||||
return [trText, isSame];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义接口 翻译
|
|
||||||
* @param {*} text
|
|
||||||
* @param {*} to
|
|
||||||
* @param {*} from
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const apiCustomTranslate = async (
|
|
||||||
translator,
|
|
||||||
text,
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
{ url, key, useCache = true }
|
|
||||||
) => {
|
|
||||||
const res = await fetchPolyfill(url, {
|
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({
|
|
||||||
text,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
}),
|
|
||||||
useCache,
|
|
||||||
usePool: true,
|
|
||||||
translator,
|
|
||||||
token: key,
|
|
||||||
});
|
|
||||||
const trText = res.text;
|
|
||||||
const isSame = to === res.from;
|
|
||||||
|
|
||||||
return [trText, isSame];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 百度语言识别
|
* 百度语言识别
|
||||||
* @param {*} text
|
* @param {*} text
|
||||||
@@ -311,6 +68,31 @@ export const apiBaiduLangdetect = async (text) => {
|
|||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 腾讯语言识别
|
||||||
|
* @param {*} text
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const apiTencentLangdetect = async (text) => {
|
||||||
|
const body = JSON.stringify({
|
||||||
|
header: {
|
||||||
|
fn: "text_analysis",
|
||||||
|
},
|
||||||
|
text,
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await fetchPolyfill(URL_TENCENT_TRANSMART, {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body,
|
||||||
|
useCache: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
return OPT_LANGS_TENCENT.get(res.language) ?? res.language;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 统一翻译接口
|
* 统一翻译接口
|
||||||
* @param {*} param0
|
* @param {*} param0
|
||||||
@@ -328,15 +110,31 @@ export const apiTranslate = async ({
|
|||||||
let trText = "";
|
let trText = "";
|
||||||
let isSame = false;
|
let isSame = false;
|
||||||
|
|
||||||
const transOpts = {
|
const from =
|
||||||
|
OPT_LANGS_SPECIAL[translator].get(fromLang) ??
|
||||||
|
OPT_LANGS_SPECIAL[translator].get("auto");
|
||||||
|
const to = OPT_LANGS_SPECIAL[translator].get(toLang);
|
||||||
|
if (!to) {
|
||||||
|
console.log(`[trans] target lang: ${toLang} not support`);
|
||||||
|
return [trText, isSame];
|
||||||
|
}
|
||||||
|
|
||||||
|
const cacheOpts = {
|
||||||
translator,
|
translator,
|
||||||
text,
|
text,
|
||||||
fromLang,
|
fromLang,
|
||||||
toLang,
|
toLang,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const transOpts = {
|
||||||
|
translator,
|
||||||
|
text,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
};
|
||||||
|
|
||||||
const res = await fetchPolyfill(
|
const res = await fetchPolyfill(
|
||||||
`${URL_CACHE_TRAN}?${queryString.stringify(transOpts)}`,
|
`${URL_CACHE_TRAN}?${queryString.stringify(cacheOpts)}`,
|
||||||
{
|
{
|
||||||
useCache,
|
useCache,
|
||||||
usePool,
|
usePool,
|
||||||
@@ -347,30 +145,44 @@ export const apiTranslate = async ({
|
|||||||
|
|
||||||
switch (translator) {
|
switch (translator) {
|
||||||
case OPT_TRANS_GOOGLE:
|
case OPT_TRANS_GOOGLE:
|
||||||
|
trText = res.sentences.map((item) => item.trans).join(" ");
|
||||||
|
isSame = to === res.src;
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_MICROSOFT:
|
case OPT_TRANS_MICROSOFT:
|
||||||
trText = res[0].translations[0].text;
|
trText = res[0].translations.map((item) => item.text).join(" ");
|
||||||
isSame = toLang === res[0].detectedLanguage?.language;
|
isSame = text === trText;
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_DEEPL:
|
case OPT_TRANS_DEEPL:
|
||||||
|
trText = res.translations.map((item) => item.text).join(" ");
|
||||||
|
isSame = to === res.translations[0].detected_source_language;
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_DEEPLFREE:
|
case OPT_TRANS_DEEPLFREE:
|
||||||
|
trText = res.result?.texts.map((item) => item.text).join(" ");
|
||||||
|
isSame = to === res.result?.lang;
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_DEEPLX:
|
case OPT_TRANS_DEEPLX:
|
||||||
|
trText = res.data;
|
||||||
|
isSame = to === res.source_lang;
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_BAIDU:
|
case OPT_TRANS_BAIDU:
|
||||||
|
trText = res.trans_result?.data.map((item) => item.dst).join(" ");
|
||||||
|
isSame = res.trans_result?.to === res.trans_result?.from;
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_TENCENT:
|
case OPT_TRANS_TENCENT:
|
||||||
trText = res.auto_translation;
|
trText = res.auto_translation;
|
||||||
isSame = text === trText;
|
isSame = text === trText;
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_OPENAI:
|
case OPT_TRANS_OPENAI:
|
||||||
|
trText = res?.choices?.[0].message.content;
|
||||||
|
isSame = text === trText;
|
||||||
break;
|
break;
|
||||||
case OPT_TRANS_CUSTOMIZE:
|
case OPT_TRANS_CUSTOMIZE:
|
||||||
|
trText = res.text;
|
||||||
|
isSame = to === res.from;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return [trText, isSame];
|
return [trText, isSame, res];
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
import { URL_TENCENT_TRANSMART, OPT_LANGS_TENCENT } from "../config";
|
|
||||||
import { fetchPolyfill } from "../libs/fetch";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 腾讯语言识别
|
|
||||||
* @param {*} text
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const apiTencentLangdetect = async (text) => {
|
|
||||||
const body = JSON.stringify({
|
|
||||||
header: {
|
|
||||||
fn: "text_analysis",
|
|
||||||
},
|
|
||||||
text,
|
|
||||||
});
|
|
||||||
|
|
||||||
const res = await fetchPolyfill(URL_TENCENT_TRANSMART, {
|
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body,
|
|
||||||
useCache: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
return OPT_LANGS_TENCENT.get(res.language) ?? res.language;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 腾讯翻译
|
|
||||||
* @param {*} text
|
|
||||||
* @param {*} to
|
|
||||||
* @param {*} from
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
export const apiTencentTranslate = async (
|
|
||||||
translator,
|
|
||||||
text,
|
|
||||||
to,
|
|
||||||
from,
|
|
||||||
{ useCache = true }
|
|
||||||
) => {
|
|
||||||
const data = {
|
|
||||||
header: {
|
|
||||||
fn: "auto_translation_block",
|
|
||||||
},
|
|
||||||
source: {
|
|
||||||
text_block: text,
|
|
||||||
},
|
|
||||||
target: {
|
|
||||||
lang: to,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (from) {
|
|
||||||
data.source.lang = from;
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await fetchPolyfill(URL_TENCENT_TRANSMART, {
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
useCache,
|
|
||||||
usePool: true,
|
|
||||||
translator,
|
|
||||||
});
|
|
||||||
const trText = res.auto_translation;
|
|
||||||
const isSame = text === trText;
|
|
||||||
|
|
||||||
return [trText, isSame];
|
|
||||||
};
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
import queryString from "query-string";
|
|
||||||
import { isExt, isGm } from "./client";
|
import { isExt, isGm } from "./client";
|
||||||
import { sendBgMsg } from "./msg";
|
import { sendBgMsg } from "./msg";
|
||||||
import { taskPool } from "./pool";
|
import { taskPool } from "./pool";
|
||||||
@@ -7,23 +6,11 @@ import {
|
|||||||
MSG_FETCH_LIMIT,
|
MSG_FETCH_LIMIT,
|
||||||
MSG_FETCH_CLEAR,
|
MSG_FETCH_CLEAR,
|
||||||
CACHE_NAME,
|
CACHE_NAME,
|
||||||
OPT_TRANS_GOOGLE,
|
|
||||||
OPT_TRANS_MICROSOFT,
|
|
||||||
OPT_TRANS_DEEPL,
|
|
||||||
OPT_TRANS_DEEPLFREE,
|
|
||||||
OPT_TRANS_DEEPLX,
|
|
||||||
OPT_TRANS_BAIDU,
|
|
||||||
OPT_TRANS_TENCENT,
|
|
||||||
OPT_TRANS_OPENAI,
|
|
||||||
OPT_TRANS_CUSTOMIZE,
|
|
||||||
DEFAULT_FETCH_INTERVAL,
|
DEFAULT_FETCH_INTERVAL,
|
||||||
DEFAULT_FETCH_LIMIT,
|
DEFAULT_FETCH_LIMIT,
|
||||||
OPT_LANGS_SPECIAL,
|
|
||||||
URL_MICROSOFT_TRAN,
|
|
||||||
URL_TENCENT_TRANSMART,
|
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import { msAuth } from "./auth";
|
|
||||||
import { isBg } from "./browser";
|
import { isBg } from "./browser";
|
||||||
|
import { newCacheReq, newTransReq } from "./req";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 油猴脚本的请求封装
|
* 油猴脚本的请求封装
|
||||||
@@ -38,153 +25,35 @@ export const fetchGM = async (input, { method = "GET", headers, body } = {}) =>
|
|||||||
url: input,
|
url: input,
|
||||||
headers,
|
headers,
|
||||||
data: body,
|
data: body,
|
||||||
onload: ({ response, responseHeaders, status, statusText }) => {
|
// withCredentials: true,
|
||||||
const headers = new Headers();
|
onload: ({ response, responseHeaders, status, statusText, ...opts }) => {
|
||||||
|
const headers = {};
|
||||||
responseHeaders.split("\n").forEach((line) => {
|
responseHeaders.split("\n").forEach((line) => {
|
||||||
const [name, value] = line.split(":").map((item) => item.trim());
|
const [name, value] = line.split(":").map((item) => item.trim());
|
||||||
if (name && value) {
|
if (name && value) {
|
||||||
headers.append(name, value);
|
headers[name] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
resolve(
|
resolve({
|
||||||
new Response(response, {
|
body: response,
|
||||||
headers,
|
headers,
|
||||||
status,
|
status,
|
||||||
statusText,
|
statusText,
|
||||||
})
|
});
|
||||||
);
|
|
||||||
},
|
},
|
||||||
onerror: reject,
|
onerror: reject,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* 构造缓存 request
|
|
||||||
* @param {*} request
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
const newCacheReq = async (input, init) => {
|
|
||||||
let request = new Request(input, init);
|
|
||||||
if (request.method !== "GET") {
|
|
||||||
const body = await request.text();
|
|
||||||
const cacheUrl = new URL(request.url);
|
|
||||||
cacheUrl.pathname += body;
|
|
||||||
request = new Request(cacheUrl.toString(), { method: "GET" });
|
|
||||||
}
|
|
||||||
|
|
||||||
return request;
|
|
||||||
};
|
|
||||||
|
|
||||||
const newTransReq = (
|
|
||||||
{ translator, text, fromLang, toLang },
|
|
||||||
{ url, key } = {}
|
|
||||||
) => {
|
|
||||||
// console.log({ translator, text, fromLang, toLang }, { url, key });
|
|
||||||
let params;
|
|
||||||
let data;
|
|
||||||
let input;
|
|
||||||
let init;
|
|
||||||
|
|
||||||
const from = OPT_LANGS_SPECIAL[translator].get(fromLang) ?? "";
|
|
||||||
const to = OPT_LANGS_SPECIAL[translator].get(toLang);
|
|
||||||
if (!to) {
|
|
||||||
throw new Error(`[trans] target lang: ${toLang} not support`);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (translator) {
|
|
||||||
case OPT_TRANS_GOOGLE:
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_MICROSOFT:
|
|
||||||
params = {
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
"api-version": "3.0",
|
|
||||||
};
|
|
||||||
input = `${URL_MICROSOFT_TRAN}?${queryString.stringify(params)}`;
|
|
||||||
init = {
|
|
||||||
headers: {
|
|
||||||
"Content-type": "application/json",
|
|
||||||
Authorization: `Bearer ${key}`,
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify([{ Text: text }]),
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_DEEPL:
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_DEEPLFREE:
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_DEEPLX:
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_BAIDU:
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_TENCENT:
|
|
||||||
data = {
|
|
||||||
header: {
|
|
||||||
fn: "auto_translation_block",
|
|
||||||
},
|
|
||||||
source: {
|
|
||||||
text_block: text,
|
|
||||||
},
|
|
||||||
target: {
|
|
||||||
lang: to,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if (from) {
|
|
||||||
data.source.lang = from;
|
|
||||||
}
|
|
||||||
input = URL_TENCENT_TRANSMART;
|
|
||||||
init = {
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify(data),
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_OPENAI:
|
|
||||||
break;
|
|
||||||
case OPT_TRANS_CUSTOMIZE:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!input) {
|
|
||||||
throw new Error(`[trans] translator: ${translator} not support`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [input, init];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发起请求
|
* 发起请求
|
||||||
* @param {*} param0
|
* @param {*} param0
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const fetchApi = async ({
|
export const fetchApi = async ({ input, init, transOpts, apiSetting }) => {
|
||||||
input,
|
|
||||||
init,
|
|
||||||
transOpts,
|
|
||||||
apiSetting,
|
|
||||||
token,
|
|
||||||
}) => {
|
|
||||||
if (token) {
|
|
||||||
apiSetting.key = token;
|
|
||||||
}
|
|
||||||
if (transOpts?.translator) {
|
if (transOpts?.translator) {
|
||||||
[input, init] = newTransReq(transOpts, apiSetting);
|
[input, init] = await newTransReq(transOpts, apiSetting);
|
||||||
}
|
}
|
||||||
// if (token) {
|
|
||||||
// if (translator === OPT_TRANS_DEEPL) {
|
|
||||||
// init.headers["Authorization"] = `DeepL-Auth-Key ${token}`; // DeepL
|
|
||||||
// } else if (translator === OPT_TRANS_OPENAI) {
|
|
||||||
// init.headers["Authorization"] = `Bearer ${token}`; // OpenAI
|
|
||||||
// init.headers["api-key"] = token; // Azure OpenAI
|
|
||||||
// } else {
|
|
||||||
// init.headers["Authorization"] = `Bearer ${token}`; // Microsoft & others
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (isGm) {
|
if (isGm) {
|
||||||
let info;
|
let info;
|
||||||
@@ -193,19 +62,26 @@ export const fetchApi = async ({
|
|||||||
} else {
|
} else {
|
||||||
info = GM.info;
|
info = GM.info;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tampermonkey --> .connects
|
// Tampermonkey --> .connects
|
||||||
// Violentmonkey --> .connect
|
// Violentmonkey --> .connect
|
||||||
const connects = info?.script?.connects || info?.script?.connect || [];
|
const connects = info?.script?.connects || info?.script?.connect || [];
|
||||||
const url = new URL(input);
|
const url = new URL(input);
|
||||||
const isSafe = connects.find((item) => url.hostname.endsWith(item));
|
const isSafe = connects.find((item) => url.hostname.endsWith(item));
|
||||||
|
|
||||||
if (isSafe) {
|
if (isSafe) {
|
||||||
if (window.KISS_GM) {
|
const { body, headers, status, statusText } = window.KISS_GM
|
||||||
return window.KISS_GM.fetch(input, init);
|
? await window.KISS_GM.fetch(input, init)
|
||||||
} else {
|
: await fetchGM(input, init);
|
||||||
return fetchGM(input, init);
|
|
||||||
}
|
return new Response(body, {
|
||||||
|
headers: new Headers(headers),
|
||||||
|
status,
|
||||||
|
statusText,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fetch(input, init);
|
return fetch(input, init);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -214,13 +90,7 @@ export const fetchApi = async ({
|
|||||||
*/
|
*/
|
||||||
export const fetchPool = taskPool(
|
export const fetchPool = taskPool(
|
||||||
fetchApi,
|
fetchApi,
|
||||||
async ({ transOpts }) => {
|
null,
|
||||||
if (transOpts?.translator === OPT_TRANS_MICROSOFT) {
|
|
||||||
const [token] = await msAuth();
|
|
||||||
return { token };
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
DEFAULT_FETCH_INTERVAL,
|
DEFAULT_FETCH_INTERVAL,
|
||||||
DEFAULT_FETCH_LIMIT
|
DEFAULT_FETCH_LIMIT
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export const taskPool = (
|
|||||||
curCount++;
|
curCount++;
|
||||||
const { args, resolve, reject, retry } = item;
|
const { args, resolve, reject, retry } = item;
|
||||||
try {
|
try {
|
||||||
const preArgs = await preFn(item.args);
|
const preArgs = preFn ? await preFn(item.args) : {};
|
||||||
const res = await fn({ ...args, ...preArgs });
|
const res = await fn({ ...args, ...preArgs });
|
||||||
resolve(res);
|
resolve(res);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
224
src/libs/req.js
Normal file
224
src/libs/req.js
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
import queryString from "query-string";
|
||||||
|
import {
|
||||||
|
OPT_TRANS_GOOGLE,
|
||||||
|
OPT_TRANS_MICROSOFT,
|
||||||
|
OPT_TRANS_DEEPL,
|
||||||
|
OPT_TRANS_DEEPLFREE,
|
||||||
|
OPT_TRANS_DEEPLX,
|
||||||
|
OPT_TRANS_BAIDU,
|
||||||
|
OPT_TRANS_TENCENT,
|
||||||
|
OPT_TRANS_OPENAI,
|
||||||
|
OPT_TRANS_CUSTOMIZE,
|
||||||
|
URL_MICROSOFT_TRAN,
|
||||||
|
URL_TENCENT_TRANSMART,
|
||||||
|
PROMPT_PLACE_FROM,
|
||||||
|
PROMPT_PLACE_TO,
|
||||||
|
} from "../config";
|
||||||
|
import { msAuth } from "./auth";
|
||||||
|
import { genDeeplFree } from "../apis/deepl";
|
||||||
|
import { genBaidu } from "../apis/baidu";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造缓存 request
|
||||||
|
* @param {*} request
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const newCacheReq = async (input, init) => {
|
||||||
|
let request = new Request(input, init);
|
||||||
|
if (request.method !== "GET") {
|
||||||
|
const body = await request.text();
|
||||||
|
const cacheUrl = new URL(request.url);
|
||||||
|
cacheUrl.pathname += body;
|
||||||
|
request = new Request(cacheUrl.toString(), { method: "GET" });
|
||||||
|
}
|
||||||
|
|
||||||
|
return request;
|
||||||
|
};
|
||||||
|
|
||||||
|
const genGoogle = ({ text, from, to, url, key }) => {
|
||||||
|
const params = {
|
||||||
|
client: "gtx",
|
||||||
|
dt: "t",
|
||||||
|
dj: 1,
|
||||||
|
ie: "UTF-8",
|
||||||
|
sl: from,
|
||||||
|
tl: to,
|
||||||
|
q: text,
|
||||||
|
};
|
||||||
|
const input = `${url}?${queryString.stringify(params)}`;
|
||||||
|
const init = {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (key) {
|
||||||
|
init.headers.Authorization = `Bearer ${key}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [input, init];
|
||||||
|
};
|
||||||
|
|
||||||
|
const genMicrosoft = async ({ text, from, to }) => {
|
||||||
|
const [token] = await msAuth();
|
||||||
|
const params = {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
"api-version": "3.0",
|
||||||
|
};
|
||||||
|
const input = `${URL_MICROSOFT_TRAN}?${queryString.stringify(params)}`;
|
||||||
|
const init = {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify([{ Text: text }]),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [input, init];
|
||||||
|
};
|
||||||
|
|
||||||
|
const genDeepl = ({ text, from, to, url, key }) => {
|
||||||
|
const data = {
|
||||||
|
text: [text],
|
||||||
|
target_lang: to,
|
||||||
|
source_lang: from,
|
||||||
|
// split_sentences: "0",
|
||||||
|
};
|
||||||
|
const init = {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
Authorization: `DeepL-Auth-Key ${key}`,
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [url, init];
|
||||||
|
};
|
||||||
|
|
||||||
|
const genDeeplX = ({ text, from, to, url, key }) => {
|
||||||
|
const data = {
|
||||||
|
text,
|
||||||
|
target_lang: to,
|
||||||
|
source_lang: from,
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
if (key) {
|
||||||
|
init.headers.Authorization = `Bearer ${key}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [url, init];
|
||||||
|
};
|
||||||
|
|
||||||
|
const genTencent = ({ text, from, to }) => {
|
||||||
|
const data = {
|
||||||
|
header: {
|
||||||
|
fn: "auto_translation_block",
|
||||||
|
},
|
||||||
|
source: {
|
||||||
|
text_block: text,
|
||||||
|
lang: from,
|
||||||
|
},
|
||||||
|
target: {
|
||||||
|
lang: to,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = {
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [URL_TENCENT_TRANSMART, init];
|
||||||
|
};
|
||||||
|
|
||||||
|
const genOpenai = ({ text, from, to, url, key, prompt, model }) => {
|
||||||
|
prompt = prompt
|
||||||
|
.replaceAll(PROMPT_PLACE_FROM, from)
|
||||||
|
.replaceAll(PROMPT_PLACE_TO, to);
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
model,
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: "system",
|
||||||
|
content: prompt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: text,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
temperature: 0,
|
||||||
|
max_tokens: 256,
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
Authorization: `Bearer ${key}`, // OpenAI
|
||||||
|
"api-key": key, // Azure OpenAI
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
|
||||||
|
return [url, init];
|
||||||
|
};
|
||||||
|
|
||||||
|
const genCustom = ({ text, from, to, url, key }) => {
|
||||||
|
const data = {
|
||||||
|
text,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
};
|
||||||
|
const init = {
|
||||||
|
headers: {
|
||||||
|
"Content-type": "application/json",
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
};
|
||||||
|
if (key) {
|
||||||
|
init.headers.Authorization = `Bearer ${key}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [url, init];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const newTransReq = ({ translator, text, from, to }, apiSetting) => {
|
||||||
|
const args = { text, from, to, ...apiSetting };
|
||||||
|
switch (translator) {
|
||||||
|
case OPT_TRANS_GOOGLE:
|
||||||
|
return genGoogle(args);
|
||||||
|
case OPT_TRANS_MICROSOFT:
|
||||||
|
return genMicrosoft(args);
|
||||||
|
case OPT_TRANS_DEEPL:
|
||||||
|
return genDeepl(args);
|
||||||
|
case OPT_TRANS_DEEPLFREE:
|
||||||
|
return genDeeplFree(args);
|
||||||
|
case OPT_TRANS_DEEPLX:
|
||||||
|
return genDeeplX(args);
|
||||||
|
case OPT_TRANS_BAIDU:
|
||||||
|
return genBaidu(args);
|
||||||
|
case OPT_TRANS_TENCENT:
|
||||||
|
return genTencent(args);
|
||||||
|
case OPT_TRANS_OPENAI:
|
||||||
|
return genOpenai(args);
|
||||||
|
case OPT_TRANS_CUSTOMIZE:
|
||||||
|
return genCustom(args);
|
||||||
|
default:
|
||||||
|
throw new Error(`[trans] translator: ${translator} not support`);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -38,7 +38,8 @@ function TestButton({ translator, api }) {
|
|||||||
text: "hello world",
|
text: "hello world",
|
||||||
fromLang: "en",
|
fromLang: "en",
|
||||||
toLang: "zh-CN",
|
toLang: "zh-CN",
|
||||||
apiSetting: { ...api, useCache: false },
|
apiSetting: api,
|
||||||
|
useCache: false,
|
||||||
});
|
});
|
||||||
if (!text) {
|
if (!text) {
|
||||||
throw new Error("empty reault");
|
throw new Error("empty reault");
|
||||||
|
|||||||
Reference in New Issue
Block a user