using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; using UnityEngine.UI; using System.Text.RegularExpressions; using System.IO; using System.Threading; namespace Assets.Scripts.Editor.LanguageTool { public static class LanguageTool { // key = ‘文字’ value = ‘ID' 导出数据时使用 private static Dictionary L2ID = new Dictionary(); // key = ‘ID’ value = ‘文字’ 导入数据时使用 private static Dictionary ID2L = new Dictionary(); // id自增的标志 private static int IDFlag = 10000; // excel 路径 private static string PrefrabCSVPath = Environment.CurrentDirectory + "/data_execl/Language_data/LanguageText.csv"; private static string LuaCSVPath = Environment.CurrentDirectory + "/data_execl/Language_data/LanguageLua.csv"; // prefrab 路径 private static string[] PrefrabPath = new string[] { "Assets/ManagedResources/Prefabs/UI", "Assets/ManagedResources/UpdatePanel" }; //private static string[] PrefrabPath = new string[] { "Assets/ManagedResources/UpdatePanel" }; // lua 路径 private static string[] LuaPath = new string[] { "Assets/ManagedResources/~Lua/Modules", "Assets/ManagedResources/~Lua/View" }; private static string[] SpecialLuaPath = new string[] { "Assets/ManagedResources/~Lua/Common/functions.lua", "Assets/ManagedResources/~Lua/Common/GlobalDefine.lua", }; // lua数据文件路径 private static string LuaDataPath = "Assets/ManagedResources/~Lua/Common/Language.lua"; // private static System.Diagnostics.Stopwatch time = new System.Diagnostics.Stopwatch(); // 从本地加载文字数据 private static void LoadLDataFromCSV(string CSVPath) { ClearLData(); if (!File.Exists(CSVPath)) { File.Create(CSVPath).Dispose(); } // time.Start(); string[] filestr = File.ReadAllLines(CSVPath, System.Text.Encoding.Default); for (int i = 0; i < filestr.Length; i++) { EditorUtility.DisplayProgressBar(string.Format("({0}/{1})", i, filestr.Length), "正在导入表数据:", (float)i / filestr.Length); string[] strList = filestr[i].Split(','); int id = Convert.ToInt32(strList[0]); string L = DecodeStr(strList[1]); if (!L2ID.ContainsKey(L)) { L2ID.Add(L, id); } ID2L.Add(id, L); if (i + 1 == filestr.Length) { IDFlag = id; } } time.Stop(); EditorUtility.ClearProgressBar(); } // 保存文字数据到本地 private static void SaveLDataToCSV(string CSVPath) { if (!File.Exists(CSVPath)) { File.Create(CSVPath).Dispose(); } time.Start(); string[] strList = new string[ID2L.Keys.Count]; int i = 0; foreach (int id in ID2L.Keys) { EditorUtility.DisplayProgressBar(string.Format("({0}/{1})", i, ID2L.Keys.Count), "正在保存数据到本地:", (float)i / ID2L.Keys.Count); string value = ""; ID2L.TryGetValue(id, out value); value = EncodeStr(value); strList[i] = id + "," + value; i++; } File.WriteAllLines(CSVPath, strList, System.Text.Encoding.Default); time.Stop(); EditorUtility.ClearProgressBar(); } // 将数据写入lua文件 private static void WriteToLuaData() { if (!File.Exists(LuaDataPath)) { File.Create(LuaDataPath).Dispose(); } time.Start(); // 构建数据 int keyCount = ID2L.Keys.Count; string[] strList = new string[keyCount + 2]; strList[0] = "Language = {"; int i = 1; foreach (int id in ID2L.Keys) { EditorUtility.DisplayProgressBar(string.Format("({0}/{1})", i, keyCount), "正在生成数据:", (float)i / keyCount); string value = ""; ID2L.TryGetValue(id, out value); // 一些转义字符要处理 value = value.Replace("\n", "\\n"); strList[i] = "\t[" + id + "] = \"" + value + "\","; i++; } strList[i] = "}"; // 写入lua文件 EditorUtility.DisplayProgressBar(string.Format("({0}/{1})", keyCount, keyCount), "正在写入Language.lua:", 0); File.WriteAllLines(LuaDataPath, strList, System.Text.Encoding.UTF8); // 停止 time.Stop(); EditorUtility.ClearProgressBar(); } // 清空本地数据 private static void ClearLData() { L2ID.Clear(); ID2L.Clear(); IDFlag = 10000; } //添加数据 返回数据的ID private static int AddLData(string L) { int id = 0; if (L2ID.TryGetValue(L, out id)) { return id; } else { id = ++IDFlag; L2ID.Add(L, id); ID2L.Add(id, L); return id; } } private static string EncodeStr(string txt) { txt = txt.Replace("\n", "\\n"); txt = txt.Replace("\r", "\\r"); txt = txt.Replace(",", "\\,"); txt = txt.Replace("\"", "\\\""); return txt; } private static string DecodeStr(string txt) { txt = txt.Replace("\\n", "\n"); txt = txt.Replace("\\r", "\r"); txt = txt.Replace("\\,", ","); txt = txt.Replace("\\\"", "\""); return txt; } // 将Text替换为LanguageText,并拷贝属性 private static void changeTextToLanguageText(Transform tr) { Text t = tr.GetComponent(); Color color = t.color; Font font = t.font; FontStyle fontStyle = t.fontStyle; int fontSize = t.fontSize; bool supportRichText = t.supportRichText; string text = t.text; float lineSpacing = t.lineSpacing; TextAnchor alignment = t.alignment; HorizontalWrapMode horizontalOverflow = t.horizontalOverflow; VerticalWrapMode verticalOverflow = t.verticalOverflow; bool resizeTextForBestFit = t.resizeTextForBestFit; int resizeTextMinSize = t.resizeTextMinSize; int resizeTextMaxSize = t.resizeTextMaxSize; bool raycastTarget = t.raycastTarget; UnityEngine.Object.DestroyImmediate(t, true); LanguageText lt = tr.gameObject.AddComponent(); lt.LanguageIndex = 0; lt.color = color; lt.font = font; lt.fontStyle = fontStyle; lt.fontSize = fontSize; lt.supportRichText = supportRichText; lt.text = text; lt.lineSpacing = lineSpacing; lt.alignment = alignment; lt.horizontalOverflow = horizontalOverflow; lt.verticalOverflow = verticalOverflow; lt.resizeTextForBestFit = resizeTextForBestFit; lt.resizeTextMinSize = resizeTextMinSize; lt.resizeTextMaxSize = resizeTextMaxSize; lt.raycastTarget = raycastTarget; } // 将LanguageText替换为Text,并拷贝属性 private static void changeLanguageTextToText(Transform tr) { LanguageText t = tr.GetComponent(); Color color = t.color; Font font = t.font; FontStyle fontStyle = t.fontStyle; int fontSize = t.fontSize; bool supportRichText = t.supportRichText; string text = t.text; float lineSpacing = t.lineSpacing; TextAnchor alignment = t.alignment; HorizontalWrapMode horizontalOverflow = t.horizontalOverflow; VerticalWrapMode verticalOverflow = t.verticalOverflow; bool resizeTextForBestFit = t.resizeTextForBestFit; int resizeTextMinSize = t.resizeTextMinSize; int resizeTextMaxSize = t.resizeTextMaxSize; bool raycastTarget = t.raycastTarget; UnityEngine.Object.DestroyImmediate(t, true); try { Text lt = tr.gameObject.AddComponent(); lt.color = color; lt.font = font; lt.fontStyle = fontStyle; lt.fontSize = fontSize; lt.supportRichText = supportRichText; lt.text = text; lt.lineSpacing = lineSpacing; lt.alignment = alignment; lt.horizontalOverflow = horizontalOverflow; lt.verticalOverflow = verticalOverflow; lt.resizeTextForBestFit = resizeTextForBestFit; lt.resizeTextMinSize = resizeTextMinSize; lt.resizeTextMaxSize = resizeTextMaxSize; lt.raycastTarget = raycastTarget; } catch (Exception e) { Debug.LogWarning(e.Message); } } // 将所有包含中文的Text转为LanguageText [MenuItem("LanguageTool/prefrab/Text转LanguageText")] public static void UITextToLanguageText() { if (EditorUtility.DisplayDialog("转换提示", "此操作会将所有Prefrab中的包含中文字符的Text组件转换为LanguageText组件,是否继续?", "是", "否")) //显示对话框 { string[] allPath = AssetDatabase.FindAssets("t:Prefab", PrefrabPath); time.Start(); for (int i = 0; i < allPath.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(allPath[i]); EditorUtility.DisplayProgressBar(string.Format("({0}/{1})", i, allPath.Length), "正在转换:" + path, (float)i / allPath.Length); var obj = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject; if (obj != null) { var newPrefab = PrefabUtility.InstantiatePrefab(obj) as GameObject; var texts = newPrefab.GetComponentsInChildren(true); foreach (var text in texts) { Regex reg = new Regex(@"[\u4e00-\u9fa5]");//正则表达式,判断是否包含中文字符 if (reg.IsMatch(text.text)) { changeTextToLanguageText(text.transform); } } PrefabUtility.SaveAsPrefabAsset(newPrefab, path); UnityEngine.Object.DestroyImmediate(newPrefab); } } time.Stop(); EditorUtility.ClearProgressBar(); Debug.Log("转换完成"); } } // 将所有LanguageText导出为数据表 [MenuItem("LanguageTool/prefrab/导出数据表")] public static void LanguageTextToExcel() { // 加载本地数据 LoadLDataFromCSV(PrefrabCSVPath); // 遍历所有的LanguageText time.Start(); string[] allPath = AssetDatabase.FindAssets("t:Prefab", PrefrabPath); for (int i = 0; i < allPath.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(allPath[i]); EditorUtility.DisplayProgressBar(string.Format("({0}/{1})", i, allPath.Length), "正在检索:" + path, (float)i / allPath.Length); var obj = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject; if (obj != null) { var newPrefab = PrefabUtility.InstantiatePrefab(obj) as GameObject; var texts = newPrefab.GetComponentsInChildren(true); foreach (var text in texts) { int lid = AddLData(text.text); text.LanguageIndex = lid; } PrefabUtility.SaveAsPrefabAsset(newPrefab, path); UnityEngine.Object.DestroyImmediate(newPrefab); } } time.Stop(); EditorUtility.ClearProgressBar(); // 数据保存到本地 SaveLDataToCSV(PrefrabCSVPath); // 清理本地数据 ClearLData(); Debug.Log("导出数据完成"); } // 从数据表导入文本 [MenuItem("LanguageTool/prefrab/导入数据表")] public static void LoadExcelToLanguageText() { // 加载本地数据 LoadLDataFromCSV(PrefrabCSVPath); // time.Start(); // 遍历所有的LanguageText string[] allPath = AssetDatabase.FindAssets("t:Prefab", PrefrabPath); for (int i = 0; i < allPath.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(allPath[i]); EditorUtility.DisplayProgressBar(string.Format("({0}/{1})", i, allPath.Length), "正在导入:" + path, (float)i / allPath.Length); var obj = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject; if (obj != null) { var newPrefab = PrefabUtility.InstantiatePrefab(obj) as GameObject; var texts = newPrefab.GetComponentsInChildren(true); foreach (var text in texts) { int lid = text.LanguageIndex; if (lid != 0) { string lan = ""; ID2L.TryGetValue(lid, out lan); text.text = lan; } } PrefabUtility.SaveAsPrefabAsset(newPrefab, path); UnityEngine.Object.DestroyImmediate(newPrefab); } } time.Stop(); EditorUtility.ClearProgressBar(); // 清理本地数据 ClearLData(); Debug.Log("导入数据完成"); } // 将所有包含中文的LanguageText转为Text /// /// TODO: /// [MenuItem("LanguageTool/prefrab/LanguageText转Text")] public static void UILanguageTextToText() { if (EditorUtility.DisplayDialog("转换提示", "此操作会将所有Prefrab中的LanguageText组件转换为Text组件,是否继续?", "是", "否")) //显示对话框 { string[] allPath = AssetDatabase.FindAssets("t:Prefab", PrefrabPath); time.Start(); for (int i = 0; i < allPath.Length; i++) { string path = AssetDatabase.GUIDToAssetPath(allPath[i]); EditorUtility.DisplayProgressBar(string.Format("({0}/{1})", i, allPath.Length), "正在转换:" + path, (float)i / allPath.Length); var obj = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject; if (obj != null) { var newPrefab = PrefabUtility.InstantiatePrefab(obj) as GameObject; var texts = newPrefab.GetComponentsInChildren(true); foreach (var text in texts) { changeLanguageTextToText(text.transform); } PrefabUtility.SaveAsPrefabAsset(newPrefab, path); UnityEngine.Object.DestroyImmediate(newPrefab); } } time.Stop(); EditorUtility.ClearProgressBar(); Debug.Log("转换完成"); } } /// /// -------------------------------------------------lua /// /// // 遍历lua文件的每一行找到 中文数据并替换 private static void CheckLuaPath(string path) { string[] lines = File.ReadAllLines(path, System.Text.Encoding.UTF8); if (lines.Length <= 0) { return; } string[] wlines = new string[lines.Length - 1]; string lastLine = ""; for (int lIndex = 0; lIndex < lines.Length; lIndex++) { string line = lines[lIndex].Trim(); if (!line.StartsWith("--") && !line.StartsWith("Log")) { Regex reg = new Regex("\"[^\"]*?[\u4e00-\u9fa5][^\"]*?\"");//正则表达式,判断是否包含中文字符 if (reg.IsMatch(line)) { MatchCollection mc = reg.Matches(line); for (int mi = 0; mi < mc.Count; mi++) { int id = AddLData(mc[mi].Value.Trim('"')); lines[lIndex] = lines[lIndex].Replace(mc[mi].Value, "Language[" + id + "]"); } } } if (lIndex == lines.Length - 1) { lastLine = lines[lIndex]; } else { wlines[lIndex] = lines[lIndex]; } } File.WriteAllLines(path, wlines, System.Text.Encoding.UTF8); File.AppendAllText(path, lastLine, System.Text.Encoding.UTF8); } // 遍历lua文件的每一行找到 中文数据并替换 private static void RevertLuaPath(string path, Dictionary o) { string[] lines = File.ReadAllLines(path, System.Text.Encoding.UTF8); if (lines.Length <= 0) { return; } string[] wlines = new string[lines.Length - 1]; string lastLine = ""; for (int lIndex = 0; lIndex < lines.Length; lIndex++) { string line = lines[lIndex].Trim(); Regex reg = new Regex("Language\\[[^Language\\[]*?[0-9][^\\]]*?\\]");//正则表达式,判断是否包含中文字符 if (reg.IsMatch(line)) { MatchCollection mc = reg.Matches(line); for (int mi = 0; mi < mc.Count; mi++) { string r = mc[mi].Value.Trim(); int id = Convert.ToInt32(r.Substring(9, 5)); Debug.Log(id); string t = o[id]; lines[lIndex] = lines[lIndex].Replace(r, t); } } if (lIndex == lines.Length - 1) { lastLine = lines[lIndex]; } else { wlines[lIndex] = lines[lIndex]; } } File.WriteAllLines(path, wlines, System.Text.Encoding.UTF8); File.AppendAllText(path, lastLine, System.Text.Encoding.UTF8); } // 遍历所有的可能包含中文文本的lua文件 [MenuItem("LanguageTool/lua/导出lua文本")] public static void ExportLanguageFromLua() { // 加载本地数据 LoadLDataFromCSV(LuaCSVPath); time.Start(); // 检索 for (int i = 0; i < LuaPath.Length; i++) { string folderPath = LuaPath[i]; string[] pathList = Directory.GetFiles(folderPath, "*.lua", SearchOption.AllDirectories); for (int pIndex = 0; pIndex < pathList.Length; pIndex++) { EditorUtility.DisplayProgressBar(string.Format(folderPath + "({0}/{1})", pIndex, pathList.Length), "正在检索数据:", (float)pIndex / pathList.Length); CheckLuaPath(pathList[pIndex]); } } // 特殊lua文件 for (int pIndex = 0; pIndex < SpecialLuaPath.Length; pIndex++) { EditorUtility.DisplayProgressBar(SpecialLuaPath[pIndex], "正在检索数据:", (float)pIndex / SpecialLuaPath.Length); CheckLuaPath(SpecialLuaPath[pIndex]); } // 停止 time.Stop(); EditorUtility.ClearProgressBar(); // 保存数据到本地 SaveLDataToCSV(LuaCSVPath); // 将数据写入lua WriteToLuaData(); // 清理本地数据 ClearLData(); // Debug.Log("导出完成"); } // LanguageLua.csv转换为Language.lua [MenuItem("LanguageTool/lua/生成Language.lua")] public static void LoadLuaCSVToLuaData() { // 加载本地数据 LoadLDataFromCSV(LuaCSVPath); // 将数据写入lua WriteToLuaData(); // 清理本地数据 ClearLData(); // Debug.Log("数据已生成"); } // 将language.lua中的中文还原到代码中 [MenuItem("LanguageTool/lua/Revert Language To Code")] private static void RevertLanguage() { Dictionary o = ReadFromLanguage(); // 检索 for (int i = 0; i < LuaPath.Length; i++) { string folderPath = LuaPath[i]; string[] pathList = Directory.GetFiles(folderPath, "*.lua", SearchOption.AllDirectories); for (int pIndex = 0; pIndex < pathList.Length; pIndex++) { EditorUtility.DisplayProgressBar(string.Format(folderPath + "({0}/{1})", pIndex, pathList.Length), "正在还原数据:", (float)pIndex / pathList.Length); RevertLuaPath(pathList[pIndex], o); } } // 特殊lua文件 for (int pIndex = 0; pIndex < SpecialLuaPath.Length; pIndex++) { EditorUtility.DisplayProgressBar(SpecialLuaPath[pIndex], "正在还原数据:", (float)pIndex / SpecialLuaPath.Length); RevertLuaPath(SpecialLuaPath[pIndex], o); } EditorUtility.ClearProgressBar(); } // 从language.lua中读取数据 [MenuItem("LanguageTool/lua/读取language.lua")] private static Dictionary ReadFromLanguage() { Dictionary o = new Dictionary(); // if (!File.Exists(LuaDataPath)) { Debug.LogError("未找到language.lua"); return o; } // string[] lines = File.ReadAllLines(LuaDataPath, System.Text.Encoding.UTF8); if (lines.Length <= 0) { return o; } // for (int i = 0; i < lines.Length; i++) { string str = lines[i].Trim(); if (str.StartsWith("[")) { int num = Convert.ToInt32(str.Substring(1, 5)); string content = str.Substring(10, str.Length - 11); o.Add(num, content); } } return o; } // 遍历lua文件的每一行找到 log打印并删除 [MenuItem("LanguageTool/lua/删除Log打印")] private static void DeleteLog() { time.Start(); // 检索 for (int i = 0; i < LuaPath.Length; i++) { string folderPath = LuaPath[i]; string[] pathList = Directory.GetFiles(folderPath, "*.lua", SearchOption.AllDirectories); for (int pIndex = 0; pIndex < pathList.Length; pIndex++) { EditorUtility.DisplayProgressBar(string.Format(folderPath + "({0}/{1})", pIndex, pathList.Length), "正在检索数据:", (float)pIndex / pathList.Length); string[] lines = File.ReadAllLines(pathList[pIndex], System.Text.Encoding.UTF8); for (int lIndex = 0; lIndex < lines.Length; lIndex++) { string line = lines[lIndex].Trim(); if (line.StartsWith("log(") || line.StartsWith("--log(")) { lines[lIndex] = ""; } else if (line.StartsWith("logErrorTrace(")) { lines[lIndex] = lines[lIndex].Replace("logErrorTrace(", "Log("); } else if (line.StartsWith("--logErrorTrace(")) { lines[lIndex] = lines[lIndex].Replace("--logErrorTrace(", "--Log("); } else if (line.StartsWith("-- logErrorTrace(")) { lines[lIndex] = lines[lIndex].Replace("-- logErrorTrace(", "-- Log("); } } File.WriteAllLines(pathList[pIndex], lines, System.Text.Encoding.UTF8); } } // 停止 time.Stop(); EditorUtility.ClearProgressBar(); Debug.Log("删除完成"); } //[MenuItem("所有Prefab添加PrefabInfoHerlper组件")] //static void AddPrefabInfoHelper() { // UnityEngine.Object[] selObjs = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets); // for (int i = 0; i < selObjs.Length; i++) // { // Object selObj = selObjs[i]; // string selfPath = AssetDatabase.GetAssetPath(selObj); // if (selfPath.EndsWith(".prefab")) // { // string[] dependPaths = AssetDatabase.GetDependencies(selfPath); // GameObject go = GameObject.Instantiate(selObj) as GameObject; // PrefabInfoHelper pih = go.GetComponent(); // if (pih == null) // { // pih = go.AddComponent(); // } // pih.isInstanced = false; // pih.selfPath = selfPath; // pih.dependPathList.Clear(); // pih.dependPathList.AddRange(dependPaths); // PrefabUtility.ReplacePrefab(go, selObj, ReplacePrefabOptions.ConnectToPrefab); // GameObject.DestroyImmediate(go); // } // } //} //---------------扩展UGUI右键Text/Image //[MenuItem("GameObject/UI/LanguageText")] //static void TextLabel() //{ // //-------创建TextLabel // GameObject go = new GameObject(); // go.name = "Text"; // LanguageText t = go.AddComponent(typeof(LanguageText)) as LanguageText; // t.text = "New TextLabel"; // t.GetComponent().localPosition = Vector3.zero; // t.transform.localScale = Vector3.one; // Selection.activeObject = go; //} } }