Skip to content

Q. 模组翻译的特殊要求

dovisutu edited this page Jan 20, 2024 · 5 revisions

这里是自用的MMLP wiki沙盒。可能会在这里不定期写一些东西,如果有朝一日能写完甚至可能会搬过去,不过现在就先这样吧。

出于比较明显的原因,本仓库仅接收Minecraft模组翻译;在翻译之前,应当对于这种特殊的翻译工作给出额外的要求。

注:在本页面中多次使用了外链。外链以链接源:链接名的方式表示,其中“链接源”可能是缩写。 特别的,下面的mcw指Minecraft Wiki(与Mojang/Microsoft没有严格的联系),确切的说是指其中文界面。


Minecraft/模组的本地化原理

尽管说,理论上如果有合适的工具,对于一个提供了标准、良好的国际化接口(即所谓的i18ninternationalization)的模组而言,译者其实不需要了解其本地化l10nlocalization)原理;但是,Minecraft模组的i18n状态可谓参差不齐,从全部可i18n到全部不可i18n的都有,所提供的接口也未必一致;因此,即便只是为了知道哪些部分是可以翻译的,并且是可以在此仓库翻译的,译者也应当了解一些本地化原理。

格式化字符串

在许多情况下,一处文本中会有一部分文字随游戏内容而变化,有时这里的变化数甚至是无穷多的。因此,给每一种变化赋予一个定值是不现实的——我们需要一些方式来简化文本的生成方式。

这个方式就是格式化字符串。这种字符串在正常的文本中插入了一个或多个格式符。在游戏运行时,这些格式符会自动替换为向其提供的参数;这些参数可以是有特定格式的数据,或者别的字符串,显示形式由格式符决定。例如:

这是一个整数值%d,这是一个十六进制数%#x,这是一个字符串%s

在提供参数17, 17, "++97"的情况下,三处%格式符分别被替换为17, 0x11, ++97

大多数模组的格式符遵照Java String.format()的格式化规则(也就是常见的%开头的格式符),详细内容可见oracledoc:Java.Util.Formatter的参考文档。一般而言,格式符内部的标记无需改变,但有一种情况例外:
一般而言,参数的替换顺序会按照格式符在字符串中的相对位置,而非我们所预期的语义位置。也就是说,如果两处格式符需要交换位置,需要特殊处理。Java为格式符提供了参数位置,可以明确地指出格式符使用哪一个参数;参数位置的格式为n$,直接放在%的后面,其余标记的前面,这里n指使用第几个参数(从1开始计算)。由于中英翻译常常需要改变语序,这一点常常用到;也有部分作者直接在翻译文本中自带了参数位置,以方便译者调整,不过并非所有文本都会如此。
此外,需要注意的是这里的百分号为英文百分号U0025(%)而非全角百分号UFF05(%);我们曾经遇到过这样的问题。

在某些文本中,可能会遇到与上述不一致的格式符;此时,除非明确知道其意义,应当尽量保持格式符完整,以免格式化异常;如有必要,可以上机实测。

需要注意的是,除非明确认识后果,不要贸然增删文本中的格式符!如果格式化字符串的参数数目不匹配,在格式化时可能会报错,甚至可能导致游戏崩溃!

Minecraft的本地化加载途径:资源包

尽管早期Minecraft的本地化不甚完善,在1.6.1(13w24a)以后,全部本地化内容都集中到了资源包中的\assets\minecraft\lang\[xx-yy.eeee]文件中,并由此进行读取。
本地化条目是以键-值对的形式提供的,游戏会根据每段文本登记的本地化键在玩家所选的语言中寻找本地化文本,如果找不到就回退到默认语言,如果还找不到就回退到键本身。
语言通过不同的文件名称指示;简体中文的标识符为zh_cn,但有消息称,可能会修改为ISO化的zho-Hans_CN

本仓库所提供的所有翻译都是通过资源包挂载的,这可以在O部分看到。

关于资源包的详细内容可参见mcw:资源包,这里由于篇幅,就不提供了。

语言文件的格式

在1.7以后,虽然文本放置的位置确定了下来,但是文本的格式有过变化

这一部分目前暂时没有找到具体的更改时间,但是在mcw上找到的是299711更改首次将资源包界面上的.lang文件的描述更换为了.json,时间对应于1.13以后1.14以前(但不确定是哪个快照);有意思的是,在mcw上1.13更新日志中,以及[mcw:资源包]中,并没有找到关于这一点的记录,尽管确定的是,1.13中的文件格式为.json,1.12的文件格式为.lang,更改必然发生在这之间。
299711更新的时间为2019年3月17日,而1.13于2018年7月18日推出,1.13.2于2018年10月22日推出,1.14于2019年4月23日推出,也就是说,当时已经进入1.14快照的中后期。

在1.13以前,键值对的储存方式是Minecraft自己的.lang格式,大致格式为每行key=item,尽管其中有一些较为混乱的细节;此外,如果在第一行加入#PARSE_ESCAPES注释,该文件将按照标准的Java Properties格式读取,这本无可厚非,但问题是,他们使用的是同一后缀......
于是,在1.13,Mojang将资源包中的本地化文件的格式更改为了标准的.json格式,具体而言,一般是在根标签下平铺的映射表。除了没有标准化的注释语法以外,这个格式应该说是一个比较正常的格式了。

由于没有标准注释语法,许多模组将注释也写成了条目,只不过使用了不存在的键名;如确有需要,译者也可加入这样的注释,只不过应当明确表明这是一条注释(如使用带下划线及comment字样的键名)。 理论上来讲,Minecraft使用的JSON库支持非标准的注释格式(直接使用//),也确有作者这么用了;理论上来讲,本库的基础设施应当也支持这样的文件——不过最好不要新增这种注释,因为这毕竟不是标准格式。

不过,有时候JSON文本也不一定是纯粹的映射表。有时,作者会直接在文件中书写原始JSON文本——一种在原版\tellraw等指令中使用的富文本格式。

键碰撞:本地化的噩梦

我们提到了,Minecraft是以本地化键作为本地化文本的唯一标识符的;然而问题来了,如果唯一标识符不唯一怎么办?

在仅Minecraft本体的情况下,这几乎是一个笑话 (除非Mojang哪天整活);然而,加上模组以后,事情就不一样了,因为模组是由不同的主体开发的;如果开发者没有考虑到与其他模组的键碰撞,后果将是灾难性的:
Minecraft进程在遇到重复的本地化键以后,并不会崩溃,而是会根据一套尚不明确的方式,从其所获取到的所有本地化文本中,抽取一个作为最终的本地化文本;其余文本将被丢弃。也就是说,重复键几乎必定会导致翻译出现严重问题,并且还很难排查,因为语言文件中的翻译文本的确是正常的。

这一问题对于目前的MMLP而言尤为麻烦,因为我们目前的分发策略是分发所有该版本文件!这样的后果是,一旦在本库中出现了键碰撞,所有使用本资源包的玩家都必定会遇到问题!不幸,我们对此的唯一解决方案是按已有模组分发文件;但由于技术问题,这一方案遥遥无期。

当然,如果开发者考虑到了这一点,解决方案还是简单的:在自己模组的所有键中都加入特殊标识符,比如说模组名。近年来,这一操作被大量采用,尽管仍有少数模组未做更改。

真的一切文本都能本地化吗?

答案是否定的。

如果回到13w24a以前,那时Mojang还没有推出统一化的资源包加载途径,当时的诸多模组出于对本地化的忽视,会直接将文本写在模组文件内;这样一来,基本就失去了本地化的可能,除非修改模组文件,复杂不说,甚至还可能违反版权协议。这种存储文本的方式,就是臭名昭著的硬编码;相比,将文本保存在代码外,需要时再动态调用,就叫做软编码,这就对本地化较为友好了。

即便到了今天,硬编码仍然存在,其中有许多都是历史遗留问题。例如,**气动工艺(PneumaticCraft)**至今都还有部分文本为硬编码;由于该模组的体量较大 虽然没有GT大,筛查较为困难,尽管在我们的反馈下现任维护者desht多次修复,但直到今天仍有遗留。

本体之外:模组特定的加载方式

总有那么一些模组出于各种原因没有采用Mojang提供的资源包途径。

一些特立独行的模组

一个著名的例子就是Gregtech(具体而言,是其1.7.10的版本):该模组的所有本地化文本都是以根目录下配置文件Gregtech.lang的形式挂载的,玩家需要单独处理该文件;当然,这也无可厚非,毕竟至少还是以一种可行的方式实现了本地化;考虑到其体量,在原有基础上修修补补也不太可能了;倒是后续从零开始做的各种高版本移植实现了正常的资源包途径。

模组手册的谜团

近年来,各种模组都开始添加模组手册;目前而言,一大部分的模组都统一使用了Patchouli提供的手册加载方式,这种统一化倒是不错。然而问题是,在高版本中的Patchouli未必会走资源包途径

结果很简单:如果不使用特殊手段,在高版本中,Patchouli手册可能无法通过资源包本地化!(确切来说,1.12是可以加载的,1.16是不能加载的,1.18版本的部分手册通过数据包挂载,因而不支持原生资源包挂载;笔者并没有考证确切的更改版本。)

但所幸,这一“特殊手段”是存在的;通过Mixin技术,我们可以在不修改Patchouli的模组文件的情况下修改其加载逻辑。考虑到Patchouli手册的推广度,在较旧版本的i18nupdatemod中,已经集成了这一功能,尽管似乎缺少了高版本的适配;在新版的i18nmod中,由于结构问题取消了这一适配,但玩家可以单独安装Patchouli 资源修复等模组来做到这一点。因此,本仓库可以接收Patchouli手册,尽管需要更加小心。

那么其他形式的手册呢?目前来说没有定数。粗略地说,如果经实测该种手册能够通过资源包正常加载,那就万事大吉;否则,可能需要像Patchouli一样另外进行适配,或者可能干脆无法适配。


社群化翻译:一致性的迷宫

对于翻译工作,一致性的意义不必多说:相信没有人会忍受本质上相同的东西凭空产生无数个名字吧。然而,一致性的难度却常常被忽略:

  • 如果一项翻译是由一个人在短时间内进行的,那么,一致性通常不会是一个大问题,因为译者的记忆与理智足以解决它;
  • 然而,如果一项翻译是由广大的社群较长的时间中,相对独立地进行的,那么,我们面对的将是一致性的迷宫
    除非*在工作伊始就搭建一套严格的标准化系统,并严格保证每位译者都遵守一致性原则,*几乎不可能以可控的成本保持一致性!

很不幸的是,Minecraft模组翻译最初并无这样的标准;因此,每一位译者都需要在一致性的迷宫中七弯八绕,与陈例、习俗的惯性做斗争。在诸多时候,一个翻译最终选定,或许并非其最贴合原文的表意,而是它最贴合最广大群体的习惯,尽管这种习惯可能根本就是最初的谬误。由Mojang撑腰的Minecraft本体本地化或许可以对抗这种习惯,修改翻译,但我们不行。确切地说,我们曾经也试图这么做过,但不知是因为我们欠考虑还是别的缘由,结果大概是这样的:

不过朝花社不久就倒闭了,我也不想说清其中的原因,总之是柔石的理想的头,先碰了一个大钉子,力气固然白化,此外还得去借一百块钱来付纸账。后来他对于我那“人心惟危”说的怀疑减少了,有时也叹息道,“真会这样的么?……”

具体的内容或许会在遥遥无期的考古文章[W部分]提及,但总之不是这里。

不过,一致性的要求并不意味着要盲目地统一文本,就像Unicode对一致性的追求也不等于盲目地统一中日韩表意文字;如果原文的表意确切地不同,一味地按照原文的近似度做统一也可能招致大祸。


Minecraft本体

Minecraft作为一款游戏,有着较为特殊的语境:这里的很多语句拥有着与日常不同的含义,甚至有许多是生造的,也就是说,Minecraft用语不完全是日常生活中的用语,而更像是一种“英语的方言”。

  • 文本:发展到今天,Minecraft有着一套标准化的中文译名,通过由Mojang授权、社群管理的Crowdin平台维护。尽管有时候这些译名不尽人意,但在译名修改之前,游戏之中显示的就是那上面的译名;即便译名已经修改,对于过旧的版本,目前而言Mojang分发的译名也不会调整了。尽管我们或许可以在本库分发的资源包中加装原版译名更改,但这样会造成更大的混乱。因此,目前而言,我们在翻译时应当遵守该版本的译名标准。一个有用的参考是mcw:译名标准化以及mcw:译名标准化/历史,或者也可以考虑CFPA术语库;如果不放心的话,也可以直接拆包游戏找本地化文件。
  • 格式化代码:在Minecraft的各种文本中,存在有以分节符U00A7(§)开头的格式化代码,具体可见mcw:格式化代码,用于改变字符颜色或实现加粗、下划线等功能。一般而言,不需要更改这些符号,只要置于正常的位置即可;如果确有需要,也可以适当地增删补改。
  • 用法:有些文本是与游戏内容密切相关的,如果对游戏毫无了解,很容易望文生义。比如wither根据指生物还是指效果有两种(还差不多的)翻译。
  • 衍生规则:有部分内容严格来说不是本体内容,却应当与本体尽量保持统一。例如,当一个模组添加了多种木制品时,其译名应当与原版的木制品命名规则一致, 尽管说原版的命名规则有时未必便于拓展。

模组词条

相对于规整的游戏本体,模组的一致性是一个更大的问题,因为模组的原文都未必统一!例如,将块状固体研磨为粉的机器到底是Macerator还是Pulverizer还是Crusher还是Grinder?译文是否要做出区分?我们不知道
目前而言,我们在处理一致性问题时,更多参照的是先例,也即相关的模组的译名,或是以往的译者总结出的一套未必精确的用词表,例如Krasjet/Mod-Translation-Styleguide这种总体性的用词表,或者各个模组特定的词汇习惯;如果翻译新模组,也往往会参照这些先例,因为对玩家而言,同时安装多个模组还是很常见的。

这种“不一致的”一致性需要处理到什么程度?粗略地说,对于通用性较高的条目,例如种类相同的矿物,除非有特殊需求,最好保持统一;而对于通用性不太高的条目,留给我们的操作空间就要多些。

测试的力量

几乎在完成一切工作后,我们都需要进行测试。测试是将潜在的问题在正式发布前捉出的工具——在这里也不例外。考虑到模组翻译的复杂性,除非你有全足把握,否则,测试都应当成为必选项。

  • 加载:如果费力做完本地化,却发现根本无法加载,或是产生乱码,那本地化的效果当然没有达到。
  • 语境:许多文本的表述较为晦涩难懂,或是译者对源语言的习惯用法不太习惯,或是缺失了上下文,甚至是原作者就写错了——这些都可能导致偏离语境的误译。为了防止这样的错误被流传下去,祸害用户(甚至将来的译者),在游戏的完整语境中实地调查,确认文本的正确含义,十分重要。
    事实上,有的时候,即便在游戏内也不一定搞得清楚一段文本;这时候甚至有可能需要参照模组源代码,即戏称的*“Minecraft 模组翻译:从入门到编程”*。当然,如果没有这个能力,也可以向其他人寻求帮助。
  • 笔误typo:我们必须承认,处理大量文本时,或多或少会产生一些笔误(甚至这篇文章里也可能有);以游戏的视角重新审视文本,有可能帮助我们发现更多笔误——不过很大程度上,严格的审核也能做到这一点。

当然了,测试的层次也有很多:丛用工具校验格式,到进入游戏审查语境,再到投稿到本仓库时的审核——这都是为了从源头上避免错译我们既然顶怕别人的错译,那就不要用自己的错译麻烦别人了。


^ 目录
P. 一般翻译的普遍要求 <--- ---> R.贡献流程导引