using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using LocalizationTool.Models;
namespace LocalizationTool.Services
{
///
/// CSV 导入导出(逗号分隔,Excel 可直接打开编辑)。
/// 列结构与主界面表格一致:第一列"中文原文",其后为各语言代码列(en-US、ja-JP…)。
/// 导出 UTF-8 带 BOM(Excel 中文不乱码);导入兼容 UTF-8 与 ANSI(GB18030)。
///
public static class CsvExchange
{
/// 导出表格行到 CSV 文件。langs 决定语言列(与表格当前勾选列一致)。
public static void Export(string path, IEnumerable rows, List langs)
{
var sb = new StringBuilder();
sb.AppendLine(JoinCsv(new[] { "中文原文" }.Concat(langs.Select(l => l.LanguageCode))));
foreach (var r in rows)
{
var fields = new List { r.Key };
foreach (var l in langs)
fields.Add(r.Cells.TryGetValue(l.LanguageCode, out var c) ? c.Value : "");
sb.AppendLine(JoinCsv(fields));
}
File.WriteAllText(path, sb.ToString(), new UTF8Encoding(true)); // BOM:Excel 识别 UTF-8
}
/// 解析 CSV 文件:返回 (表头, 数据行)。空行跳过;引号/逗号/换行转义按 RFC4180 处理。
public static Tuple, List> Parse(string path)
{
var bytes = File.ReadAllBytes(path);
if (bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
bytes = bytes.Skip(3).ToArray();
string text;
try { text = new UTF8Encoding(false, true).GetString(bytes); }
catch { text = Encoding.GetEncoding("gb18030").GetString(bytes); } // Excel 另存的 ANSI CSV
var header = new List();
var records = new List();
using (var reader = new StringReader(text))
using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(reader))
{
parser.TextFieldType = Microsoft.VisualBasic.FileIO.FieldType.Delimited;
parser.SetDelimiters(",");
parser.HasFieldsEnclosedInQuotes = true;
while (!parser.EndOfData)
{
string[] fields;
try { fields = parser.ReadFields(); }
catch (Microsoft.VisualBasic.FileIO.MalformedLineException)
{
throw new Exception($"第 {parser.ErrorLineNumber} 行格式错误(常见原因:引号未闭合)");
}
if (fields == null) continue;
if (fields.All(string.IsNullOrWhiteSpace)) continue;
if (header.Count == 0) { header.AddRange(fields); continue; }
records.Add(fields);
}
}
return Tuple.Create(header, records);
}
private static string JoinCsv(IEnumerable fields) =>
string.Join(",", fields.Select(Escape));
private static string Escape(string field)
{
field = field ?? "";
if (field.IndexOfAny(new[] { ',', '"', '\r', '\n' }) >= 0)
return "\"" + field.Replace("\"", "\"\"") + "\"";
return field;
}
}
}