From d45ebcdcb9f96c2e19792070f7ba6fe31db9c1ef Mon Sep 17 00:00:00 2001 From: PoChangSu Date: Mon, 17 Aug 2020 15:10:32 +0900 Subject: [PATCH] add language support in export dialog --- .../Editor/Format/VRMExportSettingsEditor.cs | 25 ++++-- .../UniVRM/Editor/Format/VRMExporterWizard.cs | 61 ++++++++------ .../Format/VRMExporterWizardMessages.cs | 84 +++++++++++++++++++ .../Format/VRMExporterWizardMessages.cs.meta | 11 +++ 4 files changed, 149 insertions(+), 32 deletions(-) create mode 100644 Assets/VRM/UniVRM/Editor/Format/VRMExporterWizardMessages.cs create mode 100644 Assets/VRM/UniVRM/Editor/Format/VRMExporterWizardMessages.cs.meta diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExportSettingsEditor.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExportSettingsEditor.cs index 8d1cac09e..1a4707f08 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMExportSettingsEditor.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExportSettingsEditor.cs @@ -86,25 +86,34 @@ namespace VRM private void OnEnable() { m_forceTPose = new CheckBoxProp(serializedObject.FindProperty(nameof(ForceTPose)), - "エクスポート時に強制的にT-Pose化する。これを使わずに手動でT-Poseを作っても問題ありません"); + "エクスポート時に強制的にT-Pose化する。これを使わずに手動でT-Poseを作っても問題ありません \n" + + "Force T-Pose before export. Manually making T-Pose for model without enabling this is ok"); m_poseFreeze = new CheckBoxProp(serializedObject.FindProperty(nameof(PoseFreeze)), - "エクスポート時に正規化(ヒエラルキーから回転と拡大縮小を取り除くためにベイク)する"); + "エクスポート時に正規化(ヒエラルキーから回転と拡大縮小を取り除くためにベイク)する \n" + + "Model's normalization (bake to remove roation and scaling from the hierarchy)"); m_useExcperimentalExporter = new CheckBoxProp(serializedObject.FindProperty(nameof(UseExperimentalExporter)), - "エクスポート時に新しいJsonSerializerを使う"); + "エクスポート時に新しいJsonSerializerを使う \n" + + "The new version of JsonSerializer for model export"); m_useSparseAccessor = new CheckBoxProp(serializedObject.FindProperty(nameof(UseSparseAccessor)), - "BlendShapeの容量を GLTF の Sparse Accessor 機能で削減する。修正中: UniGLTF以外でロードできません"); + "BlendShapeの容量を GLTF の Sparse Accessor 機能で削減する。修正中: UniGLTF以外でロードできません \n" + + "BlendShape size can be reduced by using Sparse Accessor"); m_onlyBlendShapePosition = new CheckBoxProp(serializedObject.FindProperty(nameof(OnlyBlendshapePosition)), - "BlendShapeClipのエクスポートに法線とTangentを含めない。UniVRM-0.53 以前ではロードがエラーになるのに注意してください"); + "BlendShapeClipのエクスポートに法線とTangentを含めない。UniVRM-0.53 以前ではロードがエラーになるのに注意してください \n" + + "BlendShape's Normal and Tangent will not be exported. Be aware that errors may occur during import if the model is made by UniVRM-0.53 or earlier versions"); m_reduceBlendShape = new CheckBoxProp(serializedObject.FindProperty(nameof(ReduceBlendshape)), - "BlendShapeClipから参照されないBlendShapeをエクスポートに含めない"); + "BlendShapeClipから参照されないBlendShapeをエクスポートに含めない \n" + + "BlendShapes that are not referenced by BlendShapeClips will not be exported"); m_reduceBlendShapeClip = new CheckBoxProp(serializedObject.FindProperty(nameof(ReduceBlendshapeClip)), - "BlendShapeClip.Preset == Unknown のBlendShapeClipをエクスポートに含めない"); + "BlendShapeClip.Preset == Unknown のBlendShapeClipをエクスポートに含めない \n" + + "BlendShapeClip will not be exported if BlendShapeClip.Preset == Unknown"); m_removeVertexColor = new CheckBoxProp(serializedObject.FindProperty(nameof(RemoveVertexColor)), - "エクスポートに頂点カラーを含めない"); + "エクスポートに頂点カラーを含めない \n" + + "Vertex color will not be exported"); } public override void OnInspectorGUI() { + EditorGUIUtility.labelWidth = 160; serializedObject.Update(); m_forceTPose.Draw(); m_poseFreeze.Draw(); diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs index 30969bba7..b735d5b4a 100644 --- a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizard.cs @@ -152,24 +152,24 @@ namespace VRM if (DuplicateBoneNameExists()) { - yield return Validation.Warning("There is a bone with the same name in the hierarchy. If exported, these bones will be automatically renamed."); + yield return Validation.Warning(Msg.DUPLICATE_BONE_NAME_EXISTS); } if (m_settings.ReduceBlendshape && ExportRoot.GetComponent() == null) { - yield return Validation.Error("ReduceBlendshapeSize needs VRMBlendShapeProxy. You need to convert to VRM once."); + yield return Validation.Error(Msg.NEEDS_VRM_BLENDSHAPE_PROXY); } var vertexColor = ExportRoot.GetComponentsInChildren().Any(x => x.sharedMesh.colors.Length > 0); if (vertexColor) { - yield return Validation.Warning("This model contains vertex color"); + yield return Validation.Warning(Msg.VERTEX_COLOR_IS_INCLUDED); } var renderers = ExportRoot.GetComponentsInChildren(); if (renderers.All(x => !x.gameObject.activeInHierarchy)) { - yield return Validation.Error("No active mesh"); + yield return Validation.Error(Msg.NO_ACTIVE_MESH); } var materials = renderers.SelectMany(x => x.sharedMaterials).Distinct(); @@ -193,15 +193,13 @@ namespace VRM continue; } - yield return Validation.Warning(string.Format("{0}: unknown shader '{1}' is used. this will export as `Standard` fallback", - material.name, - material.shader.name)); + yield return Validation.Warning($"Material: {material.name}. Unknown Shader: \"{material.shader.name}\" is used. {Msg.UNKNOWN_SHADER}"); } foreach (var material in materials) { if (IsFileNameLengthTooLong(material.name)) - yield return Validation.Error(string.Format("FileName '{0}' is too long. ", material.name)); + yield return Validation.Error(Msg.FILENAME_TOO_LONG + material.name); } var textureNameList = new List(); @@ -226,7 +224,7 @@ namespace VRM foreach (var textureName in textureNameList) { if (IsFileNameLengthTooLong(textureName)) - yield return Validation.Error(string.Format("FileName '{0}' is too long. ", textureName)); + yield return Validation.Error(Msg.FILENAME_TOO_LONG + textureName); } var vrmMeta = ExportRoot.GetComponent(); @@ -234,7 +232,7 @@ namespace VRM { var thumbnailName = vrmMeta.Meta.Thumbnail.name; if (IsFileNameLengthTooLong(thumbnailName)) - yield return Validation.Error(string.Format("FileName '{0}' is too long. ", thumbnailName)); + yield return Validation.Error(Msg.FILENAME_TOO_LONG + thumbnailName); } var meshFilters = ExportRoot.GetComponentsInChildren(); @@ -242,7 +240,7 @@ namespace VRM foreach (var meshName in meshesName) { if (IsFileNameLengthTooLong(meshName)) - yield return Validation.Error(string.Format("FileName '{0}' is too long. ", meshName)); + yield return Validation.Error(Msg.FILENAME_TOO_LONG + meshName); } var skinnedmeshRenderers = ExportRoot.GetComponentsInChildren(); @@ -250,7 +248,7 @@ namespace VRM foreach (var skinnedmeshName in skinnedmeshesName) { if (IsFileNameLengthTooLong(skinnedmeshName)) - yield return Validation.Error(string.Format("FileName '{0}' is too long. ", skinnedmeshName)); + yield return Validation.Error(Msg.FILENAME_TOO_LONG + skinnedmeshName); } } @@ -283,7 +281,10 @@ namespace VRM { m_Inspector = Editor.CreateEditor(m_settings); } + + m_lang = EnumUtil.TryParseOrDefault(EditorPrefs.GetString(LANG_KEY, default(VRMExporterWizardMessages.Languages).ToString())); } + const string LANG_KEY = "VRM_LANG"; void OnDisable() { @@ -334,7 +335,11 @@ namespace VRM } } + VRMExporterWizardMessages.Languages m_lang; + VRMExporterWizardMessages.LangMessages Msg => VRMExporterWizardMessages.M17N[m_lang]; + //@TODO: Force repaint if scripts recompile + private void OnGUI() { if (m_tmpMeta == null) @@ -345,6 +350,14 @@ namespace VRM EditorGUIUtility.labelWidth = 150; + // lang + var lang = (VRMExporterWizardMessages.Languages)EditorGUILayout.EnumPopup("lang", m_lang); + if (lang != m_lang) + { + m_lang = lang; + EditorPrefs.SetString(LANG_KEY, m_lang.ToString()); + } + EditorGUILayout.LabelField("ExportRoot"); var root = (GameObject)EditorGUILayout.ObjectField(ExportRoot, typeof(GameObject), true); UpdateRoot(root); @@ -358,24 +371,24 @@ namespace VRM // if (root == null) { - Validation.Error("ExportRootをセットしてください").DrawGUI(); + Validation.Error(Msg.ROOT_EXISTS).DrawGUI(); return; } if (root.transform.parent != null) { - Validation.Error("ExportRootに親はオブジェクトは持てません").DrawGUI(); + Validation.Error(Msg.NO_PARENT).DrawGUI(); return; } if (root.transform.localRotation != Quaternion.identity || root.transform.localScale != Vector3.one) { - Validation.Error("ExportRootに回転・拡大縮小は持てません。子階層で回転・拡大縮小してください").DrawGUI(); + Validation.Error(Msg.ROOT_WITHOUT_ROTATION_AND_SCALING_CHANGED).DrawGUI(); return; } if (!root.scene.IsValid()) { // Prefab でシーンに出していないものを判定したい // FIXME: もっと適切な判定があればそれに - Validation.Error("シーンに出していない Prefab はエクスポートできません(細かい挙動が違い、想定外の動作をところがあるため)。シーンに展開してからエクスポートしてください").DrawGUI(); + Validation.Error(Msg.PREFAB_CANNOT_EXPORT).DrawGUI(); return; } if (HasRotationOrScale(ExportRoot)) @@ -386,14 +399,14 @@ namespace VRM } else { - Validation.Warning("回転・拡大縮小を持つノードが含まれています。正規化が必用です。Setting の PoseFreeze を有効にしてください").DrawGUI(); + Validation.Warning(Msg.ROTATION_OR_SCALEING_INCLUDED_IN_NODE).DrawGUI(); } } else { if (m_settings.PoseFreeze) { - Validation.Warning("正規化済みです。Setting の PoseFreeze は不要です").DrawGUI(); + Validation.Warning(Msg.IS_POSE_FREEZE_DONE).DrawGUI(); } else { @@ -407,7 +420,7 @@ namespace VRM var animator = root.GetComponent(); if (animator == null) { - Validation.Error("ExportRootに Animator がありません").DrawGUI(); + Validation.Error(Msg.NO_ANIMATOR).DrawGUI(); return; } @@ -416,30 +429,30 @@ namespace VRM var f = GetForward(l, r); if (Vector3.Dot(f, Vector3.forward) < 0.8f) { - Validation.Error("Z+ 向きにしてください").DrawGUI(); + Validation.Error(Msg.FACE_Z_POSITIVE_DIRECTION).DrawGUI(); return; } var avatar = animator.avatar; if (avatar == null) { - Validation.Error("ExportRootの Animator に Avatar がありません").DrawGUI(); + Validation.Error(Msg.NO_AVATAR_IN_ANIMATOR).DrawGUI(); return; } if (!avatar.isValid) { - Validation.Error("ExportRootの Animator.Avatar が不正です").DrawGUI(); + Validation.Error(Msg.AVATAR_IS_NOT_VALID).DrawGUI(); return; } if (!avatar.isHuman) { - Validation.Error("ExportRootの Animator.Avatar がヒューマノイドではありません。FBX importer の Rig で設定してください").DrawGUI(); + Validation.Error(Msg.AVATAR_IS_NOT_HUMANOID).DrawGUI(); return; } var jaw = animator.GetBoneTransform(HumanBodyBones.Jaw); if (jaw != null) { - Validation.Warning("Jaw bone is included. It may not be what you intended. Please check the humanoid avatar setting screen").DrawGUI(); + Validation.Warning(Msg.JAW_BONE_IS_INCLUDED).DrawGUI(); } else { diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizardMessages.cs b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizardMessages.cs new file mode 100644 index 000000000..668c50215 --- /dev/null +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizardMessages.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; + +namespace VRM +{ + /// + /// エクスポートダイアログ用の簡易なメッセージカタログ + /// + public static class VRMExporterWizardMessages + { + public enum Languages + { + ja, + en, + } + + public struct LangMessages + { + public string ROOT_EXISTS; + public string NO_PARENT; + public string ROOT_WITHOUT_ROTATION_AND_SCALING_CHANGED; + public string PREFAB_CANNOT_EXPORT; + public string ROTATION_OR_SCALEING_INCLUDED_IN_NODE; + public string IS_POSE_FREEZE_DONE; + public string NO_ANIMATOR; + public string FACE_Z_POSITIVE_DIRECTION; + public string NO_AVATAR_IN_ANIMATOR; + public string AVATAR_IS_NOT_VALID; + public string AVATAR_IS_NOT_HUMANOID; + public string JAW_BONE_IS_INCLUDED; + public string DUPLICATE_BONE_NAME_EXISTS; + public string NEEDS_VRM_BLENDSHAPE_PROXY; + public string VERTEX_COLOR_IS_INCLUDED; + public string NO_ACTIVE_MESH; + public string UNKNOWN_SHADER; + public string FILENAME_TOO_LONG; + } + + public static readonly Dictionary M17N = new Dictionary + { + {Languages.ja, new LangMessages{ + ROOT_EXISTS ="ExportRootをセットしてください", + NO_PARENT = "ExportRootに親はオブジェクトは持てません", + ROOT_WITHOUT_ROTATION_AND_SCALING_CHANGED = "ExportRootに回転・拡大縮小は持てません。子階層で回転・拡大縮小してください", + PREFAB_CANNOT_EXPORT = "シーンに出していない Prefab はエクスポートできません(細かい挙動が違い、想定外の動作をところがあるため)。シーンに展開してからエクスポートしてください", + ROTATION_OR_SCALEING_INCLUDED_IN_NODE = "回転・拡大縮小を持つノードが含まれています。正規化が必用です。Setting の PoseFreeze を有効にしてください", + IS_POSE_FREEZE_DONE = "正規化済みです。Setting の PoseFreeze は不要です", + NO_ANIMATOR = "ExportRootに Animator がありません", + FACE_Z_POSITIVE_DIRECTION = "Z+ 向きにしてください", + NO_AVATAR_IN_ANIMATOR = "ExportRootの Animator に Avatar がありません", + AVATAR_IS_NOT_VALID = "ExportRootの Animator.Avatar が不正です", + AVATAR_IS_NOT_HUMANOID = "ExportRootの Animator.Avatar がヒューマノイドではありません。FBX importer の Rig で設定してください", + JAW_BONE_IS_INCLUDED = "humanoid設定に顎が含まれている。FBX importer の rig 設定に戻って設定を解除することをおすすめします", + DUPLICATE_BONE_NAME_EXISTS = "ヒエラルキーの中に同じ名前のGameObjectが含まれている。 エクスポートした場合に自動でリネームする", + NEEDS_VRM_BLENDSHAPE_PROXY = "VRMBlendShapeProxyが必要です。先にVRMフォーマットに変換してください", + VERTEX_COLOR_IS_INCLUDED = "ヒエラルキーに含まれる mesh に頂点カラーが含まれている", + NO_ACTIVE_MESH = "ヒエラルキーに active なメッシュが含まれていない", + UNKNOWN_SHADER = "Standard, Unlit, MToon 以外のマテリアルは、Standard になります", + FILENAME_TOO_LONG = "名前が長すぎる。リネームしてください: ", + } + }, + {Languages.en, new LangMessages{ + ROOT_EXISTS = "Please set up a ExportRoot for model export", + NO_PARENT = "ExportRoot must be topmost parent", + ROOT_WITHOUT_ROTATION_AND_SCALING_CHANGED = "ExportRoot's rotation and scaling are not allowed to change. Please set up rotation and scaling in child node", + PREFAB_CANNOT_EXPORT = "Prefab Asset cannot be exported. Prefab Asset has different behaviour with Scene GameObject. Please put the prefab into the scene", + ROTATION_OR_SCALEING_INCLUDED_IN_NODE = " Normalization is required. There are nodes (child GameObject) where rotation and scaling are not default. Please enable PoseFreeze", + IS_POSE_FREEZE_DONE = "Normalization has been done. PoseFreeze is not required", + NO_ANIMATOR = "No Animator in ExportRoot", + FACE_Z_POSITIVE_DIRECTION = "The model needs to face the positive Z-axis", + NO_AVATAR_IN_ANIMATOR = "No Avatar in ExportRoot's Animator", + AVATAR_IS_NOT_VALID = "Animator.avatar in ExportRoot is not valid", + AVATAR_IS_NOT_HUMANOID = "Animator.avatar is not humanoid. Please change model's AnimationType to humanoid", + JAW_BONE_IS_INCLUDED = "Jaw bone is included. It may not what you intended. Please check the humanoid avatar setting screen", + DUPLICATE_BONE_NAME_EXISTS = "There are bones with the same name in the hierarchy. They will be automatically renamed after export", + NEEDS_VRM_BLENDSHAPE_PROXY = "VRMBlendShapeProxy is required. Please convert to VRM format first", + VERTEX_COLOR_IS_INCLUDED = "This model contains vertex color", + NO_ACTIVE_MESH = "No active mesh", + UNKNOWN_SHADER = "It will export as `Standard` fallback", + FILENAME_TOO_LONG = "FileName is too long: ", + } + }, + }; + } +} diff --git a/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizardMessages.cs.meta b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizardMessages.cs.meta new file mode 100644 index 000000000..e67282235 --- /dev/null +++ b/Assets/VRM/UniVRM/Editor/Format/VRMExporterWizardMessages.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 515984b15b5b5bf4baca4fa2d6344fcf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: