多语言支持 link

(译者注:原文为“Translation”。将translation直译为“翻译”,容易引发歧义,所以文档中单独出现时一律使用“多语言支持”,“translation file”则翻译为“翻译文件”。) Ren’Py包含了视觉系小说多语言支持的综合框架。有4类要素支持多语言:

对话

脚本的主对话能够支持多语言,包括各行文本内容的分割、合并、删除和调整的一套规则。

菜单和接口字符串

所有接口文本都支持多语言。

图像和文件

选择某种语言时,可以使用对应的一系列图片和其他文件。

样式

可以基于语言实现样式定制化,这样游戏会自动切换为对应某种语言的样式。

目前Ren’Py的多语言支持主要聚焦在标准化的多语言支持。如果实现的话,创作者就可以使用将游戏脚本直接扔给多语言解释器,或者自己创建多语言模板。目前支持的非标准化多语言支持有诸多限制。

主语言和备选语言 link

Ren’Py需要每一个作品都使用一种主语言编写。这种主语言无论具体是哪国的,都被称作 None 语言。(如果使用英语编写,英语就是 None 语言。)

备选语言在作品中出现时,推荐使用原来的Python标识符连写两次。(格式为,以字母或下划线开头,后面跟字母、数字或者下划线。)

当选用None语言后,Ren’Py的大多数多语言支持功能都会关闭, 例如Ren’Py内建的异常提示字符串和默认菜单项等。 在你项目代码中找不到这些字符串,也不会放入游戏的最终分发版中。 你可以在 game/tl/None/common.rpym 文件中找到这些字符串。 这些字符串的用处有两点: 1. 非英语做为None语言时提供多语言支持; 2. 允许创作者在游戏中自定义翻译。

启动器的语言会作为项目创建时的默认语言。Ren’Py内部的字符串初始化时也会使用同种语言。

生成翻译文件 link

当项目脚本是正常可用的情况下,我们可以在Ren’Py启动器中选择“生成翻译文件”。启动器将提示你需要生成的语言名称,然后创建或更新翻译文件。

翻译文件是在game文件夹中一个名为“tl”的子文件夹下的同名目录中。例如,如果你为tutorial项目创建了piglatin的语言支持,对应的语言支持文件将会放在 tutorial/game/tl/piglatin 目录下。

每一个游戏脚本文件都会被创建对应的翻译文件。common.rpy文件也会被创建,其内容包含所有Ren’Py制作游戏使用的通用字符串的多语言支持。

多语言对话 link

因为Ren’Py是一个视觉系小说引擎,我们最需要的自然就是对话的多语言支持。Ren’Py包含了一个具有可塑性的框架,允许对话内容的分割、合并、调整顺序及整段删除。

多语言支持的单元 link

一个由0个或多个可支持多语言的语句构成的语句块(block)是多语言支持的基础单元,后面可选加上一条say语句。可支持多语言的语句包括voice和nvl语句。例如下面脚本中的:

label start:
    e "Thank you for taking a look at the Ren'Py translation framework."

    show eileen happy

    e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."

    e "Pretty much everything your game needs!"

这段脚本可以分割为多个多语言支持单元。每个单元都有对应的一个标识符用于声明该单元。标识符根据单元前的脚本标签(label)和单元内的语句来生成。(如果多个单元被声明为同一个多语言数字,从第二个单元开始会自动添加上一个自然数编号便于区分。)

在上面的样例脚本中,第一个单元生成的标识号为start_636ae3f5,包含这条语句:

e "Thank you for taking a look at the Ren'Py translation framework."

第二个单元的标识号是start_bd1ad9e1m,包含这条语句:

e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."

第三个单元的标识号是start_9e949aac,包含这条语句:

e "Pretty much everything your game needs!"

当游戏脚本加载时,这些多语言支持的单元会被Ren’Py自动创建。

translate语句 link

当你生成了对某种语言的支持时,Ren’Py会针对每一个多语言支持单元生成一条translate语句。我们再以刚才的那段脚本举例,Ren’Py生成的语句如下:

# game/script.rpy:95
translate piglatin start_636ae3f5:

    # e "Thank you for taking a look at the Ren'Py translation framework."
    e ""

# game/script.rpy:99
translate piglatin start_bd1ad9e1:

    # e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
    e ""

# game/script.rpy:101
translate piglatin start_9e949aac:

    # e "Pretty much everything your game needs!"
    e ""

编辑这个文件就可以实现对piglatin语言的支持了。完成编辑后的样子如下:

# game/script.rpy:95
translate piglatin start_636ae3f5:
    # e "Thank you for taking a look at the Ren'Py translation framework."
    e "Ankthay ouyay orfay akingtay away ooklay atway ethay En'Pyray anslationtray ameworkfray."

# game/script.rpy:99
translate piglatin start_bd1ad9e1:

    # e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
    e "Eway aimway otay ovidepray away omprehensivecay ameworkfray orfay anslatingtray ialogueday, ingsstray, imagesway, andway ylesstay."

# game/script.rpy:101
translate piglatin start_9e949aac:

    # e "Pretty much everything your game needs!"
    e "Ettypray uchmay everythingway ouryay amegay eedsnay!"

当引擎在主线脚本中遇到一个语句块(block),Ren’Py就会检查是否存在对应的translate语句存在。如果存在的话,Ren’Py将会执行translate语句,并向用户显示对应语言的内容。

更复杂的多语言支持 link

translate语句中数量并不要求与原语言语句数量保持1比1。例如,一行很长的语句可以分割:

# game/script.rpy:99
translate piglatin start_bd1ad9e1:
    # e "We aim to provide a comprehensive framework for translating dialogue, strings, images, and styles."
    e "Eway aimway otay ovidepray away omprehensivecay ameworkfray..."
    e "...orfay anslatingtray ialogueday, ingsstray, imagesway, andway ylesstay."

或者某条语句可以移除,并用 pass 语句代替。:

# game/script.rpy:101
translate piglatin start_9e949aac:

     # e "Pretty much everything your game needs!"
     pass

甚至可以运行非对话型的语句,比如条件语句或者Python语句。例如,我们可以把下面这句:

e "You scored [points] points!"

在其他语言中写成:

# game/script.rpy:103
translate piglatin start_36562aba:

    # e "You scored [points] points!"
    $ latin_points = to_roman_numerals(points)
    e "Ouyay oredscay [latin_points] ointspay!"

小贴士 link

在处理多语言支持的对话内容时必须非常小心,特别是某个脚本标签(label)下某个对话内容重复多次的情况。在某些时候,有必要在主语言脚本中直接声明多语言支持的标识符,像这条语句:

有时候,需要修改原语言对话内容中的某一行,但不想要修改所有翻译文件的对应内容。 例如,英语中修复了个拼写错误,但不想要修改俄语的翻译文件。

此时可以在say语句中使用 id 从句,指定语言的翻译ID。 例如:

label start:
    e "This used to have a typo." id start_61b861a2

增加文本标签(label)也可能会导致多语言支持冲突。为了防止这种情况出现,脚本标签(label)后加上一个 hide 分句就可以在翻译文件生成时忽略这个标签:

label ignored_by_translation hide:
    "..."

由于多语言语句块(block)中可以包含Python语句,这些Python语句不应该在超过其所处语句块(block)之外造成任何副作用。这是因为,切换语言会重启多语言支持语句块(block),语句块内的Python语句的副作用会发生多次。

菜单和字符串的多语言支持 link

除了对话,Ren’Py也可以提供菜单与其他字符串内文本的多语言支持。接口的各种语言文本条数是严格1比1对应的。某个字符串被对上的话,就能被另一种语言的字符串替换。

当生成翻译文件时,Ren’Py会扫描脚本文件中的菜单和 _()函数中定义的字符串。然后它会将这些字符串内容放入一个多语言字符串语句块(block)中。例如,如果我们有如下的脚本内容:

define e = Character(_("Eileen"))

# ...

menu:

    "Go West":
        # ...

    "Head East":
        # ...

Ren’Py会自动生成:

translate piglatin strings:

    old "Eileen"
    new ""

    old "Go West"
    new ""

    old "Head East"
    new ""

完成后的多语言支持内容为:

translate piglatin strings:

    old "Eileen"
    new "Eileenway"

    old "Go West"
    new "Ogay Estway"

    old "Head East"
    new "Eadhay Eastway"

字符串的多语言支持用于在对话中内插的某些字符串。那些字符串不能以对话形式支持多语言。

如果某个字符串同时用在多处,可以使用{#…}文本标签(tag)加以区别。尽管这些字符串使用同样的名字,Ren’Py把这些稍有差别的字符串看作需要多语言支持:

"New"
"New{#project}"
"New{#game}"
"New{#playlist}"

translate字符串语句可以用来对None语言脚本的转换。在使用非英语编写的游戏中,translate字符串语句可以用来转换Ren’Py的用户接口。:

translate None strings:
    old "Start Game"
    new "Artstay Amegay"

多语言替换 link

!t标志用于表示多语言的字符串转换。下面这段脚本使用了原对话和多语言字符串的组合:

if mood_points > 5:
    $ mood = _("great")
else:
    $ mood = _("awful")

"I'm feeling [mood!t]."

提取和复用多语言字符串 link

多语言字符串可以从某个项目中提取,然后移植到另一个项目。完成这点需要以下步骤:

  • 选取来源项目,并选择“生成翻译文件”。

  • 输入需要提取的语言,并点击“导出字串翻译”。

  • 回到主菜单,选取目标项目,并选择“生成翻译文件”。

  • 输入需要复用的语言(通常与之前提取的语言相通),并选择“合并字串翻译”。

这里有两个选项,控制语言的复用功能:

替换已存在的翻译

如果选用这项,已经存在的重要翻译文件会被覆盖。默认情况下,复用过程会拒绝覆盖已经存在的重要翻译文件。

反转语言

在复用之前反转主备语言类型。例如,使用一个原本英语为主语言俄语为备选语言的项目,复用为“俄语为主语言英语为备选语言”的项目时,就需要勾选该项。

图片和文件的多语言支持 link

当让一个游戏支持多语言时,最好替换文件时带一个语言版本号。例如,某个图片包含文本,最好的办法是使用带其他文字的图片替换。而那个新的图片带一个语言版本号。

Ren’Py遇到这种情况时,会在translation文件夹里寻找对应的图片。例如,假如使用了“piglatin”语言,并加载了“library.png”图片,Ren’Py就会使用 game/tl/piglatin/library.png 图片代替 game/library.png

如果文件位置直接在game目录中,该目录应该包含在对应的语言中。 例如,文件 game/gui/main_menu.png,可以使用 game/tl/piglatin/gui/main_menu.png 作为多语言替换图。

样式的多语言支持 link

当对某个游戏实现多语言支持时,最好变更样式(style)——特别是那些与字体相关的样式。Ren’Py使用多语言样式语句块(block)和多语言python语句块处理这类情况。这些语句块(block)可以更改语言相关的变量和样式。例如:

translate piglatin style default:
    font "stonecutter.ttf"

更常见的是,对话使用的字体由 gui.text_font 决定。 系统文本,比如异常界面、可达性菜单和GUI菜单,都由 gui.system_font 项决定。 系统使用的字体应能同时显示ASCII码和其他对应语言文字。 综上,可以这样定制:

translate piglatin python:
    gui.text_font = "stonecutter.ttf"
    gui.system_font = "Noto Sans.ttf"

当某种语言被激活——无论是游戏开始时还是中途修改语言——Ren’Py都会重设初始化环节内所有样式的内容。 Ren’Py会运行所有与当前激活语言相关的 translate python 语句块、style语句块和translate style语句块,保证文件中这些语句块被优先执行。 最后,Ren’Py会重建所有样式,并使语言修改生效。

样式的多语言支持可以添加在任何.rpy文件中。

翻译文件延迟加载 link

比较大的游戏如果一口气加载所有翻译文件相当耗时。为了能提速,Ren’Py提供了翻译文件延迟加载功能。 若要启用该功能,需要在脚本中添加:

define config.defer_tl_scripts = True

通常这行会写在 options.rpy 或其他加载优先级高于翻译文件的脚本中。

当该项为True时,Ren’Py不会在初始化阶段加载 tl/language 目录下的脚本。 之后,只有首次启用某种语言后,Ren’Py才会在游戏启动时加载对应翻译文件。

由于在初始化阶段不加载 tl/language 目录的文件,所以这些文件不应包含在初始化阶段必须执行的内容。 比如 initpython 开头的语句块,screenimagetransform 等语句。 翻译文件应该只有以 translatetranslate pythontranslate style 开头的语句块。

默认语言 link

使用以下方法可以选择默认语言:

多语言支持的行为、函数和变量 link

切换语言的主要办法是使用语言的行为函数。

class Language(language) link

将游戏语言改为 language

language

一个字符串,表示切换的目标语言,若为None表示游戏脚本默认语言。

语言行为函数可以用于在自定义配置界面添加一个语言自定义选项。

frame:
    style_prefix "pref"
    has vbox

    label _("Language")
    textbutton "English" action Language(None)
    textbutton "Igpay Atinlay" action Language("piglatin")

还有三个与多语言支持相关的函数:

renpy.change_language(language, force=False) link

一个字符串,表示切换的目标语言命,若为None表示游戏脚本默认语言。

renpy.get_translation_identifier() link

返回当前语句的翻译文件标识符。

renpy.known_languages() link

返回已知语言的集。不包含默认语言None。

此外,还有四个与字符串多语言支持相关的函数:

_(s) link

(单下划线)返回字符串 s 的原语言内容。Ren’Py会搜寻该函数传入的字符串,并把它们加入到多语言支持字符串列表中。这些字符串不会转换为其他语言,直到他们被显示过。

__(s) link

(双下划线)返回字符串 s 转换成当前语言后的内容。该函数返回的字符串会被加入到多语言支持字符串列表中。注意字符串可以经历过双重转换。如果其匹配到一个对应的多语言字符串则显示转换后的结果。

_p(s) link

将一个字符串重新格式化并标记其是支持多语言的。使用文本组件显示的字符串是转换过语言的。该函数的用途是,使用表单格式(form)定义多行字符串:

define config.about = _p("""
    These two lines will be combined together
    to form a long line.

    This line will be separate.
    """)

重新格式化会将整段文本断行,移除每行开头和结尾的空白。整段文本末尾的空白行会被删除。段落中的空白行会被插入段落分割符。{p}文本标签(tag)可以断行,但不会增加新的空白行。

在字符串多语言支持中的使用方式如下:

old "These two lines will be combined together to form a long line.\n\nThis line will be separate."
new _p("""
    These two lines will be combined together
    to form a long line. Bork bork bork.

    This line will be separate. Bork bork bork.
    """)
renpy.translate_string(s, language=<renpy.object.Sentinel object at 0x7f5afce071f0>) link

s 立刻翻译为指定语言 language 并返回。 如果 language 的值是Default,使用设置(preferences)中的语言。 经过该函数翻译后的字符串 不会 被添加到可翻译字符串列表中。指定某个字符串的语言可能会导致其发生两次翻译的情况。

这里有两个语言相关的变量。一个是 config.default_language ,用于改变游戏默认语言。

_preferences.language link

当前语言名称,如果使用的是默认语言则是None。需要改变语言的话,调用 renpy.change_language() 函数。

非常规多语言支持 link

Note

创建非常规多语言支持前,最好获取原游戏创作者的许可。

在没有游戏创作者原生支持的情况下,Ren’Py也有一点支持可以创建多语言支持。Ren’Py能根据游戏内所有字符串自动生成一个字符串多语言支持的文件。因为多语言字符串可以用在未转换过的对话,这个小技巧可以让游戏直接支持多语言。

想要创建一个字符串翻译文件,需要执行以下步骤:

  • 设置环境变量RENPY_LANGUAGE为你想要添加的目标语言。

  • 设置环境变量RENPY_UPDATE_STRINGS为一个非空值。

  • 执行游戏直到看见目标文本内容。

这些操作会更新 game/tl/language/strings.rpy 文件,其中包含所有多语言字符串的一个模板。

如果某个游戏内部不支持更改语言,可以在 config.language 中使用一个 init python 语句块(block),强行切换到目标语言。

define config.language = None link

若不是None,会在游戏启动时切换为该语言,覆盖用户之前更改过的设置。

除了使用字符串的多语言支持解决对话的问题,上面描述的非常规多语言支持技巧也可以应用在图片和样式上。