多言語対応の問題点
UnityではTextMeshProなどを用いて文字を表示できます。
しかし多言語に対応する場合、例えば↓のようなスクリプトを書かなくてはいけません。
var lang = Application.systemLanguage; if (lang == SystemLanguage.Japanese) { text.text = "ヘンゼルのパンくず"; } else if (lang == SystemLanguage.English) { text.text = "English"; }
でもこれは大変面倒ですし、今後言語追加された場合など変更に弱いです。
さらに、文字列を企画担当の人が変更できないというのも問題になります。
対応方針
そこで今回は↓のように言語別の文字を表にして管理し、
ラベル | 日本語 | 英語 |
---|---|---|
Title | ヘンゼルのパンくず | breadcrumbs |
Menu | メニュー | Menu |
Start | ゲームスタート | Start Game |
スクリプトからは↓のように言語に寄って書き換えが必要ないシステムを作成します。
text.text = LanguageUtil.GetText(LangTextLabel.Title, Application.systemLanguage);
3分クッキング
ご自身で使う際は、コードをコピペしてご利用ください。
まずは、対応する言語リストを定義します。
using UnityEngine; public static class AvailableLanguageList { public static SystemLanguage[] AvailableLanguages = new SystemLanguage[] { SystemLanguage.Japanese, SystemLanguage.English, }; }
続いて、スプレッドシートに入力された言語ラベルをEnumに変換するスクリプトを作成します。
このファイルはEditor
という名前のフォルダに入れると良いです。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using System.IO; using System; public class LangTextEditorExtention : MonoBehaviour { [MenuItem("多言語対応/言語シート変換")] public static void CreateLangEnumFile() { var resultStr = ""; resultStr += "public enum LangTextLabel\n{\n"; //プログレスバー表示 float progress = 0; EditorUtility.DisplayProgressBar("変換中...", "チョットマッテネ", progress); var langTextAsset = Resources.Load<TextAsset>("LanguageText"); var reader = new StringReader(langTextAsset.text); var lineCount = 0; while (reader.Peek() != -1) { var line = reader.ReadLine().Split(','); if (lineCount == 0) { // ヘッダーは読まない lineCount++; continue; } var label = line[0]; var labelSp = label.Split('.'); for (int i = 0; i < labelSp.Length; i++) { // 頭文字を大文字に var chars = labelSp[i].ToCharArray(); var initial = char.ToUpper(chars[0]); chars[0] = initial; labelSp[i] = new string(chars); } var enumKey = string.Join("", labelSp); resultStr += $" {enumKey},\n"; lineCount++; } resultStr += "}"; progress = 0.5f; EditorUtility.DisplayProgressBar("変換中...", "チョットマッテネ", progress); var stream = new StreamWriter($"{Application.dataPath}/Script/AutoGenerate/LangTextLabel.cs"); stream.WriteLine(resultStr); stream.Flush(); stream.Close(); AssetDatabase.Refresh(); LanguageUtil.Init(); progress = 0.8f; EditorUtility.DisplayProgressBar("変換中...", "チョットマッテネ", progress); // チェック foreach (SystemLanguage lang in AvailableLanguageList.AvailableLanguages) { foreach (LangTextLabel label in Enum.GetValues(typeof(LangTextLabel))) { Debug.Log($"{lang} {label} : {LanguageUtil.GetText(label, lang)}"); } } progress = 1f; EditorUtility.DisplayProgressBar("変換中...", "チョットマッテネ", progress); EditorUtility.ClearProgressBar(); } }
最後に、変換したEnumをもとに文字列を取得するためのユーティリティを作成します。
using System; using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; public static class LanguageUtil { private static bool hasInit = false; private static Dictionary<SystemLanguage, Dictionary<string, string>> langDict = null; private static SystemLanguage[] availableLanguages = new SystemLanguage[] { SystemLanguage.Japanese, SystemLanguage.English, }; public static void Init() { langDict = new Dictionary<SystemLanguage, Dictionary<string, string>>(); foreach (SystemLanguage lang in availableLanguages) { langDict.Add(lang, new Dictionary<string, string>()); } var langTextAsset = Resources.Load<TextAsset>("LanguageText"); var reader = new StringReader(langTextAsset.text); var lineCount = 0; while (reader.Peek() != -1) { var line = reader.ReadLine().Split(','); if (lineCount == 0) { // ヘッダーは読まない lineCount++; continue; } var label = line[0]; var labelSp = label.Split('.'); for (int i = 0; i < labelSp.Length; i++) { // 頭文字を大文字に var chars = labelSp[i].ToCharArray(); var initial = char.ToUpper(chars[0]); chars[0] = initial; labelSp[i] = new string(chars); } var langTextEnumKey = string.Join("", labelSp); for (int i = 0; i < availableLanguages.Length; i++) { var text = line[i + 1]; langDict[availableLanguages[i]].Add(langTextEnumKey, text); } lineCount++; } hasInit = true; } public static string GetText(LangTextLabel label, SystemLanguage language) { if (!hasInit) Init(); return langDict[language][label.ToString()]; } }
以上で準備完了です。
使い方
ステップ1 スプレッドシートを作成
こんな感じのスプレッドシートもしくはエクセルファイルを作成します。
1列目(ラベル):Enumに変換される言語ラベルです。.
を使って文字を区切ることもできます。
2列目以降:各言語に対応する文字列です。言語の順番は`AvalableLanguageListで定義した順にしてください。
備考:対応言語以降の行は自由に使ってください。
ステップ2 スプレッドシートをUnityにインポート
- スプレッドシート左上から、
ファイル > ダウンロード > カンマ区切り形式(.csv)
を選択してください。 - ダウンロードされたファイルを
Assets/Resources
フォルダに入れてください。 - ファイル名を
LanguageText
に変更して下さい。
ステップ3 言語シート変換
Unityの上部のバーから、多言語対応 > 言語シート変換
を選択してください。
ステップ4
スクリプトから下記の要領で言語別のテキストを取得できます。
EnumキーLangTextLabel
はステップ3で自動生成されたものです。
var text = LanguageUtil.GetText(LangTextLabel.MenuStageTitle, Application.systemLanguage);
最後に
なにかあればコメントでお知らせください。