CopyTranslator 翻译实现机制深度剖析:从剪贴板监听到多引擎调度与本地化加载的完整链路
【免费下载链接】CopyTranslator🔠Foreign language reading and translation assistant based on copy and translate.项目地址: https://gitcode.com/gh_mirrors/co/CopyTranslator
CopyTranslator 是一款基于"复制即翻译"理念的外语阅读与翻译辅助工具。本文以仓库内 docs/TRANSLATION_IMPLEMENTATION.md 为骨架,结合 Electron 主进程与渲染进程的源码实现,端到端剖析其翻译架构:从主/渲染进程分层与 Vuex 状态通道,到动作与配置驱动链路,再到语言决策、多引擎调度、词典系统、结果同步与界面绑定,直至本地化资源生成与加载。读完本文,你将掌握翻译功能的关键入口、底层数据流与可扩展点,能够精准定位修改位置并独立扩展新翻译器、新词典或新触发机制。
1. 架构分层与数据流:主进程、渲染进程与 Vuex 全局状态
CopyTranslator 基于 Electron 构建,翻译链路横跨主进程与渲染进程。理解这一分层是定位一切翻译相关问题的前提。
进程与控制器
- 主进程承担翻译、剪贴板、OCR 与配置响应等重活。应用启动时在
Controller中实例化TranslateController(见 src/main/controller.ts),并安装本地化模块l10n。createWindow中依次执行transCon.init()(初始化翻译器与剪贴板)、restoreFromConfig()(恢复设置)、事件绑定与代理服务启动,见 src/main/controller.ts。 - 渲染进程只负责界面渲染与交互,通过代理对象把设置写回主进程,见 src/renderer/controller.ts。渲染进程中不会真正执行翻译引擎调用——
getTranslator在渲染进程会返回"拒绝执行翻译"的轻量占位对象,避免加载重型依赖(见 src/common/translate/translators.ts)。
状态与事件通道
全局状态集中在 Vuex store(src/store/index.ts),核心 state 包括:
status:当前翻译状态(None/Translating/Listen/AutoCopy等);sharedResult:翻译结果;dictResult:词典结果;resultBuffer:多引擎缓存结果;languages:当前主引擎支持的源语言/目标语言列表;config:配置快照。
状态变更通过两类 Vuex 插件驱动:
observePlugin:监听配置变更并通知所有观察者(主进程Controller与TranslateController均注册为观察者,见 src/store/plugins/observe.ts)。当用户在界面修改配置时,渲染进程通过代理写回主进程,主进程再回调观察者的postSet完成实际行为切换。updateViewPlugin:在语言列表等数据变化时触发视图层联动刷新(如语言下拉菜单),见 src/store/plugins/update-view.ts。
从源码结构可以推断:翻译结果本身不通过 IPC 逐条推送,而是由主进程写 Vuex、通过
vuex-electron的createSharedMutations()共享到渲染进程,视图从 store 读取响应式数据完成绑定。
2. 动作与配置驱动链路:从 UI/快捷键到翻译执行
CopyTranslator 将一切可执行操作抽象为"动作(Action)",统一由ActionManager管理。
动作分发
- 动作从 UI 按钮、系统托盘或快捷键触发,经
ActionManager.dispatch解析identifier与参数,通过事件总线广播到回调(见 src/common/action.ts)。ActionManager.init()集中注册了全部动作:开关型动作(switchAction)、列表动作(listAction)、含参动作(paramNormalAction)等,见 src/common/action.ts。 - 主进程
Controller.handle负责路由动作:窗口/快照/更新类动作由自身处理,其余默认转交TranslateController.handle(见 src/main/controller.ts、src/main/translate-controller.ts)。
TranslateController.handle是翻译相关动作的统一入口,下表列举关键标识符及其行为:
| 动作标识符 | 行为 | 源码位置 |
|---|---|---|
translate | 以指定文本触发翻译,更新语言并清空旧结果、附带词典查询 | translate-controller.ts |
translateClipboard | 立即检查剪贴板并翻译 | translate-controller.ts |
doubleCopyTranslate | 连续两次复制触发翻译(使用translator-double引擎组) | translate-controller.ts |
clear | 清空原文与全部结果 | translate-controller.ts |
copySource/copyResult | 复制原文/译文,带参数时复制指定引擎缓存结果 | translate-controller.ts |
pasteResult | 复制译文后模拟粘贴 | translate-controller.ts |
retryTranslate | 重试翻译 | translate-controller.ts |
testTranslate | 用指定引擎测试翻译一段文本,结果经事件总线回传 | translate-controller.ts |
reloadCustomTranslators | 重新加载自定义(AI 供应商)翻译器 | translate-controller.ts |
另外,alias映射提供动作组合能力,例如simulateIncrementCopy展开为["incrementCounter", "simulateCopy"]两个子动作(见 src/common/action.ts)。
配置与开关
- 配置项规则集中在 src/common/configuration.ts,包含翻译开关与引擎组等。典型配置键有:
listenClipboard(剪贴板监听)、incrementalCopy(增量复制)、autoCopy/autoPaste(自动复制/粘贴)、multiSource(多源对比)、translator-enabled/translator-cache/translator-compare/translator-double(引擎组)等。 - 翻译相关配置变更最终由
TranslateController.postSet落地(见 src/main/translate-controller.ts)。典型的联动逻辑包括:multiSource打开时立即重新翻译;translator-enabled变更时更新引擎集合;sourceLanguage/targetLanguage变更时带updateLanguage: true重新翻译;autoFormat与autoCopy互斥:开启一个自动关闭另一个;translatorType/dictionaryType变更触发switchTranslator/switchDictionary并提前返回,不参与后续状态刷新;listenClipboard变更时启动或停止剪贴板监听(setWatch)。
3. 翻译触发与输入处理:剪贴板监听、增量复制与文本净化
触发来源
翻译触发有三大来源:
- 显式动作:
translate、translateClipboard、doubleCopyTranslate等,见 src/main/translate-controller.ts; - 剪贴板监听:
setWatch(true)后注册text-changed与image-changed事件,文本变更调用checkClipboard(true)触发翻译;图片变更在enableOCR开启后走 OCR 识别链路(pp_recognizer或recognizer),见 src/main/translate-controller.ts; - UI 触发:输入框 Ctrl+Enter 通过
BaseView.translate派发动作,见 src/components/BaseView.vue 与 src/components/ContrastPanel.vue。
文本预处理与校验
checkClipboard是一条完整的输入校验流水线(src/main/translate-controller.ts):
checkLength:文本长度须在(0, 3000]区间,空文本或超长文本直接忽略,见 src/main/translate-controller.ts;normalizeText:调用normalizeAppend净化文本——统一换行符、去除-\n软换行、将句末标点与换行重构为分句标记;若判定为单词则去除首尾标点,见 src/main/translate-controller.ts 与 src/common/translate/helper.ts;checkValid:与当前文本、上次增量片段相同,或与任一引擎缓存译文相同(matchAnyResults)时跳过翻译,避免重复请求,见 src/main/translate-controller.ts。
增量复制(Incremental Copy)
增量复制是 CopyTranslator 的招牌特性:连续复制多个片段,自动拼接后一次性翻译。核心在setSrc(src/main/translate-controller.ts):
- 是否进入增量模式由
isIncremental决定,条件为配置开关incrementalCopy打开或incrementCounter > 0(见 src/main/translate-controller.ts); - 拼接规则区分语言:中文片段直接拼接,非中文片段以空格连接;
incrementCounter由快捷键动作incrementCounter设置,表示"下一次监听剪贴板为增量选中",每次拼接后递减。
checkIsWord同时是词典模式与净化路径的判定函数:长度不超过 100、且仅含字母数字空格且单词数不超过 3 的文本才被认定为单词(src/common/translate/helper.ts)。
4. 语言决策与语言名称:检测、智能互译与本地化显示
语言检测与智能互译
decideLanguage决定最终源/目标语言(src/main/translate-controller.ts),流程为:
- 取文本前 50 字符(短文本取全文)作为检测样本;
- 调用
translator.detect——Compound.detect采用离线优先策略:先用@opentranslate2/translator的detectLang做本地检测,失败才回退到在线检测引擎(默认baidu),见 src/common/translate/compound.ts; - 检测结果若是
zh-CN/zh-TW,再用isTrad(繁简识别)修正,因为"繁简检测似乎不太灵"(源码注释原文); - 若源语言与目标语言相同,且开启了
smartTranslate,则将目标语言切换为用户配置的源语言,实现"中文进、英文出"的智能互译(见 src/main/translate-controller.ts)。
语言名称显示
语言名称由getLanguageLocales提供,底层是@opentranslate2/languages的本地化字典(见 src/common/translate/locale.ts)。翻译完成后,sync通过getL(lang)取本地化名称并 toast翻译完成 中文 -> English(见 src/main/translate-controller.ts)。语言下拉菜单同样由createLanguageGenerator动态生成,源语言列表含auto,目标语言列表剔除auto(见 src/common/action.ts)。
5. 翻译执行与引擎调度:注册表、后备策略与多引擎缓存
翻译器注册
内置翻译器由creators工厂表与translators实例缓存共同管理(src/common/translate/translators.ts),已注册的内置引擎包括:baidu、google(包装为GoogleWrapper)、keyan、youdao、sogou、caiyun、aliyun、azure、deepl、tencent、tencentsmart、yandex、volc、baidu-domain(医药领域定制)、stepfun、niu。
getTranslator按四级查找解析引擎(src/common/translate/translators.ts):
- 实例缓存
translators; - 内置工厂
creators(创建实例时优先使用配置中的密钥,缺失则回退defaultTokens); - 自定义翻译器(
customTranslatorManager); - 后备:打印警告并返回 Google。
多引擎与后备策略
Compound.translate是引擎调度的核心(src/common/translate/compound.ts):
- 若未显式指定引擎,使用当前
engines集合,并强制将主引擎加入队列; - 通过
isSupport按"当前源/目标语言是否被该引擎支持"过滤(DirectionalTranslator走方向支持判断,普通翻译器走语言列表包含判断,见 src/common/translate/compound.ts); - 后备策略:若主引擎不支持当前语言对,则切换到
fallbackTranslator(配置项,默认google,可在 UI 中修改); - 主引擎结果作为
mainResult返回,其余支持引擎并行发起翻译但异常仅打印日志,不阻塞主结果; - 相同
(text, from, to)组合复用resultBuffer(extend),否则清空缓存重建(clear)。
translateWith负责单引擎执行(src/common/translate/compound.ts):先查缓存命中即返回,否则调用getTranslator(engine).translate,随后依次执行autoReSegment分句重组、构造SharedResult(含transPara/textPara段落信息与chineseStyle目标语言风格标记)、写回resultBuffer并打点追踪tracker.track("translation", engine)。
结果缓存与多源模式
ResultBufferManager维护resultBufferMap,sync()将结果同步到 Vuex 的resultBuffer,未完成引擎以status: "Translating"占位,见 src/common/translate/compound.ts。TranslateController.translateSentence按当前模式选择引擎组(src/main/translate-controller.ts):- 多源对比模式(
multiSource开启):读取translator-compare引擎组,过滤掉未启用/不存在的引擎后全部并行翻译; - 普通模式:读取
translator-cache引擎组,经filterByActiveEngines只保留translator-enabled与自定义翻译器中处于启用态的引擎; - 最终
engines.sort()后交给Compound.translate。
- 多源对比模式(
doubleCopyTranslate则使用translator-double引擎组(配置了才覆盖默认组),见 src/main/translate-controller.ts。
引擎切换与缓存命中
switchTranslator处理主引擎切换(src/main/translate-controller.ts):先更新主引擎与支持语言列表;若当前源/目标语言不再被支持,自动回退到en/zh-CN并重新翻译;若语言仍受支持,则优先命中缓存——文本一致且缓存存在时直接postTranslate缓存结果,否则重新翻译。
6. 词典系统与智能词典:Polymer 聚合查询与单词判定
词典引擎聚合
词典子系统由Polymer管理(src/common/dictionary/polymer.ts):
- 默认主引擎为
youdao(构造函数默认参数),setMainEngine可切换为bing; query(words)时,主引擎发起主查询返回结果,其余注册引擎并行查询并写入各自缓存,任一引擎失败则缓存undefined;- 切换主引擎后若查询词未变,优先从
getBuffer命中缓存,缓存为空则clearDict清空界面。
当前内置词典引擎只有bing与youdao,注册在 src/common/dictionary/engines.ts。词典类型定义dictionaryTypes = ["youdao", "bing"],结果结构包含words、explains、phonetics、examples、suggests、url等字段,见 src/common/dictionary/types.ts。
智能词典触发
isWord决定是否进入词典模式(src/main/translate-controller.ts),需同时满足:
- 配置开关
smartDict打开; checkIsWord(text)判定为单词;- 当前不在增量复制状态(增量复制下强制走整段翻译)。
preTranslate在设置原文后记录needDict;realTranslate中若dict && needDict为真,则与句子翻译并行发起queryDictionary(src/main/translate-controller.ts、src/main/translate-controller.ts)。词典查询成功后若explains非空,写入dictResult并syncDict同步到 Vuex,见 src/main/translate-controller.ts。
7. 结果同步、缓存与界面绑定:从 Vuex 到四种视图
结果同步
翻译完成后postTranslate依次执行:
normalizeAppend再次净化译文(受autoPurify控制);postProcess:按autoCopy/autoPaste/autoFormat/autoShow配置自动复制、延时粘贴(pasteDelay秒)、回写原文或显示窗口,见 src/main/translate-controller.ts;sync(language):写入 VuexsharedResult,开启enableNotify时发系统通知,并 toast 显示来源语言 -> 目标语言,见 src/main/translate-controller.ts。
多引擎缓存经ResultBufferManager.sync()写入resultBuffer。整个翻译期间translating标志位防止并发打断(translateWithOption开头检查)。
渲染层展示
四种界面消费同一份状态:
- BaseView:统一读取
sharedResult/dictResult/配置,定义模式切换逻辑(普通/专注/对照),见 src/components/BaseView.vue; - ContrastPanel:对照面板,用多布局展示源文本、译文、词典与对比视图,见 src/components/ContrastPanel.vue;
- DiffTextArea:多源对比视图,读取
resultBuffer并计算差异(差异计算见 src/renderer/comparator.ts),见 src/components/DiffTextArea.vue; - DictResult:词典结果面板,渲染
dictResult的释义、音标、例句等,见 src/components/DictResult.vue; - Focus:专注模式视图,处理译文与多源/词典展示,见 src/components/Focus.vue。
8. 本地化资源生成与加载:从 TypeScript 语言包到运行时 JSON
资源定义与生成
- 源码语言包以
Map形式维护在 src/common/locales.ts,内置en与zh_cn两个基准语言; - 使用技巧轮播内容来自语言包中以
<tip>等提示类键,由 src/components/Tips.vue 组装展示; prebuild.ts将语言包序列化为dist_locales/*.json(缩进 4 格的格式化 JSON),并自动补齐缺失键:读取dist_locales中已存在的第三方语言文件,缺失键用英文兜底,见 src/prebuild.ts;- 构建脚本在
package.json的prebuild钩子中执行:先tsc编译再node运行(见 package.json),生成的资源即仓库中的 dist_locales、dist_locales/zh-CN.json 等。
运行时加载
L10N在主进程加载语言包:依次扫描系统语言目录与用户语言目录下的*.json,为每个语言包补齐缺失键,注册语言列表,并安装到 Vuex(updateLocales/updateLocaleSetting/updateLocale),见 src/main/l10n.ts;- 语言包目录由运行环境决定:开发态为项目内
dist_locales,生产态为resources/locales,并额外叠加用户目录(用户可覆盖/新增语言),见 src/common/env.ts; - 默认语言通过
app.getLocale()获取,zh归一为zh-CN,不在zh-CN/en/zh-TW范围时回退en(见 src/main/l10n.ts); - Vuex 的
l10n插件模块保存当前语言与语言列表(src/store/plugins/l10n.ts),localeSetting为auto时在启动期由L10N.install解析为系统默认语言。
9. 扩展与修改建议:新增翻译器、触发机制与多引擎策略
新增翻译器
- 内置翻译器:在
creators工厂表中注册,并在translatorTypes(见 src/common/types.ts)中补充类型即可。实例创建统一注入axios代理与配置(见 src/common/translate/translators.ts)。密钥校验由configuration.ts的规则(rule.check)或通用examToken兜底完成(见 src/main/translate-controller.ts)。 - AI 供应商(自定义翻译器):通过配置
translatorProviders声明供应商(apiBase/apiKey/启用的模型列表),CustomTranslatorManager在加载时按{providerId}-{modelName}展开为多个翻译器实例(当前支持 OpenAI 兼容 API,底层实现为 src/common/translate/openai.ts),并自动写入customTranslators配置;CustomTranslatorManager界面组件见 src/components/CustomTranslatorManager.vue,核心逻辑见 src/common/translate/custom-translators.ts。新增供应商后调用reloadCustomTranslators动作即可热加载。
修改翻译触发机制
- 所有入口动作集中在
TranslateController.handle(src/main/translate-controller.ts):新增触发方式只需在此新增case,并在ActionManager.init中注册对应动作; - 剪贴板监听集中在
setWatch与checkClipboard(src/main/translate-controller.ts、src/main/translate-controller.ts):修改轮询/事件频率、白名单过滤、OCR 联动都在此区域内。
调整多引擎策略
- 引擎组定义与设置入口:配置项在 src/common/types.ts(
translator-enabled、translator-cache、translator-compare、translator-double),UI 注册在 src/common/action.ts 与 src/common/action.ts; - 引擎切换与缓存命中处理在
switchTranslator(src/main/translate-controller.ts); - 后备引擎逻辑在
Compound.translate(src/common/translate/compound.ts):若想改变"主引擎不支持则回退"的行为,改此处过滤与fallbackEngine选择即可。
10. 关键文件索引
- 翻译控制器(触发、语言决策、结果同步、引擎组):src/main/translate-controller.ts
- 翻译器调度与缓存:
Compound/ResultBufferManager:src/common/translate/compound.ts - 翻译器注册与获取:
creators/getTranslator:src/common/translate/translators.ts - 自定义翻译器(AI 供应商展开):src/common/translate/custom-translators.ts
- 文本净化与分句重组:
normalizeAppend/autoReSegment/checkIsWord:src/common/translate/helper.ts - 词典引擎聚合:
Polymer:src/common/dictionary/polymer.ts - 多源对比计算:src/renderer/comparator.ts
- 主要 UI 绑定:src/components/BaseView.vue
- 界面本地化加载:
L10N:src/main/l10n.ts - 语言包生成脚本:src/prebuild.ts
小结
CopyTranslator 的翻译实现是一套"动作-配置-引擎-词典-状态-视图"的全链路体系:动作与配置通过ActionManager+ 观察者机制驱动TranslateController;输入经过长度/重复/单词判定层层校验后进入Compound多引擎调度,配合ResultBufferManager缓存与fallbackTranslator后备策略实现稳定翻译;词典经Polymer并行聚合;所有结果统一写入 Vuex,由 BaseView、ContrastPanel、DiffTextArea、DictResult 与 Focus 五种界面消费;本地化资源则由prebuild生成、L10N运行时加载。开发者只需沿着本文梳理的入口与索引,即可快速定位任一环节的修改点并安全扩展。
【免费下载链接】CopyTranslator🔠Foreign language reading and translation assistant based on copy and translate.项目地址: https://gitcode.com/gh_mirrors/co/CopyTranslator
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考