【Cocos Creator】アタッチするだけ!LocalizationMgr (言語切替)の実装方法【TypeScript】

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

Godot4& GDScriptではじめる 2Dゲーム開発レシピ

新品価格
¥590から
(2025/12/13 21:46時点)

Unity 6 C#スクリプト 100本ノック

新品価格
¥1,230から
(2025/12/29 10:28時点)

Cocos Creator100本ノックTypeScriptで書く!

新品価格
¥1,250から
(2025/12/29 10:32時点)

【Cocos Creator 3.8】LocalizationMgr の実装:アタッチするだけで日本語/英語を即座に切り替える汎用スクリプト

本記事では、Cocos Creator 3.8.7 + TypeScript で、TranslationServer を制御して日本語/英語を即座に切り替える「LocalizationMgr」コンポーネントを実装します。

このコンポーネントは、任意のノードにアタッチするだけで動作し、外部の GameManager やシングルトンに依存しません。Inspector から初期言語や UI 更新のタイミングを設定できるため、シーンごとに簡単にローカライズ設定を変えられるのが特徴です。


コンポーネントの設計方針

1. 機能要件の整理

  • Cocos Creator 標準の TranslationServer(3.8 では director.root?.dataPoolManager.translationServer 経由)を制御する。
  • 日本語 (ja) / 英語 (en) の 2 言語を即座に切り替える。
  • Inspector から以下を設定できるようにする:
    • 初期言語(シーン開始時に自動で設定)
    • 現在の言語の表示用(エディタ確認用)
    • キー入力やメソッド呼び出しでの言語切替制御
  • コンポーネント単体で完結させるため、他のカスタムスクリプトには一切依存しない
  • 防御的実装として、TranslationServer が取得できない場合は error ログを出し、処理を安全に中断する。

2. Cocos Creator 3.8 における TranslationServer へのアクセス方針

Cocos Creator 3.8 では、翻訳関連のサービスは director.root?.dataPoolManager.translationServer のような形で内部に保持されています。バージョンやビルド設定によって構造が変わる可能性があるため、以下のような方針で防御的にアクセスします。

  • director.root が存在するかチェック。
  • dataPoolManager が存在するかチェック。
  • translationServer が存在するかチェック。
  • いずれかが存在しない場合は、error ログを出して以降の処理を行わない。

TranslationServer 側の API は、以下のような最小想定で扱います(実際の API 名はプロジェクト設定に依存しますが、汎用的な想定として実装します)。

  • setLanguage(langCode: string) : 言語コードを指定して切り替える。
  • getLanguage(): string : 現在の言語コードを取得する。

もしプロジェクトの TranslationServer API 名が異なる場合は、該当箇所のメソッド名だけを差し替えれば動くように、実装は 1 箇所にまとめています。

3. Inspector で設定可能なプロパティ設計

LocalizationMgr コンポーネントで用意するプロパティは次の通りです。

  • initialLanguage (Enum)
    • 型: LanguageType(独自 enum: JA / EN
    • 役割: シーン開始時(start())に自動で設定する言語。
    • 例: JA を指定するとゲーム開始時に日本語 UI へ、EN なら英語 UI へ切り替え。
  • applyOnStart (boolean)
    • 初期値: true
    • 役割: シーン開始時に initialLanguage を自動適用するかどうか。
    • false にすると、手動で setJapanese() / setEnglish() / toggleLanguage() を呼ぶまで言語を変更しない。
  • enableKeyToggle (boolean)
    • 初期値: false
    • 役割: エディタ再生中に特定キーで言語を切り替えるデバッグ機能を有効にするか。
  • toggleKey (string)
    • 初期値: 'L'
    • 役割: enableKeyToggletrue のとき、このキーを押すと日本語/英語をトグルする。
    • 大文字・小文字を区別せずに判定する実装にします。
  • currentLanguage (readonly string / 表示用)
    • Inspector 上で現在の言語コード(ja / en など)を確認するための表示用プロパティ。
    • スクリプトから更新されるが、ユーザーが直接編集しても意味はない(説明を tooltip で明記)。

また、エディタの「イベントから直接呼び出しやすい public メソッド」も用意します。

  • setJapanese() : 言語を日本語に切り替え。
  • setEnglish() : 言語を英語に切り替え。
  • toggleLanguage() : 現在の言語が日本語なら英語へ、英語なら日本語へ切り替え。

これにより、ボタンの ClickEvents から LocalizationMgr のメソッドを直接呼び出して、UI ボタンで言語切替を実装できます。


TypeScriptコードの実装


import { _decorator, Component, director, systemEvent, SystemEvent, EventKeyboard, KeyCode } from 'cc';
const { ccclass, property, tooltip } = _decorator;

/**
 * 言語種別の列挙
 * Inspector では JA / EN として選択できるようにする。
 */
enum LanguageType {
    JA = 0,
    EN = 1,
}

@ccclass('LocalizationMgr')
export class LocalizationMgr extends Component {

    @property({
        type: LanguageType,
        tooltip: 'シーン開始時に適用する初期言語。\nJA: 日本語, EN: 英語',
    })
    public initialLanguage: LanguageType = LanguageType.JA;

    @property({
        tooltip: 'true の場合、start() のタイミングで initialLanguage を自動適用します。',
    })
    public applyOnStart: boolean = true;

    @property({
        tooltip: 'true にすると、再生中に特定キーを押すことで日本語/英語をトグル切り替えできます(デバッグ用)。',
    })
    public enableKeyToggle: boolean = false;

    @property({
        tooltip: '言語トグルに使用するキー(例: "L")。\n大文字・小文字は区別されません。',
    })
    public toggleKey: string = 'L';

    @property({
        tooltip: '現在の言語コードを表示します(例: "ja", "en")。\nスクリプトから自動更新されるため、手動で変更する必要はありません。',
        readonly: true,
    })
    public currentLanguage: string = '';

    /**
     * TranslationServer への参照。
     * 3.8 では director.root?.dataPoolManager.translationServer のような場所に存在することを想定。
     * any 型で保持し、存在チェックとメソッド存在チェックを行う。
     */
    private _translationServer: any | null = null;

    /**
     * キーボードトグル用のキャッシュキーコード。
     */
    private _toggleKeyCode: KeyCode | null = null;

    onLoad() {
        // TranslationServer を探す
        this._initTranslationServer();
        // キートグル用キーコードを準備
        this._initToggleKeyCode();

        // キーボードイベント登録(必要な場合のみ)
        if (this.enableKeyToggle) {
            this._registerKeyboardEvent();
        }
    }

    start() {
        // シーン開始時に初期言語を適用
        if (this.applyOnStart) {
            if (this.initialLanguage === LanguageType.JA) {
                this.setJapanese();
            } else {
                this.setEnglish();
            }
        } else {
            // 現在の言語を TranslationServer から取得して表示用プロパティを更新
            this._updateCurrentLanguageFromServer();
        }
    }

    onEnable() {
        // コンポーネントが有効化されたとき、キートグルが有効ならイベントを登録
        if (this.enableKeyToggle) {
            this._registerKeyboardEvent();
        }
    }

    onDisable() {
        // 無効化時にイベント解除
        this._unregisterKeyboardEvent();
    }

    onDestroy() {
        // 破棄時にも念のためイベント解除
        this._unregisterKeyboardEvent();
    }

    /**
     * 日本語に切り替える(Button の ClickEvents からも直接呼び出し可能)。
     */
    public setJapanese() {
        this._setLanguageCode('ja');
    }

    /**
     * 英語に切り替える(Button の ClickEvents からも直接呼び出し可能)。
     */
    public setEnglish() {
        this._setLanguageCode('en');
    }

    /**
     * 現在言語が ja なら en、そうでなければ ja に切り替える。
     */
    public toggleLanguage() {
        if (!this._translationServer) {
            console.warn('[LocalizationMgr] TranslationServer が見つからないため、toggleLanguage は動作しません。');
            return;
        }

        const current = this._getLanguageCodeFromServer();
        const next = (current === 'ja') ? 'en' : 'ja';
        this._setLanguageCode(next);
    }

    /**
     * TranslationServer を初期化して取得する。
     * 存在しない場合は error ログを出して _translationServer を null にする。
     */
    private _initTranslationServer() {
        const root: any = (director as any).root;
        if (!root) {
            console.error('[LocalizationMgr] director.root が見つかりません。TranslationServer にアクセスできません。');
            this._translationServer = null;
            return;
        }

        const dataPoolManager = root.dataPoolManager;
        if (!dataPoolManager) {
            console.error('[LocalizationMgr] dataPoolManager が見つかりません。TranslationServer にアクセスできません。');
            this._translationServer = null;
            return;
        }

        const translationServer = dataPoolManager.translationServer;
        if (!translationServer) {
            console.error('[LocalizationMgr] translationServer が見つかりません。プロジェクト設定を確認してください。');
            this._translationServer = null;
            return;
        }

        // 最低限 setLanguage が存在するかチェック(なければ API 名をプロジェクトに合わせて修正する必要がある)
        if (typeof translationServer.setLanguage !== 'function' && typeof translationServer.setLang !== 'function') {
            console.error('[LocalizationMgr] TranslationServer に setLanguage / setLang メソッドが見つかりません。プロジェクトの API 名を確認してください。');
            this._translationServer = null;
            return;
        }

        this._translationServer = translationServer;
        this._updateCurrentLanguageFromServer();
        console.log('[LocalizationMgr] TranslationServer を初期化しました。');
    }

    /**
     * TranslationServer に言語コードを設定する共通処理。
     * @param lang 設定したい言語コード(例: "ja", "en")
     */
    private _setLanguageCode(lang: string) {
        if (!this._translationServer) {
            console.error('[LocalizationMgr] TranslationServer が見つからないため、言語を設定できません。');
            return;
        }

        // TranslationServer の API 名が setLanguage か setLang かを動的に判定
        if (typeof this._translationServer.setLanguage === 'function') {
            this._translationServer.setLanguage(lang);
        } else if (typeof this._translationServer.setLang === 'function') {
            this._translationServer.setLang(lang);
        } else {
            console.error('[LocalizationMgr] TranslationServer に有効な言語設定メソッドが存在しません。setLanguage / setLang を確認してください。');
            return;
        }

        this.currentLanguage = lang;
        console.log(`[LocalizationMgr] 言語を "${lang}" に切り替えました。`);
    }

    /**
     * TranslationServer から現在の言語コードを取得し、currentLanguage を更新する。
     */
    private _updateCurrentLanguageFromServer() {
        if (!this._translationServer) {
            return;
        }
        const lang = this._getLanguageCodeFromServer();
        if (lang) {
            this.currentLanguage = lang;
        }
    }

    /**
     * TranslationServer から現在の言語コードを取得する。
     * getLanguage / getLang のどちらかが存在する前提で動的に呼び出す。
     */
    private _getLanguageCodeFromServer(): string {
        if (!this._translationServer) {
            return '';
        }

        let lang = '';
        if (typeof this._translationServer.getLanguage === 'function') {
            lang = this._translationServer.getLanguage();
        } else if (typeof this._translationServer.getLang === 'function') {
            lang = this._translationServer.getLang();
        }

        if (typeof lang !== 'string') {
            lang = '';
        }
        return lang;
    }

    /**
     * Inspector の toggleKey (文字列) から KeyCode を推定してキャッシュする。
     * 未対応のキーの場合は null のままにして警告を出す。
     */
    private _initToggleKeyCode() {
        if (!this.toggleKey || this.toggleKey.length === 0) {
            this._toggleKeyCode = null;
            return;
        }

        const keyChar = this.toggleKey.toUpperCase();

        switch (keyChar) {
            case 'A': this._toggleKeyCode = KeyCode.KEY_A; break;
            case 'B': this._toggleKeyCode = KeyCode.KEY_B; break;
            case 'C': this._toggleKeyCode = KeyCode.KEY_C; break;
            case 'D': this._toggleKeyCode = KeyCode.KEY_D; break;
            case 'E': this._toggleKeyCode = KeyCode.KEY_E; break;
            case 'F': this._toggleKeyCode = KeyCode.KEY_F; break;
            case 'G': this._toggleKeyCode = KeyCode.KEY_G; break;
            case 'H': this._toggleKeyCode = KeyCode.KEY_H; break;
            case 'I': this._toggleKeyCode = KeyCode.KEY_I; break;
            case 'J': this._toggleKeyCode = KeyCode.KEY_J; break;
            case 'K': this._toggleKeyCode = KeyCode.KEY_K; break;
            case 'L': this._toggleKeyCode = KeyCode.KEY_L; break;
            case 'M': this._toggleKeyCode = KeyCode.KEY_M; break;
            case 'N': this._toggleKeyCode = KeyCode.KEY_N; break;
            case 'O': this._toggleKeyCode = KeyCode.KEY_O; break;
            case 'P': this._toggleKeyCode = KeyCode.KEY_P; break;
            case 'Q': this._toggleKeyCode = KeyCode.KEY_Q; break;
            case 'R': this._toggleKeyCode = KeyCode.KEY_R; break;
            case 'S': this._toggleKeyCode = KeyCode.KEY_S; break;
            case 'T': this._toggleKeyCode = KeyCode.KEY_T; break;
            case 'U': this._toggleKeyCode = KeyCode.KEY_U; break;
            case 'V': this._toggleKeyCode = KeyCode.KEY_V; break;
            case 'W': this._toggleKeyCode = KeyCode.KEY_W; break;
            case 'X': this._toggleKeyCode = KeyCode.KEY_X; break;
            case 'Y': this._toggleKeyCode = KeyCode.KEY_Y; break;
            case 'Z': this._toggleKeyCode = KeyCode.KEY_Z; break;
            default:
                this._toggleKeyCode = null;
                console.warn(`[LocalizationMgr] toggleKey "${this.toggleKey}" は現在の実装では未対応です。A〜Z のいずれかを指定してください。`);
                break;
        }
    }

    /**
     * キーボードイベントを登録する。
     */
    private _registerKeyboardEvent() {
        if (!this._toggleKeyCode) {
            return;
        }
        systemEvent.on(SystemEvent.EventType.KEY_UP, this._onKeyUp, this);
    }

    /**
     * キーボードイベントを解除する。
     */
    private _unregisterKeyboardEvent() {
        systemEvent.off(SystemEvent.EventType.KEY_UP, this._onKeyUp, this);
    }

    /**
     * キーアップイベントハンドラ。
     * 指定キーが離されたときに toggleLanguage() を呼び出す。
     */
    private _onKeyUp(event: EventKeyboard) {
        if (!this.enableKeyToggle || !this._toggleKeyCode) {
            return;
        }
        if (event.keyCode === this._toggleKeyCode) {
            this.toggleLanguage();
        }
    }
}

コードの主要部分の解説

  • onLoad()
    • _initTranslationServer() で TranslationServer を取得し、存在しない場合は error ログを出して以降の処理を安全にスキップ。
    • _initToggleKeyCode() で Inspector の toggleKey から KeyCode を算出。
    • enableKeyToggletrue の場合のみ、キーボードイベントを登録。
  • start()
    • applyOnStarttrue なら、initialLanguage をもとに setJapanese() または setEnglish() を呼び出す。
    • false の場合は、TranslationServer から現在の言語を取得して currentLanguage に反映。
  • setJapanese() / setEnglish() / toggleLanguage()
    • すべて _setLanguageCode() に集約して実際の切り替え処理を行う。
    • ボタンイベントから直接呼び出せるよう public メソッドとして定義。
  • _setLanguageCode()
    • TranslationServer の setLanguage() または setLang() を動的に判定して呼び出す。
    • 成功したら currentLanguage を更新し、ログを出力。
    • TranslationServer が取得できない場合や API が見つからない場合は error ログのみで安全に終了。
  • キーボードトグル処理
    • _initToggleKeyCode()toggleKey(例: “L”)を KeyCode.KEY_L に変換。
    • enableKeyToggletrue かつ _toggleKeyCode が有効な場合のみ、systemEventKEY_UP イベントを登録。
    • 指定キーが離されたときに toggleLanguage() を呼び出す。

使用手順と動作確認

1. スクリプトファイルの作成

  1. Assets パネルで右クリック → Create → TypeScript を選択。
  2. ファイル名を LocalizationMgr.ts に変更。
  3. 生成されたスクリプトをダブルクリックして開き、本文をすべて削除して、上記の TypeScript コードを丸ごと貼り付けます。
  4. 保存します(Ctrl+S / Cmd+S)。

2. テスト用シーンノードの準備

  1. Hierarchy パネルで右クリック → Create → Empty Node を選択し、名前を LocalizationRoot などに変更します。
  2. このノードは単なる「ローカライズ制御用の入れ物」なので、特別なコンポーネントは不要です。

3. LocalizationMgr コンポーネントのアタッチ

  1. Hierarchy で LocalizationRoot ノードを選択。
  2. Inspector 下部の Add Component ボタンをクリック。
  3. Custom カテゴリから LocalizationMgr を選択してアタッチします。

4. Inspector プロパティの設定

LocalizationRoot を選択した状態で、Inspector に表示される LocalizationMgr のプロパティを確認・設定します。

  • Initial Language(initialLanguage)
    • 例: JA に設定すると、シーン開始時に日本語に切り替え。
    • 例: EN に設定すると、シーン開始時に英語に切り替え。
  • Apply On Start(applyOnStart)
    • 通常は ON(true) のままで OK。
    • シーン開始時に自動で言語を切り替えたくない場合のみ OFF にします。
  • Enable Key Toggle(enableKeyToggle)
    • デバッグ用途で、エディタ再生中にキーで言語を切り替えたい場合は ON
    • 本番ビルドでは OFF にしておくことを推奨します。
  • Toggle Key(toggleKey)
    • 例: L と入力すると、再生中にキーボードの L キー を離したタイミングで日本語/英語がトグル切り替えされます。
    • A〜Z の英字のみ対応しています。
  • Current Language(currentLanguage)
    • 現在の言語コード(ja / en)が表示されます。
    • スクリプトから自動更新されるため、ユーザーが手動で変更する必要はありません。

5. 実行して TranslationServer が動作しているか確認

  1. エディタ上部の Preview(再生ボタン) を押してシーンを実行します。
  2. Console パネル(またはブラウザの DevTools コンソール)を開きます。
  3. 初期化時に以下のようなログが出ていれば、TranslationServer の取得に成功しています:
    • [LocalizationMgr] TranslationServer を初期化しました。
    • [LocalizationMgr] 言語を "ja" に切り替えました。(または "en"
  4. enableKeyToggle = true にしている場合、L キー(デフォルト)を押して離すと、コンソールに
    • [LocalizationMgr] 言語を "en" に切り替えました。
    • [LocalizationMgr] 言語を "ja" に切り替えました。

    のようなログが交互に表示されることを確認します。

6. UI ボタンから言語切り替えを行う

次に、ゲーム内 UI ボタンから言語を切り替える手順です。

  1. Hierarchy で Canvas 配下に Button を 2 つ作成します(例: BtnJapanese, BtnEnglish)。
  2. BtnJapanese を選択し、Inspector の Button コンポーネント内の Click Events セクションを開きます。
  3. ボタンを押してイベントを追加し、対象ノードLocalizationRoot をドラッグ&ドロップします。
  4. その右側のコンポーネント選択ドロップダウンから LocalizationMgr を選択。
  5. メソッド一覧から LocalizationMgr.setJapanese を選択します。
  6. 同様に BtnEnglish に対しても ClickEvents を設定し、今度は LocalizationMgr.setEnglish を選びます。
  7. シーンを再生し、BtnJapanese / BtnEnglish をクリックすることで、TranslationServer が日本語/英語に切り替わることを確認します。

ゲーム内のテキストが TranslationServer を参照するように設定されていれば、ボタンを押すだけで UI テキストが即座に切り替わるようになります。


まとめ

本記事では、Cocos Creator 3.8.7 + TypeScript で、

  • TranslationServer を制御して日本語/英語を即座に切り替える汎用コンポーネント LocalizationMgr

を、完全に独立したスクリプトとして実装しました。

本コンポーネントのポイントは以下の通りです。

  • 他の GameManager やシングルトンに依存せず、任意のノードにアタッチするだけで動作する。
  • Inspector から
    • 初期言語(JA / EN)
    • 自動適用の有無
    • キー入力によるトグル切り替え(デバッグ用)

    を柔軟に設定できる。

  • UI ボタンの ClickEvents から setJapanese() / setEnglish() / toggleLanguage() を直接呼び出せるため、シーン側の実装コストを最小限にできる
  • TranslationServer 取得や API 名は防御的にチェックしており、問題があれば error ログで検出しやすい。

このコンポーネントをプロジェクトに組み込んでおけば、

  • タイトル画面だけ英語固定にする
  • オプション画面の「言語」メニューから即座に切り替える
  • デバッグ時にショートカットキーで言語を切り替えて UI の崩れを確認する

といった場面で、LocalizationMgr を 1 つアタッチするだけで簡単に制御できます。

必要に応じて、対応言語を増やしたり、プラットフォームの言語設定から初期言語を自動判定する処理を追加するなど、プロジェクトに合わせて拡張してみてください。

Godot 4ゲーム制作 実践ドリル 100本ノック

新品価格
¥1,250から
(2025/12/13 21:27時点)

Godot4& GDScriptではじめる 2Dゲーム開発レシピ

新品価格
¥590から
(2025/12/13 21:46時点)

Unity 6 C#スクリプト 100本ノック

新品価格
¥1,230から
(2025/12/29 10:28時点)

Cocos Creator100本ノックTypeScriptで書く!

新品価格
¥1,250から
(2025/12/29 10:32時点)

URLをコピーしました!