fix: lang detect
This commit is contained in:
@@ -3,10 +3,8 @@ import { fetchData } from "../libs/fetch";
|
|||||||
import {
|
import {
|
||||||
URL_CACHE_TRAN,
|
URL_CACHE_TRAN,
|
||||||
KV_SALT_SYNC,
|
KV_SALT_SYNC,
|
||||||
OPT_LANGS_BAIDU,
|
OPT_LANGS_TO_SPEC,
|
||||||
OPT_LANGS_TENCENT,
|
OPT_LANGS_SPEC_DEFAULT,
|
||||||
OPT_LANGS_SPECIAL,
|
|
||||||
OPT_LANGS_MICROSOFT,
|
|
||||||
API_SPE_TYPES,
|
API_SPE_TYPES,
|
||||||
DEFAULT_API_SETTING,
|
DEFAULT_API_SETTING,
|
||||||
} from "../config";
|
} from "../config";
|
||||||
@@ -41,6 +39,13 @@ export const apiSyncData = async (url, key, data) =>
|
|||||||
*/
|
*/
|
||||||
export const apiFetch = (url) => fetchData(url);
|
export const apiFetch = (url) => fetchData(url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Microsoft token
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const apiMsAuth = async () =>
|
||||||
|
fetchData("https://edge.microsoft.com/translate/auth");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Google语言识别
|
* Google语言识别
|
||||||
* @param {*} text
|
* @param {*} text
|
||||||
@@ -78,7 +83,7 @@ export const apiGoogleLangdetect = async (text) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const apiMicrosoftLangdetect = async (text) => {
|
export const apiMicrosoftLangdetect = async (text) => {
|
||||||
const [token] = await msAuth();
|
const token = await msAuth();
|
||||||
const input =
|
const input =
|
||||||
"https://api-edge.cognitive.microsofttranslator.com/detect?api-version=3.0";
|
"https://api-edge.cognitive.microsofttranslator.com/detect?api-version=3.0";
|
||||||
const init = {
|
const init = {
|
||||||
@@ -93,9 +98,9 @@ export const apiMicrosoftLangdetect = async (text) => {
|
|||||||
useCache: true,
|
useCache: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res[0].language) {
|
if (res?.[0]?.language) {
|
||||||
await putHttpCachePolyfill(input, init, res);
|
await putHttpCachePolyfill(input, init, res);
|
||||||
return OPT_LANGS_MICROSOFT.get(res[0].language) ?? res[0].language;
|
return res[0].language;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
@@ -119,9 +124,9 @@ export const apiBaiduLangdetect = async (text) => {
|
|||||||
};
|
};
|
||||||
const res = await fetchData(input, init, { useCache: true });
|
const res = await fetchData(input, init, { useCache: true });
|
||||||
|
|
||||||
if (res.error === 0) {
|
if (res?.error === 0) {
|
||||||
await putHttpCachePolyfill(input, init, res);
|
await putHttpCachePolyfill(input, init, res);
|
||||||
return OPT_LANGS_BAIDU.get(res.lan) ?? res.lan;
|
return res.lan;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
@@ -145,7 +150,7 @@ export const apiBaiduSuggest = async (text) => {
|
|||||||
};
|
};
|
||||||
const res = await fetchData(input, init, { useCache: true });
|
const res = await fetchData(input, init, { useCache: true });
|
||||||
|
|
||||||
if (res.errno === 0) {
|
if (res?.errno === 0) {
|
||||||
await putHttpCachePolyfill(input, init, res);
|
await putHttpCachePolyfill(input, init, res);
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
@@ -175,21 +180,26 @@ export const apiTencentLangdetect = async (text) => {
|
|||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
header: {
|
header: {
|
||||||
fn: "text_analysis",
|
fn: "text_analysis",
|
||||||
|
client_key:
|
||||||
|
"browser-chrome-110.0.0-Mac OS-df4bd4c5-a65d-44b2-a40f-42f34f3535f2-1677486696487",
|
||||||
},
|
},
|
||||||
text,
|
text,
|
||||||
});
|
});
|
||||||
const init = {
|
const init = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json",
|
"Content-type": "application/json",
|
||||||
|
"user-agent":
|
||||||
|
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
|
||||||
|
referer: "https://transmart.qq.com/zh-CN/index",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body,
|
body,
|
||||||
};
|
};
|
||||||
const res = await fetchData(input, init, { useCache: true });
|
const res = await fetchData(input, init, { useCache: true });
|
||||||
|
|
||||||
if (res.language) {
|
if (res?.language) {
|
||||||
await putHttpCachePolyfill(input, init, res);
|
await putHttpCachePolyfill(input, init, res);
|
||||||
return OPT_LANGS_TENCENT.get(res.language) ?? res.language;
|
return res.language;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
@@ -202,7 +212,7 @@ export const apiTencentLangdetect = async (text) => {
|
|||||||
*/
|
*/
|
||||||
export const apiTranslate = async ({
|
export const apiTranslate = async ({
|
||||||
text,
|
text,
|
||||||
fromLang,
|
fromLang = "auto",
|
||||||
toLang,
|
toLang,
|
||||||
apiSetting = DEFAULT_API_SETTING,
|
apiSetting = DEFAULT_API_SETTING,
|
||||||
docInfo = {},
|
docInfo = {},
|
||||||
@@ -214,8 +224,8 @@ export const apiTranslate = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { apiType, apiSlug, useBatchFetch } = apiSetting;
|
const { apiType, apiSlug, useBatchFetch } = apiSetting;
|
||||||
const langMap = OPT_LANGS_SPECIAL[apiType];
|
const langMap = OPT_LANGS_TO_SPEC[apiType] || OPT_LANGS_SPEC_DEFAULT;
|
||||||
const from = langMap.get(fromLang) ?? langMap.get("auto");
|
const from = langMap.get(fromLang);
|
||||||
const to = langMap.get(toLang);
|
const to = langMap.get(toLang);
|
||||||
if (!to) {
|
if (!to) {
|
||||||
kissLog(`target lang: ${toLang} not support`);
|
kissLog(`target lang: ${toLang} not support`);
|
||||||
@@ -283,8 +293,7 @@ export const apiTranslate = async ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// const isSame = srLang && (to.includes(srLang) || srLang.includes(to));
|
const isSame = fromLang !== "auto" && srLang === to;
|
||||||
const isSame = srLang && srLang.slice(0, 2) === to.slice(0, 2);
|
|
||||||
|
|
||||||
// 插入缓存
|
// 插入缓存
|
||||||
if (useCache && trText) {
|
if (useCache && trText) {
|
||||||
|
|||||||
@@ -686,7 +686,7 @@ export const parseTransRes = async (
|
|||||||
case OPT_TRANS_MICROSOFT:
|
case OPT_TRANS_MICROSOFT:
|
||||||
return res?.map((item) => [
|
return res?.map((item) => [
|
||||||
item.translations.map((item) => item.text).join(" "),
|
item.translations.map((item) => item.text).join(" "),
|
||||||
item.detectedLanguage.language,
|
item.detectedLanguage?.language,
|
||||||
]);
|
]);
|
||||||
case OPT_TRANS_DEEPL:
|
case OPT_TRANS_DEEPL:
|
||||||
return res?.translations?.map((item) => [
|
return res?.translations?.map((item) => [
|
||||||
@@ -811,7 +811,7 @@ export const handleTranslate = async ({
|
|||||||
|
|
||||||
let token = "";
|
let token = "";
|
||||||
if (apiType === OPT_TRANS_MICROSOFT) {
|
if (apiType === OPT_TRANS_MICROSOFT) {
|
||||||
[token] = await msAuth();
|
token = await msAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
const [input, init, userMsg] = await genTransReq({
|
const [input, init, userMsg] = await genTransReq({
|
||||||
|
|||||||
@@ -23,10 +23,9 @@ import {
|
|||||||
import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage";
|
import { getSettingWithDefault, tryInitDefaultData } from "./libs/storage";
|
||||||
import { trySyncSettingAndRules } from "./libs/sync";
|
import { trySyncSettingAndRules } from "./libs/sync";
|
||||||
import { fetchHandle } from "./libs/fetch";
|
import { fetchHandle } from "./libs/fetch";
|
||||||
import { getHttpCache, putHttpCache } from "./libs/cache";
|
import { tryClearCaches, getHttpCache, putHttpCache } from "./libs/cache";
|
||||||
import { sendTabMsg } from "./libs/msg";
|
import { sendTabMsg } from "./libs/msg";
|
||||||
import { trySyncAllSubRules } from "./libs/subRules";
|
import { trySyncAllSubRules } from "./libs/subRules";
|
||||||
import { tryClearCaches } from "./libs";
|
|
||||||
import { saveRule } from "./libs/rules";
|
import { saveRule } from "./libs/rules";
|
||||||
import { getCurTabId } from "./libs/msg";
|
import { getCurTabId } from "./libs/msg";
|
||||||
import { injectInlineJs, injectInternalCss } from "./libs/injector";
|
import { injectInlineJs, injectInternalCss } from "./libs/injector";
|
||||||
|
|||||||
@@ -180,48 +180,61 @@ export const OPT_LANGS_TO = [
|
|||||||
["uk", "Ukrainian - Українська"],
|
["uk", "Ukrainian - Українська"],
|
||||||
["vi", "Vietnamese - Tiếng Việt"],
|
["vi", "Vietnamese - Tiếng Việt"],
|
||||||
];
|
];
|
||||||
|
export const OPT_LANGS_LIST = OPT_LANGS_TO.map(([lang]) => lang);
|
||||||
export const OPT_LANGS_FROM = [["auto", "Auto-detect"], ...OPT_LANGS_TO];
|
export const OPT_LANGS_FROM = [["auto", "Auto-detect"], ...OPT_LANGS_TO];
|
||||||
export const OPT_LANGS_SPECIAL = {
|
export const OPT_LANGS_MAP = new Map(OPT_LANGS_TO);
|
||||||
[OPT_TRANS_GOOGLE]: new Map(OPT_LANGS_FROM.map(([key]) => [key, key])),
|
|
||||||
[OPT_TRANS_GOOGLE_2]: new Map(OPT_LANGS_FROM.map(([key]) => [key, key])),
|
// CODE->名称
|
||||||
|
export const OPT_LANGS_SPEC_NAME = new Map(
|
||||||
|
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
||||||
|
);
|
||||||
|
export const OPT_LANGS_SPEC_DEFAULT = new Map(
|
||||||
|
OPT_LANGS_FROM.map(([key]) => [key, key])
|
||||||
|
);
|
||||||
|
export const OPT_LANGS_SPEC_DEFAULT_UC = new Map(
|
||||||
|
OPT_LANGS_FROM.map(([key]) => [key, key.toUpperCase()])
|
||||||
|
);
|
||||||
|
export const OPT_LANGS_TO_SPEC = {
|
||||||
|
[OPT_TRANS_GOOGLE]: OPT_LANGS_SPEC_DEFAULT,
|
||||||
|
[OPT_TRANS_GOOGLE_2]: OPT_LANGS_SPEC_DEFAULT,
|
||||||
[OPT_TRANS_MICROSOFT]: new Map([
|
[OPT_TRANS_MICROSOFT]: new Map([
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key]),
|
...OPT_LANGS_SPEC_DEFAULT,
|
||||||
["auto", ""],
|
["auto", ""],
|
||||||
["zh-CN", "zh-Hans"],
|
["zh-CN", "zh-Hans"],
|
||||||
["zh-TW", "zh-Hant"],
|
["zh-TW", "zh-Hant"],
|
||||||
]),
|
]),
|
||||||
[OPT_TRANS_DEEPL]: new Map([
|
[OPT_TRANS_DEEPL]: new Map([
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key.toUpperCase()]),
|
...OPT_LANGS_SPEC_DEFAULT_UC,
|
||||||
["auto", ""],
|
["auto", ""],
|
||||||
["zh-CN", "ZH"],
|
["zh-CN", "ZH"],
|
||||||
["zh-TW", "ZH"],
|
["zh-TW", "ZH"],
|
||||||
]),
|
]),
|
||||||
[OPT_TRANS_DEEPLFREE]: new Map([
|
[OPT_TRANS_DEEPLFREE]: new Map([
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key.toUpperCase()]),
|
...OPT_LANGS_SPEC_DEFAULT_UC,
|
||||||
["auto", "auto"],
|
["auto", "auto"],
|
||||||
["zh-CN", "ZH"],
|
["zh-CN", "ZH"],
|
||||||
["zh-TW", "ZH"],
|
["zh-TW", "ZH"],
|
||||||
]),
|
]),
|
||||||
[OPT_TRANS_DEEPLX]: new Map([
|
[OPT_TRANS_DEEPLX]: new Map([
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key.toUpperCase()]),
|
...OPT_LANGS_SPEC_DEFAULT_UC,
|
||||||
["auto", "auto"],
|
["auto", "auto"],
|
||||||
["zh-CN", "ZH"],
|
["zh-CN", "ZH"],
|
||||||
["zh-TW", "ZH"],
|
["zh-TW", "ZH"],
|
||||||
]),
|
]),
|
||||||
[OPT_TRANS_NIUTRANS]: new Map([
|
[OPT_TRANS_NIUTRANS]: new Map([
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key]),
|
...OPT_LANGS_SPEC_DEFAULT,
|
||||||
["auto", "auto"],
|
["auto", "auto"],
|
||||||
["zh-CN", "zh"],
|
["zh-CN", "zh"],
|
||||||
["zh-TW", "cht"],
|
["zh-TW", "cht"],
|
||||||
]),
|
]),
|
||||||
[OPT_TRANS_VOLCENGINE]: new Map([
|
[OPT_TRANS_VOLCENGINE]: new Map([
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key]),
|
...OPT_LANGS_SPEC_DEFAULT,
|
||||||
["auto", "auto"],
|
["auto", "auto"],
|
||||||
["zh-CN", "zh"],
|
["zh-CN", "zh"],
|
||||||
["zh-TW", "zh-Hant"],
|
["zh-TW", "zh-Hant"],
|
||||||
]),
|
]),
|
||||||
[OPT_TRANS_BAIDU]: new Map([
|
[OPT_TRANS_BAIDU]: new Map([
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key]),
|
...OPT_LANGS_SPEC_DEFAULT,
|
||||||
["zh-CN", "zh"],
|
["zh-CN", "zh"],
|
||||||
["zh-TW", "cht"],
|
["zh-TW", "cht"],
|
||||||
["ar", "ara"],
|
["ar", "ara"],
|
||||||
@@ -269,62 +282,34 @@ export const OPT_LANGS_SPECIAL = {
|
|||||||
["id", "id"],
|
["id", "id"],
|
||||||
["vi", "vi"],
|
["vi", "vi"],
|
||||||
]),
|
]),
|
||||||
[OPT_TRANS_OPENAI]: new Map(
|
[OPT_TRANS_OPENAI]: OPT_LANGS_SPEC_DEFAULT,
|
||||||
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
[OPT_TRANS_GEMINI]: OPT_LANGS_SPEC_DEFAULT,
|
||||||
),
|
[OPT_TRANS_GEMINI_2]: OPT_LANGS_SPEC_DEFAULT,
|
||||||
[OPT_TRANS_GEMINI]: new Map(
|
[OPT_TRANS_CLAUDE]: OPT_LANGS_SPEC_DEFAULT,
|
||||||
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
[OPT_TRANS_OLLAMA]: OPT_LANGS_SPEC_DEFAULT,
|
||||||
),
|
[OPT_TRANS_OPENROUTER]: OPT_LANGS_SPEC_DEFAULT,
|
||||||
[OPT_TRANS_GEMINI_2]: new Map(
|
[OPT_TRANS_CLOUDFLAREAI]: OPT_LANGS_SPEC_DEFAULT,
|
||||||
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
[OPT_TRANS_CUSTOMIZE]: OPT_LANGS_SPEC_DEFAULT,
|
||||||
),
|
|
||||||
[OPT_TRANS_CLAUDE]: new Map(
|
|
||||||
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
|
||||||
),
|
|
||||||
[OPT_TRANS_OLLAMA]: new Map(
|
|
||||||
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
|
||||||
),
|
|
||||||
[OPT_TRANS_OPENROUTER]: new Map(
|
|
||||||
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
|
|
||||||
),
|
|
||||||
[OPT_TRANS_CLOUDFLAREAI]: new Map([
|
|
||||||
["auto", ""],
|
|
||||||
["zh-CN", "chinese"],
|
|
||||||
["zh-TW", "chinese"],
|
|
||||||
["en", "english"],
|
|
||||||
["ar", "arabic"],
|
|
||||||
["de", "german"],
|
|
||||||
["ru", "russian"],
|
|
||||||
["fr", "french"],
|
|
||||||
["pt", "portuguese"],
|
|
||||||
["ja", "japanese"],
|
|
||||||
["es", "spanish"],
|
|
||||||
["hi", "hindi"],
|
|
||||||
]),
|
|
||||||
[OPT_TRANS_CUSTOMIZE]: new Map([
|
|
||||||
...OPT_LANGS_FROM.map(([key]) => [key, key]),
|
|
||||||
]),
|
|
||||||
};
|
};
|
||||||
export const OPT_LANGS_LIST = OPT_LANGS_TO.map(([lang]) => lang);
|
|
||||||
export const OPT_LANGS_MICROSOFT = new Map(
|
const specToCode = (m) =>
|
||||||
Array.from(OPT_LANGS_SPECIAL[OPT_TRANS_MICROSOFT].entries()).map(([k, v]) => [
|
new Map(
|
||||||
v,
|
Array.from(m.entries()).map(([k, v]) => {
|
||||||
k,
|
if (v === "") {
|
||||||
])
|
return ["auto", "auto"];
|
||||||
|
}
|
||||||
|
if (v === "zh" || v === "ZH") {
|
||||||
|
return [v, "zh-CN"];
|
||||||
|
}
|
||||||
|
return [v, k];
|
||||||
|
})
|
||||||
);
|
);
|
||||||
export const OPT_LANGS_BAIDU = new Map(
|
|
||||||
Array.from(OPT_LANGS_SPECIAL[OPT_TRANS_BAIDU].entries()).map(([k, v]) => [
|
// 名称->CODE
|
||||||
v,
|
export const OPT_LANGS_TO_CODE = {};
|
||||||
k,
|
Object.entries(OPT_LANGS_TO_SPEC).forEach(([t, m]) => {
|
||||||
])
|
OPT_LANGS_TO_CODE[t] = specToCode(m);
|
||||||
);
|
});
|
||||||
export const OPT_LANGS_TENCENT = new Map(
|
|
||||||
Array.from(OPT_LANGS_SPECIAL[OPT_TRANS_TENCENT].entries()).map(([k, v]) => [
|
|
||||||
v,
|
|
||||||
k,
|
|
||||||
])
|
|
||||||
);
|
|
||||||
OPT_LANGS_TENCENT.set("zh", "zh-CN");
|
|
||||||
|
|
||||||
const defaultSystemPrompt = `Act as a translation API. Output a single raw JSON object only. No extra text or fences.
|
const defaultSystemPrompt = `Act as a translation API. Output a single raw JSON object only. No extra text or fences.
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { useCallback } from "react";
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export function useRules() {
|
export function useRules() {
|
||||||
const { data: list, save } = useStorage(
|
const { data: list = [], save } = useStorage(
|
||||||
STOKEY_RULES,
|
STOKEY_RULES,
|
||||||
DEFAULT_RULES,
|
DEFAULT_RULES,
|
||||||
KV_RULES_KEY
|
KV_RULES_KEY
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { getMsauth, setMsauth } from "./storage";
|
import { getMsauth, setMsauth } from "./storage";
|
||||||
import { fetchData } from "./fetch";
|
|
||||||
import { kissLog } from "./log";
|
import { kissLog } from "./log";
|
||||||
|
import { apiMsAuth } from "../apis";
|
||||||
|
|
||||||
const parseMSToken = (token) => {
|
const parseMSToken = (token) => {
|
||||||
try {
|
try {
|
||||||
@@ -16,28 +16,55 @@ const parseMSToken = (token) => {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
const _msAuth = () => {
|
const _msAuth = () => {
|
||||||
let { token, exp } = {};
|
let tokenPromise = null;
|
||||||
|
const EXPIRATION_MS = 1000;
|
||||||
|
|
||||||
|
const fetchNewToken = async () => {
|
||||||
|
try {
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
// 1. 查询storage缓存
|
||||||
|
const storageToken = await getMsauth();
|
||||||
|
if (storageToken) {
|
||||||
|
const storageExp = parseMSToken(storageToken);
|
||||||
|
const storageExpiresAt = storageExp * 1000;
|
||||||
|
if (storageExpiresAt > now + EXPIRATION_MS) {
|
||||||
|
return { token: storageToken, expiresAt: storageExpiresAt };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 缓存没有或失效,查询接口
|
||||||
|
const apiToken = await apiMsAuth();
|
||||||
|
if (!apiToken) {
|
||||||
|
throw new Error("Failed to fetch ms token");
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiExp = parseMSToken(apiToken);
|
||||||
|
const apiExpiresAt = apiExp * 1000;
|
||||||
|
await setMsauth(apiToken);
|
||||||
|
return { token: apiToken, expiresAt: apiExpiresAt };
|
||||||
|
} catch (error) {
|
||||||
|
kissLog("get msauth failed", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return async () => {
|
return async () => {
|
||||||
// 查询内存缓存
|
// 检查是否有缓存的 Promise
|
||||||
const now = Date.now();
|
if (tokenPromise) {
|
||||||
if (token && exp * 1000 > now + 1000) {
|
try {
|
||||||
return [token, exp];
|
const cachedResult = await tokenPromise;
|
||||||
|
if (cachedResult.expiresAt > Date.now() + EXPIRATION_MS) {
|
||||||
|
return cachedResult.token;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
//
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询storage缓存
|
tokenPromise = fetchNewToken();
|
||||||
const res = await getMsauth();
|
const result = await tokenPromise;
|
||||||
token = res?.token;
|
return result.token;
|
||||||
exp = res?.exp;
|
|
||||||
if (token && exp * 1000 > now + 1000) {
|
|
||||||
return [token, exp];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 缓存没有或失效,查询接口
|
|
||||||
token = await fetchData("https://edge.microsoft.com/translate/auth");
|
|
||||||
exp = parseMSToken(token);
|
|
||||||
await setMsauth({ token, exp });
|
|
||||||
return [token, exp];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,17 @@ import { isBg } from "./browser";
|
|||||||
import { sendBgMsg } from "./msg";
|
import { sendBgMsg } from "./msg";
|
||||||
import { blobToBase64 } from "./utils";
|
import { blobToBase64 } from "./utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除缓存数据
|
||||||
|
*/
|
||||||
|
export const tryClearCaches = async () => {
|
||||||
|
try {
|
||||||
|
caches.delete(CACHE_NAME);
|
||||||
|
} catch (err) {
|
||||||
|
kissLog("clean caches", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造缓存 request
|
* 构造缓存 request
|
||||||
* @param {*} input
|
* @param {*} input
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import {
|
import {
|
||||||
CACHE_NAME,
|
|
||||||
OPT_TRANS_GOOGLE,
|
OPT_TRANS_GOOGLE,
|
||||||
OPT_TRANS_MICROSOFT,
|
OPT_TRANS_MICROSOFT,
|
||||||
OPT_TRANS_BAIDU,
|
OPT_TRANS_BAIDU,
|
||||||
OPT_TRANS_TENCENT,
|
OPT_TRANS_TENCENT,
|
||||||
|
OPT_LANGS_TO_CODE,
|
||||||
|
OPT_LANGS_MAP,
|
||||||
} from "../config";
|
} from "../config";
|
||||||
import { browser } from "./browser";
|
import { browser } from "./browser";
|
||||||
import {
|
import {
|
||||||
@@ -14,52 +15,51 @@ import {
|
|||||||
} from "../apis";
|
} from "../apis";
|
||||||
import { kissLog } from "./log";
|
import { kissLog } from "./log";
|
||||||
|
|
||||||
const langdetectMap = {
|
const langdetectFns = {
|
||||||
[OPT_TRANS_GOOGLE]: apiGoogleLangdetect,
|
[OPT_TRANS_GOOGLE]: apiGoogleLangdetect,
|
||||||
[OPT_TRANS_MICROSOFT]: apiMicrosoftLangdetect,
|
[OPT_TRANS_MICROSOFT]: apiMicrosoftLangdetect,
|
||||||
[OPT_TRANS_BAIDU]: apiBaiduLangdetect,
|
[OPT_TRANS_BAIDU]: apiBaiduLangdetect,
|
||||||
[OPT_TRANS_TENCENT]: apiTencentLangdetect,
|
[OPT_TRANS_TENCENT]: apiTencentLangdetect,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 清除缓存数据
|
|
||||||
*/
|
|
||||||
export const tryClearCaches = async () => {
|
|
||||||
try {
|
|
||||||
caches.delete(CACHE_NAME);
|
|
||||||
} catch (err) {
|
|
||||||
kissLog("clean caches", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语言识别
|
* 语言识别
|
||||||
* @param {*} q
|
* @param {*} text
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
export const tryDetectLang = async (
|
export const tryDetectLang = async (
|
||||||
q,
|
text,
|
||||||
useRemote = false,
|
useRemote = "false",
|
||||||
langDetector = OPT_TRANS_MICROSOFT
|
langDetector = OPT_TRANS_MICROSOFT
|
||||||
) => {
|
) => {
|
||||||
let lang = "";
|
let deLang = "";
|
||||||
|
|
||||||
if (useRemote) {
|
// 远程识别
|
||||||
|
if (useRemote === "true" && langDetector) {
|
||||||
try {
|
try {
|
||||||
lang = await langdetectMap[langDetector](q);
|
const lang = await langdetectFns[langDetector](text);
|
||||||
|
if (lang) {
|
||||||
|
deLang = OPT_LANGS_TO_CODE[langDetector].get(lang) || "";
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
kissLog("detect lang remote", err);
|
kissLog("detect lang remote", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lang) {
|
// 本地识别
|
||||||
|
if (!deLang) {
|
||||||
try {
|
try {
|
||||||
const res = await browser?.i18n?.detectLanguage(q);
|
const res = await browser?.i18n?.detectLanguage(text);
|
||||||
lang = res?.languages?.[0]?.language;
|
const lang = res?.languages?.[0]?.language;
|
||||||
|
if (OPT_LANGS_MAP.has(lang)) {
|
||||||
|
deLang = lang;
|
||||||
|
} else if (lang.startsWith("zh")) {
|
||||||
|
deLang = "zh-CN";
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
kissLog("detect lang local", err);
|
kissLog("detect lang local", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return lang;
|
return deLang;
|
||||||
};
|
};
|
||||||
@@ -24,7 +24,7 @@ import { clearAllBatchQueue } from "./batchQueue";
|
|||||||
import { genTextClass } from "./style";
|
import { genTextClass } from "./style";
|
||||||
import { loadingSvg } from "./svg";
|
import { loadingSvg } from "./svg";
|
||||||
import { shortcutRegister } from "./shortcut";
|
import { shortcutRegister } from "./shortcut";
|
||||||
import { tryDetectLang } from ".";
|
import { tryDetectLang } from "./detect";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Translator
|
* @class Translator
|
||||||
@@ -436,6 +436,7 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: 利用AI总结
|
||||||
#getDocDescription() {
|
#getDocDescription() {
|
||||||
try {
|
try {
|
||||||
const meta = document.querySelector('meta[name="description"]');
|
const meta = document.querySelector('meta[name="description"]');
|
||||||
@@ -738,20 +739,30 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 提前进行语言检测
|
// 提前进行语言检测
|
||||||
const { detectRemote, toLang, skipLangs = [] } = this.#rule;
|
let deLang = "";
|
||||||
|
const {
|
||||||
|
detectRemote,
|
||||||
|
fromLang = "auto",
|
||||||
|
toLang,
|
||||||
|
skipLangs = [],
|
||||||
|
} = this.#rule;
|
||||||
|
if (fromLang === "auto") {
|
||||||
const { langDetector } = this.#setting;
|
const { langDetector } = this.#setting;
|
||||||
const deLang = await tryDetectLang(
|
deLang = await tryDetectLang(
|
||||||
node.textContent,
|
node.textContent,
|
||||||
detectRemote,
|
detectRemote,
|
||||||
langDetector
|
langDetector
|
||||||
);
|
);
|
||||||
// console.log("deLang", deLang, toLang);
|
|
||||||
if (
|
if (
|
||||||
deLang &&
|
deLang &&
|
||||||
(toLang.slice(0, 2) === deLang.slice(0, 2) || skipLangs.includes(deLang))
|
(toLang.slice(0, 2) === deLang.slice(0, 2) ||
|
||||||
|
skipLangs.includes(deLang))
|
||||||
) {
|
) {
|
||||||
|
// 保留处理状态,不做删除
|
||||||
|
// this.#processedNodes.delete(node);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let nodeGroup = [];
|
let nodeGroup = [];
|
||||||
[...node.childNodes].forEach((child) => {
|
[...node.childNodes].forEach((child) => {
|
||||||
@@ -762,13 +773,13 @@ export class Translator {
|
|||||||
if (!shouldBreak && shouldGroup) {
|
if (!shouldBreak && shouldGroup) {
|
||||||
nodeGroup.push(child);
|
nodeGroup.push(child);
|
||||||
} else if (shouldBreak && nodeGroup.length) {
|
} else if (shouldBreak && nodeGroup.length) {
|
||||||
this.#translateNodeGroup(nodeGroup, node);
|
this.#translateNodeGroup(nodeGroup, node, deLang);
|
||||||
nodeGroup = [];
|
nodeGroup = [];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (nodeGroup.length) {
|
if (nodeGroup.length) {
|
||||||
this.#translateNodeGroup(nodeGroup, node);
|
this.#translateNodeGroup(nodeGroup, node, deLang);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -834,7 +845,7 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 翻译内联节点
|
// 翻译内联节点
|
||||||
async #translateNodeGroup(nodes, hostNode) {
|
async #translateNodeGroup(nodes, hostNode, deLang) {
|
||||||
const {
|
const {
|
||||||
transTag,
|
transTag,
|
||||||
textStyle,
|
textStyle,
|
||||||
@@ -901,8 +912,10 @@ export class Translator {
|
|||||||
// return;
|
// return;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const [translatedText, isSameLang] =
|
const [translatedText, isSameLang] = await this.#translateFetch(
|
||||||
await this.#translateFetch(processedString);
|
processedString,
|
||||||
|
deLang
|
||||||
|
);
|
||||||
// console.log("translatedText", translatedText);
|
// console.log("translatedText", translatedText);
|
||||||
if (isSameLang || this.#runId !== currentRunId) {
|
if (isSameLang || this.#runId !== currentRunId) {
|
||||||
wrapper.remove();
|
wrapper.remove();
|
||||||
@@ -1060,7 +1073,7 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发起翻译请求
|
// 发起翻译请求
|
||||||
#translateFetch(text) {
|
#translateFetch(text, deLang = "") {
|
||||||
const { apiSlug, fromLang, toLang } = this.#rule;
|
const { apiSlug, fromLang, toLang } = this.#rule;
|
||||||
const apiSetting =
|
const apiSetting =
|
||||||
this.#setting.transApis.find((api) => api.apiSlug === apiSlug) ||
|
this.#setting.transApis.find((api) => api.apiSlug === apiSlug) ||
|
||||||
@@ -1068,7 +1081,7 @@ export class Translator {
|
|||||||
|
|
||||||
return apiTranslate({
|
return apiTranslate({
|
||||||
text,
|
text,
|
||||||
fromLang,
|
fromLang: deLang || fromLang,
|
||||||
toLang,
|
toLang,
|
||||||
apiSetting,
|
apiSetting,
|
||||||
docInfo: this.#docInfo,
|
docInfo: this.#docInfo,
|
||||||
@@ -1295,17 +1308,23 @@ export class Translator {
|
|||||||
this.#init();
|
this.#init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 翻译页面标题
|
|
||||||
if (this.#rule.transTitle === "true") {
|
if (this.#rule.transTitle === "true") {
|
||||||
|
this.#translateTitle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 翻译页面标题
|
||||||
|
async #translateTitle() {
|
||||||
const title = document.title;
|
const title = document.title;
|
||||||
this.#docInfo.title = title;
|
this.#docInfo.title = title;
|
||||||
this.#translateFetch(title)
|
if (!title) return;
|
||||||
.then(([trText]) => {
|
|
||||||
document.title = trText || title;
|
try {
|
||||||
})
|
const deLang = await tryDetectLang(title);
|
||||||
.catch((err) => {
|
const [translatedTitle] = await this.#translateFetch(title, deLang);
|
||||||
|
document.title = translatedTitle || title;
|
||||||
|
} catch (err) {
|
||||||
kissLog("tanslate title", err);
|
kissLog("tanslate title", err);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,24 +63,30 @@ import { kissLog } from "../../libs/log";
|
|||||||
import { useApiList } from "../../hooks/Api";
|
import { useApiList } from "../../hooks/Api";
|
||||||
import ShowMoreButton from "./ShowMoreButton";
|
import ShowMoreButton from "./ShowMoreButton";
|
||||||
|
|
||||||
|
const calculateInitialValues = (rule) => {
|
||||||
|
const base = rule?.pattern === "*" ? GLOBLA_RULE : DEFAULT_RULE;
|
||||||
|
return { ...base, ...(rule || {}) };
|
||||||
|
};
|
||||||
|
|
||||||
function RuleFields({ rule, rules, setShow, setKeyword }) {
|
function RuleFields({ rule, rules, setShow, setKeyword }) {
|
||||||
const initFormValues = useMemo(
|
|
||||||
() => ({
|
|
||||||
...(rule?.pattern === "*" ? GLOBLA_RULE : DEFAULT_RULE),
|
|
||||||
...(rule || {}),
|
|
||||||
}),
|
|
||||||
[rule]
|
|
||||||
);
|
|
||||||
const editMode = useMemo(() => !!rule, [rule]);
|
const editMode = useMemo(() => !!rule, [rule]);
|
||||||
|
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
const [disabled, setDisabled] = useState(editMode);
|
const [disabled, setDisabled] = useState(editMode);
|
||||||
const [errors, setErrors] = useState({});
|
const [errors, setErrors] = useState({});
|
||||||
const [formValues, setFormValues] = useState(initFormValues);
|
const [initialFormValues, setInitialFormValues] = useState(() =>
|
||||||
|
calculateInitialValues(rule)
|
||||||
|
);
|
||||||
|
const [formValues, setFormValues] = useState(initialFormValues);
|
||||||
const [showMore, setShowMore] = useState(!rules);
|
const [showMore, setShowMore] = useState(!rules);
|
||||||
const [isModified, setIsModified] = useState(false);
|
|
||||||
const { enabledApis } = useApiList();
|
const { enabledApis } = useApiList();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const newInitialValues = calculateInitialValues(rule);
|
||||||
|
setInitialFormValues(newInitialValues);
|
||||||
|
setFormValues(newInitialValues);
|
||||||
|
}, [rule]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
pattern,
|
pattern,
|
||||||
selector,
|
selector,
|
||||||
@@ -116,12 +122,9 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
// transRemoveHook = "",
|
// transRemoveHook = "",
|
||||||
} = formValues;
|
} = formValues;
|
||||||
|
|
||||||
useEffect(() => {
|
const isModified = useMemo(() => {
|
||||||
if (!initFormValues) return;
|
return JSON.stringify(initialFormValues) !== JSON.stringify(formValues);
|
||||||
const hasChanged =
|
}, [initialFormValues, formValues]);
|
||||||
JSON.stringify(initFormValues) !== JSON.stringify(formValues);
|
|
||||||
setIsModified(hasChanged);
|
|
||||||
}, [initFormValues, formValues]);
|
|
||||||
|
|
||||||
const hasSamePattern = (str) => {
|
const hasSamePattern = (str) => {
|
||||||
for (const item of rules.list) {
|
for (const item of rules.list) {
|
||||||
@@ -163,7 +166,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
setShow(false);
|
setShow(false);
|
||||||
}
|
}
|
||||||
setErrors({});
|
setErrors({});
|
||||||
setFormValues(initFormValues);
|
setFormValues(initialFormValues);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRestore = (e) => {
|
const handleRestore = (e) => {
|
||||||
@@ -199,7 +202,7 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
// 添加
|
// 添加
|
||||||
rules.add(formValues);
|
rules.add(formValues);
|
||||||
setShow(false);
|
setShow(false);
|
||||||
setFormValues(initFormValues);
|
setFormValues(initialFormValues);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1205,11 +1208,15 @@ function SubRules({ subRules }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function GlobalRule({ rules }) {
|
function GlobalRule({ rules }) {
|
||||||
if (!rules.list) {
|
const globalRule = useMemo(
|
||||||
|
() => rules.list[rules.list.length - 1],
|
||||||
|
[rules.list]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!globalRule) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalRule = rules.list[rules.list.length - 1];
|
|
||||||
return (
|
return (
|
||||||
<Stack spacing={3}>
|
<Stack spacing={3}>
|
||||||
<RuleAccordion
|
<RuleAccordion
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
} from "../../config";
|
} from "../../config";
|
||||||
import { sendIframeMsg } from "../../libs/iframe";
|
import { sendIframeMsg } from "../../libs/iframe";
|
||||||
import { saveRule } from "../../libs/rules";
|
import { saveRule } from "../../libs/rules";
|
||||||
import { tryClearCaches } from "../../libs";
|
import { tryClearCaches } from "../../libs/cache";
|
||||||
import { kissLog } from "../../libs/log";
|
import { kissLog } from "../../libs/log";
|
||||||
import { parseUrlPattern } from "../../libs/utils";
|
import { parseUrlPattern } from "../../libs/utils";
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { apiTranslate } from "../../apis";
|
|||||||
import CopyBtn from "./CopyBtn";
|
import CopyBtn from "./CopyBtn";
|
||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import Alert from "@mui/material/Alert";
|
import Alert from "@mui/material/Alert";
|
||||||
import { tryDetectLang } from "../../libs";
|
import { tryDetectLang } from "../../libs/detect";
|
||||||
|
|
||||||
export default function TranCont({
|
export default function TranCont({
|
||||||
text,
|
text,
|
||||||
@@ -35,7 +35,7 @@ export default function TranCont({
|
|||||||
|
|
||||||
let to = toLang;
|
let to = toLang;
|
||||||
if (fromLang === "auto" && toLang !== toLang2 && toLang2 !== "none") {
|
if (fromLang === "auto" && toLang !== toLang2 && toLang2 !== "none") {
|
||||||
const detectLang = await tryDetectLang(text, true, langDetector);
|
const detectLang = await tryDetectLang(text, "true", langDetector);
|
||||||
if (detectLang === toLang) {
|
if (detectLang === toLang) {
|
||||||
to = toLang2;
|
to = toLang2;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user