养成游戏汉化(游戏汉化日记 一)

2024-03-30 16:37:00 来源 : haohaofanwen.com 投稿人 : admin

下面是好好范文网小编收集整理的养成游戏汉化(游戏汉化日记 一),仅供参考,欢迎大家阅读!

养成游戏汉化

导言

很久没写技术文章了,一来感觉自己这技术没什么值得分享的,二来最近确实有点忙得焦头烂额。

这不刚好兴致来了,记录和整理一下最近汉化遇到的技术难题,梳理一下思路,分享一下经验。

最近汉化的几个游戏呢,都是开源的文字游戏。

作者都是野路子出身,没有技术背景,所以代码习惯很差。

逻辑和数据耦合是常态,有时甚至拿变量名或文件名来输入输出和判断,没有设计本地化配置文件有版本更新需求,这是大背景。

既然是开源,而且没有本地化配置文件,那理所当然的,汉化过程就是暴力替换源代码,然后重新编译。

当然其实也没那么暴力,大致来说分为五个主要阶段:

提取源代码中需要翻译的文本;

将文本分类存储,并发送到在线协作平台;

汉化组在平台上做翻译;

定期下载翻译文本,然后替换源代码,最后打包;

测试游戏Bug。

其中除了3以外,都多少涉及了一些技术问题,我一条条展开讲讲。

提取文本

最麻烦的第一步,首先得熟悉项目使用的语言,然后还要熟悉这个项目的结构,不然没法解析。

就拿我最近在汉化的《Era***》来说,这游戏使用了一种叫做era basic的古老小众的脚本语言,我谷歌百度找遍全网都没有一篇系统全面的文档,只有一些残卷散落在互联网的各个角落。

并且,这游戏使用的era basic居然还包含了新特性EM+EE。大概就是我连C#4.0的文档都没找到,人已经用上C#10.0了这样,真的很无助。

什么,你说era basic有一个开源解释器。但那解释器也不支持EM+EE,注释比鱼香肉丝的鱼还少而且全是日文,啃这玩意儿不如我从零造轮子。

离题了,总之当熟悉了语言和项目结构后,就可以试着提取一下文本了。

根据语言和项目熟悉程度以及作者的代码习惯,多多少少会有漏提取的内容,这就需要之后不断测试、不断改进提取工具了。也是一场麻烦的持久战。

词典分类

分类问题是一个设计问题。

可能有人要问,文本提取出来不用管那么多,直接就存成单独一个超大的词典,不就能猛猛上工了吗?NO!

下面我介绍两种分类方式,并说明为什么这样分类。

本人脑子比较拙,暂时也只想到这两种分类方式,有新想法欢迎在评论区与我交流,拜托了!

拆分文本与变量名

背景

众所周知,游戏是状态很多的一类程序,经常有字符串内嵌变量拼接的需求,这是其一。

汉化组的翻译大多不懂代码,分不清文本内嵌的各种代码符号,这是其二。

变量名会在多个地方出现,一旦翻译不同,就会发生惨烈的Bug,哪怕在平台上标记术语也不能避免,这是其三。

方案A

基于这三个痛点,文本与变量名分离的方式应运而生。

在提取文本阶段,就将识别到的变量名扔到单独的变量名词典。

而内插变量名的文本将被截断成多个短文本,避免变量名呈现到译者眼前。

那么,代价是什么呢?

代价就是译者拿到的文本都切得碎碎的,经常搞不清语境,容易闹乌龙;

并且还无法自由调整文本语序,让译文看起来十分机翻。

这可不行。

方案B

方案B在方案A的基础上做了一点优化。

现在长文本不再被切碎,而是包括内插变量名,这样译者就能搞明白上下文,也能调整语序了。

但是译者乱改变量名怎么办呢,这个倒不用操心。

在替换阶段,先使用变量名词典替换掉长文本词典内插的变量名,得到二次修改的长文本词典;

再使用二次修改的长文本词典去替换源代码,如此便能保证变量名统一。

有没有缺点呢,其实还是有的。

多了一个变量名提取-翻译-替换的工作流,每一步都增加了出错的风险。提取和替换一定会有漏的。

变量名一定要翻译吗?大多数情况下其实不翻也可以,但有的游戏变量名会直接拿来输出,那能怎么办嘛!

还有一个小众的需求,玩家可能希望他在原版的存档也能被汉化版继承,或者反过来。

前面也说了,作者都是野路子,什么东西都往存档里塞。

像什么“你今年24岁,是学生,身穿XX衣服”这种动态改变的人物描述(有时间流逝机制)都能以字符串形式存到存档里,导致检查汉化的时候莫名发现人物描述居然没变化,仔细看存档才发觉问题的严重性。

所有玩家见过的NPC的描述都以字符串形式存档,存档真的,我哭死。

为了存档兼容,汉化版只能搞一个新的映射或者扩展容器。比如原先的Cloth类只有Name成员,汉化组可以加一个NameCN成员,然后把原文的{cloth.Name}通通翻译成{cloth.NameCN}。

按文件拆分

众所周知,代码习惯再烂的游戏程序员也不会一个main函数写到尾。

按文件拆分有什么好处呢?

一是上下文语境更明确,译者能完整地了解一段文本从什么地方开始什么地方结束,到底是用在什么地方。

这方面比上一种方法更理想;

二是可以更精准的替换,只要在提取阶段标记代码行数,就极少会出现错误替换漏替换的情况。

即使出现,也很容易定位到问题并修正。

乍一看是一套完美的解决方案啊!然而和上一种方式对比,还是能找到两个缺点。

一是无法保证变量名统一,这一点前面提过。这很容易导致游戏出现Bug,而且也不是很好排查;

二是需要翻译的文本膨胀了。可能有点抽象,但对于野路子开发者来说刚刚好。

比如我前段时间在翻译的《莉莉丝的**》里,经常就出现一段文本到处复制粘贴,有的文本甚至被粘贴了二十几遍,于是译者就要在不同的文件里翻译二十几遍。

如果采用上一种方法,只分离长文本和变量名,那么重复的长文本会被合并,译者只需要翻译一次。

不妨说这其实也是为了更好的上下文语境做出的牺牲,一想到作者维护的时候一定也在痛苦扭曲抓狂尖叫,多少有点心理平衡呢。

替换代码

词典分类的方法其实直接影响了替换的方法。

如果只拆分文本和变量,就需要对目录下所有满足条件的文本做读取、修改然后保存。

性能上会有压力吗?其实没什么压力,要有性能压力也是在原作上。

根据原作的容量,替换通常在1~15秒之间就会结束。

如果按文件拆分,效率当然要高得多。但这个流程其实并不常跑,也没必要在电脑上抠这几秒的。

按文件拆分还有个优势,前面也提到过,由于替换的范围缩小了,就很难出现错漏替换

按文件拆分还可以再给每个条目添加一个行范围标记,把范围缩得更小,虽然会拖慢执行速度但显然利远大于弊。

不过就算范围缩小到行,还是会面临一个很极端的情况

比方说我有"Chin"->"下巴";"ina"->"伊娜";"Ch"->"策划"。

而我的原文是"China",正确翻译是"策划伊娜"。

如果按一般流程处理,把字典按原文长度排序,下巴>伊娜>策划,然后再替换,就会得到"下巴a"。

当然,如果范围缩小到行,错误替换概率基本可以忽略不计。

而如果是只拆分文本和变量,然后全局替换,就相当容易出现这样的状况。

行标记的问题主要是代码写起来稍微复杂一些,因为一个翻译条目很可能是跨行的。

但能直接String.replace为什么还要逐行改,这一切值得吗?

更别说原作更新后,行数也会跟着变化呢。

测试游戏

最后还要跑游戏,排查错漏提取、错漏翻译、错漏替换。

汉化真是比娘化麻烦太多了。

技术出身的同志一般习惯让反馈者上Github提issue,但反馈者绝大多数没有技术背景,也没有那个精力。

你汉化者是用爱发电,反馈者难道就不是吗?

所以最后还是会开DC频道或者QQ群啦……

然后还有一点不起眼但影响很大的,就是有没有高频率更新汉化

如果有每日或每周打包新版本的话,反馈和修正会更加准确

译者因为有了所见即所得的工作成果,工作也会更加积极

为了达到这个目的,可能需要构建自动打包工作流,可以参考Github提供的解决方案:

了解 GitHub Actions - GitHub Enterprise Cloud Docs

版本更新

虽然没遇到什么难点,但还是踩了一个小坑,不太具备参考价值,姑且简单讲讲。

因为翻译是在平台上进行的,为了保留平台上的操作记录和批注,必须要维持旧条目的键值一致

版本更新不仅会新增一些条目,也会删去一些条目。

为了保留上下文语境,新增加的条目很可能插在旧条目之间,而不是在末尾追加。

然后一开始我脑子没拎清,版本更新的时候直接取了条目总数作为追加条目的初始键值,忽略了删除条目导致条目数小于上版本最终键值的情况。

所以正确做法应该是将键值按数字大小排序,取到最大的那个再+1。

行数变动导致行标记变化也是一件麻烦事,这里就略过不表了。

谢幕

#オリジナル うたた寝 - みこフライ的插画 - pixiv


相关文章

    暂无相关信息
专题分类