diff --git a/CardSurvival-Localization/CardSurvival-Localization.csproj b/CardSurvival-Localization/CardSurvival-Localization.csproj index 1e694d2..7f80554 100644 --- a/CardSurvival-Localization/CardSurvival-Localization.csproj +++ b/CardSurvival-Localization/CardSurvival-Localization.csproj @@ -6,8 +6,8 @@ CardSurvival_Localization enable enable - 1.2.0 - 1.2.0 + 2.0.0 + 2.0.0 diff --git a/CardSurvival-Localization/Program.cs b/CardSurvival-Localization/Program.cs index 7f4ad9d..7e367a4 100644 --- a/CardSurvival-Localization/Program.cs +++ b/CardSurvival-Localization/Program.cs @@ -4,78 +4,119 @@ using CsvHelper; using CsvHelper.Configuration; + namespace CardSurvival_Localization { internal class Program { - static void Main(string[] args) + static int Main(string[] args) { - if (args.Length < 1) + try { + if (ShowUsage(args)) + { + return -2; + } - Console.Error.WriteLine("Must be at least 1 argument: SearchPath [OutputFile]"); - return; - } - Utilities.ThrowIfNull(args[0]); + string sourceDirectory; - //---Extract info from .json files - string[] files = Directory.GetFiles(Path.GetDirectoryName(args[0])!, Path.GetFileName(args[0])!, SearchOption.AllDirectories); + if (!Directory.Exists(args[0])) + { + throw new ArgumentException($"Mod Directory does not exist: {args[0]}"); + } - LocalizationKeyExtrator localizationKeyExtrator = new(); - List localizationInfos = new(); + Console.WriteLine("Processing..."); - foreach (string file in files) - { - List result = localizationKeyExtrator.Extract(File.ReadAllText(file)); + sourceDirectory = args[0]; - result.ForEach(x => x.FileName = file); - localizationInfos.AddRange(result); - } + //---Extract info from .json files + string[] files = Directory.GetFiles(sourceDirectory, "*.json", SearchOption.AllDirectories); + LocalizationKeyExtrator localizationKeyExtrator = new(); + List localizationInfos = new(); - //---- Remove exact duplicates + foreach (string file in files) + { + List result = localizationKeyExtrator.Extract(File.ReadAllText(file)); - //Remove exact key/text (case insensitive) duplicates. - //Group by items that have more than one text for the same key. - // Note - Keys are case insensitive. Currently CSTI-ModLoader is case sensitive. - List> groupedInfo = localizationInfos - .Distinct(new LocalizationGroupCompare()) - .OrderBy(x => x.LocalizationKey) - .ThenBy(x => x.DefaultText) - .GroupBy(x => x.LocalizationKey) - .OrderBy(x => x.Key) - .ToList(); + result.ForEach(x => x.FileName = file); + localizationInfos.AddRange(result); + } - bool isConsole = args.Length < 2; + //---- Remove exact duplicates - TextWriter outputWriter = isConsole ? Console.Out : new StreamWriter(args[1]); - using (outputWriter) - { + //Remove exact key/text (case insensitive) duplicates. + //Group by items that have more than one text for the same key. + // Note - Keys are case insensitive. Currently CSTI-ModLoader is case sensitive. + List> groupedInfo = localizationInfos + .Distinct(new LocalizationGroupCompare()) + .OrderBy(x => x.LocalizationKey) + .ThenBy(x => x.DefaultText) + .GroupBy(x => x.LocalizationKey) + .OrderBy(x => x.Key) + .ToList(); + + //---Write Output Errors to file. + + StringWriter sw = new StringWriter(); + GetErrorText(sw, groupedInfo); + + string errors = sw.ToString(); - //---- Output warnings to stderr - WriteErrors(outputWriter, groupedInfo); + const string errorFileName = "SimpEn_Errors.txt"; - //---- Write to output - using (CsvWriter csvWriter = new CsvWriter(outputWriter, CultureInfo.InvariantCulture)) + if (errors.Length >0) { - foreach (var item in groupedInfo.SelectMany(x => x.ToList())) + File.WriteAllText(errorFileName ,errors); + Console.WriteLine($"One or more translation errors occurred. See {errorFileName}"); + } + + const string localizationFilePath = "SimpEn.csv"; + + using (var outputWriter = new StreamWriter(localizationFilePath)) + { + //---- Write to output + using (CsvWriter csvWriter = new CsvWriter(outputWriter, CultureInfo.InvariantCulture)) { - //The game's example SimpCn.csv shows new lines to be escaped. - string encodedText = item.DefaultText.Replace("\n", "\\n"); + foreach (var item in groupedInfo.SelectMany(x => x.ToList())) + { + //The game's example SimpCn.csv shows new lines to be escaped. + string encodedText = item.DefaultText.Replace("\n", "\\n"); - csvWriter.WriteField(item.LocalizationKey); - csvWriter.WriteField(""); - csvWriter.WriteField(encodedText); + csvWriter.WriteField(item.LocalizationKey); + csvWriter.WriteField(""); + csvWriter.WriteField(encodedText); - csvWriter.NextRecord(); + csvWriter.NextRecord(); + } } } + + Console.WriteLine("Translation Completed."); + + return 0; + } + catch (Exception ex) + { + Console.WriteLine($"Error: {ex.Message}"); + return -1; } } - private static void WriteErrors(TextWriter output, List> groupedInfo) + private static bool ShowUsage(string[] args) + { + if(args.Length != 1 || args[0].Trim() == "-h" || args[0].Trim() == "/?" || args[0].Trim() == "--help") + { + Console.WriteLine("Usage: CardSurvival-Localization "); + Console.WriteLine(); + return true; + } + + return false; + } + private static void GetErrorText(TextWriter output, List> groupedInfo) { var multiDefinedInfo = groupedInfo.Where(x => x.Count() > 1); diff --git a/CardSurvival-Localization/Properties/launchSettings.json b/CardSurvival-Localization/Properties/launchSettings.json index f8846b5..322aa98 100644 --- a/CardSurvival-Localization/Properties/launchSettings.json +++ b/CardSurvival-Localization/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "CardSurvival-Localization": { "commandName": "Project", - "commandLineArgs": "$(ProjectDir)TestData/Test.json" + "commandLineArgs": "$(ProjectDir)TestData/" } } } \ No newline at end of file diff --git a/CardSurvival-Localization/TestData/Test.json b/CardSurvival-Localization/TestData/Test.json index 07e8a4d..549931e 100644 --- a/CardSurvival-Localization/TestData/Test.json +++ b/CardSurvival-Localization/TestData/Test.json @@ -9,7 +9,7 @@ }, "Description": { "DefaultText": "test", - "LocalizationKey": "test_key", + "LocalizationKey": "test_key1", "ParentObjectID": "577682ed932c11ed892404ea56599bd2", "subTest": { "DefaultText": "some \"text\"", diff --git a/README.md b/README.md index 97a31d3..2c731b6 100644 --- a/README.md +++ b/README.md @@ -22,16 +22,17 @@ This mod parses all the .json files and extracts the card translation key and re To translate a mod based on CSTI-ModLoader to English, the process is as follows: * Run the tool, pointing to the mod's folder. - * Example: `CardSurvival-Localization.exe "E:\Mods\Apocalypse-43-1-39-1679945367\*.json" ".\SimpEn.csv"` + * Example: `CardSurvival-Localization.exe "E:\Mods\Apocalypse-43-1-39-1679945367\` + * If there are errors, there will be a file named SimpEn_Errors.txt. * Translate the SimpEnv.csv output file manually or with a translator such as translate.google.com or DeepL.com. * Put the text translated from the third column into the second column. -* Fix any errors listed at the top of the output. -* Remove the error info at the top of the file. -* Copy the file into the Mod's Localization folder as SimpEn.csv. +* Fix any errors listed in the SimpEn_Errors.txt file. +* Copy the SimpEn.csv into the Mod's Localization folder. ## Example Output ### Output From Tool +SimpEn_Errors.txt ``` Error: Multiple keys exist with different text Key: "Bp_ConservatoriesNc_CardDescription" @@ -42,8 +43,10 @@ Key: "Bp_ConservatoriesNc_CardDescription" Text: 保护植物并加速生长 File: .\example.json JSON Path: CardDescription2 +``` ------ +SimpEn.csv +``` Bp_ConservatoriesNc_CardDescription,,为植物生长提供一个温馨的家园。 Bp_ConservatoriesNc_CardDescription,,保护植物并加速生长 Bp_ConservatoriesNc_Two_CardName,,二号温室 @@ -59,12 +62,12 @@ Bp_ConservatoriesNc_Two_CardName,Greenhouse No. 2,二号温室 # Spreadsheet Recommended Workflow My recommendation would be to do as follows: * Run the tool to create the SimpEn.csv output. -* Import the CSV part of the document into Excel or Google Sheets, excluding any errors at the top of the output. +* Import the CSV part of the document into Excel or Google Sheets. * Copy the entirety of the third column (which will be in Chinese) and run it through a translator like translate.google.com or deepl.com. * Alternatively, Google Sheets has a function called GoogleTranslate that can translate text in the spreadsheet. For example Chinese to English is `=GOOGLETRANSLATE(C1,"zh","en")`. * Paste those results into the spreadsheet's second column. * Save the spreadsheet as SimpEn.csv. -* With the newly created SimpEn.csv file, fix any errors that were listed at the top of the original output. +* With the newly created SimpEn.csv file, if there is an SimpEn_Error.txt file, fix any errors indicated in that file. * Copy the SimpEn.csv file to the Mod's Localization directory. When starting the game, the Mod's text should now reflect the translated text. @@ -80,8 +83,7 @@ A couple of things I've noticed in the current mods. # Command Line Parameters |Arguments|Description| |--|--| -|File Pattern|The full path to the mod with *.json at the end. For example: "SomeModLoaderMod\\\*.json"| -|Output File|If not provided, will output to the console. Otherwise, it will write to the path specified. It is recommended to use this argument since the console can corrupt Chinese characters.| +|File Pattern|The full path to the mod| ## Source and Releases for this Utility https://github.com/NBKRedSpy/CardSurvival-Localization @@ -95,6 +97,15 @@ https://github.com/dop-lm/CSTI-ModLoader (Currently the NoReflection branch has # Version +## 2.0.0 + +### Upgrade Notes +For users that have used a previous version of the app, the arguments have changed. The application now only requires the path to the target mod and will automatically create a SimpEx.csv and SimpEx_Errors.txt in the current working directory. +### Changes +* Changed arguments to only require path. +* Changed to output errors to SimpEn_Errors.txt instead of in the translated file. +* Removed second parameter. Now always exports to SimpEn.csv in the current working folder. + ## 1.2.0 * Moved errors to output instead of stderr. * Added File Name and JSON path to errors.