ローカライゼーション

キーからテキストへのルックアップ、実行時の言語切り替え、プレイヤーが言語を変更すると即座に更新される UI テキスト。

UI テキストをハードコードせずに、ゲームを多言語で出荷しましょう。

インターフェースILocalizationService
オフスイッチNullLocalization
アセンブリCommonGameSystem.Localization(オプション — Unity 組み込みの uGUI パッケージが必要)
起動ブート時に自動登録。翻訳テーブルのロードは利用者側で行う

できること

メニューに "Start" を直接書く代わりに、キー"menu.start" のような安定した識別子 — を書きます。Localization サービスは実行時にそのキーを現在の言語のテキストへ解決します。プレイヤーが設定メニューで言語を切り替えると、画面上のすべての LocalizedText コンポーネントが即座に更新されます — シーンのリロードも再起動も不要です。

翻訳の欠落でゲームがクラッシュすることはありません。現在の言語でルックアップに失敗するとフォールバック言語(デフォルトは英語)にフォールバックし、それでも失敗した場合はキーそのものが返されます。UI には常に何かが表示されます。

翻訳は LocalizationTableAsset ScriptableObject に格納します — Inspector で入力するか、スプレッドシートから生成できるプレーンなデータアセットです。言語は標準の BCP-47 言語タグで識別します。ブラウザーや OS が使うのと同じ短いコードで、"en""ko""ja""zh-CN" などです。

このモジュールは独立したオプションアセンブリに含まれているため、プロジェクトから uGUI を削除するとアセンブリが除外されるだけです — フレームワークの残りは引き続きコンパイルされ、起動します。

クイックスタート

起動スクリプトでサービスを解決し、テーブルを一度だけロードします:

using CommonGameSystem.Core;
using UnityEngine;

[DefaultExecutionOrder(100)] // Run after the framework has started.
public class GameStartup : MonoBehaviour
{
    [SerializeField] private LocalizationTableAsset[] tables; // assign in the Inspector

    private ILocalizationService _loc;

    private void Awake()
    {
        _loc = ServiceLocator.Resolve<ILocalizationService>();
        _loc.LoadTables(tables);

        // Optional: start in the player's OS language.
        _loc.SetLocale(LocaleId.FromSystemLanguage(Application.systemLanguage));
    }
}

以降は、どのスクリプトからでも Get でテキストを取得できます:

string title = _loc.Get("menu.title");

API リファレンス

ルックアップ

  • string Get(string key) — キーを解決します: 現在の言語 → フォールバック言語 → キーそのもの、の順です。決してスローしません。
  • string Get(string key, params object[] args) — 同じルックアップの後、結果をインバリアントカルチャの string.Format でフォーマットします。不正なフォーマット文字列の場合はスローせず、未フォーマットのテキストを返します。
  • bool TryGet(string key, out string value) — 副作用のないルックアップです。キーがない場合は false を返します(value にはキーが設定されます)。何もログに出さないため、警告のスパムなしにキーの存在を調べるのに便利です。

言語の切り替え

  • void SetLocale(string localeId) — アクティブな言語を切り替えます。Event Bus に LocaleChanged イベントを発行し、選択を Configuration サービス経由で保存するため、セッションをまたいで保持されます。
  • string CurrentLocale { get; } — アクティブなロケール ID。
  • IReadOnlyList<string> AvailableLocales { get; } — ロード済みテーブルから見つかったロケール ID の一覧。言語選択 UI はこのリストから構築してください。
  • string GetLocaleDisplayName(string localeId) — その言語自身での言語名(たとえば韓国語なら "한국어")。言語選択 UI 用です。未設定の場合は ID にフォールバックします。

セットアップ

  • void LoadTables(IReadOnlyList<LocalizationTableAsset> tables) — 翻訳テーブルをロードし、保存済み(またはデフォルト)の言語をアクティブにします。起動時に一度だけ呼んでください。

静的ヘルパー

  • LocaleId.FromSystemLanguage(SystemLanguage)Application.systemLanguage を BCP-47 タグにマッピングします(たとえば SystemLanguage.Korean"ko")。初回起動時にプレイヤーの OS 言語を自動検出するのに使います。

LocalizedText コンポーネント

静的な UI テキストならコードは一切不要です。uGUI の Text または TextMeshPro コンポーネントに LocalizedText コンポーネントをアタッチし、Inspector でキーを設定してください。コンポーネントは有効化時にテキストを取得し、言語が変わるたびに再取得します。

値を埋め込む動的なテキストには SetArgs を使います:

using CommonGameSystem.Core;
using UnityEngine;

public class ScoreDisplay : MonoBehaviour
{
    private LocalizedText _locText;

    private void Start()
    {
        _locText = GetComponent<LocalizedText>();
    }

    public void SetScore(int newScore)
    {
        // Table entry: "score.current" = "Score: {0}"  →  displays "Score: 42"
        _locText.SetArgs(newScore);
    }
}

例: 言語ボタン

using CommonGameSystem.Core;
using UnityEngine;

public class LanguageMenu : MonoBehaviour
{
    private ILocalizationService _loc;

    private void Start()
    {
        _loc = ServiceLocator.Resolve<ILocalizationService>();
    }

    // Wire this to a UI button, passing "en", "ko", "ja", ...
    public void OnLanguageButtonClicked(string localeId)
    {
        _loc.SetLocale(localeId); // Every LocalizedText on screen updates live.
    }
}

選択は自動的に保存されます — 次のセッションはプレイヤーが選んだ言語で始まります。

無効化する

ServiceLocator.Replace<ILocalizationService>(new NullLocalization());

Get(key) はキーをそのまま返し、SetLocaleLoadTables は静かな no-op になり、何もログに残りません。軽量ビルドやテストでローカライゼーションを完全に取り除くのに使ってください。

よくある落とし穴

  • メインスレッド専用。 ワーカースレッドから GetSetLocale を呼ぶと InvalidOperationException がスローされます。MonoBehaviour のコールバックはすべて安全です。
  • サービスをキャッシュする。 Update() での解決は、毎フレームのディクショナリ検索の繰り返しです。代わりに Awake()Start() で参照をキャッシュしてください。
  • ロケール ID は完全一致が必要。 "EN""en" ではなく、Application.systemLanguage.ToString()"ko" ではなく "Korean" を返します。自動検出には LocaleId.FromSystemLanguage() を使い、テーブルには小文字の BCP-47 タグを使ってください。
  • LocalizedText は有効化のたびに再購読する。 プールされた UI プレハブ(ダメージ数値、トースト)では、プールの 1 サイクルごとに LocaleChanged への購読と購読解除が発生します。これは正しい挙動で、再アクティブ化時に現在の言語を反映するためですが、高頻度のプールには注意してください。動的なテキストの更新には SetArgs を優先してください。
  • シャットダウン順序。 サービスは起動順の逆順でシャットダウンするため、Localization サービスが Event Bus より先に破棄されることがあります。その後に LocaleChanged イベントが届いた場合、LocalizedText は静かに握りつぶします — テキストは更新されませんが、クラッシュもしません。
  • カスタム型は IL2CPP で link.xml が必要。 ローカライゼーションキーを持つ独自の設定型をシリアライズする場合は、プロジェクトの link.xml でそれらが保持されるようにしてください。出荷されるフレームワークアセンブリは自身の型をすでに保持しています。

関連ページ

  • Event BusLocaleChanged イベント
  • Configuration — 言語の選択が保存される場所
  • UI Framework — ローカライズ済みテキストを載せるパネルと画面