Merge branch '39-add-export-for-godot-projects' into 'main'
Resolve "Add export for Godot projects" Closes #39 See merge request open-source/dotnet/i18n-commander!31
This commit is contained in:
commit
7ba7ec37b2
@ -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>
|
10
I18N Commander/Processor/ExtensionsData.cs
Normal file
10
I18N Commander/Processor/ExtensionsData.cs
Normal 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];
|
||||
}
|
||||
}
|
@ -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)
|
||||
|
151
I18N Commander/Processor/Generators/GodotCSV.cs
Normal file
151
I18N Commander/Processor/Generators/GodotCSV.cs
Normal 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
|
||||
}
|
@ -20,12 +20,14 @@ public static class TranslationProcessor
|
||||
TranslateManual = false,
|
||||
Culture = cultureInfo.Code,
|
||||
Text = string.Empty,
|
||||
TextElement = textElement,
|
||||
});
|
||||
}
|
||||
|
||||
if(missedTranslations.Count > 0)
|
||||
{
|
||||
textElement.Translations.AddRange(missedTranslations);
|
||||
db.Translations.AddRange(missedTranslations);
|
||||
db.TextElements.Update(textElement);
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user