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