Unity Localizationで動的にエントリを取得する

# コード
```cs
using UnityEngine.Localization.Settings;
using UnityEngine.Localization.Tables;

public static class LocalizedStringHandler
{
    private static StringTable _table;

    private static StringTable Table
    {
        get
        {
            if (_table != null)
            {
                return _table;
            }

            Debug.LogError($"[{nameof(LocalizedStringHandler)}] Tableがロードされていません");
            return null;
        }
    }

    public static string GetEntry(long id)
    {
        return Table.GetEntry(id).Value;
    }

    /// <summary>
    /// アプリ立ち上げ時にTableをキャッシュする
    /// </summary>
    internal static void CacheTable()
    {
        LocalizationSettings.Instance.OnSelectedLocaleChanged += _ => CacheTable();

        _table = LocalizationSettings.StringDatabase.GetTable(LocalizationConst.StringTableReference);
    }
}
```

# 使い方

```cs
string entry = LocalizedStringHandler.GetEntry({取得したいエントリのID});
```

エントリのIDはlongなのですが([stringもある](https://light11.hatenadiary.com/entry/2022/03/10/200323))ハードコーディングするのはイケてないと思います。
そこでエントリIDの定数クラスを自動生成すると良いでしょう。

```cs:自動生成されたクラス
namespace Project.Runtime.Constant
{
    /// <summary>
    /// LocalizationのStringTableのKeyの定数クラス
    /// 自動生成されたクラスです
    /// </summary>
    public static class LocalizationStringKeys
    {
    		public static long Hoge => 101385924099694606;
      		public static long Fuga => 101385924099694607;
    }

}
```


下記の記事のコードを自分なりにカスタマイズしてます。

https://kan-kikuchi.hatenablog.com/entry/ConstantsClassCreator

```csharp:自動生成を行うクラス
public static class ConstantClassCreator
{
    //拡張子
    private const string ScriptExtension = ".cs";

    //定数の区切り文字
    private const char Delimiter = '_';

    //無効な文字を管理する配列
    private static readonly string[] InvalidChars =
    {
        " ", "!", "\"", "#", "$",
        "%", "&", "\'", "(", ")",
        "-", "=", "^", "~", "\\",
        "|", "[", "{", "@", "`",
        "]", "}", ":", "*", ";",
        "+", "/", "?", ".", ">",
        ",", "<"
    };

    /// <summary>
    /// 定数を管理するクラスを自動生成する
    /// </summary>
    /// <param name="className">クラス名</param>
    /// <param name="summary">記載したいサマリ</param>
    /// <param name="variableDict">記載したい変数 Key:変数名 Value:値</param>
    /// <param name="exportDirectoryPath">Assets/ から始まるパス</param>
    /// <param name="nameSpace">名前空間</param>
    /// <param name="isVariableTypeElias">記載したい変数の型をエイリアスで記載するか</param>
    /// <typeparam name="T">記載したい変数の型</typeparam>
    public static void Create<T>(string className, string summary, Dictionary<string, T> variableDict,
        string exportDirectoryPath, string nameSpace, bool isVariableTypeElias = true)
    {
        //ディクショナリーをソートしたものに
        var sortDict = new SortedDictionary<string, T>(variableDict);

        //入力された辞書のkeyから無効な文字列を削除して、大文字に_を設定した定数名と同じものに変更し新たな辞書に登録
        //次の定数の最大長求めるところで、_を含めたものを取得したいので、先に実行
        var newValueDict = new Dictionary<string, T>();

        foreach (var valuePair in sortDict)
        {
            var newKey = RemoveInvalidChars(valuePair.Key);
            newValueDict[newKey] = valuePair.Value;
        }

        //コード全文
        var builder = new StringBuilder();

        //ネームスペースがあれば設定
        if (!string.IsNullOrEmpty(nameSpace))
        {
            builder.AppendLine("namespace " + nameSpace);
            builder.AppendLine("{");
        }

        //コメント文とクラス名を入力
        builder.AppendLine("\t/// <summary>");
        builder.AppendLine($"\t/// {summary}");
        builder.AppendLine("\t/// </summary>");
        builder.AppendLine($"\tpublic static class {className}");
        builder.AppendLine("\t{");

        //入力された定数とその値のペアを書き出していく
        var keyArray = newValueDict.Keys.ToArray();
        foreach (var key in keyArray)
        {
            if (string.IsNullOrEmpty(key))
            {
                continue;
            }

            //数字だけのkeyだったらスルー
            if (Regex.IsMatch(key, @"^[0-9]+$"))
            {
                continue;
            }

            var variableName = typeof(T).Name;
            variableName = isVariableTypeElias ? variableName.ToLower() : variableName;
            variableName = typeof(T) == typeof(float) ? "float" : variableName;
            variableName = typeof(T) == typeof(long) ? "long" : variableName;
            //型と定数名を入力
            builder.Append($"\t\tpublic static {variableName} {key} => ");

            //Tがstringの場合は値の前後に"を付ける
            if (typeof(T) == typeof(string))
            {
                builder.Append($@"""{newValueDict[key]}"";").AppendLine();
            }
            //Tがfloatの場合は値の後にfを付ける
            else if (typeof(T) == typeof(float))
            {
                builder.Append($"{newValueDict[key]}f;").AppendLine();
            }
            else
            {
                builder.Append($"{newValueDict[key]};").AppendLine();
            }
        }

        builder.AppendLine("\t}");

        //ネームスペースがあれば最後にカッコ追加
        if (!string.IsNullOrEmpty(nameSpace))
        {
            builder.AppendLine("}");
        }

        //書き出し、ファイル名はクラス名.cs
        var exportPath = Path.Combine(exportDirectoryPath, className + ScriptExtension);
        var exportText = builder.ToString();

        //書き出し先のディレクトリが無ければ作成
        var directoryName = Path.GetDirectoryName(exportPath);
        if (!Directory.Exists(directoryName) && !string.IsNullOrEmpty(directoryName))
        {
            Directory.CreateDirectory(directoryName);
        }

        //書き出し先のファイルがあるかチェック
        if (File.Exists(exportPath))
        {
            //同名ファイルの中身をチェック、全く同じだったら書き出さない
            var sr = new StreamReader(exportPath, Encoding.UTF8);
            var isSame = sr.ReadToEnd() == exportText;
            sr.Close();

            if (isSame)
            {
                return;
            }
        }

        //書き出し
        File.WriteAllText(exportPath, exportText, Encoding.UTF8);
        AssetDatabase.Refresh(ImportAssetOptions.ImportRecursive);

        CustomDebug.Log(className + ScriptExtension + "の作成が完了しました");
    }

    /// <summary>
    /// 無効な文字を削除します
    /// </summary>
    private static string RemoveInvalidChars(string str)
    {
        InvalidChars.ForEach(c => str = str.Replace(c, string.Empty));
        return str;
    }
}
```

[MenuItem](https://kan-kikuchi.hatenablog.com/entry/MenuItem)等を使用して、こちらの関数を呼び出すと良いでしょう。
```cs:使用例
ConstantClassCreator.Create(className: "LocalizationStringKeys",
                 summary: $"LocalizationのStringTableのKeyの定数クラス" + 
                          $"{Environment.NewLine}\t/// 自動生成されたクラスです",
                 variableDict: variableDict,
                 exportDirectoryPath: FilePath,
                 nameSpace: "Project.Runtime.Constant");
```