167 lines
5.0 KiB
C#
167 lines
5.0 KiB
C#
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using AlicizaX;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
public static class LocalizationCSVUtility
|
|
{
|
|
const string MainPath = "Assets/Scripts/Editor/Localization/Localization.csv";
|
|
const string HotfixPath = "Assets/Scripts/Editor/Localization/HotFixLocalization.csv";
|
|
const string MainOut = "Assets/Resources/Localization/";
|
|
const string HotfixOut = "Assets/Bundles/Configs/Localization/";
|
|
|
|
[MenuItem("Tools/Localization/Create CSV Template")]
|
|
private static void CreateCSVTemplateMenu()
|
|
{
|
|
CreateLocalizationTemplate(MainPath);
|
|
CreateLocalizationTemplate(HotfixPath);
|
|
}
|
|
|
|
public static void CreateLocalizationTemplate(string path)
|
|
{
|
|
if (string.IsNullOrEmpty(path)) return;
|
|
|
|
using (StreamWriter sw = new StreamWriter(path, false, Encoding.UTF8))
|
|
{
|
|
// 写入标题行
|
|
var sb = new StringBuilder("Key");
|
|
foreach (Language lang in System.Enum.GetValues(typeof(Language)))
|
|
{
|
|
if (lang == Language.Unspecified) continue;
|
|
sb.Append($",{lang}");
|
|
}
|
|
|
|
sw.WriteLine(sb.ToString());
|
|
}
|
|
|
|
AssetDatabase.Refresh(); // 刷新Unity资源目录[3](@ref)
|
|
}
|
|
|
|
|
|
[MenuItem("Tools/Localization/Export Localization Files")]
|
|
private static void ExportLocalizationMenu()
|
|
{
|
|
ExportLocalizationFiles(MainPath, MainOut);
|
|
ExportLocalizationFiles(HotfixPath, HotfixOut);
|
|
AssetDatabase.Refresh();
|
|
}
|
|
|
|
private const int KEY_COLUMN = 0;
|
|
private const int FIRST_LANG_COLUMN = 1;
|
|
|
|
public static void ExportLocalizationFiles(string csvPath, string outputDir)
|
|
{
|
|
var rawData = ParseCSV(csvPath);
|
|
if (rawData.Count == 0)
|
|
{
|
|
Debug.LogError("CSV文件内容为空");
|
|
return;
|
|
}
|
|
|
|
var missingValues = new List<string>();
|
|
|
|
// 解析首行获取语言列表
|
|
string[] header = rawData[0];
|
|
List<string> langs = new List<string>();
|
|
for (int i = FIRST_LANG_COLUMN; i < header.Length; i++)
|
|
{
|
|
langs.Add(header[i]);
|
|
}
|
|
|
|
// 初始化语言字典
|
|
Dictionary<string, Dictionary<string, string>> langDict = new Dictionary<string, Dictionary<string, string>>();
|
|
foreach (string lang in langs)
|
|
{
|
|
langDict[lang] = new Dictionary<string, string>();
|
|
}
|
|
|
|
// 处理数据行(从第二行开始)
|
|
for (int rowIndex = 1; rowIndex < rawData.Count; rowIndex++)
|
|
{
|
|
string[] row = rawData[rowIndex];
|
|
if (row.Length == 0) continue;
|
|
|
|
string key = row[KEY_COLUMN];
|
|
if (string.IsNullOrEmpty(key)) continue;
|
|
|
|
for (int col = FIRST_LANG_COLUMN; col < row.Length; col++)
|
|
{
|
|
int langIndex = col - FIRST_LANG_COLUMN;
|
|
if (langIndex >= langs.Count) break;
|
|
|
|
string lang = langs[langIndex];
|
|
string value = row[col];
|
|
|
|
if (string.IsNullOrEmpty(value))
|
|
{
|
|
missingValues.Add($"[Missing] Key:{key} Lang:{lang}");
|
|
continue;
|
|
}
|
|
|
|
// 覆盖重复key的警告
|
|
if (langDict[lang].ContainsKey(key))
|
|
{
|
|
Debug.LogWarning($"Key '{key}' already exists in {lang}, will be overwritten");
|
|
}
|
|
|
|
langDict[lang][key] = value;
|
|
}
|
|
}
|
|
|
|
|
|
if (!Directory.Exists(outputDir))
|
|
{
|
|
Directory.CreateDirectory(outputDir);
|
|
}
|
|
|
|
// 导出JSON文件
|
|
foreach (var lang in langDict)
|
|
{
|
|
if (lang.Value.Count == 0) continue;
|
|
|
|
// 手动构建JSON格式确保兼容性
|
|
var entries = lang.Value.Select(kvp =>
|
|
$" \"{EscapeJson(kvp.Key)}\": \"{EscapeJson(kvp.Value)}\"");
|
|
string json = "{\n" + string.Join(",\n", entries) + "\n}";
|
|
|
|
string outputPath = Path.Combine(outputDir, $"{lang.Key}.json");
|
|
File.WriteAllText(outputPath, json, Encoding.UTF8);
|
|
}
|
|
|
|
// 显示缺失值警告
|
|
if (missingValues.Count > 0)
|
|
{
|
|
Debug.LogWarning($"Missing {missingValues.Count} translations:\n" +
|
|
string.Join("\n", missingValues));
|
|
}
|
|
}
|
|
|
|
private static List<string[]> ParseCSV(string path)
|
|
{
|
|
List<string[]> data = new List<string[]>();
|
|
|
|
using (StreamReader sr = new StreamReader(path, Encoding.UTF8))
|
|
{
|
|
while (!sr.EndOfStream)
|
|
{
|
|
string line = sr.ReadLine();
|
|
if (string.IsNullOrEmpty(line)) continue;
|
|
data.Add(line.Split(','));
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
private static string EscapeJson(string input)
|
|
{
|
|
return input.Replace("\\", "\\\\")
|
|
.Replace("\"", "\\\"")
|
|
.Replace("\n", "\\n")
|
|
.Replace("\r", "\\r");
|
|
}
|
|
}
|