mcpField
L
localization

localization

github.com/jame581开发929182 次安装2 周前更新
代码仓库

关于 localization

面向 Godot 4.3+ 开发者的本地化指南,说明翻译文件、运行时语言切换及多语言界面处理,并提供 GDScript 和 C# 示例。

主要功能

  1. 01使用 tr() 标记可翻译文本
  2. 02支持 CSV 与 PO 翻译文件
  3. 03运行时切换语言环境
  4. 04RTL 布局与本地化格式处理
  5. 05Godot 4.6+ CSV 复数和上下文

适用场景

  1. 01为游戏界面添加多语言文本
  2. 02在运行时切换游戏语言
  3. 03检查 RTL 语言布局与翻译溢出

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jame581/godotprompter --skill localization

安装后在 Claude Code 中输入/localization确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
csv-plural-context.md
editor-preview.md
locale-formatting.md
rtl-support.md

详细介绍

Godot 4.3+ 中的本地化

所有示例均面向 Godot 4.3+,不使用已弃用的 API;先介绍 GDScript,再介绍 C#。

相关技能: godot-ui 用于管理 Control 节点和主题,save-load 用于保存语言设置,responsive-ui 用于根据区域设置调整布局。


1. 核心概念

Godot 本地化的工作方式
  1. 使用 tr()(Godot 的翻译函数)包装所有面向用户的字符串
  2. 创建翻译文件(CSV 或 PO),将键映射到译文
  3. 将翻译文件导入为 Translation 资源
  4. 通过 TranslationServer.set_locale() 在运行时切换区域设置

所有具有 text、tooltip_text 或 placeholder_text 属性的 Control 节点,如果其值与翻译键匹配,都会自动翻译。

翻译键策略
策略示例键优点缺点
语义键MENU_START_GAME意图明确,易于查找需要默认语言回退
以英语为键Start Game代码易读,英语无需映射文件英文文本更改时会失效

建议: 生产环境使用语义键(MENU_START_GAME);以英语为键仅适用于原型或个人项目。


2. 翻译文件

CSV 格式

最简单的格式。第一列为键,后续列为区域设置代码。

keys,en,cs,de,ja
MENU_START,Start Game,Začít hru,Spiel starten,ゲームスタート
MENU_OPTIONS,Options,Nastavení,Optionen,オプション
MENU_QUIT,Quit,Ukončit,Beenden,終了
PLAYER_HEALTH,Health: %d,Zdraví: %d,Gesundheit: %d,体力: %d
ITEM_COLLECTED,%s collected!,%s sebráno!,%s gesammelt!,%sを入手!

在项目中将文件保存为 translations.csv。Godot 会在导入时自动检测格式。

导入设置(Import 面板):

  • Delimiter:逗号(默认)、分号或制表符
  • Compress:默认开启——存储为 OptimizedTranslation;对于使用 ?context/?plural 的文件,则会跳过压缩(§10)
PO 格式(Gettext)

行业标准格式,翻译团队以及 Poedit、Weblate、Crowdin 等工具都优先使用此格式。

创建 POT 模板(messages.pot):

msgid "MENU_START"
msgstr ""

msgid "MENU_OPTIONS"
msgstr ""

msgid "MENU_QUIT"
msgstr ""

msgid "PLAYER_HEALTH"
msgstr ""

创建区域设置文件(例如,捷克语文件 cs.po):

msgid "MENU_START"
msgstr "Začít hru"

msgid "MENU_OPTIONS"
msgstr "Nastavení"

msgid "MENU_QUIT"
msgstr "Ukončit"

msgid "PLAYER_HEALTH"
msgstr "Zdraví: %d"
注册翻译

项目设置 → 本地化 → 翻译 → 添加... → 选择 .csv 或 .po 文件。

也可以在运行时注册:

var translation := load("res://translations/cs.po") as Translation
TranslationServer.add_translation(translation)
var translation = GD.Load<Translation>("res://translations/cs.po");
TranslationServer.AddTranslation(translation);

⚠️ Godot 4.7 中的更改: OptimizedTranslation.generate() 现在返回 bool(之前为 void)。GDScript 和 C# 源代码兼容,但二进制不兼容——请重新编译调用该方法的预编译 C# 插件。请参阅 4.7 迁移指南。

POT 生成钩子(Godot 4.7+)

自定义 EditorTranslationParserPlugin 可以重写 _customize_strings()——该方法会在 POT 生成期间解析完所有文件后调用一次,用于添加或移除最终提取的字符串列表中的条目:

@tool
extends EditorTranslationParserPlugin

func _customize_strings(strings: Array[PackedStringArray]) -> Array[PackedStringArray]:
    strings.append(PackedStringArray(["Test 1", "context", "test 1 plurals", "test 1 comment"]))
    # Drop internal strings that begin with "$".
    return strings.filter(func(s): return not s[0].begins_with("$"))
#if TOOLS
using System.Linq;
using Godot;

public partial class CommentAwareParser : EditorTranslationParserPlugin
{
    public override Godot.Collections.Array<string[]> _CustomizeStrings(Godot.Collections.Array<string[]> strings)
    {
        strings.Add(new[] { "Test 1", "context", "test 1 plurals", "test 1 comment" });
        // Drop internal strings that begin with "$".
        return new Godot.Collections.Array<string[]>(strings.Where(s => !s[0].StartsWith("$")));
    }
}
#endif

Godot 4.7+: POT 生成器也会提取 Control.accessibility_name 和 accessibility_description,让无障碍字符串无需手动列出即可翻译。(GH-117134)


3. 在代码中使用 tr()

GDScript
# Basic translation
var label_text: String = tr("MENU_START")  # "Start Game" or translated equivalent

# With format arguments
var health_text: String = tr("PLAYER_HEALTH") % current_health
# "Health: 85" or "Zdraví: 85"

# With string arguments
var collected_text: String = tr("ITEM_COLLECTED") % item_name
# "Sword collected!" or "Meč sebráno!"

# Pluralization (Godot 4.x)
var count := 5
var msg: String = tr_n("ONE_ENEMY", "MANY_ENEMIES", count)
# Needs plural forms in the translation: PO, or CSV `?plural` rows on Godot 4.6+ (§10)
C#
string labelText = Tr("MENU_START");
// string.Format ignores GDScript-style %d — substitute it yourself.
string healthText = Tr("PLAYER_HEALTH").Replace("%d", currentHealth.ToString());

// Pluralization
string msg = TrN("ONE_ENEMY", "MANY_ENEMIES", count);
Control 自动翻译

如果 Label、Button、RichTextLabel 和其他 Control 节点的 text 属性与翻译键匹配,就会自动翻译。将文本设为对应的键:

Button.text = "MENU_START"   → displays "Start Game" (en) or "Začít hru" (cs)

提示: 若要关闭特定 Control 的自动翻译,请将 auto_translate_mode 设为 DISABLED。

Godot 4.7+: Control.translation_context: StringName 为每个 Control 设置翻译上下文,用于翻译显示文本并生成翻译模板——相当于 tr() 的上下文参数所对应的属性(C#:TranslationContext)。(GH-115340)


4. 在运行时切换区域设置

GDScript
# Switch language
func set_language(locale_code: String) -> void:
    TranslationServer.set_locale(locale_code)
    # All Control nodes with translation keys update automatically

# Get current locale
var current: String = TranslationServer.get_locale()  # e.g. "en", "cs", "de"

# Get available locales
var locales: PackedStringArray = TranslationServer.get_loaded_locales()
C#
public void SetLanguage(string localeCode)
{
    TranslationServer.SetLocale(localeCode);
}

string current = TranslationServer.GetLocale();
语言选择菜单
extends Control

@onready var language_button: OptionButton = %LanguageButton

var _locales: Array[Dictionary] = [
    {"code": "en", "name": "English"},
    {"code": "cs", "name": "Čeština"},
    {"code": "de", "name": "Deutsch"},
    {"code": "ja", "name": "日本語"},
]

func _ready() -> void:
    for locale in _locales:
        language_button.add_item(locale["name"])

    # Set current selection
    var current_locale: String = TranslationServer.get_locale()
    for i in _locales.size():
        if _locales[i]["code"] == current_locale:
            language_button.selected = i
            break

    language_button.item_selected.connect(_on_language_selected)

func _on_language_selected(index: int) -> void:
    TranslationServer.set_locale(_locales[index]["code"])
    # Save preference — SettingsManager is a user-created autoload (see save-load skill)
    SettingsManager.set_setting("general", "locale", _locales[index]["code"])

5. 从右向左(RTL)支持

阿拉伯语、希伯来语和波斯语需要为 Control 设置 layout_direction(LOCALE 会自动跟随当前区域设置),设置 structured_text_type 以避免 URL 和路径完全反转,还需要使用支持相应文字的字体——Godot 的默认字体不支持。每次区域设置更改时,都要重新应用布局方向。TranslationServer 没有信号——请重写 _notification,并监听 Node.NOTIFICATION_TRANSLATION_CHANGED(MainLoop 也有一个同名常量)。由于从未订阅,因此无需断开任何处理程序。

完整配置步骤、各控件属性表、混合方向文本的 BBCode 以及 C# LocaleAwarePanel:references/rtl-support.md


6. 区域设置感知格式化

GDScript 不支持区域设置感知的数字分组或日期格式化——"%d" % 1234567 始终会得到 1234567,因此需要手动分组数字(TextServer.format_number() 只会将数字转换为区域设置对应的数字系统)。C# 则支持:从 TranslationServer.GetLocale() 获取 CultureInfo(将 _ 替换为 -),然后使用 ToString("N"/"C"/"d", culture)。

两种辅助方法的完整说明:references/locale-formatting.md


7. 项目组织

推荐的文件结构
res://
├── translations/
│   ├── game.csv           # Main game translations
│   ├── ui.csv             # UI-specific translations
│   └── items.csv          # Item names and descriptions
├── fonts/
│   ├── default_font.ttf   # Latin, Cyrillic
│   └── cjk_font.ttf       # Chinese, Japanese, Korean
└── themes/
    └── default_theme.tres  # Font assignments per locale
翻译键约定
# Category_Context_Description
MENU_MAIN_START          # Main menu, start button
MENU_MAIN_QUIT           # Main menu, quit button
HUD_HEALTH_LABEL         # In-game HUD, health label
DIALOGUE_NPC_GREETING    # NPC dialogue, greeting line
ITEM_SWORD_NAME          # Inventory item name
ITEM_SWORD_DESC          # Inventory item description

8. 常见问题

现象原因解决方法
显示的是翻译键,而不是文本翻译文件未在 Project Settings 中注册添加到 Project Settings → Localization → Translations
切换区域设置后文本没有更新使用了字符串字面量,而不是 tr()使用 tr() 包装所有面向用户的字符串
场景切换后 Label 显示翻译键代码在运行时添加的翻译尚未在此场景中生效在 Project Settings 中注册翻译(不要在运行时注册)
RTL 文本按 LTR 方向渲染未设置 layout_direction在根 Control 上设置为 RTL 或 LOCALE
字体无法显示字符字体缺少对应的 Unicode 字符范围导入支持目标文字的字体(推荐 Noto Sans)
CSV 无法实现复数形式Godot 4.6 之前的 CSV 不支持复数形式;4.6 及以上版本缺少 ?plural 列或续行4.6 及以上版本添加 ?plural 列(§10);4.6 之前使用 PO
翻译中的 %s 显示为字面量 %s将 tr() 的结果用作键,而不是对其进行格式化使用 tr("KEY") % value,而不是 tr("KEY" % value)

9. 编辑器区域设置预览(Godot 4.5+)

Godot 4.5 在 2D 编辑器的 View 菜单中新增了 Preview Translation 子菜单:编辑器视口会以任意已加载的区域设置重新渲染内容,让你无需进入运行模式,就能发现较长译文导致的溢出并检查 RTL 布局。此功能仅在编辑器中生效,不会影响导出的构建版本。

操作步骤和 QA 优势:references/editor-preview.md


10. CSV 复数和上下文支持(Godot 4.6+)

Godot 4.6 为 CSV 翻译新增了两个可选表头列——?context 和 ?plural——以及一个可选的 ?pluralrule 行,使 CSV 也支持上下文消歧和复数形式(此前仅 PO 支持)。额外的复数形式写在键为空的续行中,因此也能支持有 3 种及以上形式的语言(俄语、波兰语、阿拉伯语)。Control 的自动翻译会跳过这些行——请自行调用 tr() / tr_n()。

列参考、CSV 示例以及 tr() / tr_n() 用法(GDScript + C#):references/csv-plural-context.md。


11. 实施检查清单

  • 所有面向用户的字符串都使用 tr()(或将其设为 Control 节点上的翻译键)
  • 翻译文件(CSV 或 PO)已在“项目设置 → 本地化 → 翻译”中注册
  • 可以在运行时通过 TranslationServer.set_locale() 切换语言
  • 语言偏好设置会在游戏启动时保存并恢复
  • 字体涵盖所有目标语言的字符集(拉丁文、CJK、阿拉伯文等)
  • RTL 语言的根 UI 容器已将 layout_direction 设为 RTL 或 LOCALE
  • 格式字符串(%s、%d)在 tr() 之后应用,而非之前
  • 翻译键遵循一致的命名规范
  • UI 布局能适应不同语言中较长或较短的文本(不使用硬编码宽度)
  • 为每种目标语言提供复数形式 — 使用 PO,或在 Godot 4.6+ 中使用 CSV 的 ?plural 行
  • 使用编辑器区域设置预览(2D 编辑器“视图 → 预览翻译”)进行翻译质量检查,而不是运行测试(Godot 4.5+)
  • 当同一键在不同 UI 上下文中含义不同时,使用 CSV 的 ?context 列(Godot 4.6+)
  • CSV 复数形式使用 ?plural 列,每种额外的复数形式各用一行续行(仅在需要覆盖区域设置规则时使用 ?pluralrule 行)(Godot 4.6+)

评论

支持 Markdown