一种很新的Unity游戏汉化方案

起因

目前,网上的大部分汉化教程都是修改游戏和资源文件的方案,毕竟是有点缺乏灵活性,必须随游戏更新多次再版重做

所以在了解一些galgame游戏的自动翻译项目后,我开始尝试寻找类似的unity汉化方案

然后发现一个插件XUnity.AutoTranslator,但是网上的文章都是关于配合在线翻译api使用的教程

这里总结了一套比较完整的本地汉化方案(好像有点大材小用的样子

使用插件翻译,你可以:

  • 无缝衔接游戏更新
    不需要手动重制,一次发布长期使用
  • 完整(大概?)的跨平台支持
    包括Windows、Linux和MacOS,从x86到ARM
  • 容易被带反作弊的游戏制裁?
    (虽然那种本来就做不了汉化

另请参考插件项目的README

(另外,在本文从开始写稿拖了较长一段时间,发表布之前已经有dalao写过类似的了qaq

(因此你还可以参考这篇bilibili专栏

安装前置框架和AutoTranslator

参考一般插件安装教程 或 项目README

你可以按照项目README去使用其他模组框架

建议BepInEX,下文使用的也是这个

BepInEX不需要修改游戏文件,安装与使用没有其它过多额外步骤

注意,如果你的unity游戏用的是il2cpp编译(特征是游戏文件有GameAssembly.dll),那么你也应该使用插件的il2cpp版本

编写翻译文件与制定配置

创建翻译文件

启动一次游戏来生成目录后,在BepInEX/Translations/en/Text(默认,由配置文件的 Language 一项决定)下新建一个txt文件

名称随意,这里我的偏好是main-schinese.txt

语法

首先,用;表示注释开始,如下面,无论分号在哪里其后的内容绝对不参与翻译(但是注意空格)

即忽略 ;本行不参与翻译;后面这段不参与翻译至本行末尾 这两处文本:

1
2
;本行不参与翻译
正常翻译原文A=正常翻译结果B;后面这段不参与翻译,不推荐这样子写注释,因为很难看

这是用来写给自己看的标记的,通俗来讲像“书签”或者“批注”,可以用来划分文本

然后以每行为一个单位

每行语法如下,则由此行内容,实际 I'm A! 翻译为 我是A!

1
I'm A!=我是A!

在上面例子中,使用等号来分割原文和译文,以本行第一个等号为划分点

行中的等号无法被转义(即如果原文中有等号,这个 等号 可能会与用来分割原文和译文的 等号 混淆

原文中出现等号的使用空格替代,以避免冲突(匹配 =w=... Really?,翻译成 =w=... 真的吗?):

1
w ... Really?==w=... 真的吗?

小心空格,原文多了少了几个空格可能就匹配不到,译文末尾多了几个空格在游戏里也有可能不太合适

另外注意换行符 \n,在单行文本中,这个符号表示换行

对于富文本(rich text,参见unity文档),翻译文件中的原文依然需要包括xml标记,如下面的粗体标记<b></b>

1
<b>WHAT ARE YOU DOING!?</b>=<b>你在干什么!?</b>

另外有正则表达式(regex)匹配翻译,用于匹配与替换翻译(匹配 I'm No.7!,提取中间的数字 7 代入翻译成 我是第7号!):

1
r: "I'm No.([0-9])!$"=我是第$1号!

$必须放在末尾,每个()内放一个表达式块,在译文处按顺序以$数字序号引用。可以有多个表达式块

如果原文有"引号,改成\"来转义:

如果用sr代替r,被表达式匹配的这一小段文本会另外匹配翻译项再传入译文引用(匹配 I'm Apple!,提取中间的文本二次翻译后,代入翻译成 我是苹果!):

1
2
Apple=苹果
sr: "I'm ([\s\S]*)!$"=我是$1

一般正则表达式用法请自行上网搜索,常用的有 [\s\S]* 用于匹配任意长短的任意字符

正则表达式稍耗性能,尽量少用,适合的表达式可以降低性能损耗,如 [0-9],只匹配一个单独出现的数字,两位数及以上匹配不到

另有类似于regex的substitutions用于预处理翻译文本,因为不常用这里不写

到这里,剩下的就是一点一点玩游戏,顺便打原文进文件,做翻译的繁琐工作了

最终成品类似(某个游戏截取的。这里包含注释用来划分不同部分的翻译):

1
2
3
4
5
6
7
8
9
;battledock_tech_weapon_name 科技树_武器_名称
Standard Issue=标准武器
Resupply=补给包
Night Vision Goggles=夜视
Tactical Grenades=战术手榴弹

;battledock_tech_weapon_description 科技树_武器_描述
The Standard Issue weapons include the tried-and-true RK44, an SIND-7 sidearm along with equipment such as a wrench, saber and frag grenades.=包括久经实战的RK44 突击步枪, SIND-7 半自动手枪, 扳手, 军刀, 手雷这类装备
This rocket launcher is an excellent counter to enemy tanks=反敌方装甲很好用

Scope

用scope来划分每一部分的翻译文本,如下面示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#set level 1,2,3
CUSTOM MAPS=自定义地图
GAME MODE=游戏模式
#unset level 1,2,3

#set exe game1,game2
BALANCE=双方队伍人数平衡
GAME CONFIGURATION=游戏配置
CHARACTER SKINS=队伍皮肤


`#set required-resolution height > 1280 && width > 720
WEAPON SWITCH=武器编辑页面
VEHICLE SWITCH=载具编辑页面
MUTATORS=脚本模组页面

#set level 1,2,3#set level MainMenu 表示从这里开始往下,这部分的翻译只应用于 “场景id为1和2和3的场景” 或 “场景名为MainMenu的场景”,用逗号分隔

同类的是#unset level 1,2,3,表示从这里开始往下,这部分的翻译不应用于指定的场景

空行好像不会中断标记作用范围

(这部分内容未经实机测试。我隐约感觉 #set level 1,2,3 之后必须 #unset level 1,2,3 才完整有效,才能继续下一个新标记,按逻辑讲又不通)

场景和场景id是unity开发的一个概念,参见unity文档

#set exe game1 表示从这里开始往下,这部分的翻译只应用于 “exe名为game1” 的游戏

适用于有的游戏有多个exe,但bepinex不会识别具体是哪一个而全部加载本体和插件,插件全部翻译的特殊情况。同类标记同理

#set required-resolution height > 1280 && width > 720 表示这部分的翻译只应用于当游戏窗口宽高均大于 1920x1680 时才使用,防止部分译文超出显示区域的情况。可用判断符号参考C#语法?

其他有用的功能与技巧

在线翻译

启动过一次游戏,游戏目录下的BepInEX/configs/应该会出现AutoTranslator.ini文件

这就是插件的配置文件

打开它,建议配置Endpoint为空(即Endpoint=,等号后面的内容删掉),用于禁用在线翻译,防止基本不可用的默认谷歌翻译复活,生成狗屁不通的机翻到_AutoGeneratedTranslations.txt

如果你想先使用插件的自动翻译生成一部分文本,来降低工作量,参见其他教程,如知乎

这个有一个很蛋疼的问题是,生成到文件的翻译不知道是游戏里哪一处的

找某一段文本修改的时候也很吃力

打印日志与快捷键

打开 BepInEX\config\BepInEX.cfg,将 Enable Console 修改为 true 即可

这个是给下面快捷键 Ctrl + Alt + 小键盘7 用的

在游戏运行时点一下console窗口的区域可以强制暂停游戏,按回车键恢复

快捷键:

  • Alt + 0
    打开翻译器的游戏内UI
  • Alt + 1
    打开翻译文本的对照ui?
  • Alt + T
    打开或关闭游戏内翻译
  • Alt + R
    重载翻译文件和重定向的资源文件 Not guaranteed to work for all textures.
  • Alt + U
    Manual hooking. The default hooks wont always pick up texts. This will attempt to make lookups manually. Will not hook text components from frameworks not enabled.
  • Alt + F
    切换 OverrideFont 或原游戏字体
  • Alt + Q
    重启在线翻译模块
  • Ctrl + Alt + 小键盘9
    Simulate synchronous errors
  • Ctrl + Alt + 小键盘8
    Simulate asynchronous errors delayed by one second
  • Ctrl + Alt + 小键盘7
    在console输出当前场景id(-1 为未定义)和场景名

有用的配置项

  • IgnoreWhitespaceInDialogue
    忽略长文本中的空格
  • OverrideFontOverrideFontTextMeshProFallbackFontTextMeshPro
    替换字体,因为有些游戏的中文字体支持残缺,需要替换
    不带 TextMeshPro 的是通用字体
    TMPro字体在插件的release那里有,下下来打开压缩包,选一个解压到游戏根目录,在配置文件填上字体名就可以了:
    1
    OverrideFontTextMeshPro=arial_u2019_sdf
    如果不解压到游戏根目录,就需要填绝对路径
  • GeneratePartialTranslations
    启用滚动字体翻译
    如剧情对话有文本滚动动画,有些时候只有当文本完全展示完,插件才能匹配原文到
    启用这项之后就可以自动适配
    但是可能会产生新的bug
  • TextGetterCompatibilityMode
    兼容性模式,如果插件在一般情况下无法正常工作
  • ReloadTranslationsOnFileChange
    修改文件时保存后自动重加载翻译文件到游戏,不需要手动reload
  • EnableUIResizingResizeUILineSpacingScaleForceUIResizing
    重缩放ui,比如在翻译后文本超出显示区域
    先改 EnableUIResizing 以启用,然后 ResizeUILineSpacingScale 改的是文本行之间的垂直间距

快速获取原文

上文提到,翻译文件是在玩游戏的时候一点一点打把原文打进翻译文件然后再翻译的

这样有时会很繁琐

要直接获取原文,而不是手打,一个是传统方式(也就是传统汉化),如UABEA批量解包文本,请咨自行在Bing搜 Unity游戏 汉化 以查找相关已有教程,如 github.com/mskgroup/Unity-Game-localization-tutorial-and-toolkit

一个是用插件,Runtime Unity Editor,但这个的话,有unity开发基础才能用得比较顺手,所以这里不作介绍

图片汉化

没错这个插件还可以用来汉化游戏内图片

参见README

基本流程为启用此功能,设置图片导出,p图

社区化安装工具

什么你说这个是用来干嘛的?

主要是用来给不懂电脑的超萌新玩家用的,直接一步到位安装汉化

(这部分还在整理)