ゲームを世界中のプレイヤーに届けるうえで避けて通れないのが、多言語対応(i18n)です。とはいえ「UIの文字を全部コードで書き分けるの……?」と身構えてしまうかもしれません。実はGodotの TranslationServer を使えば、 コードを一切書き換えずに、CSVに一行足すだけで対応言語を増やせます 。
仕組みはシンプルで、やるこ とは3つだけ——翻訳表をCSVで用意し、プロジェクトに登録し、あとはキーで呼び出す。この記事では、日本語・英語・韓国語の3言語を例に、翻訳ファイルの作成から動的な言語切り替え、OS言語の自動検出まで、図を交えて実践的に解説します。
この記事でわかること
- TranslationServer の仕組み(翻訳キーと多言語テキストの紐付け)
- CSV翻訳ファイル の作り方と、プロジェクトへの登録
tr()と プレースホルダー による表示set_locale()での 動的な言語切り替え と、OS言語の自動検出
TranslationServerの仕組み
まず全体像です。TranslationServerは、 翻訳キー と 言語別テキスト を紐付けるシステムです。コードに「ゲームスタート」や「Start Game」を直接書く代わりに、START_GAME のような共通キーを使い、実行時に 現在の言語に応じたテキスト を取り出します。

なぜこの仕組みが要るのか——もしコードに直接日本語を書くと、英語対応のたびにコードを書き換えることになります。3言語、5言語と増えるほど修正箇所が膨れ上がり、バグの温床になります。 キーを介す ことで、コード側は一切変えずに言語を足せるのです。
# 呼ぶ側のコードは常に同じ。返るテキストだけが言語で変わる
tr("START_GAME") # ja → "ゲームスタート" / en → "Start Game" / ko → "게임 시작"
つまり多言語対応とは、 「キーと訳文の対応表」を用意して、コードからはキーで呼ぶ だけの作業に集約されます。
CSV翻訳ファイルを作って登録する
その「対応表」を、いちばん手軽なCSV形式で用意します。ExcelやGoogle Sheetsで編集でき、プログラマー以外の翻訳者ともチームで共有しやすいのが利点です。
プロジェクト内に translations/ フォルダを作り、game_text.csv を次の構造で書きます。
keys,ja,en,ko
START_GAME,ゲームスタート,Start Game,게임 시작
SETTINGS,設定,Settings,설정
QUIT,終了,Quit,종료
HEALTH,体力,Health,체력
LEVEL_COMPLETE,ステージクリア!,Level Complete!,스테이지 클리어!
- 1行目(ヘッダー)は
keysの後に、各言語の ロケールコード (ja・en・ko)を列名として並べる - 2行目以降は「キー名, 日本語, 英語, 韓国語, …」
- キー名は 大文字+アンダースコア が慣例(
START_GAME・LEVEL_COMPLETE) - 言語を足したいときは、 ヘッダーに列を1つ増やして訳文を埋めるだけ
CSVを res://translations/ に置くと、Godotが 自動でインポート し、言語ごとの .translation リソース(game_text.ja.translation など)を生成します。あとはこれをプロジェクトに登録します。

登録は「プロジェクト」→「プロジェクト設定」→「ローカライゼーション」タブ →「翻訳」で「追加」を押し、生成された .translation ファイル(ja・en・ko の3つ)をすべて追加します。これでコードから tr() が使えるようになります。
tips: Godot 4のCSVインポーターは、
keys以外の列名を すべてロケールコードとして解釈 します。commentやcontextのような列を混ぜると、それも言語だと誤認されます。 翻訳者向けの備考はCSVの外 (スプレッドシートのメモや別シート)で管理しましょう。
tr()で翻訳テキストを表示する
登録が済めば、あとはキーで呼ぶだけです。
extends Control
func _ready() -> void:
$TitleLabel.text = tr("START_GAME") # 現在のロケールに応じた訳文が返る
$SettingsButton.text = tr("SETTINGS")
$QuitButton.text = tr("QUIT")
tr() に渡すのはCSVの keys 列に書いたキー名です。 該当キーが見つからない場合は、キー名がそのまま返されます (これが後述のフォールバックに使えます)。
tips: Godot 4のUIノード(Label・Buttonなど)は
auto_translate_modeがデフォルトで有効です。テキスト欄に翻訳キーを直接入れておくだけで自動翻訳されるため、 静的なUIならtr()を書かなくても翻訳されます 。tr()は、スコア表示のようにスクリプトで文字列を組み立てるときに使います。
プレースホルダーで動的な値を埋め込む
「スコア: 1500」のように、訳文の中に数値を差し込みたい場面は頻繁にあります。CSV側に {名前} のプレースホルダーを書き、GDScriptの format() で値を流し込みます。
keys,ja,en,ko
PLAYER_SCORE,スコア: {score},Score: {score},점수: {score}
HEALTH_STATUS,体力: {current}/{max},Health: {current}/{max},체력: {current}/{max}

func update_score_label(score: int) -> void:
# tr()で訳文を取り、format()で{score}に値を差し込む
$ScoreLabel.text = tr("PLAYER_SCORE").format({"score": score})
# ja: "スコア: 1500" / en: "Score: 1500" / ko: "점수: 1500"
プレースホルダー名({score} など)は 全言語で共通 です。翻訳者は {score} をそのまま残し、前後の文章だけを訳します。数値の位置が言語で変わっても、format() が正しい場所に差し込んでくれます。
実践:言語切り替え付きオプション画面を組む
RPGのタイトル画面、対戦ゲームのオプション、モバイルの設定タブ——ジャンルを問わず、多言語ゲームには「言語を選ぶUI」が要ります。ここまでの部品を使って、 ドロップダウンで言語を選ぶと画面全体が切り替わる オプション画面を組んでみましょう。
鍵になるのは2つの仕組みです。 TranslationServer.set_locale() で言語を切り替え、 NOTIFICATION_TRANSLATION_CHANGED の通知で各UIが自分を再描画します。

まず、言語を切り替える側(オプション画面)です。やることは set_locale() を呼ぶ 1行だけ 。
extends Control
func _on_language_option_selected(index: int) -> void:
# ドロップダウンの選択に応じてロケールを切り替える
match index:
0: TranslationServer.set_locale("ja")
1: TranslationServer.set_locale("en")
2: TranslationServer.set_locale("ko")
# ↑ これだけで、対応した全ノードに翻訳変更の通知が飛ぶ
次に、翻訳されるテキストを持つ各ノード側です。_notification() で NOTIFICATION_TRANSLATION_CHANGED を受けたら、自分のテキストを更新します。
extends Label
func _notification(what: int) -> void:
# 言語が変わると全ノードにこの通知が飛んでくる
if what == NOTIFICATION_TRANSLATION_CHANGED:
_refresh_text()
func _refresh_text() -> void:
# プレースホルダー入りなど、スクリプトで組むテキストをここで再構築する
text = tr("PLAYER_SCORE").format({"score": Global.current_score})
ポイントは2つです。
- 言語変更を知るのは1箇所だけ :
set_locale()を呼ぶオプション画面だけが言語切り替えを知っていて、あとは通知に任せます。UIノードが100個あっても、切り替え側のコードは増えません。各ノードは 自分の表示更新に集中 できるので、見通しがよく壊れにくい設計になります。 - 静的なUIは通知すら不要 :
auto_translate_modeが効くLabelやButtonにキーを設定してあれば、言語変更時にGodotが自動で訳し直します。手動の_notification()が要るのは、 スコアのようにスクリプトで文字列を組み立てているノードだけ です。
初回起動時にOS言語へ自動で合わせる
初めて起動したとき、プレイヤーのOS言語に自動で合わせると親切 です。OS.get_locale_language() でOSの言語コードを取り、対応していればそれを、していなければ英語などにフォールバックします。

func _ready() -> void:
var os_lang := OS.get_locale_language() # "ja" / "en" / "fr" など言語コードのみ
var supported := ["ja", "en", "ko"]
if os_lang in supported:
TranslationServer.set_locale(os_lang)
else:
TranslationServer.set_locale("en") # 未対応の言語は英語で開く
OS.get_locale()は"ja_JP"のように地域付きで返しますが、OS.get_locale_language()は"ja"と言語コードだけを返します。ロケール設定には言語コードで十分なので、後者を使うとシンプルです。
この「OS言語で初期化」と「オプションで手動切り替え」を組み合わせれば、多言語ゲームの言語まわりはほぼ完成です。選んだ言語を次回も覚えておきたくなったら、Autoload に設定を持たせて セーブ/ロード するとよいでしょう。
よくある落とし穴とベストプラクティス
| 推奨事項 | 説明 |
|---|---|
| キー名は大文字+アンダースコア | START_GAME・LEVEL_COMPLETE のように統一する |
| プレースホルダーを活用 | 動的な値は文中に直書きせず {名前} で埋め込む |
| CJKフォントを用意する | 日本語・韓国語・中国語は、その字形を含むフォントをThemeに設定しないと豆腐(□)になる |
| フォールバック言語を決める | 未翻訳キーはキー名がそのまま出る。英語などを最終的な受け皿にする |
| 列名はロケールコードだけ | context・notes 列を混ぜない。備考はCSVの外で管理する |
未翻訳のキーは、Godotが キー名をそのまま返す 挙動を利用してフォールバックできます。例えばキー名自体を英語文にしておけば、訳が無い言語では英語がそのまま表示されます。
# キー名に英語をそのまま使う戦略(未翻訳時は英語が出る)
# CSV: keys,ja,ko
# Start Game,ゲームスタート,게임 시작
$TitleLabel.text = tr("Start Game") # 訳の無い言語では "Start Game" が表示される
CJKフォントの設定は、テーマシステムによる統一的なUI設計 でThemeにフォントを割り当てる方法が参考になります。文字が □ になったら、まずフォントを疑ってください。
おまけ:先に知っておくと良いこと
多言語対応の基本が組めたら、次はこのあたりが視野に入ります。今すぐは不要でも、名前だけ覚えておくと迷いません。
- 複数形は
tr_n()とPOファイルで :英語の「1 item / 5 items」のように数で表現が変わる言語には、tr_n(単数キー, 複数キー, 個数)を使います。ただし 複数形のルールはCSVでは定義できず、PO(Gettext)ファイルが必要 です。日本語・韓国語には単複の区別がないため、主に欧米言語向けの機能です。 - 文脈違いの同じ単語 :英語の「Home(家/ホーム画面)」のように、同じ単語でも文脈で訳が変わる場合は、
tr()の第2引数に コンテキスト を渡して訳し分けられます。 - 右横書き(RTL)言語 :アラビア語やヘブライ語は右から左へ流れます。対応する場合はレイアウトの反転も考慮が要ります。まずはLTR言語だけで土台を固めるのがおすすめです。
まとめ
- TranslationServer は翻訳キーと多言語テキストを紐付ける仕組み。コードはキーで呼ぶだけ
- CSV (
keys,ja,en,ko)で対応表を作り、自動生成される.translationをプロジェクトに登録する tr()でキーから訳文を取得。 プレースホルダー{名前}+format()で動的な値を埋め込むset_locale()で動的に切り替え、NOTIFICATION_TRANSLATION_CHANGEDで各UIが自分を再描画するOS.get_locale_language()でOS言語を検出し、未対応ならフォールバックする
まずは START_GAME の1キ ーを日英2言語で用意し、set_locale() で切り替わる瞬間を体験してみてください。「コードを触らずに言語が増える」感覚が掴めれば、i18nはもう怖くありません。
さらに学ぶために
- テーマシステムによる統一的なUI設計 ——CJKフォントをThemeに設定する
- Autoloadによるシーンをまたぐデータ管理 ——選んだ言語をグローバルに保持する
- セーブ/ロードシステムの実装 ——言語設定を次回起動に引き継ぐ
- Godot公式ドキュメント:Internationalizing games ——多言語対応の一次情報