update
This commit is contained in:
parent
0a5ec37d23
commit
e54d2144df
@ -8,7 +8,47 @@ namespace AlicizaX.Localization.Editor
|
|||||||
[AlicizaX.Editor.Setting.FilePath("ProjectSettings/LocalizationConfiguration.asset")]
|
[AlicizaX.Editor.Setting.FilePath("ProjectSettings/LocalizationConfiguration.asset")]
|
||||||
public class LocalizationConfiguration : AlicizaX.Editor.Setting.ScriptableSingleton<LocalizationConfiguration>
|
public class LocalizationConfiguration : AlicizaX.Editor.Setting.ScriptableSingleton<LocalizationConfiguration>
|
||||||
{
|
{
|
||||||
|
private const string DefaultLanguageTypesTemplate =
|
||||||
|
@"using System.Collections.Generic;
|
||||||
|
|
||||||
|
{NAMESPACE_START}/// <summary>
|
||||||
|
/// AutoGenerate
|
||||||
|
/// </summary>
|
||||||
|
public static class LanguageTypes
|
||||||
|
{
|
||||||
|
{LANGUAGE_CONSTANTS}
|
||||||
|
|
||||||
|
public static readonly IReadOnlyList<string> Languages = new List<string>
|
||||||
|
{
|
||||||
|
{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 generateScriptCodeFirstConfig;
|
||||||
|
[SerializeField] internal string generateLanguageTypesNamespace = string.Empty;
|
||||||
|
[SerializeField] internal string generateLanguageTypesTemplate = DefaultLanguageTypesTemplate;
|
||||||
|
|
||||||
[SerializeField] private List<string> LanguageTypes = new List<string>()
|
[SerializeField] private List<string> LanguageTypes = new List<string>()
|
||||||
{
|
{
|
||||||
@ -37,5 +77,9 @@ namespace AlicizaX.Localization.Editor
|
|||||||
|
|
||||||
public IReadOnlyList<string> LanguageTypeNames => LanguageTypes;
|
public IReadOnlyList<string> LanguageTypeNames => LanguageTypes;
|
||||||
public string GenerateScriptCodeFirstConfig => generateScriptCodeFirstConfig;
|
public string GenerateScriptCodeFirstConfig => generateScriptCodeFirstConfig;
|
||||||
|
public string GenerateLanguageTypesNamespace => generateLanguageTypesNamespace;
|
||||||
|
public string GenerateLanguageTypesTemplate => string.IsNullOrEmpty(generateLanguageTypesTemplate) ? DefaultLanguageTypesTemplate : generateLanguageTypesTemplate;
|
||||||
|
|
||||||
|
public static string DefaultTemplate => DefaultLanguageTypesTemplate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,52 +1,92 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using AlicizaX.Editor;
|
using AlicizaX.Editor;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.UIElements;
|
|
||||||
using UnityEditorInternal;
|
using UnityEditorInternal;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace AlicizaX.Localization.Editor
|
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 SerializedObject _serializedObject;
|
||||||
private SerializedProperty _languageTypes;
|
private SerializedProperty _languageTypes;
|
||||||
private ReorderableList _languageList;
|
|
||||||
private SerializedProperty _genLangaugeTypePath;
|
private SerializedProperty _genLangaugeTypePath;
|
||||||
private SerializedProperty generateScriptCodeFirstConfig;
|
private SerializedProperty _generateScriptCodeFirstConfig;
|
||||||
private List<string> popConfig = new List<string>();
|
private SerializedProperty _generateLanguageTypesNamespace;
|
||||||
|
private SerializedProperty _generateLanguageTypesTemplate;
|
||||||
|
private ReorderableList _languageList;
|
||||||
|
private readonly List<string> _languagePopupOptions = new();
|
||||||
|
private readonly List<string> _originalLanguages = new();
|
||||||
|
private readonly List<GameLocaizationTable> _localizationTables = new();
|
||||||
|
|
||||||
// Track original state for comparison
|
private Vector2 _scrollPosition;
|
||||||
private List<string> _originalLanguages = new List<string>();
|
private bool _hasUnsavedChanges;
|
||||||
private bool _hasUnsavedChanges = false;
|
|
||||||
|
|
||||||
public LocalizationSettingsProvider() : base("Project/Localization Settings", SettingsScope.Project)
|
[MenuItem(MenuPath)]
|
||||||
|
private static void Open()
|
||||||
{
|
{
|
||||||
|
LocalizationSettingsProvider window = GetWindow<LocalizationSettingsProvider>();
|
||||||
|
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();
|
InitGUI();
|
||||||
|
RefreshLocalizationTables();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnFocus()
|
||||||
|
{
|
||||||
|
RefreshLocalizationTables();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
_serializedObject?.Dispose();
|
||||||
|
_serializedObject = null;
|
||||||
|
LocalizationConfiguration.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitGUI()
|
private void InitGUI()
|
||||||
{
|
{
|
||||||
var setting = LocalizationConfiguration.Instance;
|
LocalizationConfiguration setting = LocalizationConfiguration.Instance;
|
||||||
_serializedObject?.Dispose();
|
_serializedObject?.Dispose();
|
||||||
_serializedObject = new SerializedObject(setting);
|
_serializedObject = new SerializedObject(setting);
|
||||||
_languageTypes = _serializedObject.FindProperty("LanguageTypes");
|
_languageTypes = _serializedObject.FindProperty("LanguageTypes");
|
||||||
_genLangaugeTypePath = _serializedObject.FindProperty("_genLangaugeTypePath");
|
_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();
|
_originalLanguages.Clear();
|
||||||
|
if (_languageTypes == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < _languageTypes.arraySize; i++)
|
for (int i = 0; i < _languageTypes.arraySize; i++)
|
||||||
{
|
{
|
||||||
_originalLanguages.Add(_languageTypes.GetArrayElementAtIndex(i).stringValue);
|
_originalLanguages.Add(_languageTypes.GetArrayElementAtIndex(i).stringValue);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 自定义 ReorderableList
|
private void BuildLanguageList()
|
||||||
|
{
|
||||||
_languageList = new ReorderableList(_serializedObject, _languageTypes,
|
_languageList = new ReorderableList(_serializedObject, _languageTypes,
|
||||||
draggable: false,
|
draggable: false,
|
||||||
displayHeader: true,
|
displayHeader: true,
|
||||||
@ -57,18 +97,11 @@ namespace AlicizaX.Localization.Editor
|
|||||||
|
|
||||||
_languageList.drawElementCallback = (rect, index, isActive, isFocused) =>
|
_languageList.drawElementCallback = (rect, index, isActive, isFocused) =>
|
||||||
{
|
{
|
||||||
var element = _languageTypes.GetArrayElementAtIndex(index);
|
SerializedProperty element = _languageTypes.GetArrayElementAtIndex(index);
|
||||||
rect.y += 2;
|
rect.y += 2f;
|
||||||
|
|
||||||
if (index < 2) // 前两个(中文、英文)禁止修改
|
bool isBuiltInLanguage = index < 2;
|
||||||
{
|
using (new EditorGUI.DisabledGroupScope(isBuiltInLanguage))
|
||||||
EditorGUI.BeginDisabledGroup(true);
|
|
||||||
EditorGUI.TextField(
|
|
||||||
new Rect(rect.x, rect.y, rect.width, EditorGUIUtility.singleLineHeight),
|
|
||||||
element.stringValue);
|
|
||||||
EditorGUI.EndDisabledGroup();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
EditorGUI.BeginChangeCheck();
|
EditorGUI.BeginChangeCheck();
|
||||||
string newValue = EditorGUI.TextField(
|
string newValue = EditorGUI.TextField(
|
||||||
@ -82,23 +115,17 @@ namespace AlicizaX.Localization.Editor
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 禁止删除前两个
|
_languageList.onCanRemoveCallback = list => list.index >= 2;
|
||||||
_languageList.onCanRemoveCallback = list =>
|
|
||||||
{
|
|
||||||
return list.index >= 2; // 只有索引 >=2 的项才能删除
|
|
||||||
};
|
|
||||||
|
|
||||||
// Hook for when a language is added
|
|
||||||
_languageList.onAddCallback = list =>
|
_languageList.onAddCallback = list =>
|
||||||
{
|
{
|
||||||
int newIndex = _languageTypes.arraySize;
|
int newIndex = _languageTypes.arraySize;
|
||||||
_languageTypes.InsertArrayElementAtIndex(newIndex);
|
_languageTypes.InsertArrayElementAtIndex(newIndex);
|
||||||
var newElement = _languageTypes.GetArrayElementAtIndex(newIndex);
|
SerializedProperty newElement = _languageTypes.GetArrayElementAtIndex(newIndex);
|
||||||
newElement.stringValue = "NewLanguage";
|
newElement.stringValue = "NewLanguage";
|
||||||
_hasUnsavedChanges = true;
|
_hasUnsavedChanges = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hook for when a language is removed
|
|
||||||
_languageList.onRemoveCallback = list =>
|
_languageList.onRemoveCallback = list =>
|
||||||
{
|
{
|
||||||
if (list.index < 2)
|
if (list.index < 2)
|
||||||
@ -107,23 +134,38 @@ namespace AlicizaX.Localization.Editor
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just remove from the list, no immediate sync
|
|
||||||
_languageTypes.DeleteArrayElementAtIndex(list.index);
|
_languageTypes.DeleteArrayElementAtIndex(list.index);
|
||||||
_hasUnsavedChanges = true;
|
_hasUnsavedChanges = true;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
popConfig.Clear();
|
private void RefreshLanguagePopupOptions()
|
||||||
if (setting.LanguageTypeNames.Count > 0)
|
|
||||||
{
|
{
|
||||||
foreach (var lang in setting.LanguageTypeNames)
|
_languagePopupOptions.Clear();
|
||||||
|
IReadOnlyList<string> languageNames = LocalizationConfiguration.Instance.LanguageTypeNames;
|
||||||
|
for (int i = 0; i < languageNames.Count; i++)
|
||||||
{
|
{
|
||||||
string name = lang.Or("Unknown");
|
string name = languageNames[i].Or("Unknown");
|
||||||
popConfig.Add(name);
|
_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<GameLocaizationTable>(assetPath);
|
||||||
|
if (table != null)
|
||||||
|
{
|
||||||
|
_localizationTables.Add(table);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnGUI(string searchContext)
|
private void OnGUI()
|
||||||
{
|
{
|
||||||
if (_serializedObject == null || !_serializedObject.targetObject)
|
if (_serializedObject == null || !_serializedObject.targetObject)
|
||||||
{
|
{
|
||||||
@ -131,37 +173,38 @@ namespace AlicizaX.Localization.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
_serializedObject.Update();
|
_serializedObject.Update();
|
||||||
EditorGUI.BeginChangeCheck();
|
RefreshLanguagePopupOptions();
|
||||||
|
|
||||||
EditorGUILayout.PropertyField(_genLangaugeTypePath);
|
EditorGUILayout.Space();
|
||||||
EditorDrawing.DrawStringSelectPopup(new GUIContent("Gen Lang"), new GUIContent("None"), popConfig.ToArray(), generateScriptCodeFirstConfig.stringValue,
|
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
|
||||||
(e) =>
|
|
||||||
|
DrawLanguageTypesSection();
|
||||||
|
EditorGUILayout.Space(8f);
|
||||||
|
DrawLanguageTypesGenerateSection();
|
||||||
|
EditorGUILayout.Space(8f);
|
||||||
|
DrawLocalizationTablesSection();
|
||||||
|
|
||||||
|
EditorGUILayout.EndScrollView();
|
||||||
|
|
||||||
|
if (_serializedObject.ApplyModifiedProperties())
|
||||||
{
|
{
|
||||||
generateScriptCodeFirstConfig.stringValue = e;
|
|
||||||
_serializedObject.ApplyModifiedProperties();
|
|
||||||
LocalizationConfiguration.Save();
|
LocalizationConfiguration.Save();
|
||||||
});
|
}
|
||||||
if (GUILayout.Button("Generate Language Types"))
|
|
||||||
{
|
|
||||||
RegenerateLanguageTypes();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DrawLanguageTypesSection()
|
||||||
|
{
|
||||||
|
using (new EditorDrawing.BorderBoxScope(new GUIContent("Language Types"), roundedBox: false))
|
||||||
|
{
|
||||||
_languageList.DoLayoutList();
|
_languageList.DoLayoutList();
|
||||||
|
|
||||||
if (EditorGUI.EndChangeCheck())
|
EditorGUILayout.Space(10f);
|
||||||
{
|
|
||||||
_serializedObject.ApplyModifiedProperties();
|
|
||||||
LocalizationConfiguration.Save();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Save button
|
|
||||||
EditorGUILayout.Space(10);
|
|
||||||
EditorGUILayout.BeginHorizontal();
|
EditorGUILayout.BeginHorizontal();
|
||||||
GUILayout.FlexibleSpace();
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
using (new EditorGUI.DisabledGroupScope(!_hasUnsavedChanges))
|
using (new EditorGUI.DisabledGroupScope(!_hasUnsavedChanges))
|
||||||
{
|
{
|
||||||
if (GUILayout.Button("Save Language Changes", GUILayout.Width(200), GUILayout.Height(30)))
|
if (GUILayout.Button("Save Language Changes", GUILayout.Width(200f), GUILayout.Height(30f)))
|
||||||
{
|
{
|
||||||
ApplyLanguageChanges();
|
ApplyLanguageChanges();
|
||||||
}
|
}
|
||||||
@ -175,83 +218,180 @@ namespace AlicizaX.Localization.Editor
|
|||||||
EditorGUILayout.HelpBox("You have unsaved language changes. Click 'Save Language Changes' to apply them to all GameLocalizationTable assets.", MessageType.Warning);
|
EditorGUILayout.HelpBox("You have unsaved language changes. Click 'Save Language Changes' to apply them to all GameLocalizationTable assets.", MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawLanguageTypesGenerateSection()
|
||||||
|
{
|
||||||
|
using (new EditorDrawing.BorderBoxScope(new GUIContent("Generate LanguageTypes"), roundedBox: false))
|
||||||
|
{
|
||||||
|
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()
|
private void RegenerateLanguageTypes()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
string filePath = _genLangaugeTypePath.stringValue;
|
||||||
|
if (string.IsNullOrWhiteSpace(filePath))
|
||||||
sb.AppendLine("using System.Collections.Generic;");
|
|
||||||
sb.AppendLine("");
|
|
||||||
sb.AppendLine("/// <summary>");
|
|
||||||
sb.AppendLine("/// AutoGenerate");
|
|
||||||
sb.AppendLine("/// </summary>");
|
|
||||||
sb.AppendLine("public static class LanguageTypes");
|
|
||||||
sb.AppendLine("{");
|
|
||||||
for (int i = 0; i < LocalizationConfiguration.Instance.LanguageTypeNames.Count; i++)
|
|
||||||
{
|
{
|
||||||
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("");
|
string directory = Path.GetDirectoryName(filePath);
|
||||||
sb.AppendLine("\tpublic static readonly IReadOnlyList<string> Languages = new List<string>");
|
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||||
sb.AppendLine("\t{");
|
|
||||||
for (int i = 0; i < LocalizationConfiguration.Instance.LanguageTypeNames.Count; i++)
|
|
||||||
{
|
{
|
||||||
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("");
|
string generatedCode = BuildLanguageTypesCode(template, _generateLanguageTypesNamespace.stringValue, LocalizationConfiguration.Instance.LanguageTypeNames);
|
||||||
sb.AppendLine("\tpublic static string IndexToString(int index)");
|
File.WriteAllText(filePath, generatedCode, Encoding.UTF8);
|
||||||
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());
|
|
||||||
AssetDatabase.Refresh();
|
AssetDatabase.Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnDeactivate()
|
private static string BuildLanguageTypesCode(string template, string namespaceName, IReadOnlyList<string> languages)
|
||||||
{
|
{
|
||||||
base.OnDeactivate();
|
StringBuilder constantsBuilder = new StringBuilder();
|
||||||
LocalizationConfiguration.Save();
|
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()
|
private void ApplyLanguageChanges()
|
||||||
{
|
{
|
||||||
// Get current language list
|
|
||||||
List<string> currentLanguages = new List<string>();
|
List<string> currentLanguages = new List<string>();
|
||||||
for (int i = 0; i < _languageTypes.arraySize; i++)
|
for (int i = 0; i < _languageTypes.arraySize; i++)
|
||||||
{
|
{
|
||||||
currentLanguages.Add(_languageTypes.GetArrayElementAtIndex(i).stringValue);
|
currentLanguages.Add(_languageTypes.GetArrayElementAtIndex(i).stringValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect changes
|
|
||||||
List<string> addedLanguages = new List<string>();
|
List<string> addedLanguages = new List<string>();
|
||||||
List<string> removedLanguages = new List<string>();
|
List<string> removedLanguages = new List<string>();
|
||||||
Dictionary<string, string> renamedLanguages = new Dictionary<string, string>(); // old -> new
|
Dictionary<string, string> renamedLanguages = new Dictionary<string, string>();
|
||||||
|
|
||||||
// Find added languages
|
foreach (string lang in currentLanguages)
|
||||||
foreach (var lang in currentLanguages)
|
|
||||||
{
|
{
|
||||||
if (!_originalLanguages.Contains(lang))
|
if (!_originalLanguages.Contains(lang))
|
||||||
{
|
{
|
||||||
@ -259,8 +399,7 @@ namespace AlicizaX.Localization.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find removed languages
|
foreach (string lang in _originalLanguages)
|
||||||
foreach (var lang in _originalLanguages)
|
|
||||||
{
|
{
|
||||||
if (!currentLanguages.Contains(lang))
|
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++)
|
for (int i = 0; i < Mathf.Min(_originalLanguages.Count, currentLanguages.Count); i++)
|
||||||
{
|
{
|
||||||
if (_originalLanguages[i] != currentLanguages[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]))
|
if (!addedLanguages.Contains(currentLanguages[i]) && !removedLanguages.Contains(_originalLanguages[i]))
|
||||||
{
|
{
|
||||||
renamedLanguages[_originalLanguages[i]] = currentLanguages[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");
|
string[] guids = AssetDatabase.FindAssets("t:GameLocaizationTable");
|
||||||
int tablesUpdated = 0;
|
int tablesUpdated = 0;
|
||||||
|
|
||||||
@ -291,12 +427,13 @@ namespace AlicizaX.Localization.Editor
|
|||||||
GameLocaizationTable table = AssetDatabase.LoadAssetAtPath<GameLocaizationTable>(assetPath);
|
GameLocaizationTable table = AssetDatabase.LoadAssetAtPath<GameLocaizationTable>(assetPath);
|
||||||
|
|
||||||
if (table == null)
|
if (table == null)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
bool tableModified = false;
|
bool tableModified = false;
|
||||||
|
|
||||||
// Handle renames first
|
foreach (KeyValuePair<string, string> rename in renamedLanguages)
|
||||||
foreach (var rename in renamedLanguages)
|
|
||||||
{
|
{
|
||||||
LocalizationLanguage language = table.Languages.Find(lang => lang.LanguageName == rename.Key);
|
LocalizationLanguage language = table.Languages.Find(lang => lang.LanguageName == rename.Key);
|
||||||
if (language != null)
|
if (language != null)
|
||||||
@ -307,26 +444,24 @@ namespace AlicizaX.Localization.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle additions
|
foreach (string newLang in addedLanguages)
|
||||||
foreach (var newLang in addedLanguages)
|
|
||||||
{
|
{
|
||||||
// Skip if already exists
|
|
||||||
if (table.Languages.Exists(lang => lang.LanguageName == newLang))
|
if (table.Languages.Exists(lang => lang.LanguageName == newLang))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Create new LocalizationLanguage asset
|
|
||||||
LocalizationLanguage newLanguage = ScriptableObject.CreateInstance<LocalizationLanguage>();
|
LocalizationLanguage newLanguage = ScriptableObject.CreateInstance<LocalizationLanguage>();
|
||||||
newLanguage.name = newLang;
|
newLanguage.name = newLang;
|
||||||
newLanguage.LanguageName = newLang;
|
newLanguage.LanguageName = newLang;
|
||||||
newLanguage.Strings = new List<LocalizationLanguage.LocalizationString>();
|
newLanguage.Strings = new List<LocalizationLanguage.LocalizationString>();
|
||||||
|
|
||||||
// Synchronize keys from existing table structure
|
foreach (GameLocaizationTable.TableData section in table.TableSheet)
|
||||||
foreach (var section in table.TableSheet)
|
|
||||||
{
|
{
|
||||||
foreach (var item in section.SectionSheet)
|
foreach (GameLocaizationTable.SheetItem item in section.SectionSheet)
|
||||||
{
|
{
|
||||||
string sectionKey = section.SectionName.Replace(" ", "");
|
string sectionKey = section.SectionName.Replace(" ", string.Empty);
|
||||||
string itemKey = item.Key.Replace(" ", "");
|
string itemKey = item.Key.Replace(" ", string.Empty);
|
||||||
string fullKey = sectionKey + "." + itemKey;
|
string fullKey = sectionKey + "." + itemKey;
|
||||||
|
|
||||||
newLanguage.Strings.Add(new LocalizationLanguage.LocalizationString
|
newLanguage.Strings.Add(new LocalizationLanguage.LocalizationString
|
||||||
@ -344,8 +479,7 @@ namespace AlicizaX.Localization.Editor
|
|||||||
tableModified = true;
|
tableModified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle removals
|
foreach (string removedLang in removedLanguages)
|
||||||
foreach (var removedLang in removedLanguages)
|
|
||||||
{
|
{
|
||||||
LocalizationLanguage languageToDelete = table.Languages.Find(lang => lang.LanguageName == removedLang);
|
LocalizationLanguage languageToDelete = table.Languages.Find(lang => lang.LanguageName == removedLang);
|
||||||
if (languageToDelete != null)
|
if (languageToDelete != null)
|
||||||
@ -366,33 +500,27 @@ namespace AlicizaX.Localization.Editor
|
|||||||
AssetDatabase.SaveAssets();
|
AssetDatabase.SaveAssets();
|
||||||
AssetDatabase.Refresh();
|
AssetDatabase.Refresh();
|
||||||
|
|
||||||
// Update original languages list
|
|
||||||
_originalLanguages.Clear();
|
_originalLanguages.Clear();
|
||||||
_originalLanguages.AddRange(currentLanguages);
|
_originalLanguages.AddRange(currentLanguages);
|
||||||
_hasUnsavedChanges = false;
|
_hasUnsavedChanges = false;
|
||||||
|
RefreshLocalizationTables();
|
||||||
|
|
||||||
// Log results
|
|
||||||
if (addedLanguages.Count > 0)
|
if (addedLanguages.Count > 0)
|
||||||
|
{
|
||||||
Debug.Log($"Added {addedLanguages.Count} language(s) to {tablesUpdated} table(s): {string.Join(", ", addedLanguages)}");
|
Debug.Log($"Added {addedLanguages.Count} language(s) to {tablesUpdated} table(s): {string.Join(", ", addedLanguages)}");
|
||||||
|
}
|
||||||
|
|
||||||
if (removedLanguages.Count > 0)
|
if (removedLanguages.Count > 0)
|
||||||
|
{
|
||||||
Debug.Log($"Removed {removedLanguages.Count} language(s) from {tablesUpdated} table(s): {string.Join(", ", removedLanguages)}");
|
Debug.Log($"Removed {removedLanguages.Count} language(s) from {tablesUpdated} table(s): {string.Join(", ", removedLanguages)}");
|
||||||
|
}
|
||||||
|
|
||||||
if (renamedLanguages.Count > 0)
|
if (renamedLanguages.Count > 0)
|
||||||
|
{
|
||||||
Debug.Log($"Renamed {renamedLanguages.Count} language(s) in {tablesUpdated} table(s)");
|
Debug.Log($"Renamed {renamedLanguages.Count} language(s) in {tablesUpdated} table(s)");
|
||||||
|
}
|
||||||
|
|
||||||
EditorUtility.DisplayDialog("Success", $"Language changes applied to {tablesUpdated} GameLocalizationTable(s).", "OK");
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,11 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 5647a4aaf19f42bf852a701955e888f5
|
guid: 5647a4aaf19f42bf852a701955e888f5
|
||||||
timeCreated: 1758196661
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.IO;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -591,10 +592,28 @@ namespace AlicizaX.Localization.Editor
|
|||||||
public static void GenerateCode(GameLocaizationTable table)
|
public static void GenerateCode(GameLocaizationTable table)
|
||||||
{
|
{
|
||||||
string filePath = table.GenerateScriptCodePath;
|
string filePath = table.GenerateScriptCodePath;
|
||||||
List<LocalizationLanguage.LocalizationString> strings = new List<LocalizationLanguage.LocalizationString>();
|
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);
|
var localizationLanguage = table.Languages.Find(t => t.LanguageName == LocalizationConfiguration.Instance.GenerateScriptCodeFirstConfig);
|
||||||
|
string namespaceName = table.GenerateScriptCodeNamespace;
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (!string.IsNullOrWhiteSpace(namespaceName))
|
||||||
|
{
|
||||||
|
sb.AppendLine($"namespace {namespaceName}");
|
||||||
|
sb.AppendLine("{");
|
||||||
|
}
|
||||||
|
|
||||||
sb.AppendLine("/// <summary>");
|
sb.AppendLine("/// <summary>");
|
||||||
sb.AppendLine("/// AutoGenerate");
|
sb.AppendLine("/// AutoGenerate");
|
||||||
sb.AppendLine("/// </summary>");
|
sb.AppendLine("/// </summary>");
|
||||||
@ -634,7 +653,14 @@ namespace AlicizaX.Localization.Editor
|
|||||||
|
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
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();
|
AssetDatabase.Refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,6 +43,7 @@ namespace AlicizaX.Localization.Editor
|
|||||||
using (new EditorDrawing.BorderBoxScope(new GUIContent("GenCode"), roundedBox: false))
|
using (new EditorDrawing.BorderBoxScope(new GUIContent("GenCode"), roundedBox: false))
|
||||||
{
|
{
|
||||||
Properties.Draw("GenerateScriptCodePath", new GUIContent("File Path"));
|
Properties.Draw("GenerateScriptCodePath", new GUIContent("File Path"));
|
||||||
|
Properties.Draw("GenerateScriptCodeNamespace", new GUIContent("Namespace"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
@ -96,10 +97,9 @@ namespace AlicizaX.Localization.Editor
|
|||||||
window.Show();
|
window.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
[MenuItem("Tools/AlicizaX/Localization/Open Localization ProjectSetting")]
|
|
||||||
public static void OpenSettings()
|
public static void OpenSettings()
|
||||||
{
|
{
|
||||||
SettingsService.OpenProjectSettings("Project/Localization Settings");
|
EditorApplication.ExecuteMenuItem("Tools/AlicizaX/Localization/Open Localization Settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ namespace AlicizaX.Localization
|
|||||||
{
|
{
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[SerializeField] internal string GenerateScriptCodePath = string.Empty;
|
[SerializeField] internal string GenerateScriptCodePath = string.Empty;
|
||||||
|
[SerializeField] internal string GenerateScriptCodeNamespace = string.Empty;
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public struct SheetItem
|
public struct SheetItem
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user