Unity Localizationを実用化してみよう。①②複数のシートを同時に&すぐにPull Allできるようにする。【hako 生活の休日】

# 前段
長いので別の記事にしています。基本的には読まなくても大丈夫。

https://qiita.com/clrfnd/items/595e288d108bd26be368

# Unity Localizationの思うところ…
Unity Localizationを導入してみてしばらく使ってみたところ、心理的障壁になっているなと感じる部分がいくつかありました。
- StringTableCollection
    - 設定や設計思想をとらえるのが少し難しい
        ⇒これはしょうがない
    - ①いつでもすぐにPullしたい（Pushはいいかな）
    - ②いつでもすぐにスプレッドシートを開きたい
- LocalizedString
    - ③Smartのチェックがめんどくさい
    - ④ドロワーが重い
    - ⑤（コード上）変数のセットがめんどくさい
- できたらいいな～という点
    - シートに話者情報やコマンドを書き込める列を作りたい

シンプルに **機能過多な部分** があり、ちょっと使用感のカロリーが高めです。インディーゲーム製作に限る部分もありますが、やはりスムーズに使用するには**エディター上での手数**が重要になってきます。

この記事では①と②について記載します。

さて、Unity Localization Packageの導入やSpreadSheetとの連携は他の方の記事をご参照ください。

https://light11.hatenadiary.com/entry/2022/03/31/195900


:::note warn
ここからは、Unity Localization PackageでGoogle Spread Sheetとの連携が完了している前提で進めます。
:::

導入が完了して、任意のシートを作成したら、StringTableCollectionはおおよそ以下のようになっていると思います。（画像は9か国語と想定）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704830/94937a63-404c-9e78-c3ee-d795a297aa70.png)
SpreadSheetからデータを取り込みたいときはPullを押すだけ。逆にエディタの情報をSpreadSheetに反映させたいときはPushを押すだけです。このシート単体ならとても便利ですよね。
ただし実際は以下のように、シートを分けたいところです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704830/d63722c7-efd8-20d4-b6d5-d2d9bd41d549.png)

エディタ上では以下のように、複数のStringTableCollectionが必要になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704830/b24e70b3-adec-e821-090d-322c04262a66.png)

例えばイベントシーンを作りこむ際など、どの単語のがどのシートにあるかを思い出し、プロジェクトビューで参照して、Pullするのは面倒です。複数あるシートを一括でPullしたい。いつでも即座にPullしたい…。

# 解決してみる：①いつでもすぐにPull or Openしたい

ということでこの面倒さを解消するため、一括Pullできる機能を作ります。
まずStringTableCollectionをリストに束ねて管理するScriptableObjectを作り、次にエディター拡張で呼び出します。
``` C# StringTableCollectionList.cs
//StringTableCollectionを一括管理するScriptableObject
//このスクリプトは任意のEditorフォルダ以下に配置すること。
#if ODIN_INSPECTOR
// Odin Inspectorを使う前提ですが、なくても動きます。
using Sirenix.OdinInspector;
#endif
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Localization;
using UnityEditor.Localization.Plugins.Google;
using UnityEngine;

[CreateAssetMenu(menuName = "Localization拡張/StringCollectionList")]
public class StringTableCollectionList : ScriptableObject
{

	public string SpreadSheetID = "任意のSpreadSheetID";
	public SheetsServiceProvider ssp;
	public List<StringTableCollection> collections = new List<StringTableCollection>();

#if ODIN_INSPECTOR
	[Button]
#endif
//シートをPullするやつ
	public void PullAll()
    {
		var gss = new GoogleSheets(ssp);
		gss.SpreadSheetId = SpreadSheetID;
        //ループでそれぞれ取得（取得の是非の判定は割愛）
		foreach (var collection in collections)
		{
			var sheetsExtension = collection.Extensions.OfType<GoogleSheetsExtension>().FirstOrDefault();
			gss.PullIntoStringTableCollection(
				sheetsExtension.SheetId,
				collection,
				sheetsExtension.Columns,
				createUndo: true);

			//後で実装するやつ
			//StringTableCollection col = collection;
			//LocalizeUtil.SetSmart(ref col, false);
		}
	}
#if ODIN_INSPECTOR
	[Button]
#endif
//シートを開くやつ
	public void OpenSheet()
	{
		GoogleSheets.OpenSheetInBrowser(SpreadSheetID);
	}
}
```

Pushを行いたい場合は同様に上記にPush用のメソッドを追加しましょう。
```
gss.PushStringTableCollection()
```
というのが使えるはずです。引数も大体一緒かな？

さて、スクリプトが正常にコンパイルできていれば、
Create > Localization拡張 > StringCollectionList
以下のScriptableObjectを作成できるはずです。
こちらもEditorフォルダに入れてしまいましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704830/841fd8eb-126e-defb-0879-593e57210720.png)

インスペクタにて、スプレッドシートと同期済みのStringTableCollectionたちをリストに登録します。
さらに、シートの連携に使用しているGoogleSpreadSheet用のSheetsServiceProviderをセットします。
SpreadSheetIDには文字通りSpreadSheetIDを張り付けましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704830/e28deb16-63b7-01e5-2dda-b5532dc4919e.png)



https://assetstore.unity.com/packages/tools/utilities/odin-inspector-and-serializer-89041?locale=ja-JP&srsltid=AfmBOop5PTcMLsiFA7t_es1og4m0VYn45tRSQj1ouYU9nQ50wumrhSMh

オススメの拡張アセットです。こちらを導入している方のみ、Pull AllとOpen Sheetのボタンが出ているはずですので、ボタンを押せばこの時点で機能を試せると思います。おすすめ。とにかく便利。全員使いましょう。


# 「すぐに」Pull Allできるようにしたい。

さて、作成したPullAll()とOpenSheet()をどこからか呼び出せれば今回の目的はクリアなんですが、どこがいいでしょうか？
StringTableCollectionListをプロジェクトビューから検索し、インスペクタで開き、Pull Allをボタンで呼び出す…これだけで3手ぐらいかかりますね。

今回は**1手にしたい**ので、強引な手段をとります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704830/5ca17614-0a79-d82e-37b5-5931c26cc4dd.png)

**ここにPull AllとOpenボタンを配置します。**

### unity-toolbar-extenderの導入
Playボタンの横に独自のGUIを追加できる拡張があります。

https://github.com/marijnz/unity-toolbar-extender

だいぶ古い記事ですが、おおよその使い方はコガネブログさんが紹介しています。

https://baba-s.hatenablog.com/entry/2019/12/06/080000

おすすめ。とにかく便利。全員使いましょう。
ちなみに、ここにシーン切り替えとうの拡張を入れると大変便利です。
デザイナーさんにUnityを触ってもらう機会があるならなおさらおすすめ。


### unity-toolbar-extenderの導入

unity-toolbar-extenderをベースに、よくあるエディター拡張のコードを記述します。

``` SceneSwitchLeftButton.cs
//こちらのスクリプトはEditorフォルダに配置します。
using UnityEngine;
using UnityToolbarExtender;
using UnityEngine.Localization;

using UnityEditor;
using UnityEditor.SceneManagement;

[InitializeOnLoad]
public class SceneSwitchLeftButton
{
    
 
     //作成したStringTableCollectionList.assetのパスをコピーして貼り付ける。
	public const string LOCALIZATION_ASSET_PATH     = "Assets/***/**~任意のパス~**/***/StringTableCollectionList.asset";
     // ついでに任意のシーンを開く機能もつけるなら
	//public const string MAIN_SYSTEM_PATH            = "Assets/**~メインシーンのパス~**/***.unity";
	
    static SceneSwitchLeftButton()
    {
        ToolbarExtender.LeftToolbarGUI.Add(OnToolbarGUILeft);
        ToolbarExtender.RightToolbarGUI.Add(OnToolbarGUIRight);
    }

    static void OnToolbarGUILeft()
	{
        //プレイボタン左側の拡張はこちらに記述
		GUILayout.FlexibleSpace();

        // ついでに任意のシーンを開く機能もつけるなら
		//if (GUILayout.Button(new GUIContent("メインシーン", "")))
		//{
		//	EditorSceneManager.OpenScene(MAIN_SYSTEM_PATH, OpenSceneMode.Single);
		//}

        //Pull Allボタンの実装
		if (GUILayout.Button(new GUIContent("LCLZ_PULL", "")))
		{

			var stcl = AssetDatabase.LoadAssetAtPath<StringTableCollectionList>(LOCALIZATION_ASSET_PATH);
			stcl.PullAll();
		}
        //Openの実装
		if (GUILayout.Button(new GUIContent("LCLZ_OPEN", "")))
		{
			var stcl = AssetDatabase.LoadAssetAtPath<StringTableCollectionList>(LOCALIZATION_ASSET_PATH);
			stcl.OpenSheet();
		}

        //Pushボタンも作る場合はここに記述。スプレッドシートをマスターとするのであれば、確認ダイアログをいれたほうがいいかも。

	}
	static void OnToolbarGUIRight()
	{
        //プレイボタン右側の拡張はこちらに記述
	}
}

```

# 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704830/2c1df9f4-c099-af76-bf60-eb3b99f6a345.png)

ボタンが追加され、即座にスプレッドシートをPull Allしたり、スプレッドシートを開くことができるようになりました。

今回はここまで。

# 次の記事

https://qiita.com/clrfnd/items/8c80a6fd148179101771