diff --git a/src/config/i18n.js b/src/config/i18n.js index c4c36eb..35f6489 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -188,7 +188,7 @@ export const I18N = { en: `Translate Timing`, }, mk_disable: { - zh: `滚动加载(建议)`, + zh: `滚动加载(推荐)`, en: `Rolling Loading (Suggested)`, }, mk_pageopen: { @@ -743,6 +743,18 @@ export const I18N = { zh: `支持用换行或英文逗号“,”分隔多个KEY轮询调用。`, en: `Supports multiple KEY polling calls separated by newlines or English commas ",".`, }, + translation_element_tag: { + zh: `译文元素标签`, + en: `Translation Element Tag`, + }, + show_only_translations: { + zh: `仅显示译文`, + en: `Show Only Translations`, + }, + show_only_translations_help: { + zh: `非完美实现,某些页面可能有样式等问题。`, + en: `It is not a perfect implementation and some pages may have style issues.`, + }, translate_page_title: { zh: `是否同时翻译页面标题`, en: `Translate Page Title`, diff --git a/src/config/index.js b/src/config/index.js index fba1ea1..d254c8d 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -437,7 +437,7 @@ export const DEFAULT_BLACKLIST = [ "https://translate.google.com", "https://www.deepl.com/translator", "oapi.dingtalk.com", - "login.dingtalk.com" + "login.dingtalk.com", ]; // 禁用翻译名单 export const DEFAULT_SETTING = { @@ -454,6 +454,8 @@ export const DEFAULT_SETTING = { detectRemote: false, // 是否使用远程语言检测 contextMenus: true, // 是否添加右键菜单(作废) contextMenuType: 1, // 右键菜单类型(0不显示,1简单菜单,2多级菜单) + transTag: "span", // 译文元素标签 + transOnly: false, // 是否仅显示译文 transTitle: false, // 是否同时翻译页面标题 subrulesList: DEFAULT_SUBRULES_LIST, // 订阅列表 owSubrule: DEFAULT_OW_RULE, // 覆写订阅规则 diff --git a/src/libs/translator.js b/src/libs/translator.js index ec23ad4..739c9ed 100644 --- a/src/libs/translator.js +++ b/src/libs/translator.js @@ -372,31 +372,64 @@ export class Translator { // 解除节点显示监听 // this._interseObserver.disconnect(); - if ( - !this._setting.mouseKey || - this._setting.mouseKey === OPT_MOUSEKEY_DISABLE - ) { - // 解除节点显示监听 - this._tranNodes.forEach((_, node) => { + // 移除键盘监听 + window.removeEventListener("keydown", this._handleKeydown); + + this._tranNodes.forEach((innerHTML, node) => { + if ( + !this._setting.mouseKey || + this._setting.mouseKey === OPT_MOUSEKEY_DISABLE + ) { + // 解除节点显示监听 this._interseObserver.unobserve(node); - // 移除已插入元素 - node.querySelector(APP_LCNAME)?.remove(); - }); - } else if (this._setting.mouseKey === OPT_MOUSEKEY_PAGEOPEN) { - this._tranNodes.forEach((_, node) => { - node.querySelector(APP_LCNAME)?.remove(); - }); - } else { - // 移除鼠标悬停监听 - window.removeEventListener("keydown", this._handleKeydown); - this._tranNodes.forEach((_, node) => { + } else if (this._setting.mouseKey !== OPT_MOUSEKEY_PAGEOPEN) { + // 移除鼠标悬停监听 // node.style.pointerEvents = "none"; node.removeEventListener("mouseenter", this._handleMouseover); node.removeEventListener("mouseleave", this._handleMouseout); - // 移除已插入元素 - node.querySelector(APP_LCNAME)?.remove(); - }); - } + } + + // 移除已插入元素 + node.querySelector(APP_LCNAME)?.remove(); + if (innerHTML && this._setting.transOnly) { + node.innerHTML = innerHTML; + } + }); + + // if ( + // !this._setting.mouseKey || + // this._setting.mouseKey === OPT_MOUSEKEY_DISABLE + // ) { + // // 解除节点显示监听 + // this._tranNodes.forEach((innerHTML, node) => { + // this._interseObserver.unobserve(node); + // // 移除已插入元素 + // node.querySelector(APP_LCNAME)?.remove(); + // if (innerHTML) { + // node.innerHTML = innerHTML; + // } + // }); + // } else if (this._setting.mouseKey === OPT_MOUSEKEY_PAGEOPEN) { + // this._tranNodes.forEach((innerHTML, node) => { + // node.querySelector(APP_LCNAME)?.remove(); + // if (innerHTML) { + // node.innerHTML = innerHTML; + // } + // }); + // } else { + // // 移除鼠标悬停监听 + // window.removeEventListener("keydown", this._handleKeydown); + // this._tranNodes.forEach((innerHTML, node) => { + // // node.style.pointerEvents = "none"; + // node.removeEventListener("mouseenter", this._handleMouseover); + // node.removeEventListener("mouseleave", this._handleMouseout); + // // 移除已插入元素 + // node.querySelector(APP_LCNAME)?.remove(); + // if (innerHTML) { + // node.innerHTML = innerHTML; + // } + // }); + // } // 清空节点集合 this._rootNodes.clear(); @@ -422,6 +455,10 @@ export class Translator { // 已翻译 if (traEl) { + if (this._setting.transOnly) { + return; + } + const preText = this._tranNodes.get(el); const curText = el.innerText.trim(); // const traText = traEl.innerText.trim(); @@ -437,7 +474,11 @@ export class Translator { } let q = el.innerText.trim(); - this._tranNodes.set(el, q); + if (this._setting.transOnly) { + this._tranNodes.set(el, el.innerHTML); + } else { + this._tranNodes.set(el, q); + } const keeps = []; // 保留元素 @@ -490,6 +531,9 @@ export class Translator { traEl = document.createElement(APP_LCNAME); traEl.style.visibility = "visible"; + if (this._setting.transOnly) { + el.innerHTML = ""; + } el.appendChild(traEl); el.style.cssText += "-webkit-line-clamp: unset; max-height: none; height: auto;"; diff --git a/src/views/Content/index.js b/src/views/Content/index.js index e776876..728832d 100644 --- a/src/views/Content/index.js +++ b/src/views/Content/index.js @@ -1,4 +1,4 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useMemo } from "react"; import LoadingIcon from "./LoadingIcon"; import { OPT_STYLE_LINE, @@ -16,7 +16,9 @@ import { import { useTranslate } from "../../hooks/Translate"; import { styled } from "@mui/material/styles"; -const LineSpan = styled("span")` +const Span = styled("span")``; + +const LineSpan = styled(Span)` opacity: 0.6; -webkit-opacity: 0.6; text-decoration-line: underline; @@ -35,7 +37,7 @@ const LineSpan = styled("span")` } `; -const BlockquoteSpan = styled("span")` +const BlockquoteSpan = styled(Span)` opacity: 0.6; -webkit-opacity: 0.6; display: block; @@ -47,7 +49,7 @@ const BlockquoteSpan = styled("span")` } `; -const FuzzySpan = styled("span")` +const FuzzySpan = styled(Span)` filter: blur(0.2em); -webkit-filter: blur(0.2em); &:hover { @@ -56,59 +58,63 @@ const FuzzySpan = styled("span")` } `; -const HighlightSpan = styled("span")` +const HighlightSpan = styled(Span)` color: #fff; background-color: ${(props) => props.$bgColor}; `; -const DiySpan = styled("span")` +const DiySpan = styled(Span)` ${(props) => props.$diyStyle} `; -function StyledSpan({ textStyle, textDiyStyle, bgColor, children }) { +function StyledSpan({ textStyle, textDiyStyle, bgColor, children, ...props }) { switch (textStyle) { case OPT_STYLE_LINE: // 下划线 return ( - + {children} ); case OPT_STYLE_DOTLINE: // 点状线 return ( - + {children} ); case OPT_STYLE_DASHLINE: // 虚线 return ( - + {children} ); case OPT_STYLE_WAVYLINE: // 波浪线 return ( - + {children} ); case OPT_STYLE_FUZZY: // 模糊 - return {children}; + return {children}; case OPT_STYLE_HIGHLIGHT: // 高亮 return ( - + {children} ); case OPT_STYLE_BLOCKQUOTE: // 引用 return ( - + {children} ); case OPT_STYLE_DIY: // 自定义 - return {children}; + return ( + + {children} + + ); default: - return {children}; + return {children}; } } @@ -117,7 +123,11 @@ export default function Content({ q, keeps, translator }) { const { text, sameLang, loading } = useTranslate(q, rule, translator.setting); const { textStyle, bgColor = "", textDiyStyle = "" } = rule; - const { newlineLength = TRANS_NEWLINE_LENGTH } = translator.setting; + const { + newlineLength = TRANS_NEWLINE_LENGTH, + transTag = "span", + transOnly = false, + } = translator.setting; const handleKissEvent = (e) => { const { action, args } = e.detail; @@ -136,10 +146,27 @@ export default function Content({ q, keeps, translator }) { }; }, [translator.eventName]); + const gap = useMemo(() => { + if (transOnly) { + return ""; + } + return q.length >= newlineLength ?
: " "; + }, [q, transOnly, newlineLength]); + + const styles = useMemo( + () => ({ + textStyle, + textDiyStyle, + bgColor, + as: transTag, + }), + [textStyle, textDiyStyle, bgColor, transTag] + ); + if (loading) { return ( <> - {q.length >= newlineLength ?
: " "} + {gap} ); @@ -149,24 +176,24 @@ export default function Content({ q, keeps, translator }) { return; } + if (keeps.length > 0) { + return ( + <> + {gap} + keeps[parseInt(p)]), + }} + /> + + ); + } + return ( <> - {q.length >= newlineLength ?
: " "} - - {keeps.length > 0 ? ( - keeps[parseInt(p)]), - }} - /> - ) : ( - text - )} - + {gap} + {text} ); } diff --git a/src/views/Options/Setting.js b/src/views/Options/Setting.js index 1a146d7..88a19da 100644 --- a/src/views/Options/Setting.js +++ b/src/views/Options/Setting.js @@ -97,6 +97,8 @@ export default function Settings() { mouseKey = OPT_MOUSEKEY_DISABLE, detectRemote = false, contextMenuType = 1, + transTag = "span", + transOnly = false, transTitle = false, touchTranslate = 2, blacklist = DEFAULT_BLACKLIST.join(",\n"), @@ -184,6 +186,33 @@ export default function Settings() { + + {i18n("translation_element_tag")} + + + + + {i18n("show_only_translations")} + + {i18n("show_only_translations_help")} + + {i18n("translate_page_title")}