Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

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

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;

いい感じ。

chocho
ちょうちょです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした