游戏的国际化
前言
虽然独立游戏和小众游戏通常不需要本地化,但瞄准更大市场的游戏通常需要本地化。Godot 提供了许多工具来使这个过程更加简单,因此本教程更像一个妙招和技巧的合集。
本地化通常是通过雇佣特定的工作室来完成的,尽管有大量的软件和文件格式可供使用,但迄今为止进行本地化最常见的方式仍然是使用电子表格。创建电子表格并导入电子表格的过程已经在《导入翻译》教程中介绍过了。如果你之前尚未阅读导入翻译页面,我们建议你在阅读本页面之前先阅读该页面。
备注
我们将使用官方演示作为示例,可以从资产库下载。
配置导入的译文
Translations can get updated and re-imported when they change, but they still have to be added to the project. This is done in :
上述对话框用于添加或移除用于整个项目范围的翻译。
资源的本地化
还可以指示 Godot 根据当前语言使用资产(资源)的替代版本。这可用于本地化诸如游戏内广告牌之类的图像或者语音。
The Remaps tab can be used for this:
选择需要重定向的资源,然后为每个区域设置添加一些替代项。
备注
DynamicFont 不支持资源重定向系统。要根据语言文字使用不同的字体,请改用 DynamicFont 回退系统,可以让你根据需要定义任意数量的回退字体。
DynamicFont 后备系统的优点是它可以忽略当前语言而工作,这使得它非常适合多人聊天即文本语言可能与客户端语言不匹配的情况。
自动设置语言
It is recommended to default to the user's preferred language which can be
obtained via OS.get_locale_language().
If your game is not available in that language, it will fall back to the
Fallback
in , or to en if empty.
Nevertheless, letting players change the language in game is recommended for
various reasons (e.g. translation quality or player preference).
var language = "automatic"
# Load here language from the user settings file
if language == "automatic":
var preferred_language = OS.get_locale_language()
TranslationServer.set_locale(preferred_language)
else:
TranslationServer.set_locale(language)
区域设置 vs 语言
区域设置通常是语言与地区或国家的组合,还可能包含文字、变体等信息。
示例:
en:英语语言en_GB:英国的英语 / 英式英语en_US:美国的英语 / 美式英语en_DE:德国的英语
独立游戏通常只需要关注语言,但请继续往下看更多信息。
可以通过美国和英国的例子来解释区域设置存在的必要性。他们说的是同一种语言(英语),但在很多方面又有区别:
Spelling: e.g. gray (USA), grey (GB)
Use of words: e.g. eggplant (USA), aubergine (GB)
Units or currencies: e.g. feet/inches (USA), metres/cm (GB)
甚至可以变得更加复杂。可以想象一下在欧洲和中国提供不同的内容(例如在 MMO 中)。你需要把每种内容变体都翻译成多种语言,进行相应的存储和加载。
将键转换为文本
Some controls, such as Button and Label,
will automatically fetch a translation if their text matches a translation key.
For example, if a label's text is MAIN_SCREEN_GREETING1 and that key exists
in the current translation, then the text will automatically be translated.
This automatic translation behavior may be undesirable in certain cases. For
instance, when using a Label to display a player's name, you most likely don't
want the player's name to be translated if it matches a translation key. To
disable automatic translation on a specific node, set the Auto Translate > Mode
to Disabled in the inspector.
在代码中,可以使用 Object.tr() 函数。这将只在翻译中查找文本,并在找到后进行转换:
level.text = tr("LEVEL_5_NAME")
status.text = tr("GAME_STATUS_%d" % status_index)
level.Text = Tr("LEVEL_5_NAME");
status.Text = Tr($"GAME_STATUS_{statusIndex}");
备注
如果更改语言后不显示任何文字,请尝试换一个字体。默认项目字体仅支持 Latin-1 字符集的子集,无法用于显示俄语、汉语等文字。
Noto Fonts 是一系列不错的多语言字体资源。如果你使用的是不太常见的语言,请确保下载正确的变体。
下载字体后,将 TTF 文件加载到 DynamicFont 资源中,并将其用作 Control 节点的自定义字体。为了获得更好的可重用性,请将新的主题资源关联到根 Control 节点,并将 DynamicFont 定义为主题中的默认字体。
占位符
若要在翻译的字符串中使用占位符,请使用 GDScript 格式字符串 或 C# 中的等效功能。这使得翻译者可以自由移动字符串中占位符的位置,使得翻译听起来更自然。为了允许翻译人员决定占位符出现的顺序,应尽可能使用搭配使用带命名的占位符和 String.format() 的函数:
# The placeholder's locations can be changed, but not their order.
# This will probably not suffice for some target languages.
message.text = tr("%s picked up the %s") % ["Ogre", "Sword"]
# The placeholder's locations and order can be changed.
# Additionally, this form gives more context for translators to work with.
message.text = tr("{character} picked up the {weapon}").format({character = "Ogre", weapon = "Sword"})
翻译上下文
如果你使用普通的英文作为源字符串(而不是类似于 LIKE_THIS 的消息代码),那么就有可能会遇到歧义的情况,同一个英文字符串可能需要在某些目标语言中翻译为不同的字符串。你可以通过指定可选的翻译上下文来消除歧义,即便源字符串是相同的,也能够让目标语言能够使用不同的字符串:
# "Close", as in an action (to close something).
button.set_text(tr("Close", "Actions"))
# "Close", as in a distance (opposite of "far").
distance_label.set_text(tr("Close", "Distance"))
// "Close", as in an action (to close something).
GetNode<Button>("Button").Text = Tr("Close", "Actions");
// "Close", as in a distance (opposite of "far").
GetNode<Label>("Distance").Text = Tr("Close", "Distance");
复数
很多语言会根据对象的单复数使用不同的字符串。但是把“是否为复数”的条件硬编码为“对象数量是否大于 1 ”并不是对所有语言都有效。
有些语言有两种以上的复数形式,不同的复数需要的对象数量也各不相同。Godot 提供了对复数的支持,目标地区可以自动进行处理。
复数应该只用于正整数(或零)的情况。负数和浮点数所代表的物理实体数量是单数还是复数一般无法明确区分。
var num_apples = 5
label.text = tr_n("There is %d apple", "There are %d apples", num_apples) % num_apples
int numApples = 5;
GetNode<Label>("Label").Text = string.Format(TrN("There is {0} apple", "There are {0} apples", numApples), numApples);
如果有需要也可以和上下文组合使用:
var num_jobs = 1
label.text = tr_n("%d job", "%d jobs", num_jobs, "Task Manager") % num_jobs
int numJobs = 1;
GetNode<Label>("Label").Text = string.Format(TrN("{0} job", "{0} jobs", numJobs, "Task Manager"), numJobs);
使控件的大小可调
不同语言的相同文本的长度差异很大。为此,请务必阅读教程《大小和锚点》,因为动态调整控件大小可能有所帮助。Container 可能很有用,Label 的文本换行选项应该也能帮上忙。
To check whether your UI can accommodate translations with longer strings than the original, you can enable pseudolocalization in the advanced Project Settings. This will replace all your localizable strings with longer versions of themselves, while also replacing some characters in the original strings with accented versions (while still being readable). Placeholders are kept as-is, so that they keep working when pseudolocalization is enabled.
例如,当启用伪本地化时,字符串 Hello world, this is %s! 会变为 [Ĥéłłô ŵôŕłd́, ŧh̀íš íš %s!]。
虽然第一眼看上去很奇怪,但是伪本地化的好处有很多:
它可以让你快速发现不可本地化的字串,这样你就可以检查它们并使它们可本地化(如果这样做有意义的话)。
它可以让你检查无法容纳长字符串的 UI 元素。许多语言的翻译会比源文本长得多,因此确保你的 UI 能够容纳比平常更长的字符串非常重要。
它可以让你检查你的字体是否包含支持各种语言所需的所有字符。然而,由于伪本地化的目标是保持原始字符串的可读性,因此它并不是检查字体是否支持 CJK(中文、日文、韩文) 或从右到左语言的有效测试。
项目设置允许你调整伪本地化行为,以便你可以根据需要禁用它的某些部分。
TranslationServer
Godot 中负责底层翻译管理的服务器叫作 TranslationServer。可以在运行时添加或删除翻译;当前语言也可以在运行时更改。
Bidirectional text and UI mirroring
阿拉伯语和希伯来语是从右到左书写的(除了混合的数字和拉丁单字),这些语言的用户界面也应该是镜像的。在某些语言中,字形的形状会根据周围的字符而变化。
对双向书写系统和 UI 镜像的支持是透明的,你通常不需要更改任何内容或了解特定的书写系统。
对于 RTL(从右至左)语言,Godot 会自动对 UI 进行以下调整:
镜像左右锚点和边距。
交换文本的左对齐和右对齐。
镜像容器中子控件的水平顺序以及 Tree/ItemList 控件中项目的水平顺序。
Uses mirrored order of the internal control elements (e.g., OptionButton dropdown button, CheckBox/CheckButton alignment, List column order, TreeItem icons and connecting line alignment). In some cases, mirrored controls use separate theme styles.
坐标系**不会**被镜像。
Non-UI nodes (sprites, etc.) are not affected.
可以使用下列控件属性来覆盖文字和控件布局方向:
text_direction设定基本文字方向。当设定为“auto”时,文字方向取决于文本中根据 Unicode 双向文本算法的第一个强方向字符。language, overrides the current project locale.The
structured_text_bidi_overrideproperty and_structured_text_parsercallback, enable special handling for structured text.layout_direction覆盖控件的镜像。
参见
你可以使用 BiDI 和字体功能演示项目来查看从右到左排版的实际工作方式。
在导出后的项目中添加分词迭代器数据
有些语言在书写时没有空格,分词和断行需要的不仅仅是基于字符序列规则。Godot 包含 ICU 规则和基于字典的分词迭代器数据,但默认情况下这些数据不包含在导出的项目中。
To include it, go to and enable Include Text Server Data, then export the project. Break iterator data is about 4 MB in size.
结构化文本 BiDi 覆盖
Unicode BiDi 算法设计用于处理自然文本,它无法处理具有更高级别顺序的文本,例如文件名、URI、电子邮件地址、正则表达式或源代码。
例如,所显示的目录结构的路径将显示不正确(顶部“LineEdit”控件)。“文件”类型结构化文本覆盖将文本拆分为段,然后将 BiDi 算法分别应用于每个段,以正确显示任何语言的目录名称并保留文件夹的正确顺序(底部“LineEdit”控件)。
自定义回调提供了一种为其他类型的结构化文本覆盖 BiDi 的方法。
数字的本地化
专为数位输入或输出设计的控件(例如 ProgressBar、SpinBox)将自动使用本地化编号系统,对于其他控件,TextServer.format_number(string, language) 可用于将西方阿拉伯数字(0..9)转换为本地化的数字系统,而 TextServer.parse_number(string, language) 可以将其转换回来。
图标和图像的本地化
当带有左右指向箭头的图标指示移动或方向(例如后退/前进按钮)时,它们可能需要在阿拉伯语和希伯来语语言环境中翻转过来。否则,它们可以保持不变。
测试翻译
你可能会想要在发布前测试项目的翻译。Godot 为此提供了三种方法。
Under (with advanced settings enabled) is a Test property. Set this property to the locale code of the language you want to test. Godot will run the project with that locale when the project is run (either from the editor or when exported).
请记住,因为这是一个项目设置,设为非空时它会在版本控制中显示。因此,将修改提交到版本控制之前,应该将其设回空值。
其次,在编辑器中点击顶部工具栏的,然后在预览翻译中选择要预览的语言。
编辑器场景中的所有文本现在都会以所选语言显示。
还可以在从命令行运行 Godot 时测试翻译。例如,要使用法语测试游戏,可以提供以下参数:
godot --language fr
翻译项目名称
The project name becomes the app name when exporting to different operating systems and platforms. To specify the project name in more than one language go to . From here click on the button, then the button. It will take you to a page where you can choose the language (and country if needed) for your project name translation. After doing that you can now type in the localized name.
如果你不确定要使用的语言代码,请参阅区域代码列表。