diff --git a/Editor/Localization/LocalizationConfiguration.cs b/Editor/Localization/LocalizationConfiguration.cs index c5a5689..7c64330 100644 --- a/Editor/Localization/LocalizationConfiguration.cs +++ b/Editor/Localization/LocalizationConfiguration.cs @@ -8,7 +8,47 @@ namespace AlicizaX.Localization.Editor [AlicizaX.Editor.Setting.FilePath("ProjectSettings/LocalizationConfiguration.asset")] public class LocalizationConfiguration : AlicizaX.Editor.Setting.ScriptableSingleton { + private const string DefaultLanguageTypesTemplate = +@"using System.Collections.Generic; + +{NAMESPACE_START}/// +/// AutoGenerate +/// +public static class LanguageTypes +{ +{LANGUAGE_CONSTANTS} + + public static readonly IReadOnlyList Languages = new List + { +{LANGUAGE_LIST} + }; + + public static string IndexToString(int index) + { + if (index < 0 || index >= Languages.Count) return ""Unknown""; + return Languages[index]; + } + + public static int StringToIndex(string s) + { + int index = -1; + for (int i = 0; i < Languages.Count; i++) + { + if (Languages[i] == s) + { + index = i; + break; + } + } + + return index; + } +} +{NAMESPACE_END}"; + [SerializeField] internal string generateScriptCodeFirstConfig; + [SerializeField] internal string generateLanguageTypesNamespace = string.Empty; + [SerializeField] internal string generateLanguageTypesTemplate = DefaultLanguageTypesTemplate; [SerializeField] private List LanguageTypes = new List() { @@ -37,5 +77,9 @@ namespace AlicizaX.Localization.Editor public IReadOnlyList LanguageTypeNames => LanguageTypes; public string GenerateScriptCodeFirstConfig => generateScriptCodeFirstConfig; + public string GenerateLanguageTypesNamespace => generateLanguageTypesNamespace; + public string GenerateLanguageTypesTemplate => string.IsNullOrEmpty(generateLanguageTypesTemplate) ? DefaultLanguageTypesTemplate : generateLanguageTypesTemplate; + + public static string DefaultTemplate => DefaultLanguageTypesTemplate; } } diff --git a/Editor/Localization/LocalizationSettingsProvider.cs b/Editor/Localization/LocalizationSettingsProvider.cs index a21c447..bf4c21b 100644 --- a/Editor/Localization/LocalizationSettingsProvider.cs +++ b/Editor/Localization/LocalizationSettingsProvider.cs @@ -1,52 +1,92 @@ +using System; using System.Collections.Generic; +using System.IO; using System.Text; using AlicizaX.Editor; using UnityEditor; -using UnityEngine; -using UnityEngine.UIElements; using UnityEditorInternal; +using UnityEngine; namespace AlicizaX.Localization.Editor { - internal class LocalizationSettingsProvider : UnityEditor.SettingsProvider + internal sealed class LocalizationSettingsProvider : EditorWindow { + private const string WindowTitle = "Localization Settings"; + private const string MenuPath = "Tools/AlicizaX/Localization/Open Localization Settings"; + private SerializedObject _serializedObject; private SerializedProperty _languageTypes; - private ReorderableList _languageList; private SerializedProperty _genLangaugeTypePath; - private SerializedProperty generateScriptCodeFirstConfig; - private List popConfig = new List(); + private SerializedProperty _generateScriptCodeFirstConfig; + private SerializedProperty _generateLanguageTypesNamespace; + private SerializedProperty _generateLanguageTypesTemplate; + private ReorderableList _languageList; + private readonly List _languagePopupOptions = new(); + private readonly List _originalLanguages = new(); + private readonly List _localizationTables = new(); - // Track original state for comparison - private List _originalLanguages = new List(); - private bool _hasUnsavedChanges = false; + private Vector2 _scrollPosition; + private bool _hasUnsavedChanges; - public LocalizationSettingsProvider() : base("Project/Localization Settings", SettingsScope.Project) + [MenuItem(MenuPath)] + private static void Open() { + LocalizationSettingsProvider window = GetWindow(); + window.titleContent = new GUIContent(WindowTitle); + window.minSize = new Vector2(760f, 520f); + window.Show(); } - public override void OnActivate(string searchContext, VisualElement rootElement) + private void OnEnable() { InitGUI(); + RefreshLocalizationTables(); + } + + private void OnFocus() + { + RefreshLocalizationTables(); + } + + private void OnDisable() + { + _serializedObject?.Dispose(); + _serializedObject = null; + LocalizationConfiguration.Save(); } private void InitGUI() { - var setting = LocalizationConfiguration.Instance; + LocalizationConfiguration setting = LocalizationConfiguration.Instance; _serializedObject?.Dispose(); _serializedObject = new SerializedObject(setting); _languageTypes = _serializedObject.FindProperty("LanguageTypes"); _genLangaugeTypePath = _serializedObject.FindProperty("_genLangaugeTypePath"); - generateScriptCodeFirstConfig = _serializedObject.FindProperty("generateScriptCodeFirstConfig"); + _generateScriptCodeFirstConfig = _serializedObject.FindProperty("generateScriptCodeFirstConfig"); + _generateLanguageTypesNamespace = _serializedObject.FindProperty("generateLanguageTypesNamespace"); + _generateLanguageTypesTemplate = _serializedObject.FindProperty("generateLanguageTypesTemplate"); - // Store original language list + CaptureOriginalLanguages(); + BuildLanguageList(); + RefreshLanguagePopupOptions(); + } + + private void CaptureOriginalLanguages() + { _originalLanguages.Clear(); + if (_languageTypes == null) + { + return; + } + for (int i = 0; i < _languageTypes.arraySize; i++) { _originalLanguages.Add(_languageTypes.GetArrayElementAtIndex(i).stringValue); } + } - // 自定义 ReorderableList + private void BuildLanguageList() + { _languageList = new ReorderableList(_serializedObject, _languageTypes, draggable: false, displayHeader: true, @@ -57,18 +97,11 @@ namespace AlicizaX.Localization.Editor _languageList.drawElementCallback = (rect, index, isActive, isFocused) => { - var element = _languageTypes.GetArrayElementAtIndex(index); - rect.y += 2; + SerializedProperty element = _languageTypes.GetArrayElementAtIndex(index); + rect.y += 2f; - if (index < 2) // 前两个(中文、英文)禁止修改 - { - EditorGUI.BeginDisabledGroup(true); - EditorGUI.TextField( - new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight), - element.stringValue); - EditorGUI.EndDisabledGroup(); - } - else + bool isBuiltInLanguage = index < 2; + using (new EditorGUI.DisabledGroupScope(isBuiltInLanguage)) { EditorGUI.BeginChangeCheck(); string newValue = EditorGUI.TextField( @@ -82,23 +115,17 @@ namespace AlicizaX.Localization.Editor } }; - // 禁止删除前两个 - _languageList.onCanRemoveCallback = list => - { - return list.index >= 2; // 只有索引 >=2 的项才能删除 - }; + _languageList.onCanRemoveCallback = list => list.index >= 2; - // Hook for when a language is added _languageList.onAddCallback = list => { int newIndex = _languageTypes.arraySize; _languageTypes.InsertArrayElementAtIndex(newIndex); - var newElement = _languageTypes.GetArrayElementAtIndex(newIndex); + SerializedProperty newElement = _languageTypes.GetArrayElementAtIndex(newIndex); newElement.stringValue = "NewLanguage"; _hasUnsavedChanges = true; }; - // Hook for when a language is removed _languageList.onRemoveCallback = list => { if (list.index < 2) @@ -107,23 +134,38 @@ namespace AlicizaX.Localization.Editor return; } - // Just remove from the list, no immediate sync _languageTypes.DeleteArrayElementAtIndex(list.index); _hasUnsavedChanges = true; }; + } - popConfig.Clear(); - if (setting.LanguageTypeNames.Count > 0) + private void RefreshLanguagePopupOptions() + { + _languagePopupOptions.Clear(); + IReadOnlyList languageNames = LocalizationConfiguration.Instance.LanguageTypeNames; + for (int i = 0; i < languageNames.Count; i++) { - foreach (var lang in setting.LanguageTypeNames) + string name = languageNames[i].Or("Unknown"); + _languagePopupOptions.Add(name); + } + } + + private void RefreshLocalizationTables() + { + _localizationTables.Clear(); + string[] guids = AssetDatabase.FindAssets("t:GameLocaizationTable"); + for (int i = 0; i < guids.Length; i++) + { + string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]); + GameLocaizationTable table = AssetDatabase.LoadAssetAtPath(assetPath); + if (table != null) { - string name = lang.Or("Unknown"); - popConfig.Add(name); + _localizationTables.Add(table); } } } - public override void OnGUI(string searchContext) + private void OnGUI() { if (_serializedObject == null || !_serializedObject.targetObject) { @@ -131,127 +173,225 @@ namespace AlicizaX.Localization.Editor } _serializedObject.Update(); - EditorGUI.BeginChangeCheck(); + RefreshLanguagePopupOptions(); - EditorGUILayout.PropertyField(_genLangaugeTypePath); - EditorDrawing.DrawStringSelectPopup(new GUIContent("Gen Lang"), new GUIContent("None"), popConfig.ToArray(), generateScriptCodeFirstConfig.stringValue, - (e) => - { - generateScriptCodeFirstConfig.stringValue = e; - _serializedObject.ApplyModifiedProperties(); - LocalizationConfiguration.Save(); - }); - if (GUILayout.Button("Generate Language Types")) + EditorGUILayout.Space(); + _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition); + + DrawLanguageTypesSection(); + EditorGUILayout.Space(8f); + DrawLanguageTypesGenerateSection(); + EditorGUILayout.Space(8f); + DrawLocalizationTablesSection(); + + EditorGUILayout.EndScrollView(); + + if (_serializedObject.ApplyModifiedProperties()) { - RegenerateLanguageTypes(); - } - - _languageList.DoLayoutList(); - - if (EditorGUI.EndChangeCheck()) - { - _serializedObject.ApplyModifiedProperties(); LocalizationConfiguration.Save(); } + } - // Add Save button - EditorGUILayout.Space(10); - EditorGUILayout.BeginHorizontal(); - GUILayout.FlexibleSpace(); - - using (new EditorGUI.DisabledGroupScope(!_hasUnsavedChanges)) + private void DrawLanguageTypesSection() + { + using (new EditorDrawing.BorderBoxScope(new GUIContent("Language Types"), roundedBox: false)) { - if (GUILayout.Button("Save Language Changes", GUILayout.Width(200), GUILayout.Height(30))) + _languageList.DoLayoutList(); + + EditorGUILayout.Space(10f); + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + using (new EditorGUI.DisabledGroupScope(!_hasUnsavedChanges)) { - ApplyLanguageChanges(); + if (GUILayout.Button("Save Language Changes", GUILayout.Width(200f), GUILayout.Height(30f))) + { + ApplyLanguageChanges(); + } + } + + GUILayout.FlexibleSpace(); + EditorGUILayout.EndHorizontal(); + + if (_hasUnsavedChanges) + { + EditorGUILayout.HelpBox("You have unsaved language changes. Click 'Save Language Changes' to apply them to all GameLocalizationTable assets.", MessageType.Warning); } } + } - GUILayout.FlexibleSpace(); - EditorGUILayout.EndHorizontal(); - - if (_hasUnsavedChanges) + private void DrawLanguageTypesGenerateSection() + { + using (new EditorDrawing.BorderBoxScope(new GUIContent("Generate LanguageTypes"), roundedBox: false)) { - EditorGUILayout.HelpBox("You have unsaved language changes. Click 'Save Language Changes' to apply them to all GameLocalizationTable assets.", MessageType.Warning); + EditorGUILayout.PropertyField(_genLangaugeTypePath, new GUIContent("File Path")); + EditorGUILayout.PropertyField(_generateLanguageTypesNamespace, new GUIContent("Namespace")); + + EditorDrawing.DrawStringSelectPopup( + new GUIContent("生成多语言Key索引文件时的注释首选语言"), + new GUIContent("None"), + _languagePopupOptions.ToArray(), + _generateScriptCodeFirstConfig.stringValue, + selected => + { + _generateScriptCodeFirstConfig.stringValue = selected; + _serializedObject.ApplyModifiedProperties(); + LocalizationConfiguration.Save(); + }); + + EditorGUILayout.LabelField("Template", EditorStyles.boldLabel); + EditorGUILayout.HelpBox("Use placeholders: {NAMESPACE_START}, {NAMESPACE_END}, {LANGUAGE_CONSTANTS}, {LANGUAGE_LIST}", MessageType.None); + + EditorGUI.BeginChangeCheck(); + string template = EditorGUILayout.TextArea(_generateLanguageTypesTemplate.stringValue, GUILayout.MinHeight(240f)); + if (EditorGUI.EndChangeCheck()) + { + _generateLanguageTypesTemplate.stringValue = template; + } + + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + + if (GUILayout.Button("Reset Template", GUILayout.Width(140f))) + { + _generateLanguageTypesTemplate.stringValue = LocalizationConfiguration.DefaultTemplate; + } + + if (GUILayout.Button("Generate Language Types", GUILayout.Width(180f))) + { + RegenerateLanguageTypes(); + } + + EditorGUILayout.EndHorizontal(); + } + } + + private void DrawLocalizationTablesSection() + { + using (new EditorDrawing.BorderBoxScope(new GUIContent("LocalizationTable"), roundedBox: false)) + { + if (GUILayout.Button("Refresh LocalizationTable List", GUILayout.Width(220f))) + { + RefreshLocalizationTables(); + } + + EditorGUILayout.Space(4f); + + if (_localizationTables.Count == 0) + { + EditorGUILayout.HelpBox("No LocalizationTable assets found in the project.", MessageType.Info); + return; + } + + for (int i = 0; i < _localizationTables.Count; i++) + { + DrawLocalizationTableEntry(_localizationTables[i], i); + if (i < _localizationTables.Count - 1) + { + EditorGUILayout.Space(6f); + } + } + } + } + + private void DrawLocalizationTableEntry(GameLocaizationTable table, int index) + { + SerializedObject tableSerializedObject = new SerializedObject(table); + SerializedProperty pathProperty = tableSerializedObject.FindProperty("GenerateScriptCodePath"); + SerializedProperty namespaceProperty = tableSerializedObject.FindProperty("GenerateScriptCodeNamespace"); + + using (new EditorDrawing.BorderBoxScope(new GUIContent($"LocalizationTable {index + 1}"), roundedBox: false)) + { + using (new EditorGUI.DisabledGroupScope(true)) + { + EditorGUILayout.ObjectField("Table", table, typeof(GameLocaizationTable), false); + } + + tableSerializedObject.Update(); + EditorGUILayout.PropertyField(pathProperty, new GUIContent("Gen Code Path")); + EditorGUILayout.PropertyField(namespaceProperty, new GUIContent("Namespace")); + + EditorGUILayout.BeginHorizontal(); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Gen Code", GUILayout.Width(120f))) + { + tableSerializedObject.ApplyModifiedProperties(); + EditorUtility.SetDirty(table); + LocalizationWindowUtility.GenerateCode(table); + } + EditorGUILayout.EndHorizontal(); + + if (tableSerializedObject.ApplyModifiedProperties()) + { + EditorUtility.SetDirty(table); + AssetDatabase.SaveAssets(); + } } } private void RegenerateLanguageTypes() { - StringBuilder sb = new StringBuilder(); - - sb.AppendLine("using System.Collections.Generic;"); - sb.AppendLine(""); - sb.AppendLine("/// "); - sb.AppendLine("/// AutoGenerate"); - sb.AppendLine("/// "); - sb.AppendLine("public static class LanguageTypes"); - sb.AppendLine("{"); - for (int i = 0; i < LocalizationConfiguration.Instance.LanguageTypeNames.Count; i++) + string filePath = _genLangaugeTypePath.stringValue; + if (string.IsNullOrWhiteSpace(filePath)) { - sb.AppendLine($"\tpublic const string {LocalizationConfiguration.Instance.LanguageTypeNames[i]} = \"{LocalizationConfiguration.Instance.LanguageTypeNames[i]}\";"); + EditorUtility.DisplayDialog("Invalid Path", "LanguageTypes output path cannot be empty.", "OK"); + return; } - sb.AppendLine(""); - sb.AppendLine("\tpublic static readonly IReadOnlyList Languages = new List"); - sb.AppendLine("\t{"); - for (int i = 0; i < LocalizationConfiguration.Instance.LanguageTypeNames.Count; i++) + string directory = Path.GetDirectoryName(filePath); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) { - sb.AppendLine($"\t\t\"{LocalizationConfiguration.Instance.LanguageTypeNames[i]}\","); + Directory.CreateDirectory(directory); } - sb.AppendLine("\t};"); + string template = string.IsNullOrEmpty(_generateLanguageTypesTemplate.stringValue) + ? LocalizationConfiguration.DefaultTemplate + : _generateLanguageTypesTemplate.stringValue; - sb.AppendLine(""); - sb.AppendLine("\tpublic static string IndexToString(int index)"); - sb.AppendLine("\t{"); - sb.AppendLine("\t\tif (index < 0 || index >= Languages.Count) return \"Unknown\";"); - sb.AppendLine("\t\treturn Languages[index];"); - sb.AppendLine("\t}"); - sb.AppendLine(""); - sb.AppendLine("\tpublic static int StringToIndex(string s)"); - sb.AppendLine("\t{"); - sb.AppendLine("\t\tint index = -1;"); - sb.AppendLine("\t\tfor (int i = 0; i < Languages.Count; i++)"); - sb.AppendLine("\t\t{"); - sb.AppendLine("\t\t\tif (Languages[i] == s)"); - sb.AppendLine("\t\t\t{"); - sb.AppendLine("\t\t\t\tindex = i;"); - sb.AppendLine("\t\t\t\tbreak;"); - sb.AppendLine("\t\t\t}"); - sb.AppendLine("\t\t}"); - sb.AppendLine(""); - sb.AppendLine("\t\treturn index;"); - sb.AppendLine("\t}"); - sb.AppendLine(""); - sb.AppendLine("}"); - - System.IO.File.WriteAllText(_genLangaugeTypePath.stringValue, sb.ToString()); + string generatedCode = BuildLanguageTypesCode(template, _generateLanguageTypesNamespace.stringValue, LocalizationConfiguration.Instance.LanguageTypeNames); + File.WriteAllText(filePath, generatedCode, Encoding.UTF8); AssetDatabase.Refresh(); } - public override void OnDeactivate() + private static string BuildLanguageTypesCode(string template, string namespaceName, IReadOnlyList languages) { - base.OnDeactivate(); - LocalizationConfiguration.Save(); + StringBuilder constantsBuilder = new StringBuilder(); + StringBuilder listBuilder = new StringBuilder(); + + for (int i = 0; i < languages.Count; i++) + { + string languageName = languages[i]; + constantsBuilder.AppendLine($" public const string {languageName} = \"{languageName}\";"); + listBuilder.AppendLine($" \"{languageName}\","); + } + + string namespaceStart = string.IsNullOrWhiteSpace(namespaceName) + ? string.Empty + : $"namespace {namespaceName}{Environment.NewLine}{{{Environment.NewLine}"; + string namespaceEnd = string.IsNullOrWhiteSpace(namespaceName) + ? string.Empty + : $"{Environment.NewLine}}}"; + + return template + .Replace("{NAMESPACE_START}", namespaceStart) + .Replace("{NAMESPACE_END}", namespaceEnd) + .Replace("{LANGUAGE_CONSTANTS}", constantsBuilder.ToString().TrimEnd()) + .Replace("{LANGUAGE_LIST}", listBuilder.ToString().TrimEnd()); } private void ApplyLanguageChanges() { - // Get current language list List currentLanguages = new List(); for (int i = 0; i < _languageTypes.arraySize; i++) { currentLanguages.Add(_languageTypes.GetArrayElementAtIndex(i).stringValue); } - // Detect changes List addedLanguages = new List(); List removedLanguages = new List(); - Dictionary renamedLanguages = new Dictionary(); // old -> new + Dictionary renamedLanguages = new Dictionary(); - // Find added languages - foreach (var lang in currentLanguages) + foreach (string lang in currentLanguages) { if (!_originalLanguages.Contains(lang)) { @@ -259,8 +399,7 @@ namespace AlicizaX.Localization.Editor } } - // Find removed languages - foreach (var lang in _originalLanguages) + foreach (string lang in _originalLanguages) { if (!currentLanguages.Contains(lang)) { @@ -268,12 +407,10 @@ namespace AlicizaX.Localization.Editor } } - // Detect renames (same index, different name) for (int i = 0; i < Mathf.Min(_originalLanguages.Count, currentLanguages.Count); i++) { if (_originalLanguages[i] != currentLanguages[i]) { - // Check if this is a rename (not an add/remove) if (!addedLanguages.Contains(currentLanguages[i]) && !removedLanguages.Contains(_originalLanguages[i])) { renamedLanguages[_originalLanguages[i]] = currentLanguages[i]; @@ -281,7 +418,6 @@ namespace AlicizaX.Localization.Editor } } - // Apply changes to all tables string[] guids = AssetDatabase.FindAssets("t:GameLocaizationTable"); int tablesUpdated = 0; @@ -291,12 +427,13 @@ namespace AlicizaX.Localization.Editor GameLocaizationTable table = AssetDatabase.LoadAssetAtPath(assetPath); if (table == null) + { continue; + } bool tableModified = false; - // Handle renames first - foreach (var rename in renamedLanguages) + foreach (KeyValuePair rename in renamedLanguages) { LocalizationLanguage language = table.Languages.Find(lang => lang.LanguageName == rename.Key); if (language != null) @@ -307,26 +444,24 @@ namespace AlicizaX.Localization.Editor } } - // Handle additions - foreach (var newLang in addedLanguages) + foreach (string newLang in addedLanguages) { - // Skip if already exists if (table.Languages.Exists(lang => lang.LanguageName == newLang)) + { continue; + } - // Create new LocalizationLanguage asset LocalizationLanguage newLanguage = ScriptableObject.CreateInstance(); newLanguage.name = newLang; newLanguage.LanguageName = newLang; newLanguage.Strings = new List(); - // Synchronize keys from existing table structure - foreach (var section in table.TableSheet) + foreach (GameLocaizationTable.TableData section in table.TableSheet) { - foreach (var item in section.SectionSheet) + foreach (GameLocaizationTable.SheetItem item in section.SectionSheet) { - string sectionKey = section.SectionName.Replace(" ", ""); - string itemKey = item.Key.Replace(" ", ""); + string sectionKey = section.SectionName.Replace(" ", string.Empty); + string itemKey = item.Key.Replace(" ", string.Empty); string fullKey = sectionKey + "." + itemKey; newLanguage.Strings.Add(new LocalizationLanguage.LocalizationString @@ -344,8 +479,7 @@ namespace AlicizaX.Localization.Editor tableModified = true; } - // Handle removals - foreach (var removedLang in removedLanguages) + foreach (string removedLang in removedLanguages) { LocalizationLanguage languageToDelete = table.Languages.Find(lang => lang.LanguageName == removedLang); if (languageToDelete != null) @@ -366,33 +500,27 @@ namespace AlicizaX.Localization.Editor AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); - // Update original languages list _originalLanguages.Clear(); _originalLanguages.AddRange(currentLanguages); _hasUnsavedChanges = false; + RefreshLocalizationTables(); - // Log results if (addedLanguages.Count > 0) + { Debug.Log($"Added {addedLanguages.Count} language(s) to {tablesUpdated} table(s): {string.Join(", ", addedLanguages)}"); + } + if (removedLanguages.Count > 0) + { Debug.Log($"Removed {removedLanguages.Count} language(s) from {tablesUpdated} table(s): {string.Join(", ", removedLanguages)}"); + } + if (renamedLanguages.Count > 0) + { Debug.Log($"Renamed {renamedLanguages.Count} language(s) in {tablesUpdated} table(s)"); + } EditorUtility.DisplayDialog("Success", $"Language changes applied to {tablesUpdated} GameLocalizationTable(s).", "OK"); } - - static LocalizationSettingsProvider s_provider; - - [SettingsProvider] - public static SettingsProvider CreateMyCustomSettingsProvider() - { - if (s_provider == null) - { - s_provider = new LocalizationSettingsProvider(); - } - - return s_provider; - } } } diff --git a/Editor/Localization/LocalizationSettingsProvider.cs.meta b/Editor/Localization/LocalizationSettingsProvider.cs.meta index c49286a..118c812 100644 --- a/Editor/Localization/LocalizationSettingsProvider.cs.meta +++ b/Editor/Localization/LocalizationSettingsProvider.cs.meta @@ -1,3 +1,11 @@ fileFormatVersion: 2 guid: 5647a4aaf19f42bf852a701955e888f5 -timeCreated: 1758196661 \ No newline at end of file +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Localization/LocalizationTableWindow/LocalizationWindowUtility.cs b/Editor/Localization/LocalizationTableWindow/LocalizationWindowUtility.cs index cdc43c0..d652dcc 100644 --- a/Editor/Localization/LocalizationTableWindow/LocalizationWindowUtility.cs +++ b/Editor/Localization/LocalizationTableWindow/LocalizationWindowUtility.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Collections.Generic; using System.Text; +using System.IO; using UnityEditor; using UnityEngine; @@ -591,10 +592,28 @@ namespace AlicizaX.Localization.Editor public static void GenerateCode(GameLocaizationTable table) { string filePath = table.GenerateScriptCodePath; - List strings = new List(); + if (string.IsNullOrWhiteSpace(filePath)) + { + EditorUtility.DisplayDialog("Invalid Path", "Localization key output path cannot be empty.", "OK"); + return; + } + + string directory = Path.GetDirectoryName(filePath); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + var localizationLanguage = table.Languages.Find(t => t.LanguageName == LocalizationConfiguration.Instance.GenerateScriptCodeFirstConfig); + string namespaceName = table.GenerateScriptCodeNamespace; StringBuilder sb = new StringBuilder(); + if (!string.IsNullOrWhiteSpace(namespaceName)) + { + sb.AppendLine($"namespace {namespaceName}"); + sb.AppendLine("{"); + } + sb.AppendLine("/// "); sb.AppendLine("/// AutoGenerate"); sb.AppendLine("/// "); @@ -634,7 +653,14 @@ namespace AlicizaX.Localization.Editor sb.AppendLine(); sb.AppendLine("}"); - System.IO.File.WriteAllText(filePath, sb.ToString()); + + if (!string.IsNullOrWhiteSpace(namespaceName)) + { + sb.AppendLine(); + sb.AppendLine("}"); + } + + File.WriteAllText(filePath, sb.ToString(), Encoding.UTF8); AssetDatabase.Refresh(); } } diff --git a/Editor/Localization/LocalizationTableWindow/Scriptable/GameLocaizationTableEditor.cs b/Editor/Localization/LocalizationTableWindow/Scriptable/GameLocaizationTableEditor.cs index 3079d69..e32298f 100644 --- a/Editor/Localization/LocalizationTableWindow/Scriptable/GameLocaizationTableEditor.cs +++ b/Editor/Localization/LocalizationTableWindow/Scriptable/GameLocaizationTableEditor.cs @@ -43,6 +43,7 @@ namespace AlicizaX.Localization.Editor using (new EditorDrawing.BorderBoxScope(new GUIContent("GenCode"), roundedBox: false)) { Properties.Draw("GenerateScriptCodePath", new GUIContent("File Path")); + Properties.Draw("GenerateScriptCodeNamespace", new GUIContent("Namespace")); } } serializedObject.ApplyModifiedProperties(); @@ -96,10 +97,9 @@ namespace AlicizaX.Localization.Editor window.Show(); } - [MenuItem("Tools/AlicizaX/Localization/Open Localization ProjectSetting")] public static void OpenSettings() { - SettingsService.OpenProjectSettings("Project/Localization Settings"); + EditorApplication.ExecuteMenuItem("Tools/AlicizaX/Localization/Open Localization Settings"); } diff --git a/Runtime/Localization/ScriptableObject/GameLocaizationTable.cs b/Runtime/Localization/ScriptableObject/GameLocaizationTable.cs index 5c86c2c..f218d85 100644 --- a/Runtime/Localization/ScriptableObject/GameLocaizationTable.cs +++ b/Runtime/Localization/ScriptableObject/GameLocaizationTable.cs @@ -8,6 +8,7 @@ namespace AlicizaX.Localization { #if UNITY_EDITOR [SerializeField] internal string GenerateScriptCodePath = string.Empty; + [SerializeField] internal string GenerateScriptCodeNamespace = string.Empty; [Serializable] public struct SheetItem