fix: lang detect

This commit is contained in:
Gabe
2025-09-27 21:21:56 +08:00
parent b1142b88f1
commit fffa448425
12 changed files with 238 additions and 181 deletions

View File

@@ -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;
};
};

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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);
}
}