
LunaTranslator 翻译优化模块详解从翻译前替换到游戏专用词条配置【免费下载链接】LunaTranslator视觉小说翻译器 / Visual Novel Translator项目地址: https://gitcode.com/GitHub_Trending/lu/LunaTranslatorLunaTranslator 的翻译优化Translation Optimization是一组位于文本处理流水线中的后处理/前处理机制用于在翻译前后对原文与译文进行字典替换、占位符保护、结果修正与自定义脚本处理。本文以 翻译优化文档中文版见 docs/zh/transoptimi.md为核心结合src/LunaTranslator/transoptimi/下的实际实现源码系统讲解五种内置优化器的工作原理、配置方法以及游戏专用翻译优化与全局默认优化之间的继承与合并关系帮助你精确控制视觉小说文本的翻译结果。一、翻译优化的整体架构前处理与后处理两个阶段在 LunaTranslator 中每个翻译优化器都实现为一个Process类统一挂在翻译流水线的两个阶段上process_before(s)翻译前在原文送入翻译引擎之前执行可以改写原文例如把专有名词替换成占位符或将原文直接替换为译文process_after(res, context)翻译后在翻译结果返回后执行例如把占位符还原成译文、修正翻译错误或运行自定义 Python 脚本。例如 vndbnamemap.py 只实现了process_beforetranserrorfix.py 只实现了process_after而 noundict.py 两个阶段都参与先用占位符替换原文翻译后再还原。这五个优化器是否启用、使用哪一套词典统一由工具函数postusewhich(name)裁决其完整逻辑位于 utils.py若当前存在游戏会话gameuid且该游戏关闭了跟随默认transoptimi_followdefault为 False若该游戏的{name}_use为 True 且{name}_merge为 True → 返回3游戏词典 全局词典合并若仅{name}_use为 True → 返回2仅用游戏专用词典否则返回0关闭。其余情况回落到全局配置若全局开关transoptimi[name]启用且语言匹配 → 返回1仅用全局词典否则0。也就是说每个优化器都支持全局词典 / 游戏专用词典 / 两者合并三种数据来源这是后文所有配置项共同的底层机制。二、翻译前替换vndbnamemap用译文直接覆盖原文原文档定位翻译优化→翻译前替换原理在翻译之前直接用译文把原文替换掉。匹配支持正则与转义可以实现非常复杂的替换规则。其核心实现是 vndbnamemap.py 中的process_beforedef process_before(self, s): namemap self.usewhich() s parsemayberegexreplace(namemap, s) return s, {}它把当前生效的词典namemap交给通用替换函数parsemayberegexreplace执行替换。该函数定义于 utils.py是翻译前替换与翻译结果修正共用的引擎支持以下逐条匹配参数参数含义默认值key要匹配的原文/翻译文本空字符串空则跳过该条value替换为的内容空字符串regex将key按正则表达式解释Falseescape将key/value中所有特殊字符安全转义Falsewhole-word仅整词匹配自动加\b词边界Falsecase-sensitive区分大小写否则使用re.IGNORECASEFalse注意regex与escape互斥若regex为 Falsekey会被re.escape处理成字面匹配若escape为 True则先对key和value双双转义适合快速录入含大量特殊字符的固定文本。VNDB 人名预设文档特别指出当游戏从 VNDB 加载元数据时程序会查询游戏中的人名信息作为预设词典。对英文用户会把提取到的英文人名填充为原文→翻译对非英文用户则填充翻译与原文相同的内容这样在用户不做修改时不会影响正常翻译对应 abstract.py 中向noundictconfig_ex写入 VNDB 数据的逻辑。配置入口设置窗口标题为翻译前替换条目列为[原文, 翻译]分别存储于全局配置global_namemap2config.json 附近与游戏数据namemap2。同其他优化器一样支持全局/游戏专用/合并三种来源见上文usewhich三态逻辑。三、专有名词翻译noundict保护专有名词不被翻译破坏原文档定位翻译优化→专有名词翻译专有名词人名、地名、物品名是最容易被机器翻译意译坏的内容。LunaTranslator 的专有名词翻译针对两类翻译引擎提供了两种完全不同的处理策略由 noundict.py 实现。3.1 大模型通用接口把词条直接注入 Prompt对于大模型通用接口ChatGPT 类如果其 prompt 模板中包含DictWithPrompt标记则命中的词条不会做占位符替换而是作为词典放入模型 prompt让模型在翻译时遵守指定译名。用法参考 国创大模型文档 中的 prompt 设置一节。解析逻辑位于 gptcommon.py它用正则\{DictWithPrompt(.*?)\[(.*?)\]\}在 prompt 中查找该标记并把词典文本嵌入到标记指定的位置。默认模板形如{DictWithPrompt[When translating, please ensure to translate the specified nouns into the translations I have designated: ]} {sentence}该默认值可见于 translatorsetting.json。词典内容由 sakura_base.py 的make_gpt_dict_text生成逐条输出原文-译文列表。此外 basetranslator.py 中的__parse_gpt_dict会收集上下文里的gpt_dict与gpt_dict_origin原始文本用于构造携带词典的请求。3.2 传统翻译引擎ZX?Z 占位符方案对于其他传统翻译引擎或大模型 prompt 中不含DictWithPrompt时LunaTranslator 采用 VNRVisual Novel Reader的做法在翻译前把原文中的专有名词替换为占位符ZX?Z翻译引擎翻译后的结果一般不会破坏这种占位符它看起来像一个专有缩写词翻译完成后再把占位符替换回译文。从源码看占位符并非固定一个而是按命中顺序递增生成。见 noundict.py 的__createfakexx ZX{}Z.format(chr(ord(B) self.zhanweifu))即依次产生ZXBZ、ZXCZ、ZXDZ……self.zhanweifu自增确保同句多词条互不冲突。process_before中按src匹配原文支持whole-word整词、case-sensitive大小写process_after中通过 case_insensitive_replace不区分大小写的re.sub把占位符还原为译文。注意noundict 词典条目包含[原文, 翻译, 注释]三列info注释列仅作备注且译文不能为空——源码注释明确说明译文置空的条目会被跳过这是为了兼容 VNDB 自动导入的人名表避免空译文破坏现有翻译noundict.py。3.3 游戏专用词条的放置建议文档特别强调游戏的专用词条不要加在文本处理 → 翻译优化的全局词典中而应添加在游戏设置→翻译优化→专有名词翻译的设置里。这样词条只对指定游戏生效不会污染其他游戏的翻译。四、翻译结果修正transerrorfix翻译完成后的二次修正原文档定位翻译优化→翻译结果修正翻译引擎给出的结果往往带有固定的、可预测的错误例如人名被音译、术语不一致、HTML 实体残留等。翻译结果修正允许在翻译完毕之后对结果进行修正且支持使用完整正则表达式进行复杂修正。实现位于 transerrorfix.pydef process_after(self, res, _): res parsemayberegexreplace(self.usewhich(), res) return res它复用了与翻译前替换完全相同的parsemayberegexreplace引擎因此第二节中列出的key/value/regex/escape/whole-word/case-sensitive参数在此同样适用。区别仅在于匹配方向这里key是翻译结果中要查找的文本value是替换目标。词典条目列为[翻译, 替换]全局数据存放在 transerrorfixdictconfig.json 的dict_v2字段默认空列表游戏专用数据存放在savehook_new_data[gameuid][transerrorfix]。同样支持全局/游戏专用/合并三种来源。五、自定义优化myprocess用 Python 脚本实现任意处理原文档定位翻译优化→自定义优化当内置优化器无法满足需求时可以撰写一个 Python 脚本来进行更复杂的处理。myprocess.py 是脚本的加载器通过selectdebugfile选择脚本文件配置项myprocess.py脚本被当作 Python 模块动态加载要求提供Process类加载器对脚本文件做MD5 检测并热重载checkmd5reloadmodule只要文件内容变化就会重新加载模块并实例化新的Process无需重启程序即可迭代调试脚本。脚本的Process类与内置优化器接口一致class Process: def process_before(self, s): # 返回 (新原文, 上下文) 或 (None, ...) 表示跳过 ... def process_after(self, res, context): # 返回修正后的译文 ...从 myprocess.py 可以看到process_after(res, contenxt)会把流水线传入的contenxt原样转交给脚本这意味着脚本可以读取其他优化器产生的上下文例如专有名词占位符映射实现跨优化器协作的复杂逻辑。六、跳过仅包含标点的句子skiponlypunctuations原文档定位翻译优化→跳过仅包含标点的句子这个优化器只做一件事判断当前句子是否全部由标点组成若是则不送入翻译引擎返回None从而省去无意义的翻译请求。其实现非常简短skiponlypunctuations.pydef process_before(self, s): if all(_ in punctuations for _ in s): return None return s标点集合取自myutils.mecab.punctuations基于 MeCab 分词的标点字符表。在游戏文本流中经常出现……之类的纯标点行开启此选项可以避免它们触发无意义的翻译调用。七、游戏专用翻译优化跟随默认与继承默认原文档定位游戏设置→翻译优化针对不同游戏维护独立的翻译优化词典是 LunaTranslator 多游戏场景下的关键设计核心由postusewhich见第一节与各优化器的get_setting_window_gameprivate实现。在游戏设置→翻译优化中取消激活跟随默认该游戏将使用游戏专用的翻译优化设置而不再跟随全局设置。此时若在游戏专有设置中开启某个优化器{name}_use还会出现继承默认{name}_merge选项激活继承默认在游戏专用优化词典之外同时使用默认的全局词典。postusewhich返回3对应的正是这种情况——此时usewhich()返回savehook_new_data[gameuid][...] globalconfig[...]游戏词典在前、全局词典在后例如 vndbnamemap.py 与 noundict.py 中的合并逻辑。需要留意的是游戏专用词典的合并发生在该优化器内部先按游戏词条替换、再按全局词条替换或反之取决于顺序因此后者的匹配可能作用于前者的替换结果。若希望两类词条完全隔离可仅启用{name}_use而不启用{name}_merge。八、小结如何选择与组合优化器优化器阶段适用场景词典结构翻译前替换vndbnamemap翻译前固定文本直接替换、正则改写原文原文 → 翻译专有名词翻译noundict前后人名/术语保护大模型走 prompt传统引擎走占位符原文 → 翻译 → 注释翻译结果修正transerrorfix翻译后修正翻译引擎的固定错误输出翻译 → 替换自定义优化myprocess前后任意 Python 逻辑、跨优化器协作Python 脚本跳过纯标点skiponlypunctuations翻译前过滤无意义文本节省翻译请求无实际使用中推荐的组合方式是将 VNDB 导入或手动整理的游戏专有名词放入游戏设置→翻译优化→专有名词翻译而非全局词典用翻译前替换处理确定性文本用翻译结果修正兜底清理翻译引擎的常见错误最后根据游戏文本特点决定是否开启跳过纯标点。所有优化器的匹配参数regex、escape、whole-word、case-sensitive在全局与游戏专用词典中行为一致可在同一界面中直接配置。【免费下载链接】LunaTranslator视觉小说翻译器 / Visual Novel Translator项目地址: https://gitcode.com/GitHub_Trending/lu/LunaTranslator创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考