1. 项目概述:为什么我们需要XUnity Auto Translator?
如果你是一个喜欢玩各种独立游戏或者小众Unity游戏的玩家,或者你是一个游戏汉化组的成员,那么“游戏内置文本无法翻译”这个问题,你一定深有体会。游戏开发者可能只发布了英文、日文版本,而社区里流传的汉化补丁要么版本老旧,要么安装复杂,甚至可能因为游戏更新而彻底失效。手动修改游戏文件?那更是大海捞针,一个现代游戏动辄成千上万个文本资源文件,根本无从下手。
XUnity Auto Translator(以下简称XUAT)的出现,就是为了解决这个核心痛点。它不是某个特定游戏的汉化补丁,而是一个运行时的、通用的文本拦截与替换框架。简单来说,它就像是在游戏和你的屏幕之间插入了一个“同声传译员”。游戏引擎(Unity)在要把一段文本显示到UI上时,XUAT会先“听到”这段文本,然后立刻去查询你准备好的翻译词典,如果找到了对应的翻译,它就把翻译后的文本“说”给屏幕听,替换掉原来的内容。整个过程对游戏本身是透明的,游戏甚至不知道自己的文本被“调包”了。
这带来了几个革命性的优势:第一是通用性,理论上支持所有基于Unity引擎开发的游戏,无论是Steam上的独立游戏还是一些小型网页游戏。第二是实时性,翻译是即时生效的,无需重启游戏。第三是可持续性,游戏更新后,只要其文本调用逻辑没变,原有的翻译文件大概率依然有效,大大降低了汉化维护成本。第四是社区友好,它催生了一种新的汉化模式:由社区维护统一的、基于文本哈希或键名的翻译文件,玩家只需下载翻译文件和这个“框架”,即可享受汉化,汉化组也无需每次都为游戏更新而重做补丁。
我接触XUAT已经有好几年,从最早的BepInEx插件形式用到现在的独立注入器形式,用它成功汉化过数十款游戏。可以说,对于Unity游戏翻译这个细分领域,XUAT是目前最强大、最灵活的“终极解决方案”,没有之一。本手册将带你从零开始,彻底掌握它的工作原理、部署方法、配置技巧以及高阶用法,让你能轻松应对绝大多数Unity游戏的翻译需求。
2. 核心架构与工作原理深度拆解
要熟练使用一个工具,绝不能停留在“点击安装”的层面。理解XUAT是如何“嵌入”游戏并工作的,能让你在遇到问题时快速定位,甚至进行一些高级定制。
2.1 核心组件与工作流
XUAT不是一个单一的exe文件,而是一个由多个组件协同工作的系统。典型的部署包含以下部分:
注入器 (Injector):这是将XUAT“植入”游戏的关键。常见的注入器有:
- BepInEx:一个强大的Unity游戏Mod框架。XUAT可以作为它的一个插件(Plugin)运行。这是最主流、最稳定的方式,尤其适用于Steam上的游戏。BepInEx本身通过修改游戏程序集(Assembly)的加载逻辑来实现注入。
- UnityInjector/MelonLoader:其他流行的Mod加载器,原理类似,都是通过劫持Unity引擎的初始化过程来加载自定义代码。
- 独立的CLI注入器:一些打包好的版本会自带一个小的命令行注入器,它通过修改游戏进程的内存或DLL加载顺序来实现注入,更适合小白用户一键操作。
XUnity.AutoTranslator 核心插件:这是翻译逻辑的本体。它被注入器加载后,会向Unity引擎的MonoBehaviour生命周期挂载钩子(Hook)。具体来说,它主要监听两类事件:
UI.Text,TextMeshProUGUI.text属性设置:当游戏脚本给任何一个UI文本组件赋值时(如someTextComponent.text = “Hello World”;),XUAT的钩子会先截获这个字符串“Hello World”。Resources.Load等资源加载调用:有些游戏文本可能直接存储在.assets资源文件中,通过Unity的API加载。XUAT也能拦截这些调用,检查加载的资源是否包含文本。
翻译引擎 (Translator):核心插件截获原文后,需要知道把它翻译成什么。XUAT支持多种后端翻译服务,形成一个可插拔的架构:
- 离线词典 (Offline Dictionary):最高优先级。这就是我们常说的“汉化补丁”文件。XUAT会先在本地词典文件中查找原文的对应翻译,找到了就直接使用,速度快且准确。
- 在线翻译API:如果本地词典未命中,且配置允许,则会调用在线服务。它内置支持谷歌翻译、百度翻译、DeepL等(需要自行配置API密钥)。在线翻译的优点是能覆盖未翻译的新文本,缺点是可能有延迟、需要网络,并且有调用频率限制。
- 缓存 (Cache):无论是离线词典还是在线翻译的结果,都会被保存到本地缓存文件(通常是
Translation.txt)。下次游戏再遇到同一句原文时,就直接从缓存读取,无需再次查询,极大提升性能并减少在线API调用。
翻译文件 (Translation Files):这是汉化工作的成果载体。XUAT主要使用一种简单的
key=value格式的文本文件(如Translation.txt)。- 键 (Key):可以是原文本身,也可以是原文经过哈希(如SHA-256)计算后的一串唯一标识符。使用哈希值作为键,可以避免因原文中细微的标点、空格差异导致翻译失效,兼容性更好。
- 值 (Value):就是对应的翻译文本。
整个工作流可以概括为:注入 -> 拦截 -> 查询(先离线,后在线)-> 替换 -> 缓存。这个过程在每帧可能发生成千上万次,但对性能的影响微乎其微,因为核心的查找操作经过高度优化。
2.2 关键技术点:挂钩(Hooking)与反射(Reflection)
XUAT实现文本拦截的核心技术是“挂钩”。在.NET(Unity使用的C#环境)中,这通常通过修改方法在内存中的地址,使其跳转到我们自定义的代码来实现。但更常见和稳定的方式是使用“Harmony”这类库。Harmony可以在运行时对已编译的方法打上“补丁”(Patch),在其执行前、后或完全替换其执行逻辑。XUAT就是利用Harmony,给Unity的Text.set_text属性设置器打上“前置补丁”(Prefix Patch),从而在游戏设置文本之前,先拿到这个文本值。
为了兼容不同版本Unity的UI系统(如旧的uGUI Text和新的TextMeshPro),XUAT需要用到“反射”(Reflection)来动态探测和访问游戏程序集中的类型和方法。例如,它会在游戏启动时检查程序集中是否存在TMPro.TextMeshProUGUI这个类,如果存在,则通过反射获取其text属性并为其打上挂钩。这种动态特性使得XUAT能够适应大量不同游戏,而无需为每个游戏单独编译。
注意:正是由于这种底层注入和挂钩机制,杀毒软件或Windows Defender可能会误报注入器或插件文件为病毒或潜在不受欢迎的程序(PUP)。在使用前,务必将相关工具和游戏目录添加到杀毒软件的白名单中,否则文件可能会被误删,导致注入失败。
3. 完整部署与配置实战指南
理论讲完,我们进入实战环节。我将以最常用的“BepInEx + XUAT插件”组合为例,详细讲解从零部署的全过程。假设我们要翻译的游戏是MyUnityGame.exe。
3.1 环境准备与工具选择
确认游戏信息:
- 找到游戏主程序
MyUnityGame.exe,右键“属性”->“详细信息”,查看文件版本和产品名称。用记事本打开MyUnityGame_Data/Managed/Assembly-CSharp.dll(如果有的话)可以确认游戏使用的.NET框架版本(通常为.NET 3.5/4.x),这关系到BepInEx版本的选择。
- 找到游戏主程序
下载必要工具:
- BepInEx:去GitHub发布页下载。对于大多数Unity游戏,选择BepInEx x64版本(如果游戏是32位则选x86)。下载后是一个压缩包,如
BepInEx_unity_win_x64_5.4.22.0.zip。 - XUnity.AutoTranslator:去官方发布页(如GitHub)下载。你需要两个文件:
XUnity.AutoTranslator-BepInEx-5.4.22.zip(核心插件)和XUnity.AutoTranslator-Japanese-5.4.22.zip(这是一个示例,包含日语翻译和在线翻译插件,我们主要需要其中的在线插件)。注意版本号尽量与BepInEx匹配。
- BepInEx:去GitHub发布页下载。对于大多数Unity游戏,选择BepInEx x64版本(如果游戏是32位则选x86)。下载后是一个压缩包,如
3.2 逐步安装与注入流程
安装BepInEx:
- 解压
BepInEx压缩包,将其中的所有文件和文件夹复制到游戏根目录(即MyUnityGame.exe所在目录)。 - 首次运行游戏。双击
MyUnityGame.exe启动游戏,等待游戏完全启动到主菜单后再关闭。这个过程会让BepInEx完成初始安装,在游戏根目录下生成完整的BepInEx文件夹结构(包括plugins,config,core等子目录)。
- 解压
安装XUAT插件:
- 解压
XUnity.AutoTranslator-BepInEx-5.4.22.zip,将其中的BepInEx文件夹合并到游戏根目录的BepInEx文件夹中。通常是plugins和config目录下的内容会被合并进去。 - 解压
XUnity.AutoTranslator-Japanese-5.4.22.zip,我们主要需要其中的BepInEx/plugins/AutoTranslator/Translation文件夹(可以删除里面的日语翻译文件)和BepInEx/plugins/AutoTranslator/Plugins文件夹(里面包含了在线翻译所需的插件,如GoogleTranslate,BaiduTranslate等)。同样合并到游戏目录。
- 解压
关键目录结构确认: 安装完成后,你的游戏
BepInEx目录下应该有以下关键结构:BepInEx/ ├── plugins/ │ └── XUnity.AutoTranslator/ │ ├── AutoTranslator.dll (核心插件) │ ├── Plugins/ (在线翻译插件目录) │ │ ├── GoogleTranslate.dll │ │ ├── BaiduTranslate.dll │ │ └── ... │ └── Translation/ (翻译文件目录) │ ├── en/ (示例英文翻译目录) │ ├── zh/ (中文翻译目录 - 需自建) │ ├── Translation.txt (主缓存文件) │ └── Substitutions.txt (文本替换规则文件) ├── config/ (配置文件目录) │ └── AutoTranslatorConfig.ini (XUAT主配置文件) └── core/ (BepInEx核心)
3.3 核心配置文件详解
BepInEx/config/AutoTranslatorConfig.ini是XUAT的大脑,所有行为都由它控制。用记事本或VS Code打开它,我们来调整关键参数。
[General] ; 目标语言,设为中文 Language=zh ; 是否启用在线翻译(当你没有离线翻译时,可以临时开启) EnableTranslation= true ; 是否将在线翻译结果自动保存到离线词典 AppendTranslationsToFile=true ; 离线词典文件名 TranslationFileName=Translation.txt [Behaviour] ; 是否在游戏启动时预加载所有翻译到内存,建议开启以提升性能 PreloadTranslations=true ; 是否翻译资源文件(如.assets中的文本),建议开启 TranslateResources=true ; 是否翻译Unity场景中的GameObject名称,按需开启 TranslateGameObjectNames=false [TextFrameworks] ; 启用对旧版uGUI Text的支持 EnableText=true ; 启用对TextMeshPro的支持(现代游戏必备) EnableTextMeshPro=true [Online] ; 选择在线翻译引擎,可选:GoogleTranslate, BaiduTranslate, DeepL等 EnabledTranslator=GoogleTranslate ; 在线翻译失败后的重试次数 MaxTranslationsPerSecond=3 [GoogleTranslate] ; 谷歌翻译需要配置,但通常有默认端点,国内可能需要特殊配置 ; 百度翻译需要申请API Key和Secret Key ;[BaiduTranslate] ;AppId=你的AppId ;Secret=你的Secret关键配置解析:
Language=zh:这是最重要的设置,告诉插件你的目标语言是中文。插件会根据这个值去寻找Translation/zh/目录下的翻译文件。AppendTranslationsToFile=true:强烈建议开启。当在线翻译成功时,会自动将原文=译文追加到Translation.txt中。这是积累和创建离线汉化补丁的“自动化流水线”。PreloadTranslations=true:开启后,游戏启动时会一次性将所有Translation.txt内容加载到内存字典中。对于翻译条目数上万的大型游戏,这能避免游戏运行时频繁读盘造成的卡顿。EnabledTranslator:如果你需要使用在线翻译,请确保对应的插件DLL文件存在于Plugins文件夹,并在此正确填写名称。使用百度/谷歌翻译需要自行申请API密钥并配置。
3.4 翻译文件的创建与管理
离线翻译是汉化质量的保证。我们需要在BepInEx/plugins/XUnity.AutoTranslator/Translation/下创建zh文件夹(如果不存在),然后创建或编辑翻译文件。
主翻译文件 (
Translation.txt): 这个文件可以放在Translation/根目录下(对所有语言生效),也可以放在Translation/zh/下(仅对中文生效)。推荐后者,便于管理。文件格式非常简单:Hello=你好 Start Game=开始游戏 Options=选项 Player Health: %d=玩家生命值:%d格式要点:
- 每行一条,格式为
原文=译文。 - 原文和译文中的等号
=需要用反斜杠转义,如Key\=Value=键\=值。 - 支持C风格的格式说明符(如
%s,%d),译文必须保留相同的占位符,且顺序一致。 - 原文可以是哈希值。当
Translation.txt中某行的键是一串长长的十六进制数(如a1b2c3...)时,说明这是原文的哈希。你不需要自己计算,XUAT在自动追加在线翻译结果时就会使用哈希键,这能提高兼容性。
- 每行一条,格式为
文本替换文件 (
Substitutions.txt): 这个文件用于进行简单的正则表达式替换,通常在翻译之前进行,用于修正一些常见的原文问题。例如,游戏原文可能有奇怪的换行符\n影响翻译,或者你想先统一某些术语。pattern=replacement示例:将所有
HP替换为生命值\bHP\b=生命值如何高效制作翻译文件:
- “偷懒”法:配置好在线翻译后,进入游戏,把所有UI界面点一遍,把所有对话剧情过一遍。XUAT会自动将所有拦截到的、未翻译的文本通过在线API翻译并追加到
Translation.txt中。然后你关闭在线翻译,基于这个自动生成的、但可能生硬的Translation.txt进行人工校对和润色。这是最快捷的起步方式。 - 专业法:使用专门的游戏文本提取工具(如
UnityEX,AssetStudio)直接解包游戏的资源文件,提取出所有字符串,在外部用CAT(计算机辅助翻译)工具(如Poedit, OmegaT)进行翻译和校对,最后整理成Translation.txt格式。这种方法质量最高,适合汉化组协作。
- “偷懒”法:配置好在线翻译后,进入游戏,把所有UI界面点一遍,把所有对话剧情过一遍。XUAT会自动将所有拦截到的、未翻译的文本通过在线API翻译并追加到
4. 高级技巧与疑难问题排查
掌握了基础部署,你已经能解决80%的问题。下面这些高级技巧和排错经验,能帮你攻克剩下的20%难题。
4.1 应对特殊游戏与兼容性调整
不是所有Unity游戏都“乖乖就范”。以下是一些常见特殊情况及处理方案:
游戏使用了IL2CPP后端: IL2CPP是Unity的一种编译技术,它将C#代码转换成C++,再编译为本地机器码,这使得传统的基于Mono的注入和挂钩方式失效。对于IL2CPP游戏,BepInEx有一个专门的版本BepInEx Il2Cpp。XUAT也有对应的Il2Cpp版本插件。你需要:
- 确认游戏是否为IL2CPP(看游戏目录是否有
GameName_Data/il2cpp_data文件夹)。 - 下载BepInEx Il2Cpp版本和XUAT for Il2Cpp版本的插件。
- 安装流程类似,但配置可能更复杂,可能需要手动配置函数签名来挂钩。
- 确认游戏是否为IL2CPP(看游戏目录是否有
游戏文本在纹理图片中: XUAT只能拦截文本,如果游戏的所有文字都是图片格式(例如一些复古风格的RPG),那么它无能为力。这种情况需要传统的“图改”汉化,使用PS等工具修改游戏贴图文件。
翻译不生效或部分生效:
- 检查日志:BepInEx会在
BepInEx/LogOutput.log中生成运行日志。打开日志文件,搜索“AutoTranslator”或“XUnity”,查看是否有加载成功、挂钩成功的信息,以及翻译查询的记录。这是最强大的排错工具。 - 检查文本组件类型:有些游戏使用自定义的文本渲染组件,而非标准的
Text或TextMeshProUGUI。你需要检查游戏使用的具体组件类型。可以尝试在配置文件中启用EnableNGUI(如果游戏使用NGUI)或EnableuGUI(这是默认)。更复杂的情况可能需要手动编写补丁插件。 - 检查文本更新方式:极少数游戏可能通过直接设置
顶点或材质的方式来“画”出文字,这种动态生成的方式无法被拦截。
- 检查日志:BepInEx会在
4.2 性能优化与翻译质量提升
合并与清理Translation.txt: 随着在线翻译的不断追加,
Translation.txt文件会变得巨大且包含大量重复或未使用的条目。你可以使用社区工具(如“XUAT Translation Manager”)来加载这个文件,它会自动:- 合并重复的键(相同的原文或哈希)。
- 找出那些译文和原文完全相同的无用条目(可能是翻译API返回了原文)。
- 按字母顺序排序,方便查找和编辑。 定期清理能显著减少文件加载时间和内存占用。
分模块翻译文件: 对于文本量巨大的游戏,可以将翻译按功能模块拆分。在
Translation/zh/目录下,你可以创建多个.txt文件,如UI.txt,Items.txt,Dialogue_Chapter1.txt。XUAT会自动加载该目录下所有的.txt文件。这样便于多人协作和版本管理。处理动态文本与变量: 游戏文本常常包含变量,如
“你击杀了 %d 个敌人”。在翻译时,必须保留这些格式符的位置和顺序,但可以调整其在句子中的位置以适应中文语序。例如,英文是%d enemies killed,中文可以翻译为击杀了%d个敌人。切记不要丢失或改变格式符的类型(如把%d写成%s)。文化适配: 高质量的翻译不仅仅是字面转换。例如,游戏中的笑话、双关语、文化梗,需要找到中文中对应的表达,或者进行意译。在
Substitutions.txt中,你可以提前将一些文化专有名词替换为本地化版本。
4.3 常见问题速查表
下表汇总了使用XUAT过程中最常见的问题、可能原因及解决方案:
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 游戏无法启动,闪退 | 1. BepInEx版本与游戏不兼容 2. XUAT插件版本与BepInEx不匹配 3. 杀毒软件拦截 | 1. 尝试更换BepInEx版本(如稳定版/测试版) 2. 确保XUAT插件是为当前BepInEx版本编译的 3. 关闭杀毒软件或添加白名单,查看 LogOutput.log中的错误信息 |
| 游戏能启动,但无任何翻译效果 | 1. 配置文件Language未设置或错误2. 翻译文件路径或名称错误 3. 文本挂钩失败 | 1. 检查AutoTranslatorConfig.ini中Language=zh2. 确认翻译文件在 Translation/zh/目录下,且名为Translation.txt3. 查看日志,确认 EnableText和EnableTextMeshPro是否针对游戏正确启用 |
| 部分UI翻译了,部分没翻译 | 1. 游戏使用了多种文本组件 2. 未翻译的文本是图片 3. 动态生成的文本未被拦截 | 1. 检查日志看未翻译文本的组件类型,尝试在配置中启用其他框架支持(风险高) 2. 确认是否为图片文字 3. 可能是脚本动态拼接的字符串,尝试使用在线翻译覆盖,或手动在词典中添加完整句子 |
| 翻译文本出现乱码或问号 | 1. 游戏字体不支持中文 2. 翻译文件编码错误 | 1. 需要替换游戏字体或添加中文字体。这是一个高级话题,涉及修改游戏资源 2. 确保 Translation.txt以UTF-8 without BOM编码保存(推荐使用Notepad++或VS Code编辑并设置编码) |
| 在线翻译不起作用 | 1. API未配置或配置错误 2. 网络问题 3. 插件文件缺失 | 1. 检查配置文件中对应翻译引擎(如[BaiduTranslate])的AppId和Secret是否正确2. 确认网络通畅,某些API可能需要特殊网络环境 3. 确认 Plugins文件夹下有对应的GoogleTranslate.dll等文件 |
| 游戏运行时卡顿明显 | 1.PreloadTranslations未开启2. Translation.txt文件过大3. 在线翻译频率过高 | 1. 在配置中设置PreloadTranslations=true2. 使用工具清理合并 Translation.txt3. 调整 MaxTranslationsPerSecond降低频率,或关闭在线翻译,使用纯离线模式 |
5. 从使用者到贡献者:参与社区汉化
XUAT的魅力在于它建立了一个可持续的社区汉化生态。你不再是一个被动的补丁使用者,而是可以轻松成为贡献者。
分享你的翻译文件:当你为一款游戏精心校对好
Translation.txt后,可以将其分享到游戏的社区论坛、贴吧或专门的模组网站(如ModDB, Nexus Mods)。在分享时,请清晰说明:- 对应的游戏名称及精确版本号。
- 使用的XUAT和BepInEx版本。
- 安装方法。
- 已知问题(哪些地方没翻译,为什么)。
协作翻译平台:一些大型游戏的汉化社区会使用GitHub、GitLab或自建平台来管理翻译文件。你可以通过提交
Pull Request来修正错别字、优化翻译语句或补充新增内容的翻译。版本控制系统能清晰地记录每个人的贡献。反馈与求助:如果你遇到无法解决的问题,可以到XUAT的官方GitHub仓库的
Issues板块搜索或提问。提问时,务必附上你的AutoTranslatorConfig.ini关键部分、LogOutput.log中的相关错误片段,以及游戏名称版本。清晰的问题描述能极大提高获得帮助的效率。
我个人最深的一个体会是:XUAT将游戏汉化从一个“黑盒”的、每次更新都要推倒重来的体力活,变成了一个“白盒”的、可积累、可协作的数据工程。最大的挑战往往不是工具本身,而是如何高效地获取、整理和校对那海量的游戏文本。一旦建立了稳定的工作流(比如:在线翻译初翻 -> 导出整理 -> CAT工具校对 -> 回填测试),你会发现为Unity游戏提供高质量的本地化支持,并没有想象中那么困难。最后一个小技巧:在测试翻译时,善用游戏的“存档/读档”功能,可以快速刷新UI文本,而无需反复重启游戏,这能节省大量的测试时间。