Added Godot generator

This commit is contained in:
Thorsten Sommer 2023-02-13 20:47:22 +01:00
parent f76ab09582
commit 4918807c60
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
4 changed files with 166 additions and 6 deletions

View File

@ -1,4 +1,5 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=CSV/@EntryIndexedValue">CSV</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=EF/@EntryIndexedValue">EF</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=JSON/@EntryIndexedValue">JSON</s:String>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hwnd/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,10 @@
namespace Processor;
public static class ExtensionsData
{
public static IEnumerable<T> ReverseIt<T>(this IList<T> items)
{
for (var i = items.Count - 1; 0 <= i; i--)
yield return items[i];
}
}

View File

@ -7,18 +7,16 @@ public static class Generator
public static IGenerator Get(Type genType) => genType switch
{
Type.DOTNET => GENERATORS.ContainsKey(genType) ? GENERATORS[genType] : GENERATORS[genType] = new DotnetBigFile(),
Type.DOTNET => GENERATORS.TryGetValue(genType, out var value) ? value : GENERATORS[genType] = new DotnetBigFile(),
Type.GODOT => GENERATORS.TryGetValue(genType, out var value) ? value : GENERATORS[genType] = new GodotCSV(),
_ => VOID_GENERATOR,
};
public static async Task<ProcessorResult<long>> TriggerAllAsync()
{
var dotnetEnabled = await AppSettings.GetGeneratorDotnetEnabled();
var godotEnabled = await AppSettings.GetGeneratorGodotEnabled();
long bytesWritten = 0;
if (dotnetEnabled)
if (await AppSettings.GetGeneratorDotnetEnabled())
{
var result = await Generator.Get(Type.DOTNET).GenerateAsync();
if(!result.Successful)
@ -27,7 +25,7 @@ public static class Generator
bytesWritten += result.Result;
}
if(godotEnabled)
if(await AppSettings.GetGeneratorGodotEnabled())
{
var result = await Generator.Get(Type.GODOT).GenerateAsync();
if(!result.Successful)

View File

@ -0,0 +1,151 @@
using System.Text;
namespace Processor.Generators;
public class GodotCSV : IGenerator
{
private static readonly List<string> CULTURE_CODES = new();
#region Implementation of IGenerator
/// <inheritdoc />
public async Task<ProcessorResult<long>> GenerateAsync()
{
const string filename = "I18N.csv";
const char delimiter = ',';
var destPath = await AppSettings.GetGeneratorGodotDestinationPath();
destPath = Environment.ExpandEnvironmentVariables(destPath);
long destBytesWritten = 0;
var pathFinal = Path.Join(destPath, filename);
var pathTemp = Path.Join(destPath, filename + ".gen");
var issueFinal = string.Empty;
try
{
if(File.Exists(pathTemp))
File.Delete(pathTemp);
}
catch (IOException e)
{
return new ProcessorResult<long>(0, false, $"Cannot delete the temporary file: '{e.Message}'. Hint: Is the ransomware protection enabled in your Windows system? If so, please make sure that the I18N Commander has write permission.");
}
CULTURE_CODES.Clear();
var cultures = await AppSettings.GetCultureInfos();
foreach (var (code, _) in cultures.OrderBy(n => n.Code))
CULTURE_CODES.Add(code);
if (CULTURE_CODES.Count == 0)
return new ProcessorResult<long>(0, true, string.Empty);
try
{
await using var fileStream = new FileStream(pathTemp, FileMode.CreateNew, FileAccess.Write, FileShare.None);
await using var writer = new StreamWriter(fileStream, Encoding.UTF8);
// Write the header:
await writer.WriteLineAsync($"keys{delimiter}{string.Join(delimiter, CULTURE_CODES)}");
//
// Iterate through all sections and text elements:
//
var sectionDepth = await SectionProcessor.GetDepth();
foreach (var sectionLayer in Enumerable.Range(0, sectionDepth + 1))
{
var sections = await SectionProcessor.LoadLayer(sectionLayer);
foreach (var section in sections.OrderBy(n => n.DataKey))
foreach (var textElement in section.TextElements.OrderBy(n => n.Code))
{
//
// Build the path to the text element:
//
var textElementPath = new List<string>(section.Depth + 2)
{
textElement.Code
};
var parent = section;
while (parent is not null)
{
textElementPath.Add(parent.DataKey);
parent = parent.Parent;
}
// Write the path to the text element as key:
await writer.WriteAsync($"{string.Join(".", textElementPath.ReverseIt())}{delimiter}");
// Load all translations:
var translations = textElement.Translations.DistinctBy(n => n.Culture).ToDictionary(translation => translation.Culture, translation => translation.Text);
// Iterate through all text elements and write the translations out:
for (var cultureIndex = 0; cultureIndex < CULTURE_CODES.Count; cultureIndex++)
{
var cultureCode = CULTURE_CODES[cultureIndex];
var cultureText = translations.TryGetValue(cultureCode, out var text) ? text : string.Empty;
// Write the text with delimiter or only the text in case of the last column:
if (cultureIndex < CULTURE_CODES.Count - 1)
await writer.WriteAsync($@"""{Escape4CSV(cultureText)}""{delimiter}");
else
await writer.WriteLineAsync($@"""{Escape4CSV(cultureText)}""");
}
}
}
}
catch(IOException e)
{
// Happens, e.g. when the ransomware protection on Windows is active and
// the I18N commander is not on the exclusion list.
return new ProcessorResult<long>(0, false, $"Cannot write the generator's result file: '{e.Message}'. Hint: Is the ransomware protection enabled in your Windows system? If so, please make sure that the I18N Commander has write permission.");
}
finally
{
if (File.Exists(pathTemp))
{
destBytesWritten = new FileInfo(pathTemp).Length;
if (destBytesWritten > 0)
{
try
{
if (File.Exists(pathFinal))
File.Delete(pathFinal);
File.Move(pathTemp, pathFinal);
}
catch (IOException e)
{
// Happens when the file is still in use by the compiler, the IDE, etc.
// Depends on the timing, this happens sometimes. We ignore it, though.
issueFinal = e.Message;
}
}
}
}
if(string.IsNullOrWhiteSpace(issueFinal))
return new ProcessorResult<long>(destBytesWritten, true, string.Empty);
else
return new ProcessorResult<long>(0, false, $"Cannot move the generator's result file to the destination: '{issueFinal}'. Hint: Is the ransomware protection enabled in your Windows system? If so, please make sure that the I18N Commander has write permission.");
}
private static string Escape4CSV(string text)
{
if (string.IsNullOrWhiteSpace(text))
return string.Empty;
var sb = new StringBuilder(text.Length);
foreach (var c in text)
{
if (c == '"')
sb.Append(@""""""); // quoted double quote, i.e. prints ""
else
sb.Append(c);
}
return sb.ToString();
}
#endregion
}