【Godot】TranslationServerで多言語対応を実装する

作成: 2026-02-08最終更新: 2026-07-09

Godotの多言語対応システムTranslationServerの使い方を、CSV翻訳ファイルの作成・登録・tr()での表示から、プレースホルダー、言語の動的切り替え、OS言語の自動検出まで、図つきで実践的に解説します。

ゲームを世界中のプレイヤーに届けるうえで避けて通れないのが、多言語対応(i18n)です。とはいえ「UIの文字を全部コードで書き分けるの……?」と身構えてしまうかもしれません。実はGodotの TranslationServer を使えば、 コードを一切書き換えずに、CSVに一行足すだけで対応言語を増やせます

仕組みはシンプルで、やることは3つだけ——翻訳表をCSVで用意し、プロジェクトに登録し、あとはキーで呼び出す。この記事では、日本語・英語・韓国語の3言語を例に、翻訳ファイルの作成から動的な言語切り替え、OS言語の自動検出まで、図を交えて実践的に解説します。

多言語対応のイメージ。1つのUIパネルの文字が、日本語・英語・韓国語へと切り替わっていく様子

この記事でわかること

  • TranslationServer の仕組み(翻訳キーと多言語テキストの紐付け)
  • CSV翻訳ファイル の作り方と、プロジェクトへの登録
  • tr()プレースホルダー による表示
  • set_locale() での 動的な言語切り替え と、OS言語の自動検出

Sponsored

TranslationServerの仕組み

まず全体像です。TranslationServerは、 翻訳キー言語別テキスト を紐付けるシステムです。コードに「ゲームスタート」や「Start Game」を直接書く代わりに、START_GAME のような共通キーを使い、実行時に 現在の言語に応じたテキスト を取り出します。

TranslationServerの仕組みの図。1つの翻訳キー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 の後に、各言語の ロケールコードjaenko)を列名として並べる
  • 2行目以降は「キー名, 日本語, 英語, 韓国語, …」
  • キー名は 大文字+アンダースコア が慣例(START_GAMELEVEL_COMPLETE
  • 言語を足したいときは、 ヘッダーに列を1つ増やして訳文を埋めるだけ

CSVを res://translations/ に置くと、Godotが 自動でインポート し、言語ごとの .translation リソース(game_text.ja.translation など)を生成します。あとはこれをプロジェクトに登録します。

CSVから翻訳リソースへの流れの図。keys/ja/en/koの表が自動インポートで.ja/.en/.koの3つのtranslationリソースに分かれ、プロジェクト設定のローカライゼーションに登録される

登録は「プロジェクト」→「プロジェクト設定」→「ローカライゼーション」タブ →「翻訳」で「追加」を押し、生成された .translation ファイル(jaenko の3つ)をすべて追加します。これでコードから tr() が使えるようになります。

tips: Godot 4のCSVインポーターは、keys 以外の列名を すべてロケールコードとして解釈 します。commentcontext のような列を混ぜると、それも言語だと誤認されます。 翻訳者向けの備考はCSVの外 (スプレッドシートのメモや別シート)で管理しましょう。

Sponsored

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}
プレースホルダーの差し込みの図。訳文スコア: {score}のうち{score}の部分にformatで1500が差し込まれ、日本語スコア: 1500・英語Score: 1500・韓国語점수: 1500になる
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() が正しい場所に差し込んでくれます。

Sponsored

実践:言語切り替え付きオプション画面を組む

RPGのタイトル画面、対戦ゲームのオプション、モバイルの設定タブ——ジャンルを問わず、多言語ゲームには「言語を選ぶUI」が要ります。ここまでの部品を使って、 ドロップダウンで言語を選ぶと画面全体が切り替わる オプション画面を組んでみましょう。

鍵になるのは2つの仕組みです。 TranslationServer.set_locale() で言語を切り替え、 NOTIFICATION_TRANSLATION_CHANGED の通知で各UIが自分を再描画します。

言語切り替えの通知フローの図。オプション画面のドロップダウンでenを選ぶとset_locale(en)が呼ばれ、TranslationServerが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の言語コードを取り、対応していればそれを、していなければ英語などにフォールバックします。

OS言語の自動検出フローの図。OS.get_locale_languageで取得した言語が対応リスト(ja/en/ko)に含まれればset_localeで設定、含まれなければ英語にフォールバックする分岐
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_GAMELEVEL_COMPLETE のように統一する
プレースホルダーを活用動的な値は文中に直書きせず {名前} で埋め込む
CJKフォントを用意する日本語・韓国語・中国語は、その字形を含むフォントをThemeに設定しないと豆腐(□)になる
フォールバック言語を決める未翻訳キーはキー名がそのまま出る。英語などを最終的な受け皿にする
列名はロケールコードだけcontextnotes 列を混ぜない。備考は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 は翻訳キーと多言語テキストを紐付ける仕組み。コードはキーで呼ぶだけ
  • CSVkeys,ja,en,ko)で対応表を作り、自動生成される .translation をプロジェクトに登録する
  • tr() でキーから訳文を取得。 プレースホルダー {名前}format() で動的な値を埋め込む
  • set_locale() で動的に切り替え、NOTIFICATION_TRANSLATION_CHANGED で各UIが自分を再描画する
  • OS.get_locale_language() でOS言語を検出し、未対応ならフォールバックする

まずは START_GAME の1キーを日英2言語で用意し、set_locale() で切り替わる瞬間を体験してみてください。「コードを触らずに言語が増える」感覚が掴めれば、i18nはもう怖くありません。

さらに学ぶために