ゲームを世界中のプレイヤーに届けるうえ で避けて通れないのが、多言語対応(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が自分を再描画します。
