diff --git a/src/common.js b/src/common.js
index d54a242..fb9887c 100644
--- a/src/common.js
+++ b/src/common.js
@@ -121,7 +121,7 @@ export async function run(isUserscript = false) {
// if (document?.documentElement?.tagName?.toUpperCase() !== "HTML") {
// return;
// }
- if (!document?.contentType?.includes("html")) {
+ if (!document?.contentType?.includes("text")) {
return;
}
diff --git a/src/config/i18n.js b/src/config/i18n.js
index bf0fefa..3d5f18c 100644
--- a/src/config/i18n.js
+++ b/src/config/i18n.js
@@ -2584,6 +2584,13 @@ export const I18N = {
ja: `原言語と目標言語が同じ場合、字幕は処理されません`,
ko: `원본 언어와 대상 언어가 동일한 경우, 자막은 처리되지 않습니다`,
},
+ plain_text_translate: {
+ zh: `纯文本翻译`,
+ en: `Plain text translation`,
+ zh_TW: `純文字翻譯`,
+ ja: `プレーンテキスト翻訳`,
+ ko: `순수 텍스트 번역`,
+ },
};
export const newI18n = (lang) => (key) => I18N[key]?.[lang] || "";
diff --git a/src/libs/translator.js b/src/libs/translator.js
index 78e387d..f7320af 100644
--- a/src/libs/translator.js
+++ b/src/libs/translator.js
@@ -274,8 +274,7 @@ export class Translator {
data, datalist, embed, head, iframe, input, noscript, map,
object, option, param, picture, progress,
select, script, style, track, textarea, template,
- video, wbr, .notranslate, [contenteditable='true'], [translate='no'],
- ${Translator.KISS_IGNORE_SELECTOR}`;
+ video, wbr, .notranslate, [contenteditable='true'], [translate='no']`;
#setting; // 设置选项
#rule; // 规则
@@ -322,6 +321,10 @@ export class Translator {
// 忽略元素
get #ignoreSelector() {
+ if (this.#rule.isPlainText) {
+ return Translator.KISS_IGNORE_SELECTOR;
+ }
+
if (this.#rule.autoScan === "false") {
return `${Translator.KISS_IGNORE_SELECTOR}, ${this.#rule.ignoreSelector}`;
}
@@ -353,7 +356,7 @@ export class Translator {
constructor({ rule = {}, setting = {}, favWords = [] }) {
this.#setting = { ...Translator.DEFAULT_OPTIONS, ...setting };
- this.#rule = { ...Translator.DEFAULT_RULE, ...rule };
+ this.#rule = { ...Translator.DEFAULT_RULE, ...rule, isPlainText: false };
this.#favWords = favWords;
this.#apisMap = new Map(
this.#setting.transApis.map((api) => [api.apiSlug, api])
@@ -413,6 +416,19 @@ export class Translator {
// 注入JS/CSS
this.#initInjector();
+ // 纯文本预处理
+ if (this.#rule.isPlainText) {
+ document
+ .querySelectorAll("pre")
+ .forEach(
+ (pre) =>
+ (pre.innerHTML = pre.innerHTML?.replace(
+ /(?:\r\n|\r|\n)/g,
+ "
"
+ ))
+ );
+ }
+
// 查找根节点并扫描
document
.querySelectorAll(this.#rule.rootsSelector || "body")
@@ -1786,7 +1802,11 @@ export class Translator {
this.#rule[key] !== newRule[key]
) {
this.#rule[key] = newRule[key];
- if (key === "autoScan" || key === "hasShadowroot") {
+ if (
+ key === "autoScan" ||
+ key === "hasShadowroot" ||
+ key === "isPlainText"
+ ) {
needsRescan = true;
} else {
hasChanged = true;
diff --git a/src/views/Popup/PopupCont.js b/src/views/Popup/PopupCont.js
index 310dbb3..84ca143 100644
--- a/src/views/Popup/PopupCont.js
+++ b/src/views/Popup/PopupCont.js
@@ -112,7 +112,10 @@ export default function PopupCont({
const handleChange = async (e) => {
try {
- const { name, value } = e.target;
+ let { name, value, checked } = e.target;
+ if (name === "isPlainText") {
+ value = checked;
+ }
setRule((pre) => ({ ...pre, [name]: value }));
if (!processActions) {
@@ -204,6 +207,7 @@ export default function PopupCont({
transOnly,
hasRichText,
hasShadowroot,
+ isPlainText = false,
} = rule;
return (
@@ -322,6 +326,20 @@ export default function PopupCont({
label={i18n("input_translate")}
/>
+
+
+ }
+ label={i18n("plain_text_translate")}
+ />
+