feat: support translate all now
This commit is contained in:
@@ -201,7 +201,7 @@ export async function run(isUserscript = false) {
|
|||||||
|
|
||||||
// 翻译网页
|
// 翻译网页
|
||||||
const rule = await matchRule(href, setting);
|
const rule = await matchRule(href, setting);
|
||||||
const translator = new Translator(rule, setting);
|
const translator = new Translator(rule, setting, isUserscript);
|
||||||
|
|
||||||
// 适配iframe
|
// 适配iframe
|
||||||
if (isIframe) {
|
if (isIframe) {
|
||||||
|
|||||||
@@ -355,9 +355,9 @@ export const I18N = {
|
|||||||
zh_TW: `滾動載入翻譯(建議)`,
|
zh_TW: `滾動載入翻譯(建議)`,
|
||||||
},
|
},
|
||||||
mk_pageopen: {
|
mk_pageopen: {
|
||||||
zh: `页面打开全部翻译`,
|
zh: `立即全部翻译`,
|
||||||
en: `Page Open`,
|
en: `Translate all now`,
|
||||||
zh_TW: `頁面開啟全部翻譯`,
|
zh_TW: `立即全部翻譯`,
|
||||||
},
|
},
|
||||||
mk_mouseover: {
|
mk_mouseover: {
|
||||||
zh: `鼠标悬停翻译`,
|
zh: `鼠标悬停翻译`,
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ background: linear-gradient(
|
|||||||
export const DEFAULT_SELECTOR =
|
export const DEFAULT_SELECTOR =
|
||||||
"h1, h2, h3, h4, h5, h6, li, p, dd, blockquote, figcaption, label, legend";
|
"h1, h2, h3, h4, h5, h6, li, p, dd, blockquote, figcaption, label, legend";
|
||||||
export const DEFAULT_IGNORE_SELECTOR =
|
export const DEFAULT_IGNORE_SELECTOR =
|
||||||
"aside, button, footer, form, header, pre, mark, nav";
|
"aside, button, footer, form, pre, mark, nav";
|
||||||
export const DEFAULT_KEEP_SELECTOR = `a:has(code)`;
|
export const DEFAULT_KEEP_SELECTOR = `a:has(code)`;
|
||||||
export const DEFAULT_RULE = {
|
export const DEFAULT_RULE = {
|
||||||
pattern: "", // 匹配网址
|
pattern: "", // 匹配网址
|
||||||
|
|||||||
@@ -149,4 +149,5 @@ export const DEFAULT_SETTING = {
|
|||||||
langDetector: OPT_TRANS_MICROSOFT, // 远程语言识别服务
|
langDetector: OPT_TRANS_MICROSOFT, // 远程语言识别服务
|
||||||
mouseHoverSetting: DEFAULT_MOUSE_HOVER_SETTING, // 鼠标悬停翻译
|
mouseHoverSetting: DEFAULT_MOUSE_HOVER_SETTING, // 鼠标悬停翻译
|
||||||
preInit: true, // 是否预加载脚本
|
preInit: true, // 是否预加载脚本
|
||||||
|
transAllnow: false, // 是否立即全部翻译
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ export const tryDetectLang = async (
|
|||||||
try {
|
try {
|
||||||
const res = await browser?.i18n?.detectLanguage(text);
|
const res = await browser?.i18n?.detectLanguage(text);
|
||||||
const lang = res?.languages?.[0]?.language;
|
const lang = res?.languages?.[0]?.language;
|
||||||
if (OPT_LANGS_MAP.has(lang)) {
|
if (lang && OPT_LANGS_MAP.has(lang)) {
|
||||||
deLang = lang;
|
deLang = lang;
|
||||||
} else if (lang.startsWith("zh")) {
|
} else if (lang?.startsWith("zh")) {
|
||||||
deLang = "zh-CN";
|
deLang = "zh-CN";
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -309,7 +309,7 @@ export class Translator {
|
|||||||
return `${Translator.BUILTIN_IGNORE_SELECTOR}, ${this.#rule.ignoreSelector}`;
|
return `${Translator.BUILTIN_IGNORE_SELECTOR}, ${this.#rule.ignoreSelector}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(rule = {}, setting = {}, isUserscript) {
|
constructor(rule = {}, setting = {}, isUserscript = false) {
|
||||||
this.#setting = { ...Translator.DEFAULT_OPTIONS, ...setting };
|
this.#setting = { ...Translator.DEFAULT_OPTIONS, ...setting };
|
||||||
this.#rule = { ...Translator.DEFAULT_RULE, ...rule };
|
this.#rule = { ...Translator.DEFAULT_RULE, ...rule };
|
||||||
this.#apiSetting =
|
this.#apiSetting =
|
||||||
@@ -767,6 +767,16 @@ export class Translator {
|
|||||||
|
|
||||||
// 开始/重新监控节点
|
// 开始/重新监控节点
|
||||||
#startObserveNode(node) {
|
#startObserveNode(node) {
|
||||||
|
if (
|
||||||
|
!this.#observedNodes.has(node) &&
|
||||||
|
this.#enabled &&
|
||||||
|
this.#setting.transAllnow
|
||||||
|
) {
|
||||||
|
this.#observedNodes.add(node);
|
||||||
|
this.#processNode(node);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 未监控
|
// 未监控
|
||||||
if (!this.#observedNodes.has(node)) {
|
if (!this.#observedNodes.has(node)) {
|
||||||
this.#observedNodes.add(node);
|
this.#observedNodes.add(node);
|
||||||
@@ -992,7 +1002,10 @@ export class Translator {
|
|||||||
wrapper.appendChild(inner);
|
wrapper.appendChild(inner);
|
||||||
nodes[nodes.length - 1].after(wrapper);
|
nodes[nodes.length - 1].after(wrapper);
|
||||||
|
|
||||||
this.#translationNodes.set(wrapper, nodes);
|
this.#translationNodes.set(wrapper, {
|
||||||
|
nodes,
|
||||||
|
isHide: transOnly === "true",
|
||||||
|
});
|
||||||
const currentRunId = this.#runId;
|
const currentRunId = this.#runId;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1210,8 +1223,9 @@ export class Translator {
|
|||||||
this.#processedNodes.delete(el.parentElement);
|
this.#processedNodes.delete(el.parentElement);
|
||||||
|
|
||||||
// 如果是仅显示译文模式,先恢复原文
|
// 如果是仅显示译文模式,先恢复原文
|
||||||
if (this.#rule.transOnly === "true") {
|
const { nodes, isHide } = this.#translationNodes.get(el) || {};
|
||||||
this.#restoreOriginal(el);
|
if (isHide) {
|
||||||
|
this.#restoreOriginal(el, nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#translationNodes.delete(el);
|
this.#translationNodes.delete(el);
|
||||||
@@ -1219,8 +1233,7 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 恢复原文
|
// 恢复原文
|
||||||
#restoreOriginal(el) {
|
#restoreOriginal(el, nodes) {
|
||||||
const nodes = this.#translationNodes.get(el);
|
|
||||||
if (nodes) {
|
if (nodes) {
|
||||||
const frag = document.createDocumentFragment();
|
const frag = document.createDocumentFragment();
|
||||||
nodes.forEach((n) => frag.appendChild(n));
|
nodes.forEach((n) => frag.appendChild(n));
|
||||||
@@ -1231,23 +1244,27 @@ export class Translator {
|
|||||||
|
|
||||||
// 移除多个节点
|
// 移除多个节点
|
||||||
#removeNodes(nodes) {
|
#removeNodes(nodes) {
|
||||||
const frag = document.createDocumentFragment();
|
if (nodes) {
|
||||||
nodes.forEach((n) => frag.appendChild(n));
|
const frag = document.createDocumentFragment();
|
||||||
|
nodes.forEach((n) => frag.appendChild(n));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换译文和双语显示
|
// 切换译文和双语显示
|
||||||
#toggleTranslationOnly(node, transOnly) {
|
#toggleTranslationOnly(node, transOnly) {
|
||||||
this.#findTranslationWrappers(node).forEach((el) => {
|
this.#findTranslationWrappers(node).forEach((el) => {
|
||||||
const br = el.querySelector(":scope > br");
|
const br = el.querySelector(":scope > br");
|
||||||
|
const { nodes } = this.#translationNodes.get(el) || {};
|
||||||
if (transOnly === "true") {
|
if (transOnly === "true") {
|
||||||
// 双语变为仅译文
|
// 双语变为仅译文
|
||||||
if (br) br.hidden = true;
|
if (br) br.hidden = true;
|
||||||
const nodes = this.#translationNodes.get(el) || [];
|
|
||||||
this.#removeNodes(nodes);
|
this.#removeNodes(nodes);
|
||||||
|
this.#translationNodes.set(el, { nodes, isHide: true });
|
||||||
} else {
|
} else {
|
||||||
// 仅译文变为双语
|
// 仅译文变为双语
|
||||||
this.#restoreOriginal(el);
|
|
||||||
if (br) br.hidden = false;
|
if (br) br.hidden = false;
|
||||||
|
this.#restoreOriginal(el, nodes);
|
||||||
|
this.#translationNodes.set(el, { nodes, isHide: false });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1396,7 +1413,11 @@ export class Translator {
|
|||||||
this.#runId++;
|
this.#runId++;
|
||||||
|
|
||||||
if (this.#isInitialized) {
|
if (this.#isInitialized) {
|
||||||
this.#reIOViewNodes();
|
if (this.#setting.transAllnow) {
|
||||||
|
this.rescan();
|
||||||
|
} else {
|
||||||
|
this.#reIOViewNodes();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.#init();
|
this.#init();
|
||||||
}
|
}
|
||||||
@@ -1507,7 +1528,7 @@ export class Translator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsRescan) {
|
if (needsRescan || (this.#enabled && this.#setting.transAllnow)) {
|
||||||
this.rescan();
|
this.rescan();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -474,25 +474,6 @@ function RuleFields({ rule, rules, setShow, setKeyword }) {
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
{/* <Grid item xs={12} sm={12} md={6} lg={3}>
|
|
||||||
<TextField
|
|
||||||
select
|
|
||||||
size="small"
|
|
||||||
fullWidth
|
|
||||||
name="transTiming"
|
|
||||||
value={transTiming}
|
|
||||||
label={i18n("trigger_mode")}
|
|
||||||
disabled={disabled}
|
|
||||||
onChange={handleChange}
|
|
||||||
>
|
|
||||||
{GlobalItem}
|
|
||||||
{OPT_TIMING_ALL.map((item) => (
|
|
||||||
<MenuItem key={item} value={item}>
|
|
||||||
{i18n(item)}
|
|
||||||
</MenuItem>
|
|
||||||
))}
|
|
||||||
</TextField>
|
|
||||||
</Grid> */}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ export default function Settings() {
|
|||||||
preInit = true,
|
preInit = true,
|
||||||
skipLangs = [],
|
skipLangs = [],
|
||||||
detectRemote = true,
|
detectRemote = true,
|
||||||
|
transAllnow = false,
|
||||||
} = setting;
|
} = setting;
|
||||||
const { isHide = false, fabClickAction = 0 } = fab || {};
|
const { isHide = false, fabClickAction = 0 } = fab || {};
|
||||||
|
|
||||||
@@ -300,6 +301,20 @@ export default function Settings() {
|
|||||||
<MenuItem value={2}>{i18n("secondary_context_menus")}</MenuItem>
|
<MenuItem value={2}>{i18n("secondary_context_menus")}</MenuItem>
|
||||||
</TextField>
|
</TextField>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
size="small"
|
||||||
|
fullWidth
|
||||||
|
name="transAllnow"
|
||||||
|
value={transAllnow}
|
||||||
|
label={i18n("trigger_mode")}
|
||||||
|
onChange={handleChange}
|
||||||
|
>
|
||||||
|
<MenuItem value={false}>{i18n("mk_pagescroll")}</MenuItem>
|
||||||
|
<MenuItem value={true}>{i18n("mk_pageopen")}</MenuItem>
|
||||||
|
</TextField>
|
||||||
|
</Grid>
|
||||||
<Grid item xs={12} sm={12} md={6} lg={3}>
|
<Grid item xs={12} sm={12} md={6} lg={3}>
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
|
|||||||
Reference in New Issue
Block a user