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

作成: 2026-02-08

Godotの多言語対応システムTranslationServerの使い方を解説。CSV翻訳ファイルの作成、動的言語切り替え、プレースホルダー活用まで網羅。

概要

動作確認環境: Godot 4.3+

ゲームを世界中のプレイヤーに届けるには、多言語対応(i18n: internationalization)が不可欠です。「UIテキストを日本語・英語・韓国語で表示したい」「プレイヤーの言語設定に応じて自動切り替えしたい」といったニーズに、Godotの TranslationServer が対応します。

多言語対応と聞くと複雑に感じるかもしれませんが、Godotでは驚くほどシンプルです。やることは基本的に3つだけ — 翻訳データをCSVで用意する、プロジェクトに登録する、tr() 関数で呼び出す。これだけで、コードを変更せずに何言語でも追加できるようになります。

この記事では、CSVファイルを使った翻訳管理から、動的な言語切り替え、プレースホルダーの活用まで、日本語・英語・韓国語の3言語を例に実践的に解説します。

TranslationServerの仕組み

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

なぜこの仕組みが必要かというと、もしコードに直接日本語を書いてしまうと、英語に対応するためにコードを書き換える必要があります。3言語、5言語と増えるたびに修正箇所が膨大になり、バグの温床になります。翻訳キーを使うことで、コードの変更なしに言語を追加できるのです。

基本フロー:

  1. 翻訳ファイル(CSVなど)に キー, 日本語, 英語, 韓国語 の対応表を記述
  2. プロジェクト設定で翻訳ファイルを登録
  3. コード内で tr("キー") を呼ぶと、現在の言語設定に応じたテキストが返される

:

# 現在の言語が日本語の場合
tr("START_GAME")  # → "ゲームスタート"

# 現在の言語が英語の場合
tr("START_GAME")  # → "Start Game"

# 現在の言語が韓国語の場合
tr("START_GAME")  # → "게임 시작"

このように、tr() を呼ぶ側のコードはまったく同じで、言語設定に応じて返されるテキストだけが変わります。

CSV翻訳ファイルの作成

TranslationServerの仕組みがわかったところで、実際に翻訳データを用意してみましょう。翻訳データの管理には、シンプルなCSV形式がおすすめです。ExcelやGoogle Sheetsでも編集できるため、翻訳者がプログラマーでなくてもチームで管理しやすいのが大きなメリットです。

  1. CSVファイルを作成:

    • プロジェクトフォルダ内に translations/ フォルダを作成
    • game_text.csv を作成
  2. CSVの構造:

keys,ja,en,ko
START_GAME,ゲームスタート,Start Game,게임 시작
SETTINGS,設定,Settings,설정
QUIT,終了,Quit,종료
HEALTH,体力,Health,체력
SCORE,スコア,Score,점수
LEVEL_COMPLETE,ステージクリア!,Level Complete!,스테이지 클리어!

ルール:

  • 1行目(ヘッダー): keys(翻訳キー列)の後に、各言語のロケールコード(ja, en, ko)を列名として並べる
  • 2行目以降: キー名, 日本語テキスト, 英語テキスト, 韓国語テキスト, ...
  • キー名は大文字+アンダースコアが慣例(START_GAME, LEVEL_COMPLETE
  • 新しい言語を追加するときは、ヘッダーに列を追加してテキストを埋めるだけ

tips: Godot 4のCSVインポーターは、keys 以外の列名をロケールコードとして解釈します。列名は必ず ja, en, ko などの有効なロケールコードにしてください。commentcontext といった列名を入れると、それもロケールとして認識されてしまう可能性があります。

プロジェクト設定への登録

CSVファイルが用意できたら、Godotエディタに認識させましょう。Godot 4ではCSVファイルを res:// 以下に配置すると 自動的にインポート されます。手動でファイル変換などをする必要はありません。

  1. CSVファイルを配置: res://translations/game_text.csv に保存
  2. 自動インポート確認: エディタがCSVを認識すると、言語ごとに .translation リソースが自動生成される(例: game_text.ja.translation, game_text.en.translation, game_text.ko.translation
  3. プロジェクト設定に登録:
    • 「プロジェクト」→「プロジェクト設定」→「ローカライゼーション」タブ
    • 「翻訳」セクションで「追加」をクリック
    • 生成された .translation ファイルをすべて追加(ja, en, ko の3ファイル)

登録が完了すれば、コード内で tr() 関数が使えるようになります。

tr()関数で翻訳テキストを表示

プロジェクト設定への登録が完了したら、あとはコード内で tr() を呼ぶだけです。ここが多言語対応の醍醐味ともいえる部分で、コードの変更なしに対応言語を増やせます。

基本的な使い方

extends Control

func _ready():
    # ラベルに翻訳テキストを設定
    $TitleLabel.text = tr("START_GAME")
    $SettingsButton.text = tr("SETTINGS")
    $QuitButton.text = tr("QUIT")

tr() に渡すのはCSVの keys 列に書いたキー名です。現在のロケールが ja なら日本語が、en なら英語が、ko なら韓国語が返されます。もし該当するキーが見つからない場合は、キー名がそのまま文字列として返されます。

tips: Godot 4のUIノード(Label、Button等)には auto_translate_mode プロパティがあり、デフォルトで有効です。テキストに翻訳キーを直接設定するだけで自動翻訳されるため、tr() を明示的に呼ぶ必要がないケースもあります。

プレースホルダーの活用

「スコア: 1500」のように、翻訳テキスト内に動的な値を埋め込みたい場面は頻繁にあります。この場合、CSV内に {key} の形式でプレースホルダーを定義し、GDScriptの format() メソッドで値を差し込みます。

CSVファイル:

keys,ja,en,ko
PLAYER_SCORE,スコア: {score},Score: {score},점수: {score}
HEALTH_STATUS,体力: {current}/{max},Health: {current}/{max},체력: {current}/{max}

GDScript:

func update_score_label(score: int):
    $ScoreLabel.text = tr("PLAYER_SCORE").format({"score": score})
    # ja: "スコア: 1500"
    # en: "Score: 1500"
    # ko: "점수: 1500"

func update_health_label(current: int, max_health: int):
    $HealthLabel.text = tr("HEALTH_STATUS").format({
        "current": current,
        "max": max_health
    })
    # ja: "体力: 75/100"
    # en: "Health: 75/100"
    # ko: "체력: 75/100"

プレースホルダーの名前({score}, {current} 等)はすべての言語で共通です。翻訳者は {score} をそのまま残し、前後の文章だけを翻訳します。

動的な言語切り替え

翻訳テキストの表示ができるようになりましたが、実際のゲームではプレイヤーがオプション画面から言語を変更できるようにしたいですよね。TranslationServer.set_locale() を使えば、実行中にいつでも言語を変更できます。言語を変更した後は、表示中のテキストを更新する処理が必要です。

extends Control

func _ready():
    # 初期言語を日本語に設定
    TranslationServer.set_locale("ja")
    update_ui()

func _on_language_option_selected(index: int):
    # 言語切り替え
    match index:
        0: TranslationServer.set_locale("ja")  # 日本語
        1: TranslationServer.set_locale("en")  # 英語
        2: TranslationServer.set_locale("ko")  # 韓国語

    # UI全体を更新
    update_ui()

func update_ui():
    $TitleLabel.text = tr("START_GAME")
    $SettingsButton.text = tr("SETTINGS")
    $QuitButton.text = tr("QUIT")

現在の言語を取得:

var current_locale = TranslationServer.get_locale()
print(current_locale)  # "ja", "en", "ko" のいずれか

OS言語の自動検出

手動での言語切り替えに加えて、初回起動時にプレイヤーの環境に合わせて自動設定できると、さらに親切なゲームになります。Godotでは OS.get_locale_language() を使ってOS言語を取得できます。

以下の例では、OSの言語が対応済みの言語リストに含まれていればそれを設定し、含まれていなければ英語をデフォルト(フォールバック)として設定しています。

extends Node

func _ready():
    # OS言語を取得
    var os_locale = OS.get_locale_language()  # "ja", "en", "ko", "fr", etc.

    # 対応言語かチェック
    var supported_locales = ["ja", "en", "ko"]
    if os_locale in supported_locales:
        TranslationServer.set_locale(os_locale)
    else:
        # 未対応の場合は英語をフォールバックに
        TranslationServer.set_locale("en")

    print("言語設定: ", TranslationServer.get_locale())

OS.get_locale() と OS.get_locale_language() の違い:

  • OS.get_locale()"ja_JP" のような地域付き形式を返す
  • OS.get_locale_language() は言語コードのみ "ja" を返す

TranslationServerのロケール設定には "ja" のような言語コードのみの形式で十分なので、OS.get_locale_language() を使う方がシンプルです。

言語変更の通知を受け取る

シーン内に多数のUIノードがある場合、言語を変更したときにすべてのノードで個別に update_ui() を呼ぶのは面倒です。_notification() を使うと、言語変更時に NOTIFICATION_TRANSLATION_CHANGED が全ノードに通知されるため、UIの再描画を各ノードで独立して管理できます。

func _notification(what: int) -> void:
    if what == NOTIFICATION_TRANSLATION_CHANGED:
        # 言語が変更された時に自動で呼ばれる
        _update_dynamic_texts()

func _update_dynamic_texts():
    $ScoreLabel.text = tr("PLAYER_SCORE").format({"score": current_score})

この方法なら、言語変更のロジックを知っているのは TranslationServer.set_locale() を呼ぶ1箇所だけで済みます。各UIノードは自分の表示更新に集中できるため、コードの見通しが良くなります。

複数形対応(tr_n)

英語の「1 item / 5 items」のように、数によって表現が変わる言語への対応が必要になることもあります。tr_n() を使うと単数形/複数形を自動切り替えできます。

# POファイル(.po)での複数形対応が必要(CSVでは非対応)
var text = tr_n("ONE_ITEM", "MANY_ITEMS", item_count)
# item_count=1: "1 item"
# item_count=5: "5 items"

tips: tr_n() による複数形はPO(Gettext)ファイルで対応します。CSVでは複数形の定義ができないため、複数形が必要な場合はPOファイルの利用を検討してください。韓国語や日本語には英語のような単数/複数の区別がないため、主に英語やフランス語など欧州言語向けの機能です。

ベストプラクティス

ここまでの実装をプロジェクトに組み込む際に、押さえておきたいポイントをまとめました。翻訳作業が本格化する前にルールを決めておくと、後からの修正コストを大幅に減らせます。

推奨事項説明
キー名は大文字+アンダースコアSTART_GAME, LEVEL_COMPLETE のように統一
プレースホルダーを活用動的な値は {key} で埋め込む
フォント対応を確認日本語・韓国語などの文字を表示するフォントが適用されているか確認
フォールバック言語を設定未翻訳テキストがある場合に備え、英語などの主要言語にフォールバック
自動翻訳を無効化EditorSettingsで「Internationalization → Editor Translation → Use Editor Translation」をオフ
CSV管理ツールを使うExcelやGoogle Sheetsでチーム管理
コンテキスト情報はCSV外で管理翻訳者向けの備考はスプレッドシートのメモ機能や別シートで管理する

フォールバック言語の実装

未翻訳のキーがある場合、Godotはキー名をそのまま文字列として返します。CSVの keys 列に英語テキストをそのままキー名として使う戦略をとれば、未翻訳時に英語がフォールバックとして表示されます。

# 戦略1: キー名に英語を使う(未翻訳時のフォールバック)
# CSV: keys,ja,ko
#      Start Game,ゲームスタート,게임 시작
# → 翻訳がない言語では "Start Game" がそのまま表示される

# 戦略2: コードでフォールバックを実装
func get_text(key: String) -> String:
    var text = tr(key)
    if text == key:
        # 翻訳が見つからなかった(キーがそのまま返された)
        # 英語ロケールで再取得
        var current = TranslationServer.get_locale()
        TranslationServer.set_locale("en")
        text = tr(key)
        TranslationServer.set_locale(current)
    return text

tips: CSVの列名には有効なロケールコード(ja, en, ko など)だけを使いましょう。contextnotes といった列を追加すると、Godot 4のCSVインポーターがそれもロケールとして解釈してしまう可能性があります。翻訳者向けの備考はGoogle Sheetsのメモ機能や別シートで管理するのが安全です。

まとめ

  • TranslationServer は翻訳キーと多言語テキストを紐付けるシステム
  • CSV形式 で翻訳ファイルを作成し、プロジェクト設定に登録
  • tr() 関数 で翻訳キーを指定すると、現在の言語設定に応じたテキストが返される
  • プレースホルダー{key})で動的な値を埋め込み可能
  • 動的言語切り替えTranslationServer.set_locale() で実現
  • OS言語自動検出OS.get_locale_language() を使用
  • CSVの列名にはロケールコードのみを使い、コンテキスト情報はCSV外で管理する
  • フォールバック言語の設定で、未翻訳テキストへの対策も忘れずに

さらに学ぶために