UnityのLocalizationパッケージであらゆるアセットをローカライズ対応する方法をまとめます。
- はじめに
- Component Localizerでローカライズできるか確認する
- Component Localizerでローカライズできるようにする
- Property Variantに対応しているか調べる
- Property Variantに対応する
- 関連
Unity2020.3.15f2
Localization 1.2.1
はじめに
Localizationパッケージでは、文字列に加えてテクスチャやスプライトなどのアセットをローカライズすることができます。
しかしながらアセットの種類によってはそのままだとローカライズできないものもあります。
本記事ではこのようなアセットをローカライズするための対応についてまとめます。
Localizationパッケージの基礎知識については以下の記事にまとめていますので、必要に応じて参照してください。
Component Localizerでローカライズできるか確認する
さてLocalizationパッケージを使ってローカライズする方法には、Component Localizer
を使う方法とProperty Variant
を使う方法の2通りの方法があります。
まずこのうち、ローカライズしたいアセットがComponent Localizer
でローカライズできるかを確認します。
上の記事に記載している通り、Component Localizer
に対応している場合には、Context MenuからLocalizeを選択できます。
例えばAudio Source
の Context Menuを開くと、Localizeメニューが存在していることを確認できます。
つまりAudio Source
はComponent Localizer
によりローカライズできます。
次にMesh Filter
のContext Menuを開いてみます。
こちらはLocalizeメニューが存在していないことがわかります。
したがって、Mesh FilterはこのままではComponent Localizerによりローカライズすることができません。
Component Localizerでローカライズできるようにする
それでは次に、前節のMesh Filter
を例にとり、メッシュのローカライズをComponent Localizerを使って行う方法についてまとめます。
LocalizedAssetEventを継承したクラスを作成する
まず以下のように以下の三つのクラスを継承したクラスを作成します。
- LocalizedAsset
- UnityEvent
- LocalizedAssetEvent
using System; using UnityEngine; using UnityEngine.Events; using UnityEngine.Localization; using UnityEngine.Localization.Components; [Serializable] public class LocalizedMesh : LocalizedAsset<Mesh> { } [Serializable] public class UnityEventMesh : UnityEvent<Mesh> { } [AddComponentMenu("Localization/Asset/Localize Mesh Event")] public class LocalizeMeshEvent : LocalizedAssetEvent<Mesh, LocalizedMesh, UnityEventMesh> { }
あとはGameObjectにLocalizeMeshEvent
をアタッチし、ローカライズ設定を行ない、下部のイベント部分でMeshFilter
を更新するように設定したらローカライズできるようになります。
Context Menuに追加する
さて前節では手動でMeshFilter
を更新するイベントを登録しました。
これは面倒なので、Audio Source
のようにContext MenuからLocalizeを選択した時にこの辺りのセットアップが自動的に完了するようにします。
Context Menuを追加したスクリプトが以下です。
using System; #if UNITY_EDITOR using UnityEditor; using UnityEditor.Events; #endif using UnityEngine; using UnityEngine.Events; using UnityEngine.Localization; using UnityEngine.Localization.Components; [Serializable] public class LocalizedMesh : LocalizedAsset<Mesh> { } [Serializable] public class UnityEventMesh : UnityEvent<Mesh> { } [AddComponentMenu("Localization/Asset/Localize Mesh Event")] public class LocalizeMeshEvent : LocalizedAssetEvent<Mesh, LocalizedMesh, UnityEventMesh> { #if UNITY_EDITOR [MenuItem("CONTEXT/MeshFilter/Localize")] private static void AttachAndSetupForMeshFilter(MenuCommand command) { var target = (MeshFilter)command.context; AttachAndSetupForMeshFilter(target); } public static LocalizeMeshEvent AttachAndSetupForMeshFilter(MeshFilter target) { var localizeEvent = (LocalizeMeshEvent)Undo.AddComponent(target.gameObject, typeof(LocalizeMeshEvent)); // イベント発生時にsharedMeshが変更されるように var setMethod = typeof(MeshFilter).GetProperty("sharedMesh")?.GetSetMethod(); if (setMethod != null) { var methodDelegate = (UnityAction<Mesh>)Delegate.CreateDelegate(typeof(UnityAction<Mesh>), target, setMethod); UnityEventTools.AddPersistentListener(localizeEvent.OnUpdateAsset, methodDelegate); localizeEvent.OnUpdateAsset.SetPersistentListenerState(0, UnityEventCallState.EditorAndRuntime); } return localizeEvent; } #endif }
UnityEventへの登録部分が若干ややこしいですが、これに関しては以下の記事にまとめていますので必要に応じて参照してください。
これで、Mesh FilterのContext Menuから簡単にローカライズを行えるようになりました。
Property Variantに対応しているか調べる
さてローカライズを行うワークフローとして、Component Localizer
とは別に、Property Variant
を使う方法あります。
デフォルトでは、Property Variant
でローカライズを行えるプロパティはJsonUtility
でシリアライズが可能なものと、Transform
、RectTransform
に限られます。
実際にプロパティがローカライズできるかどうかを確認するには、以下の手順によって実際にローカライズしてみるのが手っ取り早いです。
- Window > Asset Management > Localization Scene Controls を開く
- Active LocaleをNone以外に設定する
- Track Changesにチェックを入れる
- ローカライズしたいプロパティの値を変更する
この手順の結果として、プロパティフィールドの背景が緑色になりアイコンが表示されたらそのプロパティはProperty Variant
に対応しています。
以下は上記の手順でTransformのPosition.XとPosition.Yを変更した例です。
背景が緑色になりアイコンが表示されているため、Transoform.position
はProperty Variant
によりローカライズできることがわかります。
次に同様の手順でMesh Filter
のMeshを変更してみます。
こちらはプロパティを変更しても背景が変わりません。
したがって、Mesh Filter
はこのままではProperty Variant
によりローカライズすることができないと言えます。
Property Variantに対応する
それでは最後にMesh Filter
をProperty Variant
に対応させる方法についてまとめます。
Property Variant
に対応させるには、以下のようにLocalizedAsset
を継承したクラスと、TrackedObject
を継承したクラスを作成します。
細かい実装の説明はソースコードを見た方早いと思うのでコメントを参照してください。
using System; using UnityEngine; using UnityEngine.Localization; using UnityEngine.Localization.PropertyVariants; using UnityEngine.Localization.PropertyVariants.TrackedObjects; using UnityEngine.Localization.PropertyVariants.TrackedProperties; using UnityEngine.ResourceManagement.AsyncOperations; [Serializable] public class LocalizedMesh : LocalizedAsset<Mesh> { } [Serializable] [DisplayName("Mesh Filter")] [CustomTrackedObject(typeof(MeshFilter), false)] public sealed class TrackedMeshFilter : TrackedObject { public override AsyncOperationHandle ApplyLocale(Locale variantLocale, Locale defaultLocale) { var sharedMeshProperty = GetTrackedProperty("m_Mesh"); // ローカライズしたいプロパティパスを指定 if (sharedMeshProperty == null) return default; // アセットテーブルに保存 if (sharedMeshProperty is LocalizedAssetProperty localizedAssetProperty && localizedAssetProperty.LocalizedObject is LocalizedMesh localizedMesh) { localizedMesh.LocaleOverride = variantLocale; var loadHandle = localizedMesh.LoadAssetAsync(); if (loadHandle.IsDone) OnAssetLoaded(loadHandle); else { loadHandle.Completed += OnAssetLoaded; return loadHandle; } } // ローカル(GameObject)に保存 else if (sharedMeshProperty is UnityObjectProperty localAssetProperty) { if (localAssetProperty.GetValue(variantLocale.Identifier, defaultLocale.Identifier, out var mesh)) SetAsset((Mesh)mesh); } return default; } private void OnAssetLoaded(AsyncOperationHandle<Mesh> loadHandle) { SetAsset(loadHandle.Result); } private void SetAsset(Mesh mesh) { var meshFilter = (MeshFilter)Target; meshFilter.sharedMesh = mesh; } public override bool CanTrackProperty(string propertyPath) { return propertyPath == "m_Mesh"; } }
これで、Property Variantを使ってMesh Filterをローカライズできるようになりました。
なおCustomTrackedObjectを使う場合には、ローカライズしたプロパティの背景が緑色になったりアイコンがついたりはしないようなのでその点ご注意ください。