You've already forked TranslationApp
mirror of
https://github.com/lifebottle/TranslationApp.git
synced 2026-02-13 15:25:58 -08:00
373 lines
14 KiB
C#
373 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Xml.Linq;
|
|
|
|
namespace TranslationLib
|
|
{
|
|
public class XMLFile
|
|
{
|
|
public string Name { get; set; }
|
|
public string FriendlyName { get; set; }
|
|
public string FileType { get; set; }
|
|
public string FilePath { get; set; }
|
|
public List<XMLSection> Sections = new List<XMLSection>();
|
|
public List<XMLEntry> Speakers = null;
|
|
public XMLSection CurrentSection { get; set; }
|
|
public bool isLegacy { get; set; }
|
|
public bool needsSave { get; set; }
|
|
|
|
public XMLFile()
|
|
{
|
|
CurrentSection = new XMLSection("Default");
|
|
}
|
|
public void SetSection(string name)
|
|
{
|
|
CurrentSection = Sections.First(c => c.Name == name);
|
|
}
|
|
|
|
public void UpdateAllEntryText()
|
|
{
|
|
var keys = Speakers.Select(x => x.Id).ToList();
|
|
var values = Speakers.Select(x => !string.IsNullOrEmpty(x.EnglishText) ? x.EnglishText : x.JapaneseText).ToList();
|
|
var speakerDict = keys.Zip(values, (k, v) => new { k, v })
|
|
.ToDictionary(x => x.k, x => x.v);
|
|
|
|
foreach (var XMLSection in Sections.Where(x => x.Entries.Where(y => y.SpeakerId != null).Count() > 0))
|
|
{
|
|
foreach (var XMLEntry in XMLSection.Entries)
|
|
{
|
|
List<string> ls = new List<string>();
|
|
|
|
if (XMLEntry.SpeakerId != null)
|
|
{
|
|
foreach (var id in XMLEntry.SpeakerId)
|
|
{
|
|
ls.Add(speakerDict[id]);
|
|
}
|
|
|
|
XMLEntry.SpeakerName = string.Join(" / ", ls);
|
|
}
|
|
else
|
|
XMLEntry.SpeakerName = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public Dictionary<string, int> GetStatusData()
|
|
{
|
|
var dictionary = new Dictionary<string, int>()
|
|
{
|
|
{ "To Do", 0 },
|
|
{ "Edited", 0 },
|
|
{ "Proofread", 0 },
|
|
{ "Problematic", 0 },
|
|
{ "Done", 0 },
|
|
};
|
|
|
|
foreach (var section in Sections)
|
|
{
|
|
if (section.Name != "Other Strings" && section.Name != "All strings")
|
|
{
|
|
var sectionDictionary = section.GetStatusData();
|
|
foreach (var key in sectionDictionary.Keys)
|
|
{
|
|
dictionary[key] += sectionDictionary[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
return dictionary;
|
|
}
|
|
|
|
public Dictionary<string, int> SpeakersGetStatusData()
|
|
{
|
|
Func<List<XMLEntry>, string, int> CountEntryByStatus = (entryList, status) => entryList.Count(e => e.Status == status);
|
|
|
|
List<XMLEntry> t = Speakers ?? new List<XMLEntry>();
|
|
|
|
return new Dictionary<string, int>
|
|
{
|
|
{ "To Do", CountEntryByStatus(t,"To Do") },
|
|
{ "Edited", CountEntryByStatus(t,"Edited") },
|
|
{ "Proofread", CountEntryByStatus(t,"Proofread") },
|
|
{ "Problematic", CountEntryByStatus(t,"Problematic") },
|
|
{ "Done", CountEntryByStatus(t,"Done") },
|
|
};
|
|
}
|
|
|
|
public List<string> GetSectionNames()
|
|
{
|
|
List<string> l = Sections.Select(s => s.Name).Where(s => s != "All strings").ToList();
|
|
l.Insert(0, "All strings");
|
|
return l;
|
|
}
|
|
|
|
public void SaveToDisk()
|
|
{
|
|
|
|
var sectionsElements = Sections.Where(s => s.Name != "All strings").Select(GetXmlSectionElement);
|
|
List<XElement> allSections = new List<XElement>();
|
|
|
|
if (FriendlyName != null)
|
|
{
|
|
allSections.Add(new XElement("FriendlyName", FriendlyName));
|
|
}
|
|
|
|
if (Speakers != null)
|
|
{
|
|
var speakerElements = GetXmlSpeakerElement(Speakers);
|
|
allSections.Add(speakerElements);
|
|
}
|
|
|
|
allSections.AddRange(sectionsElements);
|
|
var document = new XDocument(
|
|
new XElement(FileType, allSections)
|
|
);
|
|
|
|
File.WriteAllText(FilePath, document.ToString().Replace(" />", "/>") + Environment.NewLine);
|
|
}
|
|
|
|
public void SaveAsCsv(string path)
|
|
{
|
|
bool hasSpeakers = Speakers != null;
|
|
using (StreamWriter writer = new StreamWriter(new FileStream(path, FileMode.Create, FileAccess.Write), new System.Text.UTF8Encoding(true)))
|
|
{
|
|
// header
|
|
writer.Write("File,");
|
|
writer.Write("Line Number,");
|
|
writer.Write("Section,");
|
|
writer.Write("Status,");
|
|
if (hasSpeakers) writer.Write("Speaker JP,");
|
|
writer.Write("Text JP,");
|
|
if (hasSpeakers) writer.Write("Speaker EN,");
|
|
writer.Write("Text EN,");
|
|
writer.Write("Comment");
|
|
writer.WriteLine();
|
|
|
|
// ident
|
|
writer.Write(Name + ".xml" + ",");
|
|
writer.Write(",");
|
|
writer.Write("Friendly Name,");
|
|
writer.Write(",");
|
|
if (hasSpeakers) writer.Write(",");
|
|
writer.Write("\"" + (FriendlyName ?? "<null>").Replace("\"", "\"\"") + "\"" + ",");
|
|
if (hasSpeakers) writer.Write(",");
|
|
writer.Write("\"" + (FriendlyName ?? "<null>").Replace("\"", "\"\"") + "\"" + ",");
|
|
writer.Write("");
|
|
writer.WriteLine();
|
|
|
|
// Speakers
|
|
Dictionary<int, string> en_names = new Dictionary<int, string>();
|
|
Dictionary<int, string> jp_names = new Dictionary<int, string>();
|
|
if (hasSpeakers)
|
|
{
|
|
foreach (XMLEntry entry in Speakers)
|
|
{
|
|
string en_name = (entry.EnglishText ?? "<null>").Replace("\"", "\"\"");
|
|
string jp_name = (entry.JapaneseText ?? "<null>").Replace("\"", "\"\"");
|
|
writer.WriteLine(
|
|
Name + ".xml" + "," +
|
|
entry.Id + "," +
|
|
"Speaker" + "," +
|
|
entry.Status + "," +
|
|
"," +
|
|
"\"" + jp_name + "\"" + "," +
|
|
"" + "," +
|
|
"\"" + en_name + "\"" + "," +
|
|
"\"" + entry.Notes + "\""
|
|
);
|
|
|
|
en_names.Add(entry.Id.Value, en_name);
|
|
jp_names.Add(entry.Id.Value, jp_name);
|
|
}
|
|
}
|
|
|
|
// Text lines
|
|
foreach (XMLSection section in Sections.Where(s => s.Name != "All strings"))
|
|
{
|
|
foreach (XMLEntry entry in section.Entries)
|
|
{
|
|
|
|
List<string> en = new List<string>();
|
|
List<string> jp = new List<string>();
|
|
|
|
string en_name = "";
|
|
string jp_name = "";
|
|
|
|
if (entry.SpeakerId != null)
|
|
{
|
|
foreach (var id in entry.SpeakerId)
|
|
{
|
|
if (!string.IsNullOrEmpty(en_names[id]))
|
|
en.Add(en_names[id]);
|
|
if (!string.IsNullOrEmpty(jp_names[id]))
|
|
jp.Add(jp_names[id]);
|
|
}
|
|
en_name = string.Join(",", entry.SpeakerId);
|
|
en_name += "[" + string.Join(" / ", en).Replace("\"", "\"\"") + "]";
|
|
jp_name = string.Join(",", entry.SpeakerId);
|
|
jp_name += "[" + string.Join(" / ", jp).Replace("\"", "\"\"") + "]";
|
|
}
|
|
|
|
string en_text = entry.EnglishText ?? "<null>";
|
|
string jp_text = entry.JapaneseText ?? "<null>";
|
|
|
|
// ident
|
|
writer.Write(Name + ".xml" + ",");
|
|
writer.Write(entry.Id + ",");
|
|
writer.Write("\"" + section.Name.Replace("\"", "\"\"") + "\"" + ",");
|
|
writer.Write(entry.Status + ",");
|
|
if (hasSpeakers) writer.Write("\"" + jp_name + "\"" + ",");
|
|
writer.Write("\"" + jp_text.Replace("\"", "\"\"") + "\"" + ",");
|
|
if (hasSpeakers) writer.Write("\"" + en_name + "\"" + ",");
|
|
writer.Write("\"" + en_text.Replace("\"", "\"\"") + "\"" + ",");
|
|
writer.Write("\"" + entry.Notes + "\"");
|
|
writer.WriteLine();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private XElement GetXmlSpeakerElement(List<XMLEntry> SpeakerList)
|
|
{
|
|
var speakerEntry = new List<XElement>
|
|
{
|
|
new XElement("Section", "Speaker"),
|
|
};
|
|
|
|
speakerEntry.AddRange(SpeakerList.Select(entry => GetXMLEntryElement(entry, isLegacy)).ToList());
|
|
|
|
return new XElement("Speakers", speakerEntry);
|
|
}
|
|
private XElement GetXmlSectionElement(XMLSection section)
|
|
{
|
|
var sectionEntry = new List<XElement>
|
|
{
|
|
new XElement("Section", section.Name),
|
|
};
|
|
|
|
sectionEntry.AddRange(section.Entries.Select(entry => GetXMLEntryElement(entry, isLegacy)).ToList());
|
|
|
|
return new XElement("Strings", sectionEntry);
|
|
}
|
|
|
|
private static XElement GetXMLEntryElement(XMLEntry entry, bool isLegacy)
|
|
{
|
|
var elemenId = entry.Id == null ? null : new XElement("Id", entry.Id);
|
|
var bubbleId = entry.BubbleId == null ? null : new XElement("BubbleId", entry.BubbleId);
|
|
var subId = entry.BubbleId == null ? null : new XElement("SubId", entry.SubId);
|
|
var speakerId = entry.SpeakerId == null ? null : new XElement("SpeakerId", string.Join(",", entry.SpeakerId));
|
|
var voiceId = entry.VoiceId == null ? null : new XElement("VoiceId", entry.VoiceId);
|
|
var maxLength = entry.MaxLength == null ? null : new XElement("MaxLength", entry.MaxLength);
|
|
var structId = entry.StructId == null ? null : new XElement("StructId", entry.StructId);
|
|
var unknownPointer = entry.UnknownPointer == null ? null : new XElement("UnknownPointer", entry.UnknownPointer);
|
|
XElement embedOffset;
|
|
|
|
if (entry.EmbedOffset)
|
|
{
|
|
var sectionEntry = new List<XElement>
|
|
{
|
|
new XElement("hi", entry.hi),
|
|
new XElement("lo", entry.lo),
|
|
};
|
|
embedOffset = new XElement("EmbedOffset", sectionEntry);
|
|
}
|
|
else
|
|
{
|
|
embedOffset = null;
|
|
}
|
|
|
|
if (isLegacy)
|
|
{
|
|
return new XElement("Entry",
|
|
new XElement("PointerOffset", entry.PointerOffset),
|
|
embedOffset,
|
|
maxLength,
|
|
voiceId,
|
|
new XElement("JapaneseText", entry.JapaneseText),
|
|
new XElement("EnglishText", entry.EnglishText),
|
|
new XElement("Notes", string.IsNullOrEmpty(entry.Notes) ? null : entry.Notes),
|
|
elemenId,
|
|
structId,
|
|
speakerId,
|
|
unknownPointer,
|
|
bubbleId,
|
|
subId,
|
|
new XElement("Status", entry.Status)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
|
|
return new XElement("Entry",
|
|
new XElement("PointerOffset", entry.PointerOffset),
|
|
embedOffset,
|
|
maxLength,
|
|
voiceId,
|
|
new XElement("JapaneseText", entry.JapaneseText),
|
|
new XElement("EnglishText", entry.EnglishText),
|
|
new XElement("Notes", string.IsNullOrEmpty(entry.Notes) ? null : entry.Notes),
|
|
speakerId,
|
|
elemenId,
|
|
bubbleId,
|
|
subId,
|
|
new XElement("Status", entry.Status)
|
|
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
public List<EntryFound> SearchJapanese(string folder, int fileId, string text, bool matchWholeentry, bool matchCase, bool matchWholeWord, string language)
|
|
{
|
|
List<EntryFound> res = new List<EntryFound>();
|
|
foreach (XMLSection section in Sections)
|
|
{
|
|
if (section.Name != "All strings")
|
|
{
|
|
var temp = section.SearchJapanese(folder, fileId, section.Name, text, matchWholeentry, matchCase, matchWholeWord, language);
|
|
|
|
if (temp.Count > 0)
|
|
res.AddRange(temp);
|
|
}
|
|
}
|
|
|
|
if (Speakers != null)
|
|
{
|
|
var speakerFound = SearchSpeaker(folder, fileId, text, matchWholeentry, matchCase, matchWholeWord, language);
|
|
if (speakerFound.Count > 0)
|
|
res.AddRange(speakerFound);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
private List<EntryFound> SearchSpeaker(string folder, int fileId, string text, bool matchWholeEntry, bool matchCase, bool matchWholeWord, string language)
|
|
{
|
|
List<EntryFound> res = new List<EntryFound>();
|
|
List<int> foundIndexes;
|
|
foundIndexes = Enumerable.Range(0, Speakers.Count)
|
|
.Where(e => Speakers[e].IsFound(text, matchWholeEntry, matchCase, matchWholeWord, language))
|
|
.ToList();
|
|
|
|
if (foundIndexes.Count > 0)
|
|
{
|
|
|
|
foreach (int index in foundIndexes)
|
|
{
|
|
EntryFound entry = new EntryFound();
|
|
entry.Folder = folder;
|
|
entry.FileId = fileId;
|
|
entry.Section = "Speaker";
|
|
entry.Id = index;
|
|
entry.Entry = Speakers[index];
|
|
res.Add(entry);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
}
|
|
} |