public Po Convert(BinaryFormat source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } source.Stream.Seek(0, SeekMode.Start); DataReader reader = new DataReader(source.Stream); Po po = new Po { Header = new PoHeader( "Attack of the Friday Monsters Translatation", "*****@*****.**", "es-ES"), }; uint numSections = reader.ReadUInt32(); if (numSections < 3) { throw new FormatException($"Missing sections"); } // We skip the first 3 sections with unknown content reader.ReadBytes(3 * 4); for (int s = 3; s < numSections; s++) { uint sectionOffset = reader.ReadUInt32(); if (sectionOffset == 0) { continue; } source.Stream.PushToPosition(sectionOffset, SeekMode.Start); ushort charId = reader.ReadUInt16(); if (charId == 0x4D30) { source.Stream.PopPosition(); continue; } if (!Characters.ContainsKey(charId)) { throw new FormatException("Unknown char: " + charId); } PoEntry entry = new PoEntry { Original = ReadTokenizedString(reader), Context = $"s:{s}", ExtractedComments = Characters[charId], }; po.Add(entry); source.Stream.PopPosition(); } return(po); }
public override void ExportPo(string path) { var directory = System.IO.Path.GetDirectoryName(path); Directory.CreateDirectory(directory); var po = new Po() { Header = new PoHeader(GameName, "*****@*****.**", "es-ES") }; var data = GetData(); foreach (var dataColumn in data.Columns) { if (dataColumn.GetType().Name != nameof(Column) && dataColumn.DataCount > 0 && dataColumn.Size > 0) { var values = dataColumn.GetUniqueValues(); for (var i = 0; i < values.Count; i++) { var value = values[i]; var original = value.Item1; var translated = value.Item2; var entry = new PoEntry(); if (string.IsNullOrEmpty(original)) { original = "<!empty>"; translated = "<!empty>"; } if (string.IsNullOrEmpty(translated)) { translated = "<!empty>"; } var tmp = original.Replace(LineEnding.ShownLineEnding, LineEnding.PoLineEnding); entry.Original = tmp; entry.Context = $"{dataColumn.Name}_{i}"; if (original != translated) { tmp = translated.Replace(LineEnding.ShownLineEnding, LineEnding.PoLineEnding); entry.Translated = tmp; } po.Add(entry); } } } var po2binary = new Yarhl.Media.Text.Po2Binary(); var binary = po2binary.Convert(po); binary.Stream.WriteTo(path); }
public void AddIsAddingEntries() { var po = CreateDummyFormat(); var entry = new PoEntry("test"); po.Add(entry); Assert.AreEqual(1, po.Entries.Count); Assert.Contains(entry, po.Entries); }
public void AddThrowsIfOriginalIsEmpty() { var po = CreateDummyFormat(); var entry = new PoEntry(); var exception = Throws.InstanceOf <FormatException>() .With.Message.EqualTo("Original is empty"); Assert.That(() => po.Add(entry), exception); }
public void AddMultipleEntries() { var po = CreateDummyFormat(); var entries = new PoEntry[] { new PoEntry("org1"), new PoEntry("org2") }; po.Add(entries); Assert.AreEqual(2, po.Entries.Count); Assert.Contains(entries[0], po.Entries); Assert.Contains(entries[1], po.Entries); }
public void TextShowsOriginalOrTranslated() { PoEntry entry = new PoEntry(); Assert.That(entry.Text, Is.EqualTo(string.Empty)); entry.Original = "original"; Assert.That(entry.Text, Is.EqualTo(entry.Original)); entry.Translated = "translated"; Assert.That(entry.Text, Is.EqualTo(entry.Translated)); }
public void MultipleEntriesDifferentTranslationThrows() { var po = CreateDummyFormat(); var entry1 = new PoEntry("orig") { Translated = "trans" }; var entry2 = new PoEntry("orig") { Translated = "trans2" }; po.Add(entry1); Assert.Throws <InvalidOperationException>(() => po.Add(entry2)); }
/// <summary> /// Search the current entry. /// </summary> /// <param name="entry">PoEntry passed</param> protected void SearchEntry(PoEntry entry, bool fixedEntry = false) { // Instance the necessary data. positionsLists = new List <int>(); withoutZero = false; fixedEntrySize = 0; textArray = encoding.GetBytes($"{entry.Original}\0"); // Search the text. var textLocation = findSequence(elf, 0, GetBytesFromString(textArray)); // Not found, but try to search without the initial zero if (textLocation == -1) { // Search the text without initial zero. textLocation = findSequence(elf, 0, GetBytesFromString(textArray, true)); // Not found. if (textLocation == -1) { throw new Exception($"The string: \"{entry.Original}\" is not found on the exe."); } withoutZero = true; } // Is a fixed entry. if (fixedEntry) { textLocation++; SearchFixedEntry(textLocation); } else { SearchPointerBasedEntry(textLocation, entry.Original); } data.Add(new ElfData() { Text = UseDictionary(entry.Text), Positions = positionsLists, FixedLength = isFixed, EncodingId = encoding.CodePage, SizeFixedLength = fixedEntrySize }); }
public void DefaultValues() { PoEntry entry = new PoEntry(); Assert.AreEqual(string.Empty, entry.Original); Assert.AreEqual(string.Empty, entry.Translated); Assert.IsNull(entry.Context); Assert.IsNull(entry.TranslatorComment); Assert.IsNull(entry.ExtractedComments); Assert.IsNull(entry.Reference); Assert.IsNull(entry.Flags); Assert.IsNull(entry.PreviousContext); Assert.IsNull(entry.PreviousOriginal); entry = new PoEntry("original"); Assert.AreEqual("original", entry.Original); }
public void MergeEntriesIfWithSameId() { var po = CreateDummyFormat(); var entry1 = new PoEntry("orig") { Reference = "ref1" }; var entry2 = new PoEntry("orig") { Reference = "ref2" }; po.Add(entry1); Assert.DoesNotThrow(() => po.Add(entry2)); Assert.AreEqual(1, po.Entries.Count); Assert.AreEqual("orig", po.Entries[0].Original); Assert.AreEqual("ref1,ref2", po.Entries[0].Reference); }
public void CanAddMultipleEntriesSameIdDifferentContext() { var po = CreateDummyFormat(); var entry1 = new PoEntry("orig") { Context = "1", Reference = "ref1" }; var entry2 = new PoEntry("orig") { Context = "2", Reference = "ref2" }; po.Add(entry1); Assert.DoesNotThrow(() => po.Add(entry2)); Assert.AreEqual(2, po.Entries.Count); Assert.AreEqual("ref1", po.Entries[0].Reference); Assert.AreEqual("ref2", po.Entries[1].Reference); }
public Po Convert(BinaryFormat source) { reader = new DataReader(source.Stream) { DefaultEncoding = new UTF8Encoding(), Endianness = EndiannessMode.LittleEndian, }; LoadCount(); for (int i = 0; i < Count; i++) { PoEntry entry = new PoEntry(); //Generate the entry on the po file entry.Original = DumpText(); //Text entry.Context = i.ToString(); //Context entry.ExtractedComments = Comment + "\n#. (ASCII Char = 1 char, Special char = 2 char)"; po.Add(entry); } return(po); }
public Po Convert(Rpy source) { for (int i = 0; i < source.OriginalText.Count; i++) { var entry = new PoEntry { Context = i + "|" + source.Names[i], Reference = source.Variables[i], Original = (!string.IsNullOrEmpty(source.OriginalText[i])) ? source.OriginalText[i] : "<!empty>" }; if (!string.IsNullOrEmpty(source.TranslatedText[i])) { entry.Translated = source.TranslatedText[i]; } entry.ExtractedComments = source.Names[i]; po.Add(entry); } return(po); }
public Po Convert(Rpy source) { for (int i = 0; i < source.OriginalText.Count; i++) { PoEntry entry = new PoEntry(); entry.Context = i.ToString() + "|" + source.Names[i]; entry.Reference = source.Variables[i]; entry.Original = source.OriginalText[i]; if (!String.IsNullOrEmpty(source.TranslatedText[i])) { entry.Translated = source.TranslatedText[i]; } entry.ExtractedComments = source.Names[i]; //Exclusivo para DDLC, luego lo haré configurable entry.Flags = "game-doki, max-length:191"; po.Add(entry); } return(po); }
public override void ExportPo(string path) { var directory = System.IO.Path.GetDirectoryName(path); Directory.CreateDirectory(directory); var po = new Po() { Header = new PoHeader(GameName, "*****@*****.**", "es-ES") }; var subtitles = GetSubtitles(); foreach (var subtitle in subtitles) { var entry = new PoEntry(); var original = subtitle.Text; var translation = subtitle.Translation; if (string.IsNullOrEmpty(original)) { original = "<!empty>"; translation = "<!empty>"; } entry.Original = original.Replace(LineEnding.ShownLineEnding, LineEnding.PoLineEnding); entry.Context = GetContext(subtitle); if (original != translation) { entry.Translated = translation.Replace(LineEnding.ShownLineEnding, LineEnding.PoLineEnding); } po.Add(entry); } var po2binary = new Yarhl.Media.Text.Po2Binary(); var binary = po2binary.Convert(po); binary.Stream.WriteTo(path); }
// Modified from here // https://github.com/pleonex/AttackFridayMonsters/blob/master/Programs/AttackFridayMonsters/AttackFridayMonsters.Formats/Text/Code/BinaryStrings2Po.cs public Po Convert(BinaryFormat source) { string yaml = new TextReader(source.Stream).ReadToEnd(); block = new DeserializerBuilder() .WithNamingConvention(CamelCaseNamingConvention.Instance) .Build() .Deserialize <StringDefinitionBlock>(yaml); Po po = new Po { Header = new PoHeader( "Generic game", "*****@*****.**", "es-ES"), }; DataReader reader = new DataReader(streamElf); foreach (var definition in block.Definitions) { reader.Stream.Position = definition.Address - block.Offset[0].Ram; var encoding = Encoding.GetEncoding(definition.Encoding); string text = reader.ReadString(definition.Size, encoding).Replace("\0", string.Empty); string pointers = string.Join(",", definition.Pointers?.Select(p => $"0x{p:X}") ?? Enumerable.Empty <string>()); var entry = new PoEntry { Original = text, Context = $"0x{definition.Address:X8}", Flags = "c-format", Reference = $"0x{definition.Address:X}:{definition.Size}:{definition.Encoding}:{pointers}", }; po.Add(entry); } return(po); }
public Po Convert(BinaryFormat source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (block == null) { throw new InvalidOperationException("Converter not initialized"); } Po po = new Po { Header = new PoHeader( "Attack of Friday Monsters translation", "*****@*****.**", "es-ES"), }; DataReader reader = new DataReader(source.Stream); foreach (var definition in block.Definitions) { source.Stream.Position = definition.Address - block.Offset[0].Ram; var encoding = Encoding.GetEncoding(definition.Encoding); string text = reader.ReadString(definition.Size, encoding).Replace("\0", string.Empty); string pointers = string.Join(",", definition.Pointers?.Select(p => $"0x{p:X}") ?? Enumerable.Empty <string>()); var entry = new PoEntry { Original = text, Context = $"0x{definition.Address:X8}", Flags = "c-format", Reference = $"0x{definition.Address:X}:{definition.Size}:{definition.Encoding}:{pointers}", }; po.Add(entry); } return(po); }
public Po Convert(Clyt source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } Po po = new Po { Header = new PoHeader( "Attack of the Friday Monsters Translation", "*****@*****.**", "es-ES"), }; Stack <Panel> stack = new Stack <Panel>(); stack.Push(source.RootPanel); while (stack.Count > 0) { Panel panel = stack.Pop(); if (panel is TextSection text && !string.IsNullOrEmpty(text.Text)) { PoEntry entry = new PoEntry { Context = text.Name, Original = text.Text, }; po.Add(entry); } foreach (var child in panel.Children.Reverse()) { stack.Push(child); } } return(po); }
public override void ExportPo(string path) { var directory = System.IO.Path.GetDirectoryName(path); Directory.CreateDirectory(directory); var po = new Po() { Header = new PoHeader(GameName, "*****@*****.**", "es-ES") }; var entry = new PoEntry(); var text = GetText(); var tmp = text.Text.Replace(LineEnding.ShownLineEnding, LineEnding.PoLineEnding); if (string.IsNullOrEmpty(tmp)) { tmp = "<!empty>"; } entry.Original = tmp; if (text.Text != text.Translation) { tmp = text.Translation.Replace(LineEnding.ShownLineEnding, LineEnding.PoLineEnding); if (string.IsNullOrEmpty(tmp)) { tmp = "<!empty>"; } entry.Translated = tmp; } po.Add(entry); var po2binary = new Yarhl.Media.Text.Po2Binary(); var binary = po2binary.Convert(po); binary.Stream.WriteTo(path); }
public static string Get(string original, string context = null) { if (po == null) { return(original); } PoEntry entry = po.FindEntry(original, context); if (entry == null) { Logger.Log($"PO is missing entry for: {original} || {context}"); return(original); } if (string.IsNullOrEmpty(entry.Translated)) { Logger.Log($"PO is missing translation for: {original} || {context}"); return(original); } return(entry.Translated); }
private void DumpBlock(DataReader reader, Po po, bool fullWidth = false) { for (int i = 0; i < SizeBlock; i++) { if (!(JapaneseStrings.Contains(Count) || BadPointers.Contains(Count))) { PoEntry entry = new PoEntry(); //Generate the entry on the po file //Get position int position = reader.ReadInt32() - 0x401600; reader.Stream.PushToPosition(position); //Get the text DumpText(reader); //Normalize the text NormalizeText(fullWidth); //Return to the original position reader.Stream.PopPosition(); //entry.Original = ReplaceText(TextNormalized, true); //Add the string block entry.Original = TextNormalized.Replace("\0", ""); entry.Context = Count.ToString(); //Context po.Add(entry); //Clear the text TextNormalized = ""; } else { reader.Stream.Position += 4; } Count++; } }
private static void UpdateTranslation(string oldFile, string newFile) { Node oldFileNode = NodeFactory.FromFile(oldFile); Node newFileNode = NodeFactory.FromFile(newFile); oldFileNode.TransformWith <Binary2Po>(); newFileNode.TransformWith <Binary2Po>(); Po oldPo = oldFileNode.GetFormatAs <Po>(); Po newPo = newFileNode.GetFormatAs <Po>(); foreach (PoEntry entry in newPo.Entries) { string[] context = entry.Context.Split('\n'); string field = context[0]; string id = context[1].Split(',')[0]; // Find "field + id" in old Po PoEntry oldEntry = oldPo.Entries.FirstOrDefault(x => x.Context.StartsWith($"{field}\n{id}")); if (oldEntry == null && field == "English") { oldEntry = oldPo.Entries.FirstOrDefault(x => x.Context.StartsWith($"{id}")); } if (oldEntry == null) { Console.WriteLine($"Translation for \"{field} {id}\" not found."); continue; } entry.Translated = oldEntry.Translated; } newFileNode.TransformWith <Po2Binary>(); newFileNode.Stream.WriteTo(newFile); }
public void TestProperties() { PoEntry entry = new PoEntry { Original = "test0", Translated = "test1", Context = "test2", TranslatorComment = "test3", ExtractedComments = "test4", Reference = "test5", Flags = "test6", PreviousContext = "test7", PreviousOriginal = "test8", }; Assert.AreEqual("test0", entry.Original); Assert.AreEqual("test1", entry.Translated); Assert.AreEqual("test2", entry.Context); Assert.AreEqual("test3", entry.TranslatorComment); Assert.AreEqual("test4", entry.ExtractedComments); Assert.AreEqual("test5", entry.Reference); Assert.AreEqual("test6", entry.Flags); Assert.AreEqual("test7", entry.PreviousContext); Assert.AreEqual("test8", entry.PreviousOriginal); }
public Po Convert(BinaryFormat source) { //Read the language used by the user' OS, this way the editor can spellcheck the translation. - Thanks Liquid_S por the code System.Globalization.CultureInfo currentCulture = System.Threading.Thread.CurrentThread.CurrentCulture; Po po = new Po { Header = new PoHeader("Disgaea", "*****@*****.**", currentCulture.Name) }; var reader = new DataReader(source.Stream) { DefaultEncoding = new UTF8Encoding(), Endianness = EndiannessMode.LittleEndian, }; //Check if the variable dictionary exist if (System.IO.File.Exists("TextVar.map")) { DictionaryEnabled = true; GenerateFontMap("TextVar.map"); } //Check if the dictionary exist if (System.IO.File.Exists("TextArea.map")) { GenerateFontMap("TextArea.map"); } //Read the number of blocks on the file Count = reader.ReadInt32(); //Jump to the first block reader.Stream.Position = 0x08; //Get the positions Positions = GetBlocks(reader); //Get the sizes -- Thanks Krisan GetSizes(reader); //Search the strings GetText(reader); //Generate po for (int i = 0; i < Text.Count; i++) { PoEntry entry = new PoEntry(); //Generate the entry on the po file string result = Text[i]; if (string.IsNullOrEmpty(result)) { result = "<!empty>"; } if (result.IndexOf("[START]") != -1) { if (DictionaryEnabled) { result = ReplaceText(result, true); //Reemplace the strings with the preloaded dictionary } entry.Original = result; //Add the string block entry.Context = i.ToString(); //Context if (HeaderText[i] != "") { entry.Reference = HeaderText[i]; } po.Add(entry); } } return(po); }
static void Main(string[] args) { { Console.WriteLine("TEXT2PO 1.2 - A simple converter for the text from the games Lord of Magna and Rune Factory 4 by Darkmet98."); Console.WriteLine("Massive thanks to Pleonex, Leeg and Megaflan for all."); if (args.Length != 3 && args.Length != 2) { System.Console.WriteLine("Usage: TEXT2PO <mode> <file1> <file2>"); System.Console.WriteLine("Mode for Rune Factory 4: -exportrune (export to po)/-importrune (import po)/-transrune(import the translation from another file)/-exportrunefix(export and fix bad newlines from another programs)"); System.Console.WriteLine("Mode for Lord Of Magna Maiden Heaven: -exportlord (export to po)/-importlord (import po)/-translord(import the translation from another file)/-exportlordfix(export and fix bad newlines from another programs)"); System.Console.WriteLine(""); System.Console.WriteLine("Example 1: TEXT2PO.exe -exportlord msg.nxtxt"); System.Console.WriteLine("Example 2: TEXT2PO.exe -importlord msg.nxtxt.po"); System.Console.WriteLine("Example 3: TEXT2PO.exe -translord msg.nxtxt.po msgESP.nxtxt"); System.Console.WriteLine("Example 4: TEXT2PO.exe -exportlordfix msgESP.nxtxt"); return; } List <String> Filestrings = new List <String>(); List <String> Postrings = new List <String>(); List <int> stringsizes = new List <int>(); List <int> stringpositions = new List <int>(); string result = ""; Int32 magic; Int32 count; Int32 size; Int32 position; Int32 textsize; int i = 0; switch (args[0]) { case "-exportlord": using (BinaryReader reader = new BinaryReader(File.Open(args[1], FileMode.Open))) { Po poexport = new Po { Header = new PoHeader("Lord Of Magna Maiden Heaven", "*****@*****.**", "es") { LanguageTeam = "Glowtranslations", } }; magic = reader.ReadInt32(); count = reader.ReadInt32(); Console.WriteLine("Exporting..."); for (i = 0; i < count; i++) { size = reader.ReadInt32(); position = reader.ReadInt32(); stringsizes.Add(size); stringpositions.Add(position); } for (i = 0; i < count; i++) { reader.BaseStream.Position = stringpositions[i]; //El puto flan byte[] array = reader.ReadBytes(stringsizes[i]); result = Encoding.Unicode.GetString(array); if (string.IsNullOrEmpty(result)) { result = "<!empty>"; } poexport.Add(new PoEntry(result) { Context = i.ToString() }); } poexport.ConvertTo <BinaryFormat>().Stream.WriteTo(args[1] + ".po"); Console.WriteLine("The file is exported."); } break; case "-exportlordfix": using (BinaryReader reader = new BinaryReader(File.Open(args[1], FileMode.Open))) { Po poexport = new Po { Header = new PoHeader("Lord Of Magna Maiden Heaven", "*****@*****.**", "es") { LanguageTeam = "Glowtranslations", } }; magic = reader.ReadInt32(); count = reader.ReadInt32(); Console.WriteLine("Exporting..."); for (i = 0; i < count; i++) { size = reader.ReadInt32(); position = reader.ReadInt32(); stringsizes.Add(size); stringpositions.Add(position); } for (i = 0; i < count; i++) { reader.BaseStream.Position = stringpositions[i]; //El puto flan byte[] array = reader.ReadBytes(stringsizes[i]); result = Encoding.Unicode.GetString(array); result = result.Replace("\r", ""); if (string.IsNullOrEmpty(result)) { result = "<!empty>"; } poexport.Add(new PoEntry(result) { Context = i.ToString() }); } poexport.ConvertTo <BinaryFormat>().Stream.WriteTo(args[1] + ".po"); Console.WriteLine("The file is exported."); } break; case "-exportrune": using (BinaryReader reader = new BinaryReader(File.Open(args[1], FileMode.Open))) { Po poexport = new Po { Header = new PoHeader("Rune Factory 4", "*****@*****.**", "es") { LanguageTeam = "Glowtranslations", } }; magic = reader.ReadInt32(); count = reader.ReadInt32(); Console.WriteLine("Exporting..."); for (i = 0; i < count; i++) { size = reader.ReadInt32(); position = reader.ReadInt32(); stringsizes.Add(size); stringpositions.Add(position); } for (i = 0; i < count; i++) { reader.BaseStream.Position = stringpositions[i]; //El puto flan byte[] array = reader.ReadBytes(stringsizes[i]); result = Encoding.UTF8.GetString(array); if (string.IsNullOrEmpty(result)) { result = "<!empty>"; } poexport.Add(new PoEntry(result) { Context = i.ToString() }); } poexport.ConvertTo <BinaryFormat>().Stream.WriteTo(args[1] + ".po"); Console.WriteLine("The file is exported."); } break; case "-exportrunefix": using (BinaryReader reader = new BinaryReader(File.Open(args[1], FileMode.Open))) { Po poexport = new Po { Header = new PoHeader("Rune Factory 4", "*****@*****.**", "es") { LanguageTeam = "Glowtranslations", } }; magic = reader.ReadInt32(); count = reader.ReadInt32(); Console.WriteLine("Exporting..."); for (i = 0; i < count; i++) { size = reader.ReadInt32(); position = reader.ReadInt32(); stringsizes.Add(size); stringpositions.Add(position); } for (i = 0; i < count; i++) { reader.BaseStream.Position = stringpositions[i]; //El puto flan byte[] array = reader.ReadBytes(stringsizes[i]); result = Encoding.UTF8.GetString(array); result = result.Replace("\r", ""); if (string.IsNullOrEmpty(result)) { result = "<!empty>"; } poexport.Add(new PoEntry(result) { Context = i.ToString() }); } poexport.ConvertTo <BinaryFormat>().Stream.WriteTo(args[1] + ".po"); Console.WriteLine("The file is exported."); } break; case "-importlord": DataStream inputLord = new DataStream(args[1], FileOpenMode.Read); BinaryFormat binaryLord = new BinaryFormat(inputLord); Po poLord = binaryLord.ConvertTo <Po>(); inputLord.Dispose(); Console.WriteLine("Importing..."); using (BinaryWriter writer = new BinaryWriter(File.Open(args[1] + ".exported", FileMode.Create))) { writer.Write(0x54584554); writer.Write(poLord.Entries.Count); for (i = 0; i < poLord.Entries.Count * 2; i++) { writer.Write(0x00000000); } foreach (var entry in poLord.Entries) { string potext = string.IsNullOrEmpty(entry.Translated) ? entry.Original : entry.Translated; if (potext == "<!empty>") { potext = string.Empty; } stringpositions.Add((int)writer.BaseStream.Position); byte[] stringtext = Encoding.Unicode.GetBytes(potext += "\0"); textsize = stringtext.Length; stringsizes.Add(textsize); writer.Write(stringtext); } writer.BaseStream.Position = 0x8; int countposition = 0x8 * poLord.Entries.Count + 1; for (i = 0; i < poLord.Entries.Count; i++) { writer.Write(stringsizes[i] - 2); writer.Write(stringpositions[i]); } Console.WriteLine("The file is imported."); } break; case "-importrune": Console.WriteLine("Importing..."); DataStream input = new DataStream(args[1], FileOpenMode.Read); BinaryFormat binary = new BinaryFormat(input); Po po = binary.ConvertTo <Po>(); input.Dispose(); using (BinaryWriter writer = new BinaryWriter(File.Open(args[1] + ".exported", FileMode.Create))) { writer.Write(0x54584554); writer.Write(po.Entries.Count); for (i = 0; i < po.Entries.Count * 2; i++) { writer.Write(0x00000000); } foreach (var entry in po.Entries) { string potext = string.IsNullOrEmpty(entry.Translated) ? entry.Original : entry.Translated; if (potext == "<!empty>") { potext = string.Empty; } stringpositions.Add((int)writer.BaseStream.Position); byte[] stringtext = Encoding.UTF8.GetBytes(potext += "\0"); textsize = stringtext.Length; stringsizes.Add(textsize); writer.Write(stringtext); } writer.BaseStream.Position = 0x8; int countposition = 0x8 * po.Entries.Count + 1; for (i = 0; i < po.Entries.Count; i++) { writer.Write(stringsizes[i] - 1); writer.Write(stringpositions[i]); } Console.WriteLine("The file is imported."); } break; case "-transrune": using (BinaryReader reader = new BinaryReader(File.Open(args[2], FileMode.Open))) { Console.WriteLine("Importing old translation..."); magic = reader.ReadInt32(); count = reader.ReadInt32(); for (i = 0; i < count; i++) { size = reader.ReadInt32(); position = reader.ReadInt32(); stringsizes.Add(size); stringpositions.Add(position); } for (i = 0; i < count; i++) { reader.BaseStream.Position = stringpositions[i]; //El puto flan byte[] array = reader.ReadBytes(stringsizes[i]); result = Encoding.UTF8.GetString(array); Filestrings.Add(result); } } Console.WriteLine("Old translation preloaded."); DataStream inputimp = new DataStream(args[1], FileOpenMode.Read); BinaryFormat binaryimp = new BinaryFormat(inputimp); Po poimp = binaryimp.ConvertTo <Po>(); inputimp.Dispose(); Console.WriteLine("Importing original translation..."); foreach (var entry in poimp.Entries) { Postrings.Add(entry.Original); } Console.WriteLine("Original text preloaded."); Po poexport1 = new Po { Header = new PoHeader("Rune Factory 4", "*****@*****.**", "es") { LanguageTeam = "Glowtranslations", } }; for (i = 0; i < count; i++) { PoEntry entry = new PoEntry(); Console.WriteLine("Checking and comparing line " + i + " from " + count + " lines"); if (string.IsNullOrEmpty(Filestrings[i])) { Filestrings[i] = "<!empty>"; } if (Filestrings[i] == Postrings[i]) { entry.Context = i.ToString(); entry.Original = Postrings[i]; } else { entry.Context = i.ToString(); entry.Translated = Filestrings[i]; entry.Original = Postrings[i]; } poexport1.Add(entry); //poexport1.ConvertTo<BinaryFormat>().Stream.WriteTo(args[1] + "(exported)" + ".po"); //Pasta code } using (var poStream = poexport1.ConvertTo <BinaryFormat>()) poStream.Stream.WriteTo(args[1] + "(exported).po"); //Thanks pleonex Console.WriteLine("Finished."); break; case "-translord": using (BinaryReader reader = new BinaryReader(File.Open(args[2], FileMode.Open))) { Console.WriteLine("Importing old translation..."); magic = reader.ReadInt32(); count = reader.ReadInt32(); for (i = 0; i < count; i++) { size = reader.ReadInt32(); position = reader.ReadInt32(); stringsizes.Add(size); stringpositions.Add(position); } for (i = 0; i < count; i++) { reader.BaseStream.Position = stringpositions[i]; //El puto flan byte[] array = reader.ReadBytes(stringsizes[i]); result = Encoding.Unicode.GetString(array); Filestrings.Add(result); } } Console.WriteLine("Old translation preloaded."); DataStream inputimp1 = new DataStream(args[1], FileOpenMode.Read); BinaryFormat binaryimp1 = new BinaryFormat(inputimp1); Po poimp1 = binaryimp1.ConvertTo <Po>(); inputimp1.Dispose(); Console.WriteLine("Importing original translation..."); foreach (var entry in poimp1.Entries) { Postrings.Add(entry.Original); } Console.WriteLine("Original text preloaded."); Po poexport2 = new Po { Header = new PoHeader("Rune Factory 4", "*****@*****.**", "es") { LanguageTeam = "Glowtranslations", } }; for (i = 0; i < count; i++) { PoEntry entrada = new PoEntry(); Console.WriteLine("Checking and comparing line " + i + " from " + count + " lines"); if (string.IsNullOrEmpty(Filestrings[i])) { Filestrings[i] = "<!empty>"; } if (Filestrings[i] == Postrings[i]) { entrada.Context = i.ToString(); entrada.Original = Postrings[i]; } else { entrada.Context = i.ToString(); entrada.Translated = Filestrings[i]; entrada.Original = Postrings[i]; } poexport2.Add(entrada); } //poexport2.ConvertTo<BinaryFormat>().Stream.WriteTo(args[1] + "(exported)" + ".po"); //Pasta code using (var poStream = poexport2.ConvertTo <BinaryFormat>()) poStream.Stream.WriteTo(args[1] + "(exported).po"); //Thanks pleonex Console.WriteLine("Finished."); break; } } }
public Po Convert(BinaryFormat source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } source.Stream.Position = 0; var reader = new Yarhl.IO.TextDataReader(source.Stream, Encoding.UTF8); string data = reader.ReadToEnd(); data = data.Replace("\n", "<NewLine>", StringComparison.InvariantCulture); string[] lines = data.Split('\r'); string csvHeader = lines[0]; var poHeader = new PoHeader("Sakuna: Of Rice and Ruin", "*****@*****.**", "es"); var po = new Po(poHeader); po.Header.Extensions.Add("CSVHeader", csvHeader); po.Header.Extensions.Add("FileExtension", this.parameters.FileExtension); string[] fields = csvHeader.Split(','); string[] translationFieldArray = SakunaTools.Constants.TranslationFields.Split(','); var translationIndexes = new int[translationFieldArray.Length]; for (var i = 0; i < translationIndexes.Length; i++) { translationIndexes[i] = -1; } for (var i = 0; i < fields.Length; i++) { int index = Array.IndexOf(translationFieldArray, fields[i]); if (index != -1) { translationIndexes[index] = i; } } if (translationIndexes.All(x => x == -1)) { throw new FormatException("File without English fields."); } for (var i = 1; i < lines.Length; i++) { if (string.IsNullOrEmpty(lines[i])) { continue; } string[] split = lines[i].Split(','); for (var j = 0; j < translationIndexes.Length; j++) { if (translationIndexes[j] == -1) { continue; } var entry = new PoEntry(); string original = split[translationIndexes[j]]; if (string.IsNullOrEmpty(original)) { original = "<!empty>"; } entry.Context = $"{translationFieldArray[j]}\n{lines[i]}"; entry.Original = original.Replace("\\1", ",").Replace("<NewLine>", "\n"); po.Add(entry); } } return(po); }
static void Main(string[] args) { Console.WriteLine("Persona2PO 1.0 - A simple converter for the txt files (PersonaEditor text file) to po from the games Persona 3 and Persona 4 by Darkmet98."); Console.WriteLine("Thanks to Pleonex for the help and Yarhl libraries."); if (args.Length != 2) { Console.WriteLine("USAGE: [mono] persona2po.exe file -exportP3/-exportP4/import/generatenames/split"); Console.WriteLine("Export to Po example: persona2po.exe E101_001.txt -exportP4 "); Console.WriteLine("Generate the dictionary for names: Persona2po.exe alltxts.txt -generatenames"); Console.WriteLine("Import to txt from the Po: persona2po.exe E101_001.txt.po -import "); Console.WriteLine("Split the txt: persona2po.exe E101.txt -split "); Console.WriteLine("Read first the readme file before use this program!"); Environment.Exit(-1); } switch (args[1]) { case "-exportP4": Po po = new Po { Header = new PoHeader("Persona 4", "*****@*****.**", "es") { LanguageTeam = "Glowtranslations", } }; string[] textfile = System.IO.File.ReadAllLines(args[0]); foreach (string line in textfile) { string[] lineFields = line.Split('\t'); if (lineFields.Length < 4) { Console.WriteLine("FAAAAAAILLL: {0}", line, args[0]); //It's that a Pleonex's reference!!!!???? } foreach (string part in lineFields) { PoEntry entry = new PoEntry(); if (lineFields.Length == 6) { entry.Context = $"{lineFields[0]}:{lineFields[1]}:{lineFields[2]}"; if (string.IsNullOrEmpty(lineFields[3])) { lineFields[3] = "<!empty>"; } if (string.IsNullOrWhiteSpace(lineFields[3])) { lineFields[3] = "Pensamiento del protagonista"; } lineFields[3] = lineFields[3].Replace("�", "<NCHAR>"); entry.ExtractedComments = lineFields[3]; if (string.IsNullOrWhiteSpace(lineFields[4])) { lineFields[4] = "[CUADRO DE TEXTO EN BLANCO]"; } lineFields[4] = lineFields[4].Replace("{0A}", "\n"); lineFields[4] = lineFields[4].Replace("{F1 82}", "{PROTAGONISTA}"); entry.Original = lineFields[4]; po.Add(entry); } if (lineFields.Length >= 7) { entry.Context = $"{lineFields[0]}:{lineFields[1]}:{lineFields[2]}"; if (string.IsNullOrEmpty(lineFields[3])) { lineFields[3] = "<!empty>"; } if (string.IsNullOrWhiteSpace(lineFields[3])) { lineFields[3] = "Pensamiento del protagonista"; } lineFields[3] = lineFields[3].Replace("�", "<NCHAR>"); entry.ExtractedComments = lineFields[3]; if (string.IsNullOrWhiteSpace(lineFields[4])) { lineFields[4] = "[CUADRO DE TEXTO EN BLANCO]"; } lineFields[4] = lineFields[4].Replace("{0A}", "\n"); lineFields[4] = lineFields[4].Replace("{F1 82}", "{PROTAGONISTA}"); lineFields[6] = lineFields[6].Replace("{0A}", "\n"); lineFields[6] = lineFields[6].Replace("{F1 82}", "{PROTAGONISTA}"); entry.Original = lineFields[4]; entry.Translated = lineFields[6]; po.Add(entry); } } } po.ConvertTo <BinaryFormat>().Stream.WriteTo(args[0] + ".po"); break; case "-exportP3": po = new Po { Header = new PoHeader("Persona 3", "*****@*****.**", "es") { LanguageTeam = "Traducciones del Tío Victor", } }; textfile = System.IO.File.ReadAllLines(args[0]); foreach (string line in textfile) { string[] lineFields = line.Split('\t'); if (lineFields.Length < 4) { Console.WriteLine("FAAAAAAILLL: {0}", line, args[0]); //It's that a Pleonex's reference!!!!???? } foreach (string part in lineFields) { PoEntry entry = new PoEntry(); if (lineFields.Length == 6) { entry.Context = $"{lineFields[0]}:{lineFields[1]}:{lineFields[2]}"; if (string.IsNullOrEmpty(lineFields[3])) { lineFields[3] = "<!empty>"; } if (string.IsNullOrWhiteSpace(lineFields[3])) { lineFields[3] = "Pensamiento del protagonista"; } lineFields[3] = lineFields[3].Replace("�", "<NCHAR>"); entry.ExtractedComments = lineFields[3]; if (string.IsNullOrWhiteSpace(lineFields[4])) { lineFields[4] = "[CUADRO DE TEXTO EN BLANCO]"; } lineFields[4] = lineFields[4].Replace("{0A}", "\n"); lineFields[4] = lineFields[4].Replace("{F1 0C}", "{Nombre y apellidos prota}"); lineFields[4] = lineFields[4].Replace("{F1 0B}", "{Apellido prota}"); lineFields[4] = lineFields[4].Replace("{F1 0A}", "{Nombre prota}"); entry.Original = lineFields[4]; po.Add(entry); } if (lineFields.Length >= 7) { entry.Context = $"{lineFields[0]}:{lineFields[1]}:{lineFields[2]}"; if (string.IsNullOrEmpty(lineFields[3])) { lineFields[3] = "<!empty>"; } if (string.IsNullOrWhiteSpace(lineFields[3])) { lineFields[3] = "Pensamiento del protagonista"; } lineFields[3] = lineFields[3].Replace("�", "<NCHAR>"); entry.ExtractedComments = lineFields[3]; if (string.IsNullOrWhiteSpace(lineFields[4])) { lineFields[4] = "[CUADRO DE TEXTO EN BLANCO]"; } lineFields[4] = lineFields[4].Replace("{0A}", "\n"); lineFields[4] = lineFields[4].Replace("{F1 0C}", "{Nombre y apellidos prota}"); lineFields[4] = lineFields[4].Replace("{F1 0B}", "{Apellido prota}"); lineFields[4] = lineFields[4].Replace("{F1 0A}", "{Nombre prota}"); lineFields[6] = lineFields[6].Replace("{0A}", "\n"); lineFields[6] = lineFields[6].Replace("{F1 0C}", "{Nombre y apellidos prota}"); lineFields[6] = lineFields[6].Replace("{F1 0B}", "{Apellido prota}"); lineFields[6] = lineFields[6].Replace("{F1 0A}", "{Nombre prota}"); entry.Original = lineFields[4]; entry.Translated = lineFields[6]; po.Add(entry); } } } po.ConvertTo <BinaryFormat>().Stream.WriteTo(args[0] + ".po"); break; case "-generatenames": po = new Po { Header = new PoHeader("Persona names", "*****@*****.**", "es") { LanguageTeam = "Glowtranslations", } }; string[] textnames = System.IO.File.ReadAllLines(args[0]); foreach (string line in textnames) { string[] lineFields = line.Split('\t'); if (lineFields.Length < 4) { Console.WriteLine("FAAAAAAILLL: {0}", line, args[0]); //It's that a Pleonex's reference!!!!???? } foreach (string part in lineFields) { PoEntry entry = new PoEntry(); if (string.IsNullOrEmpty(lineFields[3])) { lineFields[3] = "<!empty>"; } if (string.IsNullOrWhiteSpace(lineFields[3])) { lineFields[3] = "Pensamiento del protagonista"; } lineFields[3] = lineFields[3].Replace("�", "<NCHAR>"); entry.Original = lineFields[3]; po.Add(entry); } } po.ConvertTo <BinaryFormat>().Stream.WriteTo("names.po"); break; case "-import": DataStream input = new DataStream(args[0], FileOpenMode.Read); BinaryFormat binary = new BinaryFormat(input); po = binary.ConvertTo <Po>(); input.Dispose(); DataStream name = new DataStream("names.po", FileOpenMode.Read); BinaryFormat binaryname = new BinaryFormat(name); Po poname = binaryname.ConvertTo <Po>(); name.Dispose(); Yarhl.IO.TextWriter writer = new Yarhl.IO.TextWriter(new DataStream(args[0] + ".txt", FileOpenMode.Write)); foreach (var entry in po.Entries) { string potext = entry.Text; if (potext == "<!empty>") { potext = string.Empty; } PoEntry nameEntry = poname.FindEntry(entry.ExtractedComments); string names = nameEntry.Text; entry.Context = entry.Context.Replace(":", "\t"); entry.Original = entry.Original.Replace("\n", "{0A}"); entry.Translated = entry.Translated.Replace("\n", "\\n"); entry.Translated = entry.Translated.Replace("{PROTAGONISTA}", "{F1 82}"); entry.Translated = entry.Translated.Replace("{Nombre y apellidos prota}", "{F1 0C}"); entry.Translated = entry.Translated.Replace("{Apellido prota}", "{F1 0B}"); entry.Translated = entry.Translated.Replace("{Nombre prota}", "{F1 0A}"); writer.WriteLine(entry.Context + "\t" + entry.ExtractedComments + "\t" + entry.Original + "\t" + names + "\t" + entry.Translated + "\t"); } break; case "-split": string[] textfilex = System.IO.File.ReadAllLines(args[0]); List <string> text = new List <string>(); foreach (string line in textfilex) { string[] lineFields = line.Split('\t'); if (lineFields.Length < 4) { Console.WriteLine("FAAAAAAILLL: {0}", line, args[0]); //It's that a Pleonex's reference!!!!???? } if (lineFields.Length == 6) { text.Add(lineFields[0] + "\t" + lineFields[1] + "\t" + lineFields[2] + "\t" + lineFields[3] + "\t" + lineFields[4] + "\t"); } if (lineFields.Length >= 7) { text.Add(lineFields[0] + "\t" + lineFields[1] + "\t" + lineFields[2] + "\t" + lineFields[3] + "\t" + lineFields[4] + "\t" + lineFields[5] + "\t" + lineFields[6] + "\t"); } string result = string.Join(Environment.NewLine, text.ToArray()); System.IO.File.WriteAllText(@lineFields[0], result); } break; } }
public Po Convert(BinaryFormat source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } DataReader reader = new DataReader(source.Stream); Po po = new Po { Header = new PoHeader( "Attack of the Friday Monsters Translation", "*****@*****.**", "es-ES"), }; if (reader.ReadString(4) != "CLYT") { throw new FormatException("Invalid magic stamp"); } if (reader.ReadUInt16() != 0xFEFF) { throw new FormatException("Invalid endianess"); } uint headerSize = reader.ReadUInt32(); reader.ReadUInt16(); // version reader.ReadUInt32(); // file size uint numSections = reader.ReadUInt32(); for (int i = 0; i < numSections; i++) { string section = reader.ReadString(4); uint size = reader.ReadUInt32(); if (section != "txt1") { reader.Stream.Position += size - 0x08; continue; } uint unk1 = reader.ReadUInt32(); string font = reader.ReadString(0x18).Replace("\0", string.Empty); float[] unk2 = new float[10]; for (int j = 0; j < 10; j++) { unk2[j] = BitConverter.ToSingle(reader.ReadBytes(4), 0); } byte[] data = reader.ReadBytes(0x6C - 0x18 - 4 - (10 * 4)); Encoding encoding = Encoding.GetEncoding("utf-16"); string text = string.Empty; if (size > 0x74) { text = reader.ReadString(encoding); } var entry = new PoEntry(text); entry.Context = $"s:{i}"; entry.ExtractedComments = $"1:{unk1:X8},font:{font},points:{unk2[0]},{unk2[1]},{unk2[2]},{unk2[3]},{unk2[4]},{unk2[5]},{unk2[6]},{unk2[7]},{unk2[8]},{unk2[9]},data:{BitConverter.ToString(data)}"; po.Add(entry); while (reader.Stream.Position % 4 != 0) { reader.ReadByte(); } } return(po); }
/// <summary> /// Load a PO file from a stream /// </summary> /// <param name="input">The input stream to parse.</param> /// <returns>The parsed PO file.</returns> public static PO FromFile(Stream input) { var result = new List <PoEntry>(); var previousCategory = PoLineCategory.Blank; var currentPoEntry = new PoEntry(); foreach (var line in EnumerateLines(new StreamReader(input))) { if (!CheckLine(line, previousCategory)) { continue; } if (previousCategory == PoLineCategory.MessageString && line.category != PoLineCategory.MessageString) { result.Add(currentPoEntry); currentPoEntry = new PoEntry(); } switch (line.category) { case PoLineCategory.ExtractedComment: currentPoEntry.ExtractedComments.Add(line.content); break; case PoLineCategory.NormalComment: currentPoEntry.Comments.Add(line.content); break; case PoLineCategory.SourceReference: currentPoEntry.SourceReference.Add(line.content); break; case PoLineCategory.Flags: currentPoEntry.Flags.Add(line.content); break; case PoLineCategory.MessageContext: currentPoEntry.Context = line.content; break; case PoLineCategory.MessageId: currentPoEntry.OriginalText = line.content; break; case PoLineCategory.MessageString: currentPoEntry.EditedText = line.content; break; case PoLineCategory.String: if (previousCategory == PoLineCategory.MessageContext) { currentPoEntry.Context += line.content; } else if (previousCategory == PoLineCategory.MessageId) { currentPoEntry.OriginalText += line.content; } else if (previousCategory == PoLineCategory.MessageString) { currentPoEntry.EditedText += line.content; } continue; case PoLineCategory.Blank: break; } previousCategory = line.category; } if (!result.Contains(currentPoEntry)) { result.Add(currentPoEntry); } return(new PO(result.Cast <TextEntry>().ToArray())); }
public BinaryFormat Convert(Po source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (Original == null) { throw new ArgumentNullException(nameof(Original)); } BinaryFormat binary = new BinaryFormat(); DataWriter writer = new DataWriter(binary.Stream); DataReader reader = new DataReader(Original); reader.Stream.Position = 0; // Header writer.Write(reader.ReadString(4), false); // magic stamp writer.Write(reader.ReadUInt16()); // endianness writer.Write(reader.ReadUInt32()); // header size writer.Write(reader.ReadUInt16()); // version // placeholder for size binary.Stream.PushCurrentPosition(); writer.Write(0x00); reader.ReadUInt32(); uint numSections = reader.ReadUInt32(); writer.Write(numSections); Encoding encoding = Encoding.GetEncoding("utf-16"); Queue <PoEntry> entries = new Queue <PoEntry>(source.Entries); for (int i = 0; i < numSections; i++) { string section = reader.ReadString(4); int size = reader.ReadInt32(); // Skip other sections if (section != "txt1" || size == 0x74) { writer.Write(section, false); writer.Write(size); writer.Write(reader.ReadBytes(size - 0x08)); continue; } // Get encoded text PoEntry entry = entries.Dequeue(); string text = string.IsNullOrEmpty(entry.Translated) ? entry.Original : entry.Translated; // Write new section writer.Write("txt1", false); long sizePosition = binary.Stream.Position; writer.Write(0x00); writer.Write(reader.ReadBytes(0x6C)); reader.ReadString(encoding); writer.Write(text, true, encoding); writer.WritePadding(0x00, 4); while (reader.Stream.Position % 4 != 0) { reader.ReadByte(); } long endPosition = binary.Stream.Position; binary.Stream.Position = sizePosition; writer.Write((uint)(endPosition - binary.Stream.Position + 4)); binary.Stream.Position = endPosition; } binary.Stream.PopPosition(); writer.Write((uint)binary.Stream.Length); return(binary); }