Files
zeling_v2/Assets/_Game/Scripts/Editor/Localization/LocalizationCsvTool.cs
2026-06-06 09:00:11 +08:00

218 lines
8.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using BaseGames.Localization;
namespace BaseGames.Editor.Localization
{
/// <summary>
/// 本地化 CSV 导入/导出工具。
///
/// 每个表导出为独立 CSV含 UTF-8 BOMExcel 中文不乱码列顺序key, ChineseSimplified, English, Japanese, Korean。
/// 文件存放路径Assets/_Game/Localization/Export/{TableName}.csv
///
/// 导入:读取 CSV → 合并回写 Assets/_Game/Data/Localization/{Language}/{TableName}.json经 LocalizationFileIO
///
/// 注日常单表编辑请用「BaseGames / Localization / 表格编辑器」,此窗口用于批量多表导入导出。
/// 菜单BaseGames / Localization / CSV 导入导出工具
/// </summary>
public class LocalizationCsvTool : EditorWindow
{
[MenuItem("BaseGames/Localization/CSV 导入导出工具")]
private static void Open()
{
var win = GetWindow<LocalizationCsvTool>("本地化 CSV 工具");
win.minSize = new Vector2(480, 360);
}
// ── 状态 ─────────────────────────────────────────────────────────────
private static readonly string[] s_allTables =
{
LocalizationTable.UI,
LocalizationTable.Dialogue,
LocalizationTable.Quest,
LocalizationTable.Spells,
LocalizationTable.Skills,
LocalizationTable.Items,
LocalizationTable.Character,
LocalizationTable.Tutorial,
};
private const string ExportDir = "Assets/_Game/Localization/Export";
private const string DataDir = LocalizationPaths.DataRoot;
private readonly bool[] _exportSelected = new bool[s_allTables.Length];
private readonly bool[] _importSelected = new bool[s_allTables.Length];
private string _statusMessage = "";
private MessageType _statusType = MessageType.None;
private Vector2 _scroll;
// ── GUI ───────────────────────────────────────────────────────────────
private void OnGUI()
{
_scroll = EditorGUILayout.BeginScrollView(_scroll);
EditorGUILayout.Space(6);
GUILayout.Label("📤 导出 → CSV", EditorStyles.boldLabel);
EditorGUILayout.HelpBox(
$"将 {DataDir}/ 中的 JSON 表导出为 CSV 文件UTF-8 BOMExcel 可直接打开)。\n" +
$"目标目录:{ExportDir}/",
MessageType.Info);
EditorGUI.indentLevel++;
for (int i = 0; i < s_allTables.Length; i++)
_exportSelected[i] = EditorGUILayout.Toggle(s_allTables[i], _exportSelected[i]);
EditorGUI.indentLevel--;
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("全选")) SetAll(_exportSelected, true);
if (GUILayout.Button("全不选")) SetAll(_exportSelected, false);
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(4);
if (GUILayout.Button("▶ 导出选中表", GUILayout.Height(30)))
RunExport();
EditorGUILayout.Space(16);
EditorGUILayout.LabelField("", GUI.skin.horizontalSlider);
GUILayout.Label("📥 导入 ← CSV", EditorStyles.boldLabel);
EditorGUILayout.HelpBox(
$"读取 {ExportDir}/ 中的 CSV合并回写至 {DataDir}/ JSON 文件。\n" +
"已有 Key 覆盖,新增 Key 追加,不删除多余 Key。",
MessageType.Info);
EditorGUI.indentLevel++;
for (int i = 0; i < s_allTables.Length; i++)
_importSelected[i] = EditorGUILayout.Toggle(s_allTables[i], _importSelected[i]);
EditorGUI.indentLevel--;
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("全选")) SetAll(_importSelected, true);
if (GUILayout.Button("全不选")) SetAll(_importSelected, false);
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space(4);
if (GUILayout.Button("▶ 导入选中表", GUILayout.Height(30)))
RunImport();
EditorGUILayout.Space(8);
if (!string.IsNullOrEmpty(_statusMessage))
EditorGUILayout.HelpBox(_statusMessage, _statusType);
EditorGUILayout.Space(6);
EditorGUILayout.EndScrollView();
}
// ── 导出 ─────────────────────────────────────────────────────────────
private void RunExport()
{
LocalizationManager.ClearEditorPreviewCache();
int exported = 0;
try
{
for (int ti = 0; ti < s_allTables.Length; ti++)
{
if (!_exportSelected[ti]) continue;
string tableName = s_allTables[ti];
EditorUtility.DisplayProgressBar("导出 CSV", $"导出 {tableName}…", (float)ti / s_allTables.Length);
// 经统一门面读取各语言字典(正确路径),交给 LocalizationCsv 写出(含 BOM
var langDicts = new Dictionary<Language, Dictionary<string, string>>();
bool any = false;
foreach (var lang in LocalizationFileIO.AllLanguages)
{
var dict = LocalizationFileIO.Read(lang, tableName);
langDicts[lang] = dict;
if (dict.Count > 0) any = true;
}
if (!any)
{
Debug.LogWarning($"[CsvTool] 表「{tableName}」无数据,跳过导出。");
continue;
}
LocalizationCsv.ExportToFile(tableName, langDicts);
exported++;
}
}
finally
{
EditorUtility.ClearProgressBar();
}
AssetDatabase.Refresh();
SetStatus($"✅ 成功导出 {exported} 个表到 {ExportDir}/", MessageType.Info);
}
// ── 导入 ─────────────────────────────────────────────────────────────
private void RunImport()
{
int imported = 0;
int errors = 0;
try
{
for (int ti = 0; ti < s_allTables.Length; ti++)
{
if (!_importSelected[ti]) continue;
string tableName = s_allTables[ti];
EditorUtility.DisplayProgressBar("导入 CSV", $"导入 {tableName}…", (float)ti / s_allTables.Length);
try
{
// 合并语义 + 正确格式/目录/Addressable 注册,全部由统一门面处理
int affected = LocalizationCsv.ImportFileToJson(tableName);
if (affected == 0)
{
Debug.LogWarning($"[CsvTool] CSV 文件不存在或为空,跳过:{ExportDir}/{tableName}.csv");
continue;
}
imported++;
}
catch (Exception ex)
{
Debug.LogError($"[CsvTool] 导入「{tableName}」失败:{ex.Message}");
errors++;
}
}
}
finally
{
EditorUtility.ClearProgressBar();
}
AssetDatabase.Refresh();
LocalizationManager.ClearEditorPreviewCache();
string msg = errors == 0
? $"✅ 成功导入 {imported} 个表。"
: $"⚠ 导入 {imported} 个表,{errors} 个失败(见控制台)。";
SetStatus(msg, errors == 0 ? MessageType.Info : MessageType.Warning);
}
// ── 工具函数 ─────────────────────────────────────────────────────────
private static void SetAll(bool[] arr, bool v)
{
for (int i = 0; i < arr.Length; i++) arr[i] = v;
}
private void SetStatus(string msg, MessageType type)
{
_statusMessage = msg;
_statusType = type;
Repaint();
}
}
}