るっちょ らいつ

るっちょ ぷれぜんつ 開発の日々。

【Unity】uGUIテキストを簡単にローカライズする

はじめに

ローカライズ手法といえば、おそらく言語ごとの設定ファイルを別で作成するというのが主流なのでしょうが、多くのテキストとの対応関係を整理して把握しきるのは大変です。特に個人開発者にとっては、あまりシステム化されていなくても手早く実装できる手段が必要なこともあるでしょう。

イメージ

  1. スクリプトTextLocalizerを作成する
  2. uGUIのTextがアタッチされているGameObjectにTextLocalizerをアタッチする
  3. Inspectorから各種言語を設定する
  4. 反映される

実装

まず、最初に以下のようなコードを書いてみました。

SystemLanguage lang;
public System.Collections.Generic.Dictionary<SystemLanguage, string> TextDict;

void Update()
    {

        lang = Application.systemLanguage;

        string outText;
        //現在の言語をキーに持つアイテムを検索
        if (TextDict.TryGetValue(lang, out outText))
        {
            GetComponent<Text>().text = outText;
        }
        else
        {
            Debug.LogWarning("Could not find text localized to current language");
        }
    }

(usingなどは省略してます。)

言語環境をキーに持つDictionaryをインスペクタから編集し、それを参照する手筈だったのですが。。。

インスペクタはDictionaryの編集が無理らしい(´゚д゚`)

ひょっとしてこれは常識なのか…?しらなかった

調べたらこんなサイトがありました。 qiita.com

内部的には独自でKey-Valueを実装し、Dictionaryとしても扱える。先達はあらまほしきことなり。

とまあ、この記事のSerializableDictionary.csを拝借しました。

さらに、ローカライズ後の見た目の検査のために言語環境を変更する機能とか、設定された言語が未ローカライズドの場合のエラーメッセージの挙動の改善などを実装して最終的なコードは以下のようになりました。

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;


[RequireComponent(typeof(Text))]

//ここから引用!

/// <summary>
/// ジェネリックを隠すために継承してしまう
/// [System.Serializable]を書くのを忘れない
/// </summary>
[System.Serializable]
public class LocalizeTable : Serialize.TableBase<SystemLanguage, string, LocalizePair>
{


}

/// <summary>
/// ジェネリックを隠すために継承してしまう
/// [System.Serializable]を書くのを忘れない
/// </summary>
[System.Serializable]
public class LocalizePair : Serialize.KeyAndValue<SystemLanguage, string>
{

    public LocalizePair(SystemLanguage key, string value) : base(key, value)
    {

    }
}

//ここまで引用!

public class TextLocalizer : MonoBehaviour
{

    SystemLanguage lang;
    SystemLanguage tmpLang;
    [Tooltip("デバッグ時のみ有効な言語設定です。")]
    public SystemLanguage LangForDebug;
    public LocalizeTable table;

    void Update()
    {

        lang = Application.systemLanguage;
#if UNITY_EDITOR
        lang = LangForDebug;
#endif
        string outText;
        if (table.GetTable().TryGetValue(lang, out outText))
        {
            GetComponent<Text>().text = outText;
        }
        else
        {
#if UNITY_EDITOR
            if (tmpLang != LangForDebug)
            {
                Debug.LogWarning("Could not find text localized to current language");
            }
#endif
        }
#if UNITY_EDITOR
        tmpLang = LangForDebug;
#endif
    }

f:id:ruccho:20161023145708g:plain

果たして汎用性はあるのか怪しいですがひとまずこれで行ってみたいと思います。