- AI 应用
- 计算机视觉
- 图像处理
- NLP
- 桌面应用
【免费下载链接】BallonsTranslator
深度学习辅助漫画翻译工具, 支持一键机翻和简单的图像/文本编辑 | Yet another computer-aided comic/manga translation tool powered by deeplearning
本篇技术指南围绕 BallonsTranslator 官方文档 doc/加别的翻译器.md 展开,完整讲解如何通过实现BaseTranslator子类为这个深度学习辅助漫画翻译工具添加自定义翻译器。读完本文,你将掌握本地扩展与内置翻译器的文件放置规则、惰性模块发现机制、_translate契约、语言映射与参数定义方式,以及一套可直接运行的验证方法,并能结合仓库源码理解翻译管线的底层调用链。
概述:翻译器在 BallonsTranslator 中的角色
BallonsTranslator 的翻译环节由ballontranslator/modules/translators/目录下的多个模块提供,每个模块以trans_<name>.py命名,通过register_translator装饰器注册到全局TRANSLATORS注册表(定义见 translators/base.py)。仓库内已内置 Google、DeepL、Sakura、m2m100、Sugoi、EZTrans 等翻译器实现,新增翻译器时只需要遵循同一套扩展约定,即可被设置界面自动发现、被翻译管线自动调用,无需修改主程序其他代码。
文件放置与模块发现机制
添加翻译器文件后,需要重启应用才能生效。文件可以放在两个位置:
- 本地扩展:
custom_modules/trans_<name>.py(放在程序运行目录下,属于用户自建扩展,不会随仓库更新被覆盖); - 内置模块:
ballontranslator/modules/translators/trans_<name>.py(作为仓库的一部分提交)。
模块命名遵循MODULE_SCRIPTS中定义的trans_(.*?).py正则模式(见 modules/base.py),也就是说文件名中间段name会成为模块的候选标识。同理,OCR、文本检测、图像修复模块分别使用ocr_、detector_、inpaint_前缀。
一个关键设计是:模块发现只读取静态元数据,不导入具体实现。启动时由 lazy_registry.py 通过ast语法树扫描(_scan_file、_collect_class_attrs、_collect_translator_langs)来解析装饰器注册键、params、语言列表等元信息,具体翻译器类的导入被推迟到真正被选中使用时。因此:
- 不要在
__init__.py中增加提前导入。例如 translators/init.py 只有一句from .base import *,一旦加入from .trans_xxx import Xxx就会破坏"启动不加载模块实现"的惰性设计,拖慢启动速度,甚至在没有安装该模块依赖时导致整个应用无法启动。 - 自定义模块若语法扫描失败,只会产生日志警告(见 lazy_registry.py),不会影响其他模块。
最小示例:一个可运行的翻译器骨架
英文主指南 how_to_add_new_translator.md 中给出了完整的最小模块示例。将以下代码保存为custom_modules/trans_example.py:
from typing import List from ballontranslator.modules.translators.base import BaseTranslator, register_translator @register_translator("example_copy") class ExampleTranslator(BaseTranslator): concate_text = False params = {"description": "Copy source text without a translation service."} def _setup_translator(self) -> None: self.lang_map["日本語"] = "ja" self.lang_map["English"] = "en" def _translate(self, src_list: List[str]) -> List[str]: return list(src_list)这个模块不做任何翻译,直接把原文复制为结果,因此无需 API、无需模型、无需任何网络请求,非常适合用来验证三件事:注册是否成功、语言选择是否生效、结果映射是否正确。真正可运行的完整代码以英文主指南为准维护,中文文档与英文主指南保持同步引用。
最小示例已经体现了所有核心约定:
@register_translator("example_copy")把类注册到注册表,注册键example_copy会被写入配置文件持久化,因此必须选择唯一且稳定的名称——改名字会导致旧配置失效;- 类级
concate_text = False告诉基类"本实现是列表感知的,不要帮我合并文本"(详见下文合并模式); params中的description会在设置界面显示为模块说明;_setup_translator()中通过self.lang_map[...] = ...建立界面语言名到服务语言代码的映射。
扩展约定(Extension Contracts)
继承与注册
- 翻译器必须继承
BaseTranslator(定义于 translators/base.py),并用register_translator注册一个唯一且稳定的名称; - 语言名称必须使用 translators/base.py 中
LANGMAP_GLOBAL的键(即界面显示的中英文语言名,如简体中文、日本語、English、한국어等),lang_map的值填写服务实际使用的语言代码(如ja、en、zh-CN); - 运行时可以通过
self.lang_map[self.lang_source]和self.lang_map[self.lang_target]读取当前源语言/目标语言对应的服务代码,这两个属性由基类构造函数根据初始化参数lang_source、lang_target设置(见 translators/base.py)。
_translate契约与concate_text
子类只需要实现_translate:它接收一个字符串列表src_list,必须返回数量相同、顺序一致的字符串列表。这是整个翻译管线对结果对齐的硬性要求——如果数量不一致,基类的translate()会直接抛出断言异常并记录错误日志(见 translators/base.py)。
关于文本合并模式(concate_text):
- 列表感知的 API 和本地模型一律使用
concate_text = False,例如 Google 翻译器逐条请求即可(见 trans_google.py)、Sakura 按换行拼接但内部自行处理对齐(见 trans_sakura.py)、m2m100 本地模型批量推理(见 trans_m2m100.py); - 只有当服务能保留分隔符时才使用合并模式(基类默认
concate_text = True)。合并模式把整页文本用textblk_break(默认'\n##\n',见 translators/base.py)连接成一个字符串发送给服务,再按同样的分隔符切回列表(textlist2text/text2textlist,见 translators/base.py)。选用##而非普通换行,是为了避免某些服务自动剥离\n导致行数错位。
公共translate()方法
子类不应直接覆写公共管线方法,而应优先覆写_translate。基类公共方法translate()(见 translators/base.py)统一负责:
- 处理单个字符串输入与空输入(
text_is_empty检查,空文本直接原样返回,不触发模型加载); - 按需加载模型(
all_model_loaded()检查 +load_model()触发); - 判断是否启用合并模式(合并模式仅在"输入为列表 +
concate_text=True+ 全局配置翻译上下文为整页"三者同时成立时启用); - 调用
_translate并保证返回数量与输入一致。
另外,基类的translate()接受project、page_key、commit_history_window等可选关键字以透传页面上下文,第三方翻译器如果覆写此公共方法,应同样接受这些关键字(见 translators/base.py)。
参数定义与读取
配置字段放在类级params字典中,支持两种形态:
- 普通字符串直接写值,例如
'api baseurl': 'http://127.0.0.1:8080/v1'(Sakura 示例); - 选择器使用
{"type": "selector", "options": [...], "value": ...}结构,例如 Sakura 的版本选择器'version': {'type': 'selector', 'options': ['0.9', '1.0', 'galtransl-v1'], 'value': '0.9'}(见 trans_sakura.py),以及 m2m100 的设备选择器'device': DEVICE_SELECTOR()(见 trans_m2m100.py)。
运行时通过get_param_value(param_key)读取参数值(见 modules/base.py)。只有当参数变化确实需要更新运行时状态时,才覆写updateParam(),且必须先调用基类实现再执行额外逻辑。典型例子是 m2m100 在设备参数变化时重建 CTranslate2 运行时对象(见 trans_m2m100.py),以及 Sakura 在字典路径或版本变化时重载字典(见 trans_sakura.py)。
惰性注册约束:元数据必须静态可读
这是本仓库最重要的架构约束之一。设置界面在列出模块时不能依赖构造、初始化、下载、模型加载或网络调用,因此:
params和语言赋值必须是字面量,或仅使用SafeEval支持的纯函数(如list(...)、dict.keys()、DEVICE_SELECTOR()、copy.deepcopy、platform.system()等,完整白名单见 lazy_registry.py);- 惰性扫描器
_collect_translator_langs会解析_setup_translator中的self.lang_map[...] = ...赋值和self.lang_map.update({...})调用,从中推导支持的语言列表(见 lazy_registry.py); - 无法静态求值的元数据会生成
metadata_warnings,并在validate_lazy_module_specs中提示(见 lazy_registry.py)。
非对称语言支持(源语言集合与目标语言集合不同)可以覆写返回固定字面量列表的supported_src_list/supported_tgt_list属性。基类默认两者都等于valid_lang_list(见 translators/base.py),而 m2m100 就是一个典型:它通过属性返回一百多种语言的字面量列表(见 trans_m2m100.py),并在构造函数里用check_language_support装饰器校验所选语言是否在支持列表内,不合法时抛出InvalidSourceOrTargetLanguage(见 translators/base.py)。
重型模型的加载生命周期
如果翻译器依赖重型模型(如本地推理模型),应该把模型状态放入BaseModule提供的生命周期中:
- 用
_load_model_keys声明模型属性名,例如 m2m100 的_load_model_keys = {'translator', 'tokenizer'}(见 trans_m2m100.py); - 在
_load_model()中真正加载模型,load_model()会先获取全局模型加载锁再调用它,unload_model()负责释放,all_model_loaded()用于判断模型是否已在内存(见 modules/base.py)。
这套机制保证模型加载可以放在工作线程中执行,且兼容无界面(headless)模式——翻译管线只依赖模块 API,不依赖 Qt 界面。
依赖与文件下载
- 可选第三方依赖放在类级
dependencies列表中,例如 DeepLX 的['httpx[socks,brotli]'](见 trans_deeplx_api.py)、Sakura 的['openai>=2.8.1'](见 trans_sakura.py)、m2m100 的['ctranslate2', 'sentencepiece', 'transformers==4.57.6']; - 需要下载的模型文件通过
download_file_list声明(URL、文件名、SHA256、保存目录),例如 m2m100 模型文件清单(见 trans_m2m100.py)。
共享 LLM 上下文的归属
如果集成需要共享 LLM 上下文(记忆、术语表、历史窗口),遵循 LLM 翻译器指南 中定义的归属边界,不要自行在翻译器内部重复实现一套上下文管理。
深入源码:翻译结果的后处理管线
理解BaseTranslator不止于_translate,基类还负责文本块的预处理与结果后处理。translate_textblk_lst()(见 translators/base.py)是整页翻译的入口,流程如下:
_prepare_textblock_sources()收集非空文本块,并对原文应用pcfg.pre_mt_sublist关键词替换(preprocess_translation_text→substitute_keywords,见 translators/base.py);- 调用
translate()批量翻译; - 对每个结果执行
postprocess_translation_text():按顺序应用标准化、关键词替换、大小写处理(letter_case),目标语言为繁体中文且模块声明cht_require_convert = True时还会用 OpenCC 做简转繁(见 translators/base.py)。
也就是说,子类只需保证_translate的输入输出契约,繁简转换、关键词替换、大小写等通用逻辑由基类统一处理,无需在子类中重复实现。这也解释了为什么 Sakura 声明cht_require_convert = True后,只需在lang_map中给出简体中文映射即可获得繁体中文支持。
参考真实实现:三类典型翻译器
1. 在线 API 型:Google(trans_google.py)
类TransGoogle注册键为google,concate_text = False,在_setup_translator中建立了从界面语言名到 Google 服务代码(如zh-CN、ja、en)的完整映射(见 trans_google.py),_translate逐条调用内部 provider 并把异常收敛为同长度的空字符串列表(见 trans_google.py)。
2. 自建端点型:DeepLX API(trans_deeplx_api.py)
注册键DeepLX API,通过用户提供的api_url参数(params中带display_name)请求自建的 DeepLX 翻译服务,_translate对每条文本 POST 请求并解析data字段,失败时返回空串(见 trans_deeplx_api.py)。它展示了"参数驱动端点 + 失败返回空串"的常见写法。
3. 本地模型型:m2m100(trans_m2m100.py)
注册键m2m100,使用 CTranslate2 加载 1.2B 多语种模型,concate_text = False,_translate中批量编码、批量推理、批量解码(见 trans_m2m100.py)。它同时展示了设备参数、模型下载清单、_load_model_keys生命周期和非对称supported_*_list的完整用法。
4. 本地 LLM 型:Sakura(trans_sakura.py)
注册键Sakura,通过 OpenAI 兼容接口调用本地 Sakura 翻译模型,params中同时包含复选框、选择器、文本输入等多种控件类型,并在_translate中实现了术语表注入、重复文本检测、行数对齐检查与自动重试等质量保障逻辑(见 trans_sakura.py),是参数复杂度和运行期状态管理方面的最佳参考。
验证方法
英文主指南 how_to_add_new_translator.md#verification 提供了两条可以直接复制的验证命令,在仓库根目录、使用应用的 Python 环境执行:
# 1) 语法编译检查 python -m py_compile custom_modules/trans_example.py # 2) 注册检查 + 语言选择 + 字符串/列表输入 + 结果映射 python -c 'from ballontranslator.modules import TRANSLATORS; t = TRANSLATORS.get("example_copy")("日本語", "English"); assert t.translate(["one", "two"]) == ["one", "two"]; assert t.translate("one") == "one"'第二条命令做了四件事:从TRANSLATORS注册表取出模块类、以源语言日本語/ 目标语言English实例化、验证列表输入["one", "two"]得到等长同序输出、验证单字符串输入"one"得到"one"。
真实翻译器还需要额外验证:
- 初始化前的元数据:语言列表与
params在未实例化时即可由惰性注册器静态读取(确认设置界面不会因此触发构造/下载/网络调用); - 输入形态:字符串、列表、空输入(空输入应被基类短路返回,不触发模型加载);
- 输出对齐:结果数量与输入一致、顺序一致;
- 失败路径:服务错误、网络异常、模型加载失败时的行为(参考内置实现普遍采用"失败返回同长度空串或原文"的降级策略);
- 自动化测试应模拟网络服务,不要真实请求外部 API;同时遵守 AGENTS.md 的验证规范(见 AGENTS.md#verification)与数据安全规则(见 AGENTS.md#changes-and-data-safety)。
常见问题与注意事项
- 改注册键会导致配置失效:注册键会持久化到配置文件,改名后旧配置指向的模块将无法解析,因此务必从一开始就确定稳定的键名;
lang_map键必须来自LANGMAP_GLOBAL:界面语言下拉框的数据源基于LANGMAP_GLOBAL,使用其键才能保证语言选择器正常工作;自定义键不会被惰性扫描器识别,也无法在界面上出现;- 不要在
_setup_translator里做无法静态解析的赋值:例如self.lang_map[lang] = some_dynamic_value,这类写法会产生惰性元数据警告,导致设置界面无法预先显示支持语言; - 不要覆写公共管线方法:
translate()、translate_textblk_lst()已封装空输入、模型加载、合并拆分、后处理等通用逻辑,覆写它们容易破坏契约;确需覆写时(如需要上下文关键字),应保持相同的方法签名与行为边界; - 避免在导入期执行重活:模块文件顶层只做导入与类定义,任何需要构造、下载、联网的逻辑都应放到
_setup_translator/_load_model/_translate中,否则会拖慢应用启动并被惰性扫描器拒绝; - 确认"打开设置不会加载模型或访问服务":这是仓库对设置界面的硬性要求(见 AGENTS.md),新增翻译器时应验证:仅打开设置面板、切换翻译器、查看参数,都不会触发模型加载或网络请求。
小结
添加翻译器的完整流程可以概括为四步:选位置建文件(custom_modules/trans_<name>.py)→写最小骨架(继承BaseTranslator+register_translator+_setup_translator+_translate)→按需扩展(params参数、concate_text合并模式、_load_model_keys模型生命周期、supported_*_list非对称语言)→验证(语法编译 + 注册表断言 + 元数据与失败路径检查)。坚持"惰性元数据、静态可读"这一核心约束,你的翻译器就能与内置模块一样,被 BallonsTranslator 的设置界面、翻译管线和配置文件无缝集成。相关英文主指南与更多实现细节可继续阅读 how_to_add_new_translator.md、LLM 翻译器指南 以及 translators 目录 下的内置实现源码。
- AI 应用
- 计算机视觉
- 图像处理
- NLP
- 桌面应用
【免费下载链接】BallonsTranslator
深度学习辅助漫画翻译工具, 支持一键机翻和简单的图像/文本编辑 | Yet another computer-aided comic/manga translation tool powered by deeplearning
相关推荐
BallonsTranslator开发者指南:如何添加新的翻译器模块
BallonsTranslator开发者指南:如何添加新的翻译器模块 BallonsTranslator是一个强大的深度学习辅助漫画翻译工具,支持一键机翻和简单
AI 应用计算机视觉图像处理NLP桌面应用Windows终极优化方案:Atlas-OS让你的电脑性能飙升30%
Windows终极优化方案:Atlas OS让你的电脑性能飙升30% 你是否厌倦了Windows系统的卡顿、隐私泄露和臃肿体验?Atlas OS作为一款开源透明
操作系统隐私合规BallonsTranslator翻译器全解析:从Google到Sakura-13B的AI翻译革命
BallonsTranslator翻译器全解析:从Google到Sakura 13B的AI翻译革命 BallonsTranslator是一款革命性的深度学习辅助
AI 应用计算机视觉图像处理NLP桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考