LoginSignup
8
5

More than 5 years have passed since last update.

Unityでローカライズしたい。Textの、多言語対応ってどうやるのかな。

Posted at

検索しても実装してるスクリプト見当たらないなって思ったけど
もう少し検索していると、

Unityのチュートリアルの中に
「ライブセッション:ローカライゼーションツール」というのがあったので
ここのスクリプトを使ってみる(動画はみてません)

Localized Text Component - Unity

  • LocalizationData.cs
  • LocalizationManager.cs
  • StartupManager.cs
  • LocalizedText.cs
  • LocalizedTextEditor.cs

処理を調整

(localizedText_en.json, localizedText_de.json) があったのでとりあえず、localizedText_ja.json も追加する。

Assets/StreamingAssets/localizedText_ja.json
{"items":[{"key":"test1","value":"テスト"},{"key":"test2","value":"てすと。"}]}

StartupManager.cs の内容を、自分のプロジェクトの初期化のシーンで呼ぶようにする。

        IEnumerator Start()
        {
            LocalizationManager.instance.LoadLocalizedText("localizedText_ja.json");
            yield return new WaitUntil(LocalizationManager.instance.GetIsReady);

            // 遷移とか
        }

LocalizedText.cs に、RequireComponentをつけておく。

LocalizedText.cs
+    [RequireComponent(typeof(Text))]
     public class LocalizedText : MonoBehaviour

TextMeshProUGUI だとこう。

LocalizedText.cs
+    [RequireComponent(typeof(TextMeshProUGUI))]
     public class LocalizedText : MonoBehaviour

多分そんな感じで使っていけば、良さそうです。
おわり。

以降は、なんかやりたいことをやっている・・なにかです(?)

(playしてない時)エディタ上でUIレアウト確認用に、日本語を入れておきたい。

OnValidate() で、キーが変更されるたびに、テキストの値も置き換えるようにする。
キーが間違ってると、"Localized text not found"
になるからわかりやすくてお気に入り。(っていうか、enum使えって話かな。)

txt.gif

本当は、テキストの部分(TextMeshProUGUI.text)はインスペクタ上でさわれないようにしたい
[CustomEditor(typeof(TextMeshProUGUI))] すればいいのかな・・。

(clickで開く LocalizedText.cs)
LocalizedText.cs
using TMPro;
using UnityEngine;

namespace Localization
{
    /// <summary>
    ///  キー設定用
    /// </summary>
    [RequireComponent(typeof(TextMeshProUGUI))]
    public class LocalizedText : MonoBehaviour
    {
        [SerializeField] string key;
        public string GetKey => key;

        private TextMeshProUGUI _ui;
        private TextMeshProUGUI UI => _ui ?? GetComponent<TextMeshProUGUI>();
        private string value;

#if UNITY_EDITOR
        public void OnValidate()
        {
            if (UI != null) UI.text = LocalizationManager.GetLocalizedValue(key);
        }
#endif

        public void Awake()
        {
            if (string.IsNullOrEmpty(value))
            {

                var txt = LocalizationManager.GetInitializeValue(key);
                UI.text = txt;
            }
            else UI.text = value;
        }

        /// <summary>
        /// キー変更
        /// </summary>
        public void TextWithKey(string key, params object[] args)
        {
            this.key = key;
            Text(args);
        }

        /// <summary>
        /// テキストを設定する
        /// </summary>
        public void Text(params object[] args)
        {
            string format = LocalizationManager.GetLocalizedFormat(key);
            value = string.Format(format, args);
            UI.text = value;
        }
    }
}

(string format)と(bool 初期値として使うかどうか)を追加する

LocalizationData.cs

+        /// <summary>
+        /// The key.
+        /// </summary>
        public string key;
+        /// <summary>
+        /// The format.
+        /// </summary>
+        public string format;
+        /// <summary>
+        /// The value.
+        /// </summary>
        public string value;
+        /// <summary>
+        /// true:実行時にはvalue入れないで空にする。UIレアウト確認用。false:実行時もそのまま使う
+        /// </summary>
+        public bool value_is_test;
LocalizationManager.cs
     public static class LocalizationManager
     {
-        private static Dictionary<string, string> localizedText;
+        private static Dictionary<string, LocalizationItem> localizedText;
         private static readonly string missingTextString = "Localized text not found";
+        private static readonly string missingFormatString = "{0}";

全体としてはこう。
StreamingAsset やめて Resources.Load にして楽してる。
のちのち、ロードは変更すると思う。

(clickで開く LocalizationManager.cs)
LocalizationManager.cs
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Localization
{
    /// <summary>
    /// Localization manager.
    /// </summary>
    public static class LocalizationManager
    {
        private static Dictionary<string, LocalizationItem> localizedText;
        private static readonly string missingTextString = "Localized text not found";
        private static readonly string missingFormatString = "{0}";

        /// <summary>
        /// 準備状態を取得する
        /// </summary>
        public static bool IsReady { get; private set; } = false;

        /// <summary>
        /// 読み込み開始
        /// </summary>
        public static void LoadLocalizedText()
        {
            if (IsReady) return;
            LoadAsset();
        }

        /// <summary>
        /// 読み込み
        /// </summary>
        public static void LoadAsset()
        {
            string filePath = Path.Combine("Localization", "common_ja");
            string dataAsJson = Resources.Load<TextAsset>(filePath).text;
            CreateDictionary(dataAsJson);
        }

        /// <summary>
        /// 設定する
        /// </summary>
        private static void CreateDictionary(string dataAsJson)
        {
            localizedText = new Dictionary<string, LocalizationItem>();

            LocalizationData loadedData = JsonUtility.FromJson<LocalizationData>(dataAsJson);
            for (int i = 0; i < loadedData.items.Length; i++)
            {
                 localizedText.Add(loadedData.items[i].key, loadedData.items[i]);
            }

            Debug.Log("Data loaded, dictionary contains: " + localizedText.Count + " entries");

            IsReady = true;
        }

        /// <summary>
        /// ローカライズされた値を取得する
        /// </summary>
        public static string GetLocalizedValue(string key)
        {
#if UNITY_EDITOR
            if (string.IsNullOrEmpty(key)) return missingTextString;
            if (!UnityEditor.EditorApplication.isPlaying
            && localizedText == null) LoadAsset();
#endif
            if (!localizedText.ContainsKey(key)) return missingTextString;
            localizedText.TryGetValue(key, out LocalizationItem result);
            return result.value;
        }

        /// <summary>
        /// ゲーム中の初期値を取得する
        /// </summary>
        public static string GetInitializeValue(string key)
        {
            if (!localizedText.ContainsKey(key)) return missingTextString;
            localizedText.TryGetValue(key, out LocalizationItem result);
            if (result.value_is_test) return null;
            return result.value;
        }

        /// <summary>
        /// ローカライズされたテキストフォーマットを取得する
        /// </summary>
        public static string GetLocalizedFormat(string key)
        {
            localizedText.TryGetValue(key, out LocalizationItem result);

            if (string.IsNullOrEmpty(result?.format)) return missingFormatString;
            return result.format;
        }

    }
}

1ファイルはしんどいから、ファイル分割したい。

あとは、

とっても大きなファイルになりそうなので
ファイル分けが出来ると、幸せになれると思う。

LocalizationManager.cs
         private static void LoadAsset()
         {
-            string filePath = Path.Combine("Localization", "common_ja");
-            string dataAsJson = Resources.Load<TextAsset>(filePath).text;
-            CreateDictionary(dataAsJson);
+            var txt = Resources.LoadAll<TextAsset>("Localization/ja");
+            CreateDictionary(txt);
         }

         /// <summary>
         /// 設定する
         /// </summary>
-        private static void CreateDictionary(string dataAsJson)
+        private static void CreateDictionary(TextAsset[] txt)
         {
             localizedText = new Dictionary<string, LocalizationItem>();
+            var objs = txt.Select(o => JsonUtility.FromJson<LocalizationData>(o.text));

-            LocalizationData loadedData = JsonUtility.FromJson<LocalizationData>(dataAsJson);
-            for (int i = 0; i < loadedData.items.Length; i++)
-            {
-                localizedText.Add(loadedData.items[i].key, loadedData.items[i]);
-            }
+            foreach (var o in objs)
+                foreach (var item in o.items)
+                    localizedText.Add($"{o.prefix}-{item.key}", item);
LocalizationData.cs
    public class LocalizationData
    {
+        /// <summary>
+        /// The prefix.
+        /// </summary>
+        public string prefix;
        /// <summary>
        /// The items.
        /// </summary>
        public LocalizationItem[] items;

いい感じ。

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5