跳到主要内容

高级自定义选项

你可以在扩展配置页面 -> 开发者设置 -> User Config 里编辑更多 UI 里无法编辑的自定义配置,适用于高级用户,参数讲解详见最后的说明。当前内置的 config 可以在这里,点击 Click to expand the final config 找到。

User Rules

通过 Rules 可以对特定的网站进行自定义配置,决定哪些内容是否需要被翻译,或调整网页样式等。

[
{
"matches": "www.google.com",
"selectors": [".title"]
},
{
"matches": "twitter.com",
"selectors": [".text"],
"excludeSelectors": ["nav", "footer"]
}
]

使用 matches 来匹配对应的网站。允许通配符,如 *.google.com,www.google.com/test/*,file://*

使用 selectors 会覆盖智能翻译范围,仅翻译该选择器匹配到的元素。

使用 excludeSelectors 可以排除元素,不翻译该位置。

使用 selectors.add 会在默认的基础上添加一些 selectors

使用 selectors.remove 会在默认的基础上减少一些 selectors

[
{
"matches": "www.google.com",
"selectors.add": ["baidu.com"],
"excludeSelectors": ["buzzing.cc"]
}
]

如果希望翻译某个区域时,将元素视为一个整体,不将其分行,可以用 atomicBlockSelectors 选择器。比如 Instagram 的个人简介。要注意的是,使用 atomicBlockSelectors 前需要先用 selectors 进行选择。

{
"matches": "https://www.instagram.com/*",
"selectors": [
"div._aa_c h1",
"li._acaz div[role=\"menuitem\"]"
]
"atomicBlockSelectors": [
"div._aa_c h1",
"li._acaz div[role=\"menuitem\"]"
]
}

如果译文导致页面错位,文字重叠等边缘情况,可以使用 globalStyles 调整网页样式来修复。比如 youtube 的标题,用来移除原网页的最大高度。

{
"matches": "www.google.com",
"globalStyles": { ".title": "max-height:unset;" }
}

Injected CSS

通过 Injected CSS 可以向全局注入自定义网页样式。可以搭配 RulestranslationClasses 一起使用。

.immersive-translate-target-wrapper img { width: 16px; height: 16px }

也可以像常规的网页样式管理器那样,对网站进行更加个性化的样式设计。(甚至利用 display:none 去广告)

.title {
color: red;
}

User Config

通过 Config 可以自定义此插件的相关配置,如翻译服务、特定语言语言翻译选项等。

{
"translationService": "tencent",
"translationServices": {
"tencent": {
"secretId": "xxx",
"secretKey": "xxx",
"matches": ["twitter.com"]
}
},
"translationUrlPattern": {
"excludeMatches": ["www.google.com"]
},
"translationLanguagePattern": {
"matches": ["en"]
},
"translationTheme": "none",
"translationThemePatterns": {
"underline": {
"matches": ["discord.com"]
}
},
"sourceLanguageUrlPattern": {
"en": {
"matches": ["*.google.com"]
}
},
"generalRule": {
"_comment": "",
"normalizeBody": "",
"injectedCss": [],
"additionalInjectedCss": [],
"wrapperPrefix": "smart",
"wrapperSuffix": "smart",
"isPdf": false,
"isTransformPreTagNewLine": false,
"urlChangeDelay": 20,
"isShowUserscriptPagePopup": true,
"observeUrlChange": true,
"paragraphMinTextCount": 8,
"paragraphMinWordCount": 2,
"blockMinTextCount": 32,
"blockMinWordCount": 5,
"containerMinTextCount": 18,
"lineBreakMaxTextCount": 0,
"globalAttributes": {},
"globalStyles": {},
"selectors": [],
"preWhitespaceDetectedTags": ["DIV", "SPAN"],
"stayOriginalSelectors": [],
"additionalSelectors": [],
"atomicBlockTags": [],
"excludeSelectors": [],
"additionalExcludeSelectors": [],
"translationClasses": [],
"atomicBlockSelectors": [],
"excludeTags": [],
"metaTags": ["META", "SCRIPT", "STYLE", "NOSCRIPT"],
"additionalExcludeTags": [],
"stayOriginalTags": ["CODE", "TT", "IMG", "SUP"],
"additionalStayOriginalTags": [],
"inlineTags": [],
"additionalInlineTags": [],
"extraInlineSelectors": [],
"additionalInlineSelectors": [],
"extraBlockSelectors": [],
"allBlockTags": [],
"pdfNewParagraphLineHeight": 2.4,
"pdfNewParagraphIndent": 1.2,
"pdfNewParagraphIndentRightIndentPx": 130,
"fingerCountToToggleTranslagePageWhenTouching": 4
},
"rules": [
{
"matches": "www.google.com",
"selectors": [".class"]
}
]
}

其中,rules 里的规则字段,可以使用 generalRule 里的全部字段。rules 拥有最高优先级,当匹配到特定网站的某一条 rule 时,会合并 generalRule 和该 rule 的规则。

介绍一些 Config 常见的字段。

允许渲染普通 HTML 标签

开发设置 -> Edit Full User Config

编辑 "enableRenderHtmlTag": true

不在 popup 面板里展示未配置的翻译服务

"showUnconfiguredTranslationServiceInPopup": false

翻译服务配置

使用 translationService 选择默认的翻译引擎,当前支持:

| "bing"
| "transmart"
| "google"
| "deepl"
| "openai"
| "gemini"
| "baidu"
| "volc"
| "youdao"
| "caiyun"
| "tencent"
| "openl"

使用 translationServices 配置各家翻译服务的 apikey,不同服务商需要的参数不一样,它们的 API 密钥均可在各自官网的开发者中心申请。

如腾讯翻译君,需要配置 secretId, secretKey。你可以前往腾讯云申请 API 密钥,每月免费字符 500 万。具体申请过程参考这里

"translationServices": {
"tencent": {
"secretId": "xxx",
"secretKey": "xxx",
"matches":["twitter.com"],
"limit": 3,
"apiUrl":"",
"maxTextGroupLengthPerRequest": 25,
"maxTextLengthPerRequest": 1800
}
}

matches 字段, 为特定网站使用该翻译服务。

limit字段,指定该翻译服务的每秒最多请求数(有些服务会限制每秒最大请求数)。

maxTextGroupLengthPerRequest 字段,每次请求最大的段落数

maxTextLengthPerRequest 字段,每次请求最大的字符数

apiUrl 可以自定义翻译接口的地址。

总是翻译特定网站

translationUrlPattern 配置总是翻译的网站,以及永不翻译的网站。

  • matches 配置总是翻译的网站,
  • excludeMatches 配置永不翻译的网站。

配置值可以是域名或带有 * 的网址,比如:www.google.com/mail/*

"translationUrlPattern": {
"matches": ["stackoverflow.com"]
"excludeMatches": ["www.google.com/mail/*"]
}

总是翻译特定语言

translationLanguagePattern, 配置总是翻译的语言,以及永不翻译的语言。

  • matches 配置总是翻译的语言,比如 en,
  • excludeMatches 配置永不翻译的语言。

译文显示格式

translationTheme 为译文的显示格式,当前支持以下样式:

| "none"
| "dashed"
| "dotted"
| "underline"
| "mask"
| "paper"
| "highlight"
| "blockquote"
| "weakening"
| "italic"
| "bold"
| "thinDashed";

对应的中文名:

{
"none": "无",
"dashed": "虚线下划线",
"dotted": "点状下划线",
"underline": "直线下划线",
"mask": "模糊效果",
"paper": "白纸阴影效果",
"highlight": "高亮",
"blockquote": "引用样式",
"weakening": "弱化",
"italic": "斜体",
"bold": "加粗",
"thinDashed": "细虚线下划线"
}

translationThemePatterns 可以为不同网站配置不同的译文样式。

"translationThemePatterns": {
"underline": {
"matches": ["discord.com"]
}
}

类 gpt 页面流消息翻译

{
"matches": ["chat.openai.com"], //类 gpt 网址
"excludeSelectors": [".markdown *"],
"aiRule": {
"streamingSelector": ".result-streaming.markdown",
"messageWrapperSelector": ".markdown",
"streamingChange": true
}
}

Rules

rules 为数组对象,可以配置针对特别网站的规则,比如让推特只翻译某一部分区域:

{
"rules": [
{
"id": "twitter",
"matches": ["twitter.com", "mobile.twitter.com", "tweetdeck.twitter.com"],
"selectors": [
"[data-testid='tweetText']",
".tweet-text",
".js-quoted-tweet-text",
"[data-testid='card.layoutSmall.detail'] > div:nth-child(2)",
"[data-testid='developerBuiltCardContainer'] > div:nth-child(2)",
"[data-testid='card.layoutLarge.detail'] > div:nth-child(2)"
],
"extraInlineSelectors": ["[data-testid=\"tweetText\"] div"]
}
]
}

当前内置的 rules 可以在这里 找到。

以下挑选部分重要字段进行说明:

export interface Rule {
// 匹配网站
id?: string; //系统每个适配的规则都有自己的id,如果用户想要复用这条规则在此基础之上变动的话,需要在自己的规则上加上这个相应的id就可以复用了
matches?: string | string[]; // 该条Rule将仅匹配此处的网站。
excludeMatches?: string | string[]; // 排除特定的网站。
selectorMatches?: string | string[]; // 用选择器来匹配,而无需指定所有url
excludeSelectorMatches?: string | string[]; // 排除规则,同上。

// 指定翻译范围
selectors?: string | string[]; // 仅翻译匹配到的元素
excludeSelectors?: string | string[]; // 排除元素,不翻译匹配的元素
excludeTags?: string | string[]; // 排除Tags,不翻译匹配的Tag

// 追加翻译范围,而不是覆盖
additionalSelectors?: string | string[]; // 追加翻译范围。在智能翻译的区域,追加翻译位置。
additionalExcludeSelectors?: string | string[]; // 追加排除元素,让智能翻译不翻译特定位置。
additionalExcludeTags?: string | string[]; // 追加排除Tags

// 保持原样
stayOriginalSelectors?: string | string[]; // 匹配的元素将保持原样。常用于论坛网站的标签。
stayOriginalTags?: string | string[]; // 匹配到的Tag将保持原样,比如 `code`

// 区域翻译
atomicBlockSelectors?: string | string[]; // 区域选择器, 匹配的元素将被视为一个整体, 不会分段翻译
atomicBlockTags?: string | string[]; // 区域Tag选择器, 同上

// Block or Inline
extraBlockSelectors?: string | string[]; // 额外的选择器,匹配的元素将作为 block 元素,独占一行。
extraInlineSelectors?: string | string[]; // 额外的选择器,匹配的元素将作为 inline 元素。

inlineTags?: string | string[]; // 匹配的 Tag 将作为 inline 元素
preWhitespaceDetectedTags?: string | string[]; // 匹配的 Tag 将自动换行

// 译文样式
translationClasses?: string | string | string[]; // 为译文添加额外的 Class

// 全局样式
globalStyles?: Record<string, string>; // 修改页面样式,若译文导致页面错乱,这个很有用。`
globalAttributes?: Record<string, Record<string, string>>; // 修改页面元素的属性

// 嵌入样式
injectedCss?: string | string[]; // 嵌入CSS样式
additionalInjectedCss?: string | string[]; // 追加CSS样式,而不是直接覆盖。

// 上下文
wrapperPrefix?: string; // 译文区域的前缀,默认为 smart,根据字数决定是否换行。
wrapperSuffix?: string; // 译文区域的后缀

// 译文换行字数
blockMinTextCount?: number; // 将译文作为 block 的最小字符数,否则译文为 inline 元素。
blockMinWordCount?: number; // 同上。如果希望它们始终换行, 可以都填0.

// 内容可翻译的最小字数
containerMinTextCount?: number; // 智能识别时,元素最少包含的字符数,才会被翻译,默认为18
paragraphMinTextCount?: number; // 原文段落的最小字符数, 大于数字的内容将被翻译
paragraphMinWordCount?: number; // 原文段落的最小单词数

// 长段落强制换行字数
lineBreakMaxTextCount?: number; // 开启翻译长段落时,强制进行分行的段落最大字符数。

// 启动翻译的时机
urlChangeDelay?: number; // 进入页面后,延迟多少毫秒开始翻译。为了等网页的初始化,目前默认为250ms
observeUrlChange?: boolean; // 检测url地址发生变化时,再次启动翻译,默认为true。

// 移动端
isShowUserscriptPagePopup?: boolean; // 在移动设备上展示页面内的浮窗, 默认为true.
fingerCountToToggleTranslagePageWhenTouching?: number; // 四指触摸则翻译,可以设置为 0,2,3,4,5

// AI streaming 翻译
aiRule: {
streamingSelector: string; //gpt 网页中标记正在翻译元素的选择器
messageWrapperSelector: string; // 消息正文选择器
streamingChange: boolean; //类 gpt 网页反复的消息是增量更新还是全量更新。gpt 是增量
};
}

高级自定义选项实战

实用小技巧

这部分会介绍一些即插即用的保姆级配置。

将这些配置一键复制,打开开发者设置,展开 Edit Full User Config ,复制到最后一项即可,注意不要忘记给前一项加上逗号,以及最后一项不能加逗号

不能用的翻译服务太多了,如何在插件面板里只展示能用的翻译服务

  "showUnconfiguredTranslationServiceInPopup": false

如何让不同的站点默认选择不同的翻译服务?例如有的网站我想要好一点但要花钱的翻译效果,有的网站我只需要免费能看的翻译就行了

注意看,眼前这个配置叫翻译服务,他配置了谷歌翻译,让有关推特的相关站点的翻译都使用他去翻译,因为 google 翻译是免费的,推特是冲浪的,只要能看懂就行了。

仔细看,他还配置了 deepl 的翻译服务,他让 deepl 专门去翻译 scihub 这种容错率低的需要高精确的学术网站

  "translationServices": {
"google": {
"matches":["https://twitter.com"]
},
"bing": {
"matches":["https://www.sci-hub.se"]
}
}

⚠️ 请注意,若您希望翻译属于同一域名的所有网站,简单使用 .twitter.com 或 https://twitter.com/ 是无效的。正确的做法应参照上文所示。这是因为 .twitter.com 仅能匹配子域名如 xxx.twitter.com,而不包括顶级域名本身。

网站适配案例

这部分会介绍一些插件自己对常见的网站的 rules,通过实际例子来理解高级自定义选项。同时为了简洁,这里只会介绍最常用的字段,比如 selectors , excludeSelectors 等等,如果你对这部分内容感兴趣的话,欢迎联系我们,我们会继续更新相关的内容。

在介绍之前,一个非常关键的东西就是沉浸式翻译插件的工作原理,同时也是一个插件的工作原理。在此之前,需要有一定的 HTMLCSSJavaScript 基础,相关基础可以在 MDN 网站上学习。Okay,话不多说,让我们走进沉浸式翻译的内部一探究竟。插件的工作机制简单来说,就是向网页中注入第三方脚本,这个脚本可以对网页结构,样式,甚至行为进行相当自由地魔改。

我们的沉浸式翻译插件也不例外,让我们来简单分析一下沉浸式翻译它干了个什么事

  • 获取需要翻译的元素集合
  • 翻译元素集合中的文本
  • 将翻译的结果插入到元素集合中

Okay,但是再仔细想想,自然而然就会带出接下来两个问题

  • 我们还需要确定哪些元素需要被翻译,如果全盘翻译,往往会破坏用户的沉浸式体验,像一些简单明了的按钮,或者导航栏。
  • 将翻译的结果插入到元素集合中也会带来一个新的挑战,如何保证插入的结果与原生网页保持一致,不去影响原生网页的样式。

我们的 Rules 的核心就是解决上述两个问题。因为作为插件,沉浸式翻译面对的是市面上所有的网页,加起来可能超过几十万,甚至几百万的网页,这些网页的页面结构,使用的技术也是相差殆尽。因为网页的不同,导致了一个通用的逻辑是几乎不可能的,很难找到一套通用的逻辑,能够去适配所有的网站内容。这样看来,解决方法似乎只有挨着挨着对每个网站进行单独的适配。接着为了更方便地适配,我们又利用了配置即代码的思想,将适配的工作转换成了配置字段的工作。这样的另一个好处就是,用户也可以参与到适配工作起来。

同时,在进行配置的时候,最好不要直接使用下面几个字段,这样会导致覆盖掉原先的配置项,而是采用 selector.add excludeSelector.add 这几个字段以继承的方式,在原先的配置项的基础上进行修改

下面,我们将会介绍沉浸式翻译对站点的适配工作

下面是推特的 Rules,为了简洁,我们将关注其中的几个关键字段,剩余字段可以结合上文中的 Rules 理解

[
{
"id": "twitter",
"matches": [
"twitter.com",
"mobile.twitter.com",
"tweetdeck.twitter.com",
"pro.twitter.com",
"https://platform.twitter.com/embed*"
],
"selectors": [
// 指定翻译的元素,只会翻译选择器匹配到的元素
"[data-testid=\"tweetText\"]",
".tweet-text",
".js-quoted-tweet-text",
"[data-testid='card.layoutSmall.detail'] > div:nth-child(2)",
"[data-testid='developerBuiltCardContainer'] > div:nth-child(2)",
"[data-testid='card.layoutLarge.detail'] > div:nth-child(2)",
"[data-testid='cellInnerDiv'] div[data-testid='UserCell'] > div> div:nth-child(2)",
"[data-testid='UserDescription']",
"[data-testid='HoverCard'] div[dir=auto]",
"[data-testid='HoverCard'] span[dir=auto]",
"[data-testid='HoverCard'] [role='dialog'] div[dir=ltr]",
"[data-testid='birdwatch-pivot'] div[dir=ltr]"
],
"excludeSelectors": [
// 不会翻译的被CSS选择器选中的元素
"[aria-describedby][role=button]",
"header",
"[data-testid='radioGroupplayback_rate'] div",
"[data-testid='userFollowIndicator']",
"[class='css-901oao r-14j79pv r-37j5jr r-n6v787 r-16dba41 r-1cwl3u0 r-bcqeeo r-qvutc0']",
"[class='css-175oi2r r-1wbh5a2 r-dnmrzs']"
],
"globalStyles": {
// 全局样式,强制覆盖掉原样式
"[data-testid='card.layoutLarge.detail'] > div:nth-child(2)": "-webkit-line-clamp: unset;",
"[data-testid='card.layoutSmall.detail'] > div:nth-child(2)": "-webkit-line-clamp: unset;",
"[data-testid='tweetText']": "-webkit-line-clamp: unset;"
}
}
]
  • selector: 指定翻译的元素集合

    为什么需要这个字段

    • 因为不是所有元素都有文字且需要翻译的,提供这样一个字段既可以保证性能又可以保证用户的沉浸式体验

    举个例子

    • 在推特中,如果我们不指定 selector,那么他将会将页面中的所有识别为英文的文字都进行翻译一遍,如下图,用户的昵称往往是不需要翻译的。

    用户主页

    字段含义

    •   "selectors": [ // 会被翻译的CSS选择器集合
      "[data-testid=\"tweetText\"]",
      ]

    这里数组的每一项都是一个 CSS 选择器,用来选择页面中的需要翻译的元素,这里我们以第一个选择器为例,如下图所示,第一个选择器命中的是所有推文的元素

    tweet

  • excludeSelectors: 不会被翻译的元素集合

    为什么需要这个字段

    • 因为一个仅翻译的选择器是不够的,可能会出现,匹配中的元素却不需要翻译的,即两者可能存在重合的部分,因此需要再设置一个字段来排除掉不需要翻译的元素
    • 由于页面结构是非常复杂的,提供这样两个配置项,让配置更加灵活
    • 相关的优先级是:对于同等选择器,selectors > excludeSelectors,剩下的依靠 CSS 优先级来比较

    字段含义

    •   "excludeSelectors": [ // 不会翻译的被CSS选择器选中的元素
      "[aria-describedby][role=button]",
      ],

    还是看第一个,这里我们排除掉了关注按钮的这个翻译 twitter-follow

  • globalStyles: 添加全局样式,强制覆盖掉原先的样式

    为什么需要这个字段

    • 在某些情况下,因为原先网页的相关 CSS 样式,会导致整个的翻译展示效果不是很好,出现被截断,不换行等等效果
    • 通过这个字段,提供一种暴力的解决方案,直接修改原生网页的 CSS 属性来解决

    字段含义

    •     "globalStyles": {
      // 全局样式,强制覆盖掉原样式
      "[data-testid='card.layoutLarge.detail'] > div:nth-child(2)": "-webkit-line-clamp: unset;",
      "[data-testid='card.layoutSmall.detail'] > div:nth-child(2)": "-webkit-line-clamp: unset;",
      "[data-testid='tweetText']": "-webkit-line-clamp: unset;"
      }

    -webkit-line-clamp 这个属性用来控制显示的行数,多余的行会被截断,这里设置成 unset ,可以保证译文不会被这个属性所截断

自定义网站适配

关于适配规则,当然你也可以自定义规则,进入到插件选项页面,点击开发者设置,展开 Edit User Rules ,在这里进行各个网站的自定义适配。下面结合实际规则进行讲解

[
{
"selectors.remove": [
"[data-testid=\"tweetText\"]"
],
"selectors.add": [
""
],
"excludeSelectors.add":[
""
],
"excludeSelectors.remove:[
""
],
"id": "twitter"
}
]

这个规则会让推特页面的推文不进行翻译。下面详细介绍字段的含义

id 是沉浸式翻译目前已经定义好的相关网站的集合,每个 id 都对应相关的站点。id 的好处有两个

  • 使用 id 能继承沉浸式翻译之前的适配规则,用户可以在这基础上进行增删
  • 使用 id 就不用写繁琐的匹配字段了

下面介绍一些沉浸式翻译内置服务的常见的 id

  • "isEbook" epub 阅读器页面的配置
  • "isEbookBuilder" 生成 epub 双语书页面的配置
  • "pdf" pdf 双语对照翻译页面的配置

完整的 id 集合可以在开发者设置中,Click to expand the final config 中找到

selectors 负责指定需要翻译的CSS选择器,建议使用子项 .add .remove 在原先的基础上进行增删

excludeSelectors 负责排除不需要翻译的CSS选择器,建议使用子项 .add .remove 在原先的基础上进行增删

更多讲解

Block 和 inline 的区别,如果想了解更多可以看这里

  • block 元素会独占一行,多个相邻的 block 元素会各自新起一行.
  • inline 元素不会独占一行,多个相邻的 inline 元素会排列在同一行里,直到一行排列不下才会新换一行。