Files
HauntedBloodlines/Assets/Editor/LocalizationMultiTableImporter.cs
2025-05-29 22:31:40 +03:00

196 lines
5.5 KiB
C#

using UnityEditor;
using UnityEngine;
using UnityEngine.Localization;
using UnityEngine.Localization.Tables;
using UnityEditor.Localization;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
public class LocalizationMultiTableImporter
{
[MenuItem("Localization/Import All Tables from CSV")]
public static void ImportAllLocalizationTables()
{
string path = EditorUtility.OpenFilePanel("Import Localization CSV", "", "csv");
if (string.IsNullOrEmpty(path)) return;
string rawCsv = File.ReadAllText(path, Encoding.UTF8);
var lines = SplitCSVRows(rawCsv);
if (lines.Count < 2)
{
Debug.LogError("CSV file is empty or missing header.");
return;
}
// Header: Table,Key,locale1,locale2,...
var header = SplitCSVLine(lines[0]);
if (header.Count < 3)
{
Debug.LogError("CSV header must contain at least 'Table,Key,<Locale>'");
return;
}
var localeCodes = header.Skip(2).ToList();
var locales = LocalizationEditorSettings.GetLocales();
var localeMap = locales.ToDictionary(l => l.Identifier.Code, l => l);
var collections = LocalizationEditorSettings.GetStringTableCollections();
for (int lineIndex = 1; lineIndex < lines.Count; lineIndex++)
{
var line = lines[lineIndex];
var cells = SplitCSVLine(line);
if (cells.Count < 2) continue;
string tableName = cells[0];
string key = cells[1];
var collection = collections.FirstOrDefault(c => c.TableCollectionName == tableName);
if (collection == null)
{
Debug.LogWarning($"Skipping unknown table: {tableName}");
continue;
}
for (int i = 0; i < localeCodes.Count; i++)
{
string localeCode = localeCodes[i];
if (!localeMap.TryGetValue(localeCode, out var locale)) continue;
var table = collection.GetTable(locale.Identifier) as StringTable;
if (table == null)
{
table = collection.AddNewTable(locale.Identifier) as StringTable;
}
var sharedData = collection.SharedData;
var sharedEntry = sharedData.GetEntry(key);
if (sharedEntry == null)
{
sharedEntry = sharedData.AddKey(key);
}
var entry = table.GetEntry(sharedEntry.Id);
if (entry == null)
{
entry = table.AddEntry(sharedEntry.Id, "");
}
if (i + 2 < cells.Count)
{
entry.Value = cells[i + 2];
}
EditorUtility.SetDirty(table);
}
}
AssetDatabase.SaveAssets();
Debug.Log(" Localization import complete!");
}
/// <summary>
/// Splits CSV into rows, handling multiline quoted entries.
/// </summary>
private static List<string> SplitCSVRows(string csvText)
{
var rows = new List<string>();
var sb = new StringBuilder();
bool inQuotes = false;
for (int i = 0; i < csvText.Length; i++)
{
char c = csvText[i];
sb.Append(c);
if (c == '"')
{
// Check for escaped quote
if (i + 1 < csvText.Length && csvText[i + 1] == '"')
{
sb.Append('"');
i++;
}
else
{
inQuotes = !inQuotes;
}
}
else if ((c == '\n' || c == '\r') && !inQuotes)
{
// Handle Windows \r\n
if (c == '\r' && i + 1 < csvText.Length && csvText[i + 1] == '\n')
{
sb.Append('\n');
i++;
}
rows.Add(sb.ToString().TrimEnd('\r', '\n'));
sb.Clear();
}
}
if (sb.Length > 0)
rows.Add(sb.ToString().TrimEnd('\r', '\n'));
return rows;
}
/// <summary>
/// Splits a CSV line into fields, handling commas and quotes correctly.
/// </summary>
private static List<string> SplitCSVLine(string line)
{
var result = new List<string>();
var sb = new StringBuilder();
bool inQuotes = false;
for (int i = 0; i < line.Length; i++)
{
char c = line[i];
if (inQuotes)
{
if (c == '"')
{
if (i + 1 < line.Length && line[i + 1] == '"')
{
sb.Append('"'); // escaped quote
i++;
}
else
{
inQuotes = false;
}
}
else
{
sb.Append(c);
}
}
else
{
if (c == '"')
{
inQuotes = true;
}
else if (c == ',')
{
result.Add(sb.ToString());
sb.Clear();
}
else
{
sb.Append(c);
}
}
}
result.Add(sb.ToString());
return result;
}
}