大概是我目前见过最好的Renpy游戏翻译教程V2.0 您所在的位置:网站首页 汉化的定义 大概是我目前见过最好的Renpy游戏翻译教程V2.0

大概是我目前见过最好的Renpy游戏翻译教程V2.0

2023-12-16 19:48| 来源: 网络整理| 查看: 265

        大家好!

        我是Moskys。

(译注:大家好,我是译者尼特。后文中原作者Moskys都以西班牙语为例,为了让使用中文的读者们更好理解,我对这些例子做了不少改动,若有违和的地方,敬请谅解。)

        既然你已经在看这篇教程了,那你应当已经知道,Renpy是一款开源且免费的游戏引擎(一般来说是用来制作视觉小说类游戏的),最近已经成为业余开发者们制作此类游戏的首选引擎之一。它基于Python编程语言开发,具有简单、灵活两大优点,可以让开发者们即使没有编程知识也能得到可以接受的成品。

        Renpy的功能多种多样,其中一个就是为使用这个引擎制作的游戏生成翻译文件,尽管引擎本身并不会进行翻译这个操作。我游玩各种复杂程度不同的Renpy游戏已有三年多的时间,并且还将其中许多游戏翻译成西班牙语。在2020年12月,我决定写下这篇教程的第一版,向对翻译感兴趣的各位解释翻译Renpy游戏的流程。

        现在,一年以后,我有了更多的经验,我又写下了这篇更充实(同时希望也更好)的教程。尽管这篇教程是面向非官方的翻译者们的,但其中记载的方法显然也可以帮到一些希望用多种语言发布自己的游戏的开发者们。

        请注意,我只会介绍如何做好翻译前的准备工作,以及如何解决翻译过程中可能遇到的一些技术问题;如果你想找的是帮助你快速翻译文本的工具,请另寻他处吧。不管你是机器翻译还是人工翻译,这篇教程都可以帮助你理解翻译Renpy游戏的整个流程,以及为你完善自己的翻译提供方法,但你不会学到到底要怎么去“翻译”。

0-.十步学会翻译

        行吧行吧,我都懂。这篇教程实在太长了,里面写了一大堆东西,你急着翻译呢,可能觉得根本用不上这么多。既然我没法给你一个做的很精致的视频教程,那我就简单说说翻译Renpy游戏时要做的十个主要步骤吧:

    1.    确保game文件夹里有.rpy后缀的脚本文件

    2.    如果没有的话,就使用UnRen等软件解包.rpa文件/反编译.rpyc文件。

    3.    你是在翻译某个游戏的一次更新吗?是的话,请把旧版本的翻译文件复制过来。

    4.    检查脚本文件,找出Renpy引擎无法侦测、导出的字符串。

    5.    启动Renpy引擎,并生成翻译文件:

        1)    选择你想翻译的游戏(如果工程列表里没有,就在设置里重新设置一下工程目录)

        2)    点击生成翻译文件

        3)    在“语言”这一栏里,填入你想翻译的对应语言(一定要记住这里你填进去的东西)

        4)    根据自己的喜好来决定要不要给“为翻译生成空字串”这一栏打钩

        5)    点击生成翻译文件

    6.    编辑游戏的设置界面,添加切换语言的选项。

    7.    翻译”game/tl/你输入的语言名称”文件夹里的每一个rpy文件。

    8.    把翻译完的游戏玩一遍,测试有没有bug:

        1)    游戏无法启动/不停报错?检查errors.txt和traceback.txt

        2)    有没有超出了文本框的文本?

        3)    有没有字体问题/方框字?有的话,尝试更换文本的样式(Style)

        4)    有没有办法翻译包含文本的图片?

        5)    有的选项尽管已经被翻译了,却感觉非常奇怪?可能是文本相同,但表达的意思却不同

        6)    有些词语还是显示原文?重新做一遍第四步,尽管这些词语也有可能是一些变量文本

        7)    还是没法把全部内容都翻译过来?那就试试最后一招吧

    9.    想分享自己的翻译吗?创建一个补丁吧。

    10.补丁已经创建好了?那就再进一步,发给游戏的作者看看吧!

1.-绪论1.1.-揭开Renpy游戏的面纱

        一个非常明显的道理,如果你想翻译一款游戏的话,那首先你需要先有这个游戏。任意打开一个Renpy游戏的根目录,你会看到这样的界面:

        一般来说,我们只会打开exe文件,就开始玩游戏了。但这次,我们要仔细看看这里面各个不同的子文件夹,那里才是魔法发生的地方。宽泛地讲,在“renpy”文件夹里,是预先写好的程序函数,而在“lib”文件夹里,存放着各种能让游戏在不同操作系统上运行的技术文件。这两个文件夹可以让我们不用下载任何其他软件,就能正常玩游戏;可以说这两个文件夹让Renpy游戏变成了能自动运行的程序。

        真正的游戏都藏在“game”文件夹里。这个可是复杂得很,你别被吓到了:

        这里面又有几个子文件夹,不过可以暂时忽略掉,先集中在这些单个文件上。在打包游戏的时候,Renpy会建议开发者们不对各种文件进行特别的处理,结果就会像图里显示的这样。我们可以看到有许多文件名相同的文件,但有的后缀是rpy,有的后缀是rpyc。这里面的文件的数量实际上只取决于开发者对游戏代码结构的把控,哪怕所有代码都在一个文件里,Renpy运行起来也不会有任何问题。但是,一般而言,只会有少数几个文件(比这个例子里的数量少得多),但也会有把文件存储在game文件夹里的几个子文件夹的情况。

1.2.-三个基本概念和两项基本原则

        这些在“game”文件夹里的文件被称作脚本。游戏的所有代码和文本都写在这些脚本里面。只需要在文本编辑器里输入需要的内容,然后用Renpy专用的后缀名“rpy”保存,就可以完成这一点。

        所以,只需要用像是Windows自带的写字板(或者用一些更好的程序,比如Atom或者Notepad++)之类的文本编辑器,就可以打开这些rpy文件,亲眼看看Renpy游戏到底是怎么被创造出来的。用游戏“What a Legend!”做个示范,打开其中的一个rpy文件,可以看到以下的代码:

        在#符号右边的所有内容都会被Renpy引擎忽略。所以开发者们都使用这个符号来写注释,注释不会在游戏内出现,但会方便作者在之后的工作。稍后我们会讲到这个符号对翻译者的用处。在第三行,可以看到一个词,label,这个词非常重要。一个label就是游戏脚本的一部分。这一部分到底有多大,取决于开发者本身,但一般来说,一个label就代表着一个场景或者一个场景中的一部分,在玩家游玩的过程中,看到的正是一个又一个label代表的场景。根据Python语言的语法,一个label中的代码全都要使用缩进,在一个label里可能还有其他使用缩进的区块,这些区块总是跟随在一行以冒号:结尾的代码后面。

        Renpy的第一项基本原则:一定要牢记缩进,并且永远不能使用Tab键来制造缩进,一定要用空格键(一般来说是4个空格)。如果Renpy检测到了Tab或者不匹配的缩进(也包括翻译文件中),游戏甚至根本无法启动。

        沿着图片里的代码继续往下看,就在这个名为“convo_gate”的label里,我们还可以看到一些其他的函数,用来控制屏幕上显示的图片,以及根据变量的值来决定玩家看到的不同场景。同时,我们还可以看到一些在引号里的句子:这些句子就是显示在屏幕上的对话。这些带引号的对话就是我们要翻译的主要内容,被称作串,或者文本串。

        Renpy的第二项基本原则:串的两端一定要用两个引号””包裹。如果串中有落单的引号,那么游戏将无法启动。

        在写文本串时,如果想要在文本中显示引号,那么需要用\”这种写法。只有这样,Renpy才会把引号识别为文本的一部分。

1.3.-Renpy(在我眼里)是怎么运行的?第三项基本原则

        考虑到我不是IT专家,也很可能说出一些很蠢的东西来,我会尽可能快速地解释一下当我们打开一个Renpy游戏时,到底会发生什么事。

        还记得”game”文件夹里那些克隆文件吗?实际上,它们并不算是克隆:有着.rpy后缀的文件是明文文件,开发者就是用这种文件来写代码的;但Renpy实际运行的却是.rpyc文件,这种文件是.rpy文件编译过后的版本。当开发者第一次在他们的电脑上运行自己的游戏的时候,Renpy会使用算法,根据代码在脚本里的位置和类别(文本串,变量,函数,等等),给.rpy文件里每个编程元素都分配一个独特的标识,而这些标识在编译后,就被存储在和原本的.rpy文件拥有相同的文件名的.rpyc文件里。为了进行最初的编译,Renpy会生成一个AST(Abstract Syntax Tree,抽象语法树)。这个AST中包含着刚刚提到的标识,并且能将它们全部连接起来,然后Renpy可以凭借着AST的指导,对游戏项目进行进一步的编译。

        每次游戏被启动时,Renpy都会寻找”game”文件夹里的.rpy文件,并且,如果这些文件存在的话(实际上这些文件并不一定存在,因为游戏的运行并不需要.rpy文件),就会开始编译,生成.rpyc文件。但是,如果对应的.rpyc文件已经存在的话,Renpy就会搜索AST中有关部分,并把上次编译之后,.rpy文件中新编辑的部分更新到.rpyc文件里。简单来说,让我们想象这样的场景。.rpy文件中的第三行代码经过了第一次编译,并被AST分配了标识“3”,于是它在.rpyc文件中就被存储为“3”。如果我们之后编辑.rpy文件,使得这行代码变为第七行,那么Renpy就会准备将其编译为“7”,但它又会检测到这行代码已经在.rpyc文件里被存储为“3”了,所以就不会进行改动。这样一来,已经存在的,且仍然在被游戏使用的内容,就会一直保留原本被编译时的样子,而新的内容在编译时也不会影响到原本已有的东西。

        为什么我要告诉你这些东西?因为,如果我们删除掉已有的.rpyc文件,那么Renpy就会生成一套新的,但是却没有了原本的AST作指导。这样一来,Renpy会使用现有的.rpy文件生成出所谓的“初次编译”。这就代表着在新的.rpyc文件中,标识之间的连接就和之前不同了:还用之前的例子,.rpy文件的第七行,在旧的.rpyc文件中依然被编译为“3”,因为它来自之前的版本;但要是生成了新的.rpyc文件,它就会被编译为“7”,因为Renpy没有旧的数据可以做参考了。这时,游戏依然可以运行,玩家若是开始新游戏,也不会受到影响。但是,一些涉及到AST的功能,比如在使用旧版本的.rpyc文件时保存的存档,就可能损坏。有时候,翻译也会受到影响。

        Renpy的第三项基本原则:不允许删除原本的.rpyc文件,因为这可能会给玩家带来预料之外的问题。

1.4.-Unren和.rpa文件

        在你打开“game”文件夹的时候,也有可能完全没有看到在1.1中提到的文件。这是因为,在打包游戏,准备发布时,Renpy会给开发者提供一些可选项。Renpy推荐的选项是在游戏中同时包含.rpy文件和.rpyc文件,但这也只是推荐而已。因为Renpy游戏仅需要.rpyc文件就可以运行,有些开发者在游戏里只会留下.rpyc文件。这样一来,游戏的体积会稍小一点,还有,可能更重要的一点是,玩家们就无法直接修改游戏的源代码了,因为.rpyc文件中没有可供修改的文本,只有乱码而已。

        还有一种可能性(这种情况其实非常常见),我们会发现在“game”文件夹里没有任何.rpy和.rpyc文件。这是因为开发者选择了Renpy提供的另一种打包游戏的方式:把脚本和其他文件(比如图片)全部压缩进.rpa文件里。这样一来,“game”文件夹里就不会有一长串的.rpy和.rpyc文件,而是会像下面这样:

        首先,我们可以确认,你可能也猜到了,这没什么大不了的。游戏依然可以正常运行,但要翻译的话,我们就要做一些额外的工作,因为我们必须要有.rpy文件才能进行翻译。幸运的是,有不少工具可以帮助我们完成解包的工作,并且完全不需要学习Python语言。考虑到其出色的便捷性,我认为最好用的工具是UnRen。

        在下载之后,需要把UnRen放入我们要翻译的游戏的根目录里,要注意的是需要跟游戏的exe可执行文件放到同一个目录里。看图的话应该能更快理解:

接着只需要运行UnRen并选择要做的操作就好了。这是UnRen的开始界面:

        不难看出,只需要用到键盘就可以了。选择要做的操作,然后输入对应的数字即可。

        选项1)会解包.rpa文件到“game”文件夹里,如果完成之后就已经可以看到.rpy文件了,那很好,我们不需要再做其他的了。这些脚本就是游戏的开发者使用的原文件,里面包含着所有开发者可能在#号后写下的注释(这些注释是非常有用的,有时可以帮助我们理解一些我们不知道该如何翻译的句子)。也有可能,在.rpa文件里也只包含.rpyc文件,这时我们就需要使用2)选项来把所有.rpyc文件反编译为我们翻译时需要用到的.rpy文件。

        在UnRen完成任务以后,我们回到“game”文件夹,可以看到原本被压缩在.rpa文件里的文件全部被解包了出来。根据游戏不同,甚至还可能看到一些同样包含着脚本的额外文件夹。

        现在我们可以开始翻译了。但是,首先,请让我解释一下接下来要做的事。现在,在“game”文件夹里有着.rpy文件和.rpyc文件,但是,在.rpa文件中,还压缩着同样的文件。这样一来,我们就真的有克隆文件了。还好,Renpy解决重复文件的办法比较简单:如果有两个相同名称的脚本,Renpy只会运行被改动过的时间更靠后的那个。在这个例子里,改动时间更靠后的就是我们刚刚解包出来的文件,于是,我们可以安心地删除掉原本的.rpa文件了。但是,一定要牢记第三项基本原则,我们永远不应该删除从中解包出来的.rpyc文件。

1.5.-Renpy引擎

        我们已经知道,Renpy游戏不需要安装额外的软件就可以运行。它们都是可以自启动的,也允许我们使用简单的文本编辑器对源代码进行修改。但是,显而易见的是,要想创建一个Renpy游戏,就必须安装一个软件。Renpy引擎就是那个使得我们可以制作Renpy游戏——以及进行翻译的软件。所以,要翻译Renpy游戏,第一步就是下载这个软件。它是免费的,不含病毒,完全可以信任。在下载并解压之后,就会看到这样的界面:

        这和我们看到过的游戏的结构有些类似,有许多子文件夹,并且至少在Windows版本里,有两个.exe文件(通用的.exe和32位版本的.exe,供老版本的Windows,比如XP和Vista使用)。我们只需要打开renpy.exe就可以开始工作了。在打开之后,可以看到Renpy的主界面。在“工程”这一栏里,可以看到两个游戏:“教程”和“The Question”;两个游戏都是帮助我们学习、理解Renpy编程的教程。要打开玩玩也无妨,但这两个教程对翻译并没有太大帮助。

如果安装打开之后,界面是用英文显示的,只需要点击红圈处的按钮,然后在右边选择Simplified Chinese即可切换为中文。

  

2.-开始翻译吧

        不管是开发者给我们提供了方便也好,还是我们通过努力最终做到了也好,总之到了现在,我们已经准备好了.rpy文件,可以开始翻译了。通常来说,我们一开始的想法会是打开源文件,并且直接修改脚本里的文本串。尽管这样的做法一样有效果,但是直接修改源文件不仅是在践踏开发者的心血,也会大大增加产生bug的风险。实际上,Renpy为翻译者们提供了不少贴心的辅助功能:有许多函数可以帮助我们提取出可翻译的串,使得我们可以不改动源代码就完成翻译的工作。当然,有时候我们依然要对源文件进行一些必要的修改,但是经由Renpy的翻译方法要比直接修改脚本干净许多,并且,学会如何使用Renpy进行翻译,并且克服这之中的种种困难和限制,正是这篇教程存在的唯一意义。所以,选择权在你手中。

2.1.-生成翻译文件(并且学习第四项基本原则)

        在打开Renpy引擎之后,第一步就是找到我们要翻译的游戏。我们要点击右下角的“设置”按钮,然后在“工程目录”这一栏,把目录设置为游戏的根目录所在的文件夹。例如,“Eternum”文件夹放在D盘根目录,那么我们就选择D盘。然后点击返回。

        回到主界面以后,可以看到工程目录里的所有游戏都会出现在左侧的“工程”一栏里。只需要点击选择对应的游戏,然后再点击右侧的“生成翻译文件”按钮。

        在这个界面的“语言”这一栏里,我们可以填入我们想要翻译的语言的名称。这个名称仅仅用作程序内部的识别,所以我们可以随意填写(需要注意的是不可以使用特殊字符,建议只使用英文字母)。最重要的是,一定要牢牢记住在这里填入的名字,并且也要记住Renpy的第四项基本原则:

        Renpy第四项基本原则:在Renpy中,不管在任何情况下,大写字母和小写字母都是不一样的。

        所以你可以填chinese,Chinese,schinese,zhongwen,hanyu,yellow或者Monkey。想填什么都可以。但显然,最好的做法是填一个能让人方便快捷地辨认出你翻译的语言的词。以及,我刚才也说过,最重要的是一定要时刻记住你在这里填进去的词,以及这个词具体的拼写。比如说,我一直用的都是“chinese”,开头的“c”是小写的,所以在之后的例子里也一直都会是这样的。

        然后我们可以看到有许多选项,目前来说,对我们唯一有用的选项就是“为翻译生成空字串”。这个选项打开与否,完全看的是个人喜好。在翻译时,我们总能看到一行原文本给我们提供指导,但如果打开这个选项的话,那么生成的翻译文件就只会有空行,让我们可以填入自己的翻译。如果不打开的话,那么原文本就会再显示一次,我们就必须删除掉这一行原文,并填入我们的翻译。

        这样来看,似乎生成空字串更加方便一些(实际上也确实如此),但是,如果我们不小心忘记翻译了某一行的话,那么当玩家在游戏里看到那一行文本的时候,屏幕上就一个字都不会显示。如果我们没有生成空字串的话,此时屏幕上还是会显示这句文本的原文,这一特性在测试没有完成的翻译的时候非常方便。这一点对于菜单界面来说尤为重要,因为不生成空字串使得我们可以在没有翻译菜单界面的时候,依然可以自由地调整游戏的设置。因此,我个人更喜欢不生成空字串。但是,就像我刚才说的,这完全是个人喜好的问题,你完全可以进行测试,选择最适合自己的方法。

        上图就是生成空字串与否的直观对比图,左生成空字串,右为不生成空字串。

        现在我们只需要点击红圈里的“生成翻译文件”就可以了。如同右方的说明文本说的一样,点击后Renpy引擎就会在“game/tl/chinese”文件夹生成翻译文件(最后一级文件夹的名称会随着你输入的语言名称不同而发生变化)。

        如果没有出现其他问题的话,在Renpy引擎放完魔法之后,一条提示成功的信息就会出现,我们就可以点击继续回到主界面,或者直接关闭Renpy引擎了。

        我们现在前往“game”文件夹,可以看到在“tl”子文件夹里有两个文件夹:一个叫做“None”(这个文件夹之前就已经存在了),还有一个刚刚创建的新文件夹,名称和刚刚填入的语言名称一致。在我的例子里,是“chinese”:

        在“chinese”文件夹里面,就是生成好的翻译文件了。Renpy引擎在生成它们的时候都做了什么呢?实际上,它按照字母顺序检查了所有原本的.rpy文件,然后一旦发现可翻译的文本,就生成一个与原文件具有相同文件名的.rpy文件(以及对应的.rpyc),把我们需要翻译的串写在里面。

        而且,还会生成一个名叫“common.rpy”的额外脚本(原本的common.rpy存放在“tl/None”文件夹里)。这个脚本里存储着Renpy游戏的菜单界面中通用的一些可翻译指令。比如说,在关闭游戏的时候弹出的询问我们是否确定的警告信息,残障人士辅助功能以及开发者界面,错误界面,等等。这个文件很大,翻译起来也很费劲,但也有个好消息:这个文件在所有使用相同版本的Renpy引擎制作的游戏之间都是通用的,所以可以把其他游戏里已经翻译好的文件直接复制过来。当然,在复制替换之前,我们还是要检查一遍,看看是不是每一条都能对上,因为有时候这些文件可能会有小的改动,使得出现意料外的问题,甚至创造出了相同的串,导致bug。

        到了这一步,只需要用我们喜欢用的文本编辑器打开“tl/chinese”文件夹里的.rpy文件,就可以开始工作了。我们可以更改这些脚本文件的名字(甚至全部合并到一个文件里),因为Renpy是逐行、逐串地寻找翻译的,并不关心这些翻译被存放在哪个文件里。但标准的做法是“什么都别碰”:这样一来,可以更容易分辨出每个翻译文件和原文件之间的关系。

 

2.2.-两种翻译函数(以及又一项基本原则)

        当我们第一次开始翻译的时候,一种并不少见的情况是,我们突然发现要翻译的文本跟原脚本中写的顺序或者/以及和游戏中出现的顺序并不相同。不用怕,这完全是正常的,因为,在从游戏的脚本中提取可翻译的串的时候,Renpy会把它们分成两组:一组是所谓的“对话块”中包含的所有串,另一组是菜单选项,变量,角色名字等等所对应的串。为什么这样子?因为这两个组所使用的提取方法和翻译函数都是不一样的。

        2.2.1-对话块和加密码:Renpy引擎可以没有任何问题地把对话块中的串全部识别并提取出来。但之后对这些串进行的操作则有些麻烦,因为它们会被加密,以节省内存:每行代码,根据其所在的label以及这行代码本身的内容,都会使用8位的16进制MD5加密法进行加密,得到一个字母与数字混合的独特标识码。这一特性配合例子来说明会更加容易理解。首先,我们来看看来自游戏“Eternum”的“script.rpy”中的一段:

        第一行有着可翻译文本的代码(第一个“串”)是第236行:在“start”这个label里,一个标识为a的角色说了“Hi!”(with dissolve是一种转场效果)。这一行之前的所有代码都不包含可以翻译的文本。

        在生成空字串的情况下生成翻译文件之后,Renpy就把源代码中的所有信息转换成了上图中的样子:所有那些函数和代码指令都被移除了,只留下了可以翻译的文本串,每个原串都对应着一个四行代码的代码块。我们通过看缩进就可以分辨出不同的代码块:每当看到一行在最左端开始的代码,就是一个新的翻译块。

        现在,我们来分析一下这些代码块吧:

        我们已经知道,#号后面的内容都是注释,可以任意删除,不会有任何影响,尽管我并不建议这么做。第一行注释告诉我们这句话位于原文件的哪一行:是“script.rpy”文件的第164行。另一行以#开头的句子就是需要翻译的原文,Renpy把它放在这里是方便我们知道要翻译的内容。最后一行是我们填入译文的地方(我们应该只翻译在上一行的引号里的内容,其他的部分都应当保持原文不动)。如果我们没有生成空字串的话,这里就会再显示一次原文,我们就需要把它删掉之后再填入译文。

        第二行代码是关键。就是这行代码激活了这一个代码块所代表的那一行源代码的翻译函数。当我们在玩一个被翻译过的游戏的时候,Renpy实际上运行的是“game”文件夹里的.rpyc源文件,但同时又收到了指令,使得它必须把翻译过后的文本显示在屏幕上,而不是原来的文本。这条指令告诉Renpy,对于每个对话块里的串,都必须检查脚本,寻找一行带有translate指令以及合适的语言(这个例子里,就是“chinese”,也就是生成翻译文件时填入的那个词),以及被分配给源代码的加密码的代码。这个加密码以代码所在的label为起始(start),之后则是那一行文本的内容用MD5加密算法加密之后的结果:显然根据这个算法,a “Hi!” with dissolve在加密后就会变成ea0fb88e。

        那么,如果在同样的“start”这个label里,有一个完全相同的串(又是这位a说了一句“Hi!”,还带有with dissolve),Renpy会给它分配一个相同的加密码。但这样一来就会出现冲突,所以在加密码后会加上一个_1以示区分,以此类推。这样一来,对于每个串,都会有一个与之对应的独特的加密码,哪怕是完全相同的串也是如此,这就意味着原对话块里的所有串都会被提取到翻译文件里。所以,如果有十个相同的串,那我们就要填同一个句子十次,因为我们实际上是在翻译十个不同的代码。

        但是假如我们把源代码里的“Hi!”改成“HI!”,或者改变说话的人呢?这样的话,那句话原本的翻译就不起作用了,因为修改之后它对应的MD5码就是新的了(原因是我们改变了用来计算MD5码的内容),使得Renpy无法在翻译文件里找到新的加密码,所以就会显示原文。这一特性使得我们在翻译正在开发的游戏的新版本的时候会遇到很多麻烦,因为开发者经常会修改一些不起眼的错别字,或者重写某些地方的句子。对原文本的任何修改都会使得加密码发生变化,于是对Renpy来说,它就已经变成完全不一样的新句子了,我们就需要重新翻译一次。如果一个串所在的label的名字发生了变化,那么哪怕其中的代码没有任何修改,我们也会遭遇同样的困境。

        Renpy的第五项基本原则:对源代码中原文本的任何一丁点修改都会使得原有的翻译失效。

        Renpy现在添加了一项新功能,可以帮助我们避免这个问题:如果开发者把旧的MD5码添加到编辑后的代码里(比如说:a “Hi!” with dissolve id start_ea0fb88e),那么Renpy就仍然能够识别旧的翻译。遗憾的是,几乎没有开发者知道这一点。

 

        2.2.2.-剩下的串与old和new指令:正如刚刚提到的一样,Renpy使用两种不同的翻译方式。除了基于加密码的方式以外,剩下的那些不在对话块里的串是用一种更加简单的直接翻译法。那么我们在谈论的是哪种串呢?基本上就是玩家们在游戏中遇到的选项,但还有角色的名字,储存有文本的变量,以及像是设置或者是保存/读取界面的系统菜单,等等。

        当Renpy在进行翻译操作的时候,所有这些串都会通过直接替换的方式显示在屏幕上,而不会有任何加密。为了做到这一点,在生成翻译文件的时候,Renpy引擎会把这些串集中放到脚本的底部,具体来说是放在”translate chinese strings:”指令之后。

        上图中显示了“Eternum”中“script”的翻译文件第二部分的开头。可以看出,其中并没有奇怪的代码。而且只需要一行”translate chinese"指令,就可以翻译跟在其后的所有串。第一行依然是#号开头的注释,用来提醒我们文本位于原文件的哪个位置。但之后则是使用“old”指令显示的原文本,我们需要把译文填入“new”指令之后。要注意,现在,原文并不是用来给予我们指导的文本了,而是翻译函数的一部分:作为MD5码的替代,“old”中的值正是Renpy要寻找的东西。

        我们一定需要注意的一点是,在生成翻译文件时,如果有某几个串中的文本是相同的(即使它们位于不同的脚本或label中),Renpy引擎只会提取出最先扫描到的那个串(要注意这里和提取对话块中的串时的区别,在那种情况下,即使串的内容相同,也都会被全部提取出来)。之后,在运行游戏时,每个与“old”中的文本相同的文本,都会被“new”中的译文文本替换。所以,在我们翻译过上图的文本之后,我们就不需要在其他地方再翻译一次“Do you want pregnancy content?”了,每当这句话出现的时候,对应的翻译都会显示在屏幕上。

        尽管这可能会给我们省下一些麻烦,但在遇到某些文本相同,所表达的意思却完全不同的文本串时,却会变得非常不方便。举例来说,一个内容为“Right”的串,有时候它的意思可能是“正确的”,但根据上下文,它也可能是“右边”的意思。Renpy引擎只会提取出第一个“Right”串,我们也只能翻译它一次,也就只能有一个译文显示出来,所以有时候译文会驴头不对马嘴。稍后我们会介绍如何解决这个问题。

        理论上说,这种直接替换式的翻译方法可以应用于游戏中的每个串,但是对话块通常来说有着非常多内容,其中有许多很长且几乎不会重复使用的句子。当Renpy要显示翻译时,搜索、替换加密码花的时间要比搜索、替换更长的句子少很多。然而,这些使用直接替换式的文本串往往很短,在数量上也很少,同时还更有可能在脚本中的不同地方被重复使用,所以Renpy有足够的时间搜索它们的文本内容,而不至于出现卡顿。这就是两种翻译方式被同时使用的原因。

        总之,这些都是忘记也无妨的额外知识。真正重要的是,Renpy引擎会把文本串识别为成两种类型,并对它们使用不同的两种翻译方式,这也是为什么我们在翻译文件里会看到它们被分为了两个部分:首先我们会看到属于对话块的串,之后是所有来自菜单、设置和变量的串。

 

2.3.-确保提取出所有文本串

        在上一节中花费篇幅解释Renpy的两种翻译函数的原因是,很遗憾,Renpy引擎并不是总能提取出游戏里的所有可翻译的串:尽管所有在对话块中的串都总能被全部提取出来(归功于它们独特的加密码),但使用直接替换法进行翻译的串却往往不能被全部识别并提取(幸运的是,这个问题并不会影响到游戏内玩家要选择的选项,那些串都会被提取出来)。

        举例来说,要想让Renpy引擎自动探测并提取出角色的名字,那游戏的开发者就需要在定义角色名时进行一些额外的操作。不过,因为这一点并不为人所知,许多开发者并不会这样做。但如果他们不做的话,我们可以做。

        让我们看看“Eternum”的作者是怎么定义故事中的其中一个角色的。可以看到,在“script.rpy”里,他创建了一个名为Annie的角色:

        这是一行典型的Renpy代码。开头的是指令(define),用来表明这一行代码的具体作用,在这个例子里就是定义一个变量。这个变量被分配了一个名字(a),用以在脚本的其他地方辨识它,还被指定为角色类型的变量(Character)。这样一来,Renpy就会知道,只要它在一个串之前发现了a这个字母,那就必须在文本框上面显示一个名字,好让玩家知道是哪个角色在说话。到底会显示什么名字呢?那就是括号中的内容:角色的名字(“Annie”),以及对应的颜色。

        显然,“Annie”是一个我们需要翻译的串,但实际上我们用Renpy引擎生成翻译文件之后,这个串不会出现在任何地方。实在是Renpy的未解之谜。那我们该怎么办呢?我们有三个选项。第一个选项,也是我们根本不会选的,就是放着不管,让它一直以原文状态显示。第二个选项,也是最推荐的做法,是让Renpy引擎理解,这个串是需要翻译的文本串,而不是像是定义颜色一样的代码。请看:

        我们修改了原脚本,把“Annie”放进了括号里,还在括号前加上了下划线,就像这样:_(“Annie”)。这个特定的符号组合,也就是_(),会让Renpy引擎知道,括号内的内容是需要翻译的文本串。而这时我们再生成翻译文件的话,就可以看到我们刚刚修改的那个串也出现在翻译文件里了。

        可以看出,如果我们不把源代码中的“Annie”修改为_(“Annie”)的话,它根本不会出现在翻译文件里。但这并不意味着我们永远没法翻译它了:既然这种串使用直接替换式的翻译,那我们总是可以不借助Renpy引擎,直接把对应的串写进翻译文件里。这就是我上面说的三个选项里的最后一个:我们可以不修改源代码,而是把Renpy引擎没法探测到的串全部手动写进翻译文件里。具体如何做,可以参照上文对old和new命令的介绍,再注意遵守Renpy的五项基本原则即可。

        不管你最终到底选择哪种方法,总而言之,为了翻译完所有内容,我们都必须浏览一遍游戏的所有脚本,并且重点寻找以下这些代码,因为它们不会被Renpy自动检测并提取:

·Character(“...”),用来定义角色,我们已经在例子里看过

·text “...”,用来在文本框以外的地方显示文本

·textbutton “...”,用来显示可以在点击后执行某种操作的文本

·tooltip ‘...’,用来在鼠标悬停在某处时显示出一条提示信息

·renpy.input(“...”),用来在游戏内打字输入(一般是让玩家给角色命名)

·$ renpy.notify(‘...’, ‘unlock’),用来在完成一项操作后显示一条信息

除此之外,还有值为文本的变量:

·default variable_name = “...”

·define variable_name = “...”

·$ variable_name = “...”

        总之,要点就是把上面提到代码的引号外面加上 _( ) 再生成翻译文件,或者是把其中的内容复制到翻译文件里,使用old和new指令对进行翻译。需要注意的是,需要把引号内的内容全部复制过去,而不是只复制需要翻译的文本。有时,文本后还会有放在{ }里的标识,用来让文本以加粗,斜体,另一种字体,不同大小等等样式显示。这些标识也是Renpy搜索并替换的一部分,所以必须出现在old指令后的引号里,好让Renpy可以正确识别出这个串来。还有,有时候,要让翻译能被正确显示的话,我们还需要再做一些额外的工作。

        最后,再额外补充一点:_( )符号组只会被Renpy用来提取括号内的串,而对实际的翻译功能的实现来说并不是必要的。因此,当翻译一款游戏的更新的时候,如果一些串已经被提取过了,那么没有必要再次修改源代码。而且,也没有必要把添加了_( )符号的修改过的脚本文件放入我们制作的翻译补丁里,因为玩家在玩翻译版本时并不需要用到。

2.4.-翻译更新

        在如今这个时代,游戏在发布时并不完整,而是以章节的形式慢慢更新发布的情况是非常常见的。这样一来,我们在新版本发布时就必须更新我们的翻译。这个过程并不复杂……除非我们要用Renpy引擎推荐的方式来做。Renpy给我们提供的正式做法是,使用其提供的一项功能提取出游戏旧版本的翻译,再导入新版本的游戏里,并把新的内容更新到翻译文件里。然而,悲惨的现实却是,一旦检测到新版本的源文件与旧版本的有差别,Renpy引擎就会生成一个新的翻译文件,而不是和已有的翻译文件合并,这样一来我们就要做重复的工作了。所以,最有效率的做法是按着以下的步骤做:

    1.    下载游戏的新版本。

    2.    如果需要的话,使用UnRen提取出.rpy文件。

    3.    把旧版本游戏中的“game/tl/chinese”文件夹(也就是我们的翻译文件夹)复制到新版本游戏的对应位置。

    4.    使用Renpy引擎生成新版本的翻译文件。

        如果我们在第四步中使用的语言和之前版本保持一致(也就是说,和上个版本生成翻译文件时填入的那个词语一模一样,丝毫不差),并且不选中“替换已存在的翻译”,Renpy引擎就会把无法找到有效翻译的串更新到现有的翻译文件里去。假如有新的脚本文件的话,那理所当然的也会生成新的翻译文件。总之,在生成结束后,只会添加新的未翻译的语句,而不会影响到我们之前已有的工作。

 

2.5.-对翻译进行翻译

        有时候,会有游戏以我们不会说的语言发布。我们当然可以使用机器翻译,但是我们都知道机器翻译的质量具有很大的进步空间,而且即使我们花时间进行润色,也有可能没法完全理解并翻译其中的一些俗语和表达。但有一种可能性是,尽管游戏的原语言我们并不了解,但已经有人把它翻译成了另一种我们会说的语言,或者开发者在发布游戏时,就已经包含了其他语言的翻译;在这种情况下,我们可以在他人的翻译的基础上来进行我们的翻译。

        假设其他的译者遵循了这篇教程中讲解的翻译方法,那么现在应该已经存在“game/tl/MyLanguage”文件夹了(这里的MyLanguage指的是其他译者在翻译时填入的语言名称)。其中有着所有的翻译文件,并且文本串都已经被翻译成了对应的语言。我们已经知道,这些翻译文件里都有两部分:一部分是对话块里的串;另一部分是变量、选项、菜单等等。在这些脚本里我们可以看到前文中已经讲解过的翻译函数,只是语言的名称从之前讲解时用的“chinese”变为了“MyLanguage”(当然,我们也会看到被翻译成了其他语言的文本)。

        在这种情况下,我们在生成翻译文件时就可以不使用Renpy引擎了:只需要在“game/tl”文件夹内新建一个文件夹,并取名为“chinese”,然后把“game/tl/MyLanguage”中的所有文件全部复制粘贴过来即可。接下来,我们把翻译文件里所有翻译函数中的“MyLanguage”替换为“chinese”就可以了。这一点通过文本编辑器的查找与替换功能可以轻易实现。

        现在,对于那些使用了加密码的对话,所有的 translate MyLanguage XXXXXXXX: 函数都应该变为 translate chinese XXXXXXXX: (注意,每行文本的加密码只与原文件中的label和句子中的内容有关,所以对于每种语言来说,加密码都是一样的)。而使用直接替换法的翻译函数则会发生这样的变化:从 translate MyLanguage strings 变为 translate chinese strings 。

        这样就大功告成了。接下来,我们把已翻译的文本再翻译成我们的语言,之后再替换掉原有的文本,就可以完成对已有的翻译进行翻译的操作了。

 

2.6.-切换语言的选项

        最后,或者说应该在翻译前最开始就应该做的事,就是我们要考虑如何在翻译完成后,能让玩家切换到我们制作的翻译。我们需要知道的是,在默认情况下,所有Renpy游戏都会以初始语言启动,这个语言在Renpy内部被标识为None(与实际的语言叫什么无关);在第一次启动以后,之后每次打开时,游戏都会显示最后一次被选择的语言。举例来说,游戏是用英语写的,因此第一次启动时会显示英语,但如果我们在游戏启动后选择了切换到西班牙语,然后退出游戏,那么之后再打开的时候,游戏就会显示西班牙语了。

        不过,这种默认的设置是可以通过代码进行更改的。首先要提到的这段代码可以用来命令Renpy在第一次启动游戏时就使用其他语言,而不是原本的None语言。我们可以打开任意一个脚本文件(甚至是翻译文件也可以),然后不使用任何缩进,写下这行指令:

define config.default_language = “chinese”

        在这里,chinese只是我使用的语言名称,请将其替换为你在创建翻译文件时使用的语言名称。这一指令会让Renpy在第一次启动时就使用指令中指定的语言,但也仅限第一次启动,之后还是会遵循Renpy的默认设置:也就是说,如果玩家在第一次启动后切换回了游戏原本的语言,那么游戏在下次启动时还是会使用原语言。这个做法的问题在于,如果玩家在安装翻译补丁之前就已经打开过了游戏,那么这一指令就会变得毫无用处,因为已经有其他的语言被标记为“上次使用过”了。

        也有可能,开发者在制作游戏时使用了自己的语言,但在发布时自带了其他语言的翻译,同时也使用了这个 config.default_language 指令来让第二种语言作为默认的启动语言。这样,在原文件中(最可能是在gui.rpy或者options.rpy里,但具体的位置并不重要)就可以找到这行代码。我们可以编辑这行代码,把原语言换成我们的语言(不过更好的做法是使用后文会提到的 init 指令),但是,不管怎么说,只要玩家在安装我们的翻译补丁之前启动过游戏,在安装了翻译补丁之后,再次启动游戏时,使用的语言也不会自动变化。

        所以,如果我们想让游戏无视上次退出之前使用的语言,并且总是用我们的语言启动的话,我们就要在脚本的任意地方,不加缩进地写下这行代码:

define config.language = “chinese”

        这样一来,哪怕玩家在上次玩的时候选择了其他语言,游戏也永远都会以指定语言启动。也就是说,config.language这个变量不仅覆盖了config.default_language,还同时禁用了Renpy中有关默认启动语言的设置。

        总之,即使我们强制游戏以我们的语言启动,我们也应该总是给玩家提供在游戏中切换语言的选项,而最合理的做法就是在游戏的设置界面中添加切换语言的选项。假设游戏使用了Renpy的默认设置界面,那么在源文件中的screens.rpy里,我们可以看到screen preferences ( ): 的部分:

        在这篇教程的第一版中我已经提到过,我们应该编辑这部分代码,并在与“Rollback Side”和“Skip”有着相同缩进的地方添加下列代码(请时刻牢记用空格键来制造缩进):

    vbox:

        style_prefix “radio”

        label _(“Language”)

        textbutton _(“English”) action Language(None)

        textbutton _(“中文”) text_font “此处使用你的字体路径”action Language(“chinese”)

        显然,这里的 _(“English”)文本按钮仅在游戏的原语言是英语的时候才合理;如果游戏的原语言是其他语言,这里就要填入其他的语言名称,但不要改动这一行其他的地方,因为无论原语言的名称叫什么,在游戏内部使用的名字都是None。而且我刚刚也提到过,这些代码只有在游戏使用Renpy默认的设置界面时才有作用。如果游戏使用了自制的设置界面,你就应该仔细研究一下新的设置界面的代码,试着用类似的风格添加代码。最简单的做法就是复制其他部分的代码,并更改其中的textbutton和action。

        但最重要的是,在添加了textbutton(或者imagebutton)的screen之后,必须添加一个点击之后可以激活 action Language(“chinese”) 指令的选项。这里的“chinese”是生成翻译文件时填入的语言名称。如果这里的名称和当初填入的不符(比如说写成了“Chinese”)那么Renpy就没法探测到我们的翻译,使得这个按钮失效。另一点需要记住的是None这个词从来不会出现在引号里,但其他的语言都要被引号包裹。

        可以看出,在上文的代码里有几个使用了 _( ) 符号包裹的串,我们已经知道这个符号内的文本会被Renpy标识为可翻译并提取出来。但是,我们应该只翻译“Language”这个串,因为所有语言的名字都应当一直使用其对应的语言显示。比如说,假如我们不翻译“English”这个词,然后,偶然有一个不懂我们的语言的玩家下载了被我们翻译过的游戏,那他在看到没有被翻译的“English”之后,可以很容易地联想到这个按钮可以帮他把语言切换为英语。想象一下,当你被不认识的文字和符号包围的时候,突然看到了你自己的语言的名字,那你该有多高兴啊!这下,你应该就明白为什么语言的名字永远都要用对应的语言写出来了吧。

        当然,要在Renpy的默认设置界面中添加切换语言功能的方法有很多种,甚至多到我无法一一列举。但说到底,这些方法到头来都要用这两种方法的其中之一:要么是添加 action Language(“chinese”) 这个前面已经提到过的指令,要么是激活 $ renpy.change_language(“chinese”) 这个变量(这个方法通常是在切换语言选项作为游戏内的一个问题出现的时候被使用)。但我非常建议你多做点逆向工程,并且多看看Renpy的帮助文档和交流论坛,学习一下如何创建和编辑界面、图片、按钮等等。要添加一个按钮,实际上有许多虽然比较复杂,但视觉效果要好得多的方法。

        话虽如此,在一年的实践和学习之后,我得出的结论是:最好的方法是复制出一个设置界面来,并且在玩家使用翻译时转而显示带有语言切换的新界面,而不是原本的界面;原本的界面不要做任何修改,这样如果玩家决定删除翻译补丁,就可以让游戏变回没有修改过的原版。现在我使用一个特定的.rpy文件来处理这个修改过的界面,还有一些其他的修改,具体的方法在后文我会提到。

        胡适不打牌(转载者)说:

        因为哔哩哔哩专栏字数限制,剩下一半的内容见#2

        内容是关于:遇到各种bug的解决办法,无计可施的“三把宝剑”,各种函数的讲解,翻译补丁的制作方法等等。非常有含金量,也是教程最重要的部分。

        但是我个人感觉,前面几章的内容已经足够让你翻译出一点东西了。而剩下的是大佬们总结出的一些应对各种情形的解决方法,想要理解不能光看,得多实践。遇到不懂的再来学习。

        所以,如果你是翻译的初学者,或者是像我一样已经入门的萌新,建议好好看前面的内容,然后去具体地做一些工作,发现问题,带着问题好好研究剩下的教程,这样会学的更快更好。

        喜欢请多多三连支持!我们有缘再见!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有