1. 项目概述:为什么我们需要XUnity.AutoTranslator?
如果你是一名热爱日系或独立游戏的玩家,或者是一名需要处理多语言文本的Unity开发者,那么“语言不通”这个问题一定让你头疼过。面对一款没有官方中文、文本量巨大的游戏,传统的汉化补丁往往需要社区投入大量人力进行文本提取、翻译、校对和重新打包,周期长且版本更新后极易失效。而XUnity.AutoTranslator的出现,彻底改变了这一局面。它不是一个简单的文本替换工具,而是一个运行在游戏进程内的、高度可配置的实时翻译框架,能够自动拦截游戏内文本,调用你指定的AI翻译服务(如Google、DeepL、百度等),并将翻译结果实时呈现在游戏UI上,实现“所见即所得”的本地化体验。
这个插件的核心价值在于其“自动化”和“可扩展性”。它像一位不知疲倦的、精通多国语言的同声传译,静静地坐在你的游戏进程里,每当游戏引擎(Unity)试图在屏幕上绘制一段文本时,它就会立刻介入,查询本地翻译缓存或调用在线API,然后将翻译好的文本替换上去。整个过程对玩家而言几乎是瞬间完成的,无需等待完整的汉化包发布。对于开发者或Mod作者来说,它提供了一套完整的API和资源重定向机制,让你不仅能翻译文本,还能替换游戏内的图片、字体等资源,甚至可以为自己的Mod编写专用的翻译逻辑。
2. 核心原理与架构拆解:它如何实现“无侵入”翻译?
要理解XUnity.AutoTranslator的强大,首先得明白它是如何在“不修改游戏原始文件”的前提下工作的。这主要依赖于两大核心技术:运行时方法钩子(Hooking)和资源重定向(Resource Redirection)。
2.1 运行时方法钩子(Hooking):文本拦截的基石
Unity游戏中的所有文本,无论是UGUI的Text组件、TextMeshPro的TMP_Text组件,还是传统的GUILayout.Label,最终都会调用某个底层的set_text或类似的方法来设置字符串内容。XUnity.AutoTranslator的核心任务就是“监听”这些方法调用。
插件主要使用两种钩子技术:
- Harmony:这是一个流行的.NET库,用于在运行时修改、替换或包装方法。它通过创建方法的“前缀”(Prefix)和“后缀”(Postfix)来注入自定义逻辑。对于大多数有方法体的函数,Harmony都能完美工作。
- MonoMod.RuntimeDetour:当Harmony遇到“空方法体”(如抽象方法或某些IL2CPP优化后的方法)或运行在
.NET Standard 2.0API表面下的Unity版本时,可能会失效。MonoMod作为备选方案,提供了更底层的钩子能力,确保了更广泛的兼容性。
插件会智能选择使用哪种技术。当游戏启动时,它会尝试用Harmony钩住所有识别出的文本设置方法。如果失败(例如在IL2CPP环境下),它会自动回退到MonoMod。一旦钩子成功挂载,每当游戏试图设置一段文本(比如textComponent.text = “こんにちは”),我们的插件代码就会先一步被执行。
注意:IL2CPP是Unity的一种编译技术,它将C#代码转换为C++,再进行编译,极大地提升了性能和安全性,但也使得传统的反射和钩子操作变得困难。XUnity.AutoTranslator对IL2CPP的支持是“部分”的,某些高级功能(如
TextGetterCompatibilityMode)可能无法使用,有时需要配合AutoTranslator.IL2CPP.BruteForceFix这样的辅助插件来强制刷新文本组件。
2.2 资源重定向(Resource Redirection):超越文本的本地化
文本钩子解决了动态文本的翻译,但游戏里还有很多“静态”资源,比如直接嵌入在AssetBundle或Resources文件夹里的文本文件(.txt,.json,.xml)、字体文件,甚至是UI贴图。修改这些资源通常需要解包、修改、再重新打包,过程繁琐且易出错。
XUnity.AutoTranslator内置的XUnity.ResourceRedirector模块解决了这个问题。它允许你在资源被游戏加载的“瞬间”进行拦截和替换。其工作流程如下:
- 注册钩子:插件向Unity的资源加载API(
Resources.Load,AssetBundle.LoadAsset等)注册前缀和后缀回调。 - 拦截请求:当游戏请求加载一个资源时(例如一个名为
Dialogues.ja.txt的文本资源),Resource Redirector会先收到通知。 - 路径重定向:插件会检查配置的
PreferredStoragePath(例如Translation\zh-CN\RedirectedResources)目录下,是否存在同名或对应哈希值的文件。 - 提供替代资源:如果找到了,插件会加载这个替代文件并返回给游戏;如果没找到,则放行,让游戏加载原始资源。
这意味着,你可以将翻译好的文本文件、替换的中文字体、甚至本地化后的图片,直接放在指定的文件夹里,游戏运行时就会自动使用它们,完全不需要动原始的.assets文件。这对于替换游戏内的Logo、带有文字的按钮图标等尤为有用。
2.3 翻译流程与缓存机制
一次完整的翻译请求,其内部流程是高度优化的:
- 文本捕获:钩子捕获到游戏设置的原始文本(如“新しいゲーム”)。
- 预处理:根据配置(
PreprocessorsFile),对原始文本进行清洗,比如移除多余的空格、替换特定字符。 - 缓存查询:插件首先查询内存中的翻译字典。这个字典在启动时从
Translation\{Lang}\Text\目录下的所有.txt文件(包括_AutoGeneratedTranslations.txt)加载。如果找到完全匹配的条目,直接返回翻译结果。 - 在线翻译:如果缓存未命中,且配置了在线翻译端点(如GoogleTranslate),插件会将文本(可能经过批处理以合并多个短句)发送到对应的翻译API。
- 后处理:收到翻译结果后,根据配置(
PostprocessorsFile、RomajiPostProcessing等)进行处理,比如调整标点、处理音调符号。 - UI适配:将最终文本设置回UI组件。如果翻译后文本过长导致显示不全,插件会根据
EnableUIResizing等设置,尝试调整文本框的溢出模式、字体大小或行间距。 - 缓存写入:将“原始文本 -> 翻译结果”这对映射,追加写入到
_AutoGeneratedTranslations.txt文件中。下次游戏启动时,这条翻译就直接从本地缓存读取,无需再次联网。
这个流程确保了首次翻译可能稍有延迟(取决于网络和API速度),但之后的每一次都是瞬间完成,并且翻译结果可以被保存和手动编辑。
3. 实战部署:从零开始配置你的第一个游戏翻译
理论讲完了,我们来点实际的。假设你手头有一款名为“MyFantasyGame.exe”的日文Unity游戏,你想为它启用实时中文翻译。
3.1 环境准备与插件安装
首先,你需要一个插件管理器。XUnity.AutoTranslator支持多种管理器,最常用的是BepInEx,因为它兼容性最好,社区支持最广。
- 安装BepInEx:前往BepInEx的GitHub发布页,下载对应你游戏架构(x86或x64)的版本。通常是一个压缩包。
- 部署BepInEx:将压缩包内的所有文件解压到游戏根目录(即
MyFantasyGame.exe所在的文件夹)。运行一次游戏,此时会生成BepInEx文件夹及其子目录。 - 安装XUnity.AutoTranslator:从插件的Release页面下载
XUnity.AutoTranslator-BepInEx-{VERSION}.zip。将其解压,把plugins文件夹下的XUnity.AutoTranslator目录整个复制到游戏的BepInEx\plugins\目录下。 - 目录结构确认:完成后,你的游戏目录结构应类似如下:
MyFantasyGame/ ├── MyFantasyGame.exe ├── BepInEx/ │ ├── core/ │ ├── plugins/ │ │ └── XUnity.AutoTranslator/ │ │ ├── AutoTranslatorConfig.ini <-- 核心配置文件 │ │ ├── Translation/ │ │ │ ├── en/ │ │ │ └── zh-CN/ <-- 我们将在这里工作 │ │ └── (其他.dll文件) │ └── (其他BepInEx文件) └── (其他游戏文件)
3.2 核心配置详解:AutoTranslatorConfig.ini
插件的所有行为都由BepInEx/config/AutoTranslatorConfig.ini文件控制。首次运行后会自动生成。我们挑最关键的几个部分来配置:
3.2.1 [General] 基础设置
[General] Language=zh-CN Endpoint=GoogleTranslateLanguage: 目标语言。填zh-CN表示简体中文。其他选项如en(英语)、ja(日语)、romaji(罗马音)等。Endpoint: 翻译服务。GoogleTranslate是默认的免费服务。你还可以选择BaiduTranslate(需配置AppID/密钥)、DeepL(需API Key)、Papago等。如果留空或设为None,则禁用自动翻译,仅使用本地翻译文件。
3.2.2 [Behaviour] 行为控制
[Behaviour] EnableTranslationScoping=True EnableUIResizing=True MaxCharactersPerTranslation=400EnableTranslationScoping: 启用翻译作用域。允许你根据游戏场景或可执行文件名来应用不同的翻译文件,非常有用。EnableUIResizing: 自动调整UI。中文通常比英文长,开启后插件会尝试调整文本框属性以适应更长文本。MaxCharactersPerTranslation: 单次翻译最大字符数。严禁在分发插件时将此值设为大于400,以免对翻译API造成过大压力。
3.2.3 配置在线翻译服务(以GoogleTranslate为例)
默认的GoogleTranslate端点使用的是公开的网页接口,可能不稳定或被限制。配置文件里有一个被注释掉的[Google]段:
;[Google] ;ServiceUrl=这个ServiceUrl参数可以被用来指向一个自定义的反代服务地址,以解决某些网络访问问题。请注意,你必须自行确保该服务的合法性与可用性,且不得用于任何违反服务条款的行为。
3.2.4 配置百度翻译API(更稳定的选择)
对于国内用户,百度翻译API往往是更稳定快速的选择。你需要:
- 注册百度翻译开放平台账号,创建通用翻译API应用,获取
App ID和密钥。 - 在配置文件中启用并配置
[Baidu]段:
[General] Endpoint=BaiduTranslate ; 将端点切换为百度翻译 [Baidu] BaiduAppId=你的AppID BaiduAppSecret=你的密钥- 将
Endpoint改为BaiduTranslate。
3.3 首次运行与热键操作
配置完成后,启动游戏。如果一切正常,游戏内文本将开始被自动翻译。插件提供了一系列热键方便你操作:
- ALT+0:打开翻译端点选择窗口,可以快速切换或禁用翻译服务。
- ALT+T:全局切换翻译的开启/关闭。这是你判断问题是否由翻译引起的首要方法。
- ALT+R:强制重新加载所有翻译文件。当你手动修改了
_AutoGeneratedTranslations.txt后,按此键无需重启游戏即可生效。 - CTRL+ALT+NP7:在控制台打印当前加载的场景ID,用于高级的翻译作用域配置。
打开游戏后,留意游戏根目录下Translation\zh-CN\Text\_AutoGeneratedTranslations.txt文件,它会逐渐被翻译结果填充。这个文件就是你的本地翻译缓存库。
4. 高级技巧与深度定制:从使用者到专家
仅仅能用还不够,要想让翻译体验完美,必须深入插件的各项高级功能。
4.1 手动翻译与词条管理
自动翻译的译文质量可能不尽如人意,尤其是专有名词、技能名称、特定文化梗。这时就需要手动干预。
- 直接编辑缓存文件:打开
_AutoGeneratedTranslations.txt,你会看到类似这样的行:
你可以直接将等号右边修改为更准确的翻译,例如新しいゲーム=New Game ロード=Load新しいゲーム=开始新游戏。保存文件后,在游戏中按ALT+R重载,修改立即生效。 - 创建独立翻译文件:不建议直接在
_AutoGeneratedTranslations.txt里做大面积修改,因为它是自动生成的,理论上可以被覆盖。更好的做法是:- 在
Translation\zh-CN\Text\目录下新建一个Manual.txt。 - 将需要固化的翻译对从自动生成文件里剪切过来。
- 插件会读取该目录下所有
.txt文件,且_AutoGeneratedTranslations.txt优先级最低。所以Manual.txt中的翻译会覆盖自动生成的。
- 在
- 使用正则表达式(Regex):对于有规律的文本,正则表达式是神器。例如,游戏中有大量“
アイテム獲得: {物品名}”的文本。你可以创建一个Regex.txt文件,写入:
这样,所有以“アイテム獲得: ”开头的句子都会被正确匹配和替换,r:"^アイテム獲得: (.+)$"=获得物品:$1$1代表捕获的第一个分组(即物品名)。
实操心得:管理大量手动翻译时,建议按功能模块分文件,如
UI.txt、Items.txt、Dialogue_Chapter1.txt。这样不仅易于维护,在多人协作翻译时也能有效避免冲突。
4.2 字体替换:解决中文显示为“口口口”
许多日文或英文游戏使用的默认字体不包含中文字形,导致翻译出来的中文显示为方块或问号。XUnity.AutoTranslator提供了字体覆盖功能。
- 获取中文字体文件:你需要一个包含中文的
.ttf或.otf字体文件(如“思源黑体”、“方正准圆”),并确保你有权在修改中使用它。 - 创建字体AssetBundle(针对UGUI):这是最复杂的一步。你需要使用与游戏相同版本的Unity Editor。
- 新建一个Unity工程。
- 将字体文件导入
Assets目录。 - 在Project窗口选中该字体,在Inspector中确保
Font Names属性已设置(通常是文件名)。 - 右键点击字体文件 ->
Create->TextMeshPro->Font Asset(如果游戏用TextMeshPro)。 - 或者,对于旧版UGUI,你可能需要创建一个材质球并与字体关联。
- 最后,将该字体资产(或TMP Font Asset)添加到AssetBundle中(在Inspector底部设置AssetBundle名称)。
- 使用Unity的Build Pipeline构建AssetBundle,得到一个
.assets文件。
- 配置与放置:
- 将构建好的
.assets文件(例如SourceHanSans.assets)放入游戏根目录。 - 在
AutoTranslatorConfig.ini中配置:[Behaviour] OverrideFont=SourceHanSans.assets ; UGUI字体 OverrideFontTextMeshPro=SourceHanSans SDF.assets ; TextMeshPro字体,或使用FallbackFontTextMeshPro ; FallbackFontTextMeshPro=SourceHanSans SDF.assets ; 更推荐的方式:作为后备字体 FallbackFontTextMeshPro是更安全的选择,它只在不支持某个字符时使用后备字体,避免了完全替换字体可能带来的UI布局错乱。
- 将构建好的
4.3 纹理(图片)翻译:替换游戏内图片
对于游戏内的UI图标、标题Logo等图片资源,也可以进行替换。
- 启用纹理翻译:在配置中开启相关选项。
[Texture] EnableTextureTranslation=True EnableTextureDumping=True ; 首次使用时开启,用于导出游戏内图片 TextureDirectory=Translation\Texture TextureHashGenerationStrategy=FromImageName - 导出原始纹理:启动游戏,插件会将检测到的纹理图片以
文件名 [哈希值].png的格式导出到Translation\Texture目录。哈希值用于唯一标识该纹理。 - 编辑并替换:用图像处理软件(如Photoshop, GIMP)打开导出的PNG文件,将上面的日文修改为中文。关键一步:保存时必须保持文件名(包括哈希值)完全不变。例如,将
title_logo [A1B2C3D4-E5F6A7B8].png中的日文抹去,写上中文,然后保存。 - 关闭导出,启用替换:编辑完成后,将配置中的
EnableTextureDumping设为False,再次启动游戏。插件会从TextureDirectory加载你修改过的图片,替换游戏内的原始纹理。
注意事项:纹理替换功能对性能有影响,尤其是开启
EnableTextureScanOnSceneLoad时。TextureHashGenerationStrategy推荐使用默认的FromImageName,仅在图片资源名不唯一导致替换错误时,才尝试FromImageData(性能开销大)或FromImageNameAndScene。
4.4 翻译作用域与性能优化
当为一个大型游戏制作完整翻译包时,合理使用作用域可以提升加载速度和避免翻译冲突。
- 基于场景(Level)的作用域:在翻译文件中,可以使用指令来限定翻译条目只在特定场景生效。
这表示“町の広場”这个翻译只在场景ID为5、10、15时生效。场景ID可以通过热键#set level 5,10,15 町の広場=Town Square #unset levelCTRL+ALT+NP7在控制台查看。 - 基于可执行文件的作用域:如果你有多个游戏版本(如试玩版和完整版)共用翻译文件,可以用
#set exe指令区分。 - 文件路径参数化:最有效的性能优化方式。在
[Files]段,你可以利用{GameExeName}和{Lang}变量来组织翻译文件。
这样,不同游戏的翻译文件会完全隔离,插件启动时无需加载无关游戏的巨大翻译字典,显著提升加载速度和内存使用。[Files] Directory=Translation\{GameExeName}\{Lang}\Text OutputFile=Translation\{GameExeName}\{Lang}\Text\_AutoGeneratedTranslations.txt
5. 常见问题排查与开发者集成
即使配置无误,在实际使用中也可能遇到各种问题。这里汇总了一些典型情况及解决方案。
5.1 翻译不生效或游戏崩溃
- 检查插件是否加载:查看游戏根目录下的
BepInEx/LogOutput.log文件,搜索XUnity.AutoTranslator,确认插件DLL被正确加载,并且没有抛出红色错误异常。 - 检查热键冲突:尝试按
ALT+0是否能调出端点选择窗口。如果不能,可能是游戏本身占用了这些热键。插件的热键目前无法修改,这是一个已知限制。 - 禁用其他Mod:特别是其他也修改UI或文本的Mod,可能会产生冲突。尝试只启用XUnity.AutoTranslator进行测试。
- 启用TextGetterCompatibilityMode:有些游戏逻辑会检查显示的文字内容。如果翻译后游戏功能异常(如选项无法点击),在配置中设置
TextGetterCompatibilityMode=True,这个模式会“欺骗”游戏,让它认为显示的仍是原始文本。 - IL2CPP游戏的特殊处理:对于使用IL2CPP编译的游戏,文本钩子可能不完整。尝试使用社区提供的
AutoTranslator.IL2CPP.BruteForceFix插件,它通过更积极的方式刷新文本来解决问题。
5.2 翻译质量不佳或格式错乱
- 空格与换行处理:日文和中文对空格的处理不同。如果翻译后断句奇怪,可以调整
[Behaviour]下的IgnoreWhitespaceInDialogue、MinDialogueChars等参数,优化发送给翻译API的文本格式。 - 使用预处理与后处理:创建
Preprocessors.txt和Postprocessors.txt文件。例如,在Preprocessors.txt中加入「=“和」=”,可以将日文引号替换为中文引号,避免翻译API误解。在Postprocessors.txt中,可以修正翻译API常见的错误,如将“它”替换为“他”(针对特定角色)。 - UI布局错乱:中文通常更长。确保
EnableUIResizing=True。对于特定UI元素,可以创建resizer.txt文件进行精细控制。例如,通过EnableTextPathLogging=True获取组件路径,然后添加规则:UI/SomePanel/Text=ChangeFontSizeByPercentage(0.9),将该处字体缩小到90%。
5.3 为你的Mod集成翻译支持
如果你是一名Unity Mod开发者,你可以让自己的Mod界面也能被XUnity.AutoTranslator翻译,或者直接调用它的翻译API。
- 让Auto Translator忽略你的Mod UI:如果你的Mod使用GameObject,只需将包含Text组件的GameObject名称中包含
XUAIGNORE字符串,插件就会跳过它。如果想忽略整个子树,使用XUAIGNORETREE。 - 调用翻译API(v3.7.0+):在你的Mod代码中,可以直接查询翻译:
// 异步查询,优先缓存,若无则调用在线服务 AutoTranslator.Default.TranslateAsync("お前はもう死んでいる!", result => { if(result.Succeeded) { Debug.Log(result.TranslatedText); // 输出翻译结果 } }); // 同步查询,仅查缓存 if(AutoTranslator.Default.TryTranslate("お前はもう死んでいる!", out string translation)) { // 使用 translation } - 为你的Mod提供专用翻译文件:在
Translation\{Lang}\Text\目录下创建Plugins文件夹,再在里面为你Mod的DLL文件(不含扩展名)创建一个文件夹。将翻译文件放在里面。例如,你的Mod是MyCoolMod.dll,则路径为Translation\zh-CN\Text\Plugins\MyCoolMod\。你还可以在翻译文件中加入#enable fallback指令,允许在找不到专用翻译时回退到通用翻译。
5.4 实现自定义翻译端点
如果内置的翻译服务都不满足需求(比如你想接入本地部署的大语言模型),你可以开发自己的翻译插件。
- 创建类库项目:新建一个.NET Framework 3.5或.NET Standard类库项目(后改为net35目标框架)。
- 引用与继承:引用
XUnity.AutoTranslator.Plugin.Core.dll。创建一个类,实现ITranslateEndpoint接口,或更简单地,继承HttpEndpoint基类。 - 实现核心方法:
Id和FriendlyName:返回你端点的标识符和显示名称。Initialize:在这里读取你的配置(如本地LLM的API地址和密钥),并进行初始化验证。OnCreateRequest:构建发送给翻译服务的HTTP请求。OnExtractTranslation:从HTTP响应中提取翻译文本。
- 处理SSL证书:旧版Unity的Mono可能拒绝所有SSL证书。在
Initialize方法中,调用context.DisableCertificateChecksFor("your.api.host")来禁用对特定主机的证书检查。 - 编译与部署:将编译好的DLL放入游戏目录的
BepInEx\plugins\XUnity.AutoTranslator\Translators\文件夹中。重启游戏,即可在端点选择列表(ALT+0)中看到你的自定义翻译服务。
整个过程将游戏本地化从一项浩大、静态的工程,转变为一个动态、可实时迭代的过程。XUnity.AutoTranslator不仅仅是一个工具,它更是一套完整的实时本地化解决方案的基石。无论是玩家想即时体验外语游戏,还是开发者想为自己的作品快速搭建多语言测试环境,它都提供了前所未有的灵活性和强大功能。掌握它,你就掌握了为任何Unity游戏开启世界之门的钥匙。