
Hướng dẫn đầy đủ về bản địa hóa trò chơi Godot
Từ TranslationServer đến phông chữ dự phòng: bản địa hóa trò chơi Godot bằng tệp CSV, PO, GDScript và bản dịch AI tự động.
Kiến thức cơ bản về TranslationServer
TranslationServer tích hợp sẵn của Godot là thành phần cốt lõi trong hệ thống bản địa hóa. Công cụ này tải tài nguyên dịch khi khởi động và phân giải khóa qua hàm tr(). Mọi lệnh gọi tr() trong GDScript đều đi qua TranslationServer mà không cần thư viện bổ sung.
# TranslationServer is Godot's built-in localization system.
# It loads translations at startup and resolves keys via tr().
# Set the game's locale
TranslationServer.set_locale("ja")
# Get the current locale
var current = TranslationServer.get_locale() # "ja"
# Translate a key — works everywhere in GDScript
var text = tr("MENU_START") # "ゲームスタート"
# Translate with context (Godot 4.x)
var text = tr("OPEN", "verb") # "Open" (action)
var text = tr("OPEN", "adj") # "Open" (state)Tệp dịch CSV
CSV là định dạng đơn giản nhất để dịch trong Godot. Một tệp chứa tất cả ngôn ngữ theo từng cột. Cột đầu tiên là khóa và mỗi cột tiếp theo là một ngôn ngữ. Godot tự động nhập tệp .csv và tạo tài nguyên .translation.
# translations.csv
# First column = key, subsequent columns = locale codes
keys,en,ja,de,es
MENU_START,Start Game,ゲームスタート,Spiel starten,Iniciar juego
MENU_SETTINGS,Settings,設定,Einstellungen,Configuración
MENU_QUIT,Quit,終了,Beenden,Salir
ITEM_SWORD,Sword,剣,Schwert,Espada
ITEM_SHIELD,Shield,盾,Schild,Escudo
DIALOG_GREETING,"Hello, adventurer!",冒険者よ、こんにちは!,"Hallo, Abenteurer!","¡Hola, aventurero!"# In Godot Editor:
# 1. Place your .csv file in the project (e.g., res://translations.csv)
# 2. Godot auto-imports it — creates .translation resources
# 3. Go to Project > Project Settings > Localization > Translations
# 4. Add the generated .translation filesTệp dịch PO / Gettext
Tệp PO (Portable Object) là tiêu chuẩn ngành để bản địa hóa phần mềm. Godot 4.x hỗ trợ PO nguyên bản, bao gồm dạng số nhiều, phân biệt ngữ cảnh và ghi chú cho người dịch. Hãy tạo một tệp .po cho mỗi ngôn ngữ trong thư mục locale/.
# translations.po — Gettext format for Godot
# Place in res://locale/ja.po
msgid ""
msgstr ""
"Language: ja\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=1; plural=0;\n"
# Simple translation
msgid "MENU_START"
msgstr "ゲームスタート"
# Translation with context (disambiguates identical source strings)
msgctxt "verb"
msgid "OPEN"
msgstr "開く"
msgctxt "adj"
msgid "OPEN"
msgstr "開いている"
# Plural form
msgid "You collected %d coin."
msgid_plural "You collected %d coins."
msgstr[0] "%d枚のコインを集めました。"# Project Settings > Localization > Translations
# Add each .po file:
# res://locale/en.po
# res://locale/ja.po
# res://locale/de.po
# res://locale/es.po
# Or load programmatically:
func _ready():
var translation = load("res://locale/ja.po")
TranslationServer.add_translation(translation)Sử dụng bản dịch trong GDScript
Dùng tr() ở bất cứ đâu trong GDScript để dịch chuỗi. Kết hợp với toán tử % của GDScript để định dạng chuỗi. Để quản lý ngôn ngữ ổn định, hãy tạo một tập lệnh Autoload phụ trách phát hiện, lưu và chuyển đổi ngôn ngữ bằng tín hiệu.
extends Control
func _ready():
# Simple key lookup
$TitleLabel.text = tr("MENU_START")
# With string formatting (positional)
$GreetingLabel.text = tr("DIALOG_GREETING_NAME") % [player_name]
# With multiple placeholders
$StatusLabel.text = tr("PLAYER_STATUS") % [player_name, level, health]
# Context-aware translation (Godot 4.x)
$ActionButton.text = tr("OPEN", "verb")
# Update UI when locale changes
TranslationServer.set_locale("de")
_update_ui()
func _update_ui():
# Re-apply all translated strings
$TitleLabel.text = tr("MENU_START")
$GreetingLabel.text = tr("DIALOG_GREETING_NAME") % [player_name]# locale_manager.gd — Register as Autoload in Project Settings
extends Node
signal locale_changed(new_locale: String)
const SUPPORTED_LOCALES = ["en", "ja", "de", "es", "fr", "ko", "zh"]
func _ready():
var system_locale = OS.get_locale_language()
if system_locale in SUPPORTED_LOCALES:
set_locale(system_locale)
else:
set_locale("en")
func set_locale(locale: String):
TranslationServer.set_locale(locale)
locale_changed.emit(locale)
func get_locale() -> String:
return TranslationServer.get_locale()Dạng số nhiều và phần giữ chỗ
Godot xử lý dạng số nhiều qua các dạng số nhiều trong tệp PO. Mỗi ngôn ngữ xác định công thức số nhiều riêng trong phần đầu PO. Toán tử % của GDScript xử lý phần giữ chỗ theo vị trí (%s cho chuỗi, %d cho số nguyên). Với phần giữ chỗ có tên, hãy dùng String.replace().
# Godot uses Gettext PO plural rules.
# Each language defines its own plural formula.
# English (2 forms: one, other)
msgid "You collected %d coin."
msgid_plural "You collected %d coins."
msgstr[0] "You collected %d coin."
msgstr[1] "You collected %d coins."
# Japanese (1 form: other — no singular/plural distinction)
msgid "You collected %d coin."
msgid_plural "You collected %d coins."
msgstr[0] "%d枚のコインを集めました。"
# Russian (3 forms: one, few, many)
msgid "You collected %d coin."
msgid_plural "You collected %d coins."
msgstr[0] "Вы собрали %d монету."
msgstr[1] "Вы собрали %d монеты."
msgstr[2] "Вы собрали %d монет."# GDScript string formatting with tr()
# Positional placeholders with %
var msg = tr("SCORE_MSG") % [score] # "Score: %d" → "Score: 1500"
var msg = tr("STATS") % [name, level, hp] # "%s — Lv %d — HP: %d"
# Named placeholders (manual replacement)
var template = tr("WELCOME_BACK")
var msg = template.replace("{player}", name).replace("{days}", str(days))Phông chữ dự phòng cho CJK, tiếng Ả Rập và các hệ chữ khác
Phông chữ chính của trò chơi có thể không chứa ký tự tượng hình cho hệ chữ tiếng Nhật, Hàn, Trung, Ả Rập hoặc Thái. Godot 4.x hỗ trợ chuỗi phông chữ dự phòng: khi phông chữ chính thiếu một ký tự tượng hình, Godot sẽ lần lượt kiểm tra các phông chữ dự phòng. Nếu không thiết lập, văn bản không dùng chữ Latinh sẽ hiển thị thành ô vuông trống.
# Godot 4.x supports font fallback chains.
# When a glyph is missing from the primary font, fallbacks are checked in order.
# In the Editor:
# 1. Create a LabelSettings or Theme resource
# 2. Set the primary font (e.g., Noto Sans for Latin)
# 3. Add fallback fonts: Noto Sans JP, KR, SC, Arabic
# Programmatically:
func setup_fonts():
var font = FontFile.new()
font.load_dynamic_font("res://fonts/NotoSans-Regular.ttf")
var fallback_jp = FontFile.new()
fallback_jp.load_dynamic_font("res://fonts/NotoSansJP-Regular.ttf")
font.add_fallback(fallback_jp)
$Label.add_theme_font_override("font", font)# Right-to-left (RTL) support for Arabic, Hebrew, etc.
# In the Editor:
# Select your Control node > Layout > Text Direction = RTL
# Programmatically:
func setup_rtl():
var locale = TranslationServer.get_locale()
var rtl_locales = ["ar", "he", "fa", "ur"]
if locale.substr(0, 2) in rtl_locales:
$Label.text_direction = Control.TEXT_DIRECTION_RTL
$Container.layout_direction = Control.LAYOUT_DIRECTION_RTLBản địa hóa cảnh và UI
Có ba cách bản địa hóa cảnh Godot: dịch trong _ready() bằng tr(), dùng thuộc tính Auto Translate trong trình chỉnh sửa hoặc tải các cảnh hoàn toàn khác cho ngôn ngữ cần bố cục riêng (như ngôn ngữ RTL).
# Approach 1: Translate in _ready() using tr()
extends Control
func _ready():
$StartButton.text = tr("MENU_START")
$SettingsButton.text = tr("MENU_SETTINGS")
$QuitButton.text = tr("MENU_QUIT")
# Approach 2: Use auto-translate in the editor
# Set the Text property to the translation key (e.g., "MENU_START")
# and enable "Auto Translate" on the node.
# Approach 3: Locale-specific scenes for complex layouts
func load_localized_scene():
var locale = TranslationServer.get_locale().substr(0, 2)
var path = "res://ui/main_menu_%s.tscn" % locale
if ResourceLoader.exists(path):
add_child(load(path).instantiate())
else:
add_child(load("res://ui/main_menu_en.tscn").instantiate())Dự phòng ngôn ngữ thông minh bằng LocaleChain
TranslationServer của Godot chuyển thẳng sang ngôn ngữ mặc định của dự án khi thiếu một biến thể vùng. Người chơi pt-BR sẽ thấy tiếng Anh thay vì tiếng Bồ Đào Nha nếu chỉ có bản dịch pt-PT. LocaleChain khắc phục vấn đề này bằng cách hợp nhất bản dịch từ các chuỗi dự phòng có thể cấu hình vào TranslationServer tại thời điểm cấu hình.
# LocaleChain for Godot — smart locale fallback
# Install from Godot AssetLib or copy addons/locale_chain/ into your project
# Problem: Godot's TranslationServer falls back directly to the default locale.
# A pt-BR player with only pt-PT translations sees English, not Portuguese.
# Solution: One-line setup
func _ready():
LocaleChain.configure() # Uses built-in fallback chains
# Now pt-BR falls back to pt-PT → pt → default
# es-MX falls back to es-419 → es → default
# zh-Hant-HK falls back to zh-Hant-TW → zh-Hant → default
# Custom configuration:
func _ready():
# Override specific chains
LocaleChain.configure({"pt-BR": ["pt"]})
# Full custom — only your chains
LocaleChain.configure(
{"pt-BR": ["pt-PT", "pt"], "es-MX": ["es-419", "es"]},
false # don't merge defaults
)
# Reset to original state
LocaleChain.reset()Tự động dịch trò chơi
Sau khi hoàn tất thiết lập bản địa hóa, hãy dịch tệp CSV hoặc PO bằng AI. Tự động dịch chuỗi trò chơi, văn bản UI, mô tả vật phẩm và lời thoại ngay từ IDE hoặc quy trình CI/CD.
# Translate your Godot locale files with AI
# CSV files:
# In your IDE, ask your AI assistant:
> Translate translations.csv to Japanese, Korean, and German
# PO files:
> Translate locale/en.po to ja, ko, de
# Or use the CLI in CI/CD:
npx i18n-agent translate locale/en.po --lang ja,ko,de
# The tool preserves:
# - CSV column structure and delimiters
# - PO msgctxt, msgid_plural, and plural forms
# - Placeholder syntax (%s, %d, {name})
# - Comments and metadata headersTự động bảo đảm chất lượng bản dịch
Lỗi thường gặp
Chưa nhập tệp dịch
Giá trị CSV chứa dấu phẩy hoặc dấu ngoặc kép làm lỗi phân tích cú pháp
Văn bản CJK hoặc tiếng Ả Rập hiển thị ô vuông trống
Số dạng số nhiều trong phần đầu PO không chính xác
Mã ghi đè tính năng Auto Translate
Cấu trúc dự án đề xuất
my_godot_game/
├── addons/
│ └── locale_chain/ # LocaleChain plugin (optional)
│ ├── fallback_map.gd
│ ├── locale_chain.gd
│ └── plugin.cfg
├── fonts/
│ ├── NotoSans-Regular.ttf # Primary font (Latin)
│ ├── NotoSansJP-Regular.ttf # Japanese fallback
│ ├── NotoSansKR-Regular.ttf # Korean fallback
│ └── NotoSansArabic-Regular.ttf # Arabic fallback
├── locale/
│ ├── en.po # English (source)
│ ├── ja.po # Japanese
│ ├── de.po # German
│ ├── es.po # Spanish
│ └── ar.po # Arabic
├── translations.csv # Alternative: CSV format
├── scenes/
│ └── ui/
│ ├── main_menu.tscn
│ └── settings_menu.tscn
├── scripts/
│ ├── locale_manager.gd # Autoload for locale management
│ └── ui/
│ └── main_menu.gd
├── project.godot
└── export_presets.cfgDịch thêm:
Dùng thử i18n Agent ngay
Thả tệp bản dịch của bạn vào đây
JSON, YAML, PO, XML, CSV, Markdown, Properties
hoặc nhấp để duyệt
Ngôn ngữ đích
Dự phòng ngôn ngữ bằng locale-chain-godot
Khi thiếu khóa dịch trong một ngôn ngữ vùng như pl_PL, Godot chuyển thẳng sang ngôn ngữ mặc định của dự án thay vì kiểm tra ngôn ngữ cha pl trước.
# Cài đặt từ Godot Asset Library
# Tìm kiếm: locale-chain-godotvar lc = LocaleChain.new()
lc.configure({
"pl": ["pl_PL", "en"],
"pt_BR": ["pt", "en"],
"zh_Hant_HK": ["zh_Hant", "zh", "en"],
})Xem Hướng dẫn dự phòng ngôn ngữ của chúng tôi để biết danh sách đầy đủ các framework được hỗ trợ và 75 chuỗi tích hợp sẵn. Learn more →