Merge branch '6-add-code-generator-for-non-win-forms-projects' into 'main'

Resolve "Add code generator for non win forms projects"

Closes #6

See merge request open-source/dotnet/i18n-commander!20
This commit is contained in:
Thorsten 2022-11-01 18:28:15 +00:00
commit cf3791ed70
26 changed files with 983 additions and 273 deletions

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RiderMarkupStore">
<option name="version" value="-2154046885505616848" />
</component>
</project>

View File

@ -1,5 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CommitMessageInspectionProfile">
<profile version="1.0">
<inspection_tool class="BodyLimit" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SubjectBodySeparation" enabled="true" level="ERROR" enabled_by_default="true" />
<inspection_tool class="SubjectLimit" enabled="true" level="ERROR" enabled_by_default="true" />
</profile>
</component>
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>

View File

@ -0,0 +1,7 @@
namespace DataModel.Database;
public enum SettingGeneratorMode
{
AUTOMATIC,
MANUAL,
}

View File

@ -2,9 +2,16 @@
public static class SettingNames
{
public static readonly string DEEPL_SOURCE_CULTURE = "DeepL Source Culture";
public static readonly string CULTURE = "Culture";
public static readonly string DEEPL_ACTION = "DeepL Action";
public static readonly string DEEPL_API_KEY = "DeepL API Key";
public static readonly string DEEPL_SOURCE_CULTURE = "DeepL Source Culture";
public static readonly string DEEPL_MODE = "DeepL Mode";
public static readonly string GENERATOR_MODE = "Generator Mode";
public static readonly string GENERATOR_DOTNET_ENABLED = "Generator .NET Enabled";
public static readonly string GENERATOR_DOTNET_DESTINATION_PATH = "Generator .NET Destination Path";
public static readonly string GENERATOR_DOTNET_NAMESPACE = "Generator .NET Namespace";
public static readonly string GENERATOR_DOTNET_DEFAULT_CULTURE = "Generator .NET Default Culture";
public static readonly string GENERATOR_GODOT_ENABLED = "Generator Godot Enabled";
public static readonly string GENERATOR_GODOT_DESTINATION_PATH = "Generator Godot Destination Path";
}

View File

@ -7,284 +7,200 @@ namespace Processor;
public static class AppSettings
{
#region Common DB Code
private static readonly Dictionary<string, object> CACHES = new();
private static readonly Dictionary<string, bool> CACHE_LOADED = new();
private static async Task<T> GetSetting<T>(string settingName, T defaultValue)
{
// When possible, use the cache:
if (CACHE_LOADED.ContainsKey(settingName) && CACHE_LOADED[settingName])
return (T)CACHES[settingName];
var settingValue = defaultValue;
try
{
// Get the database:
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
// Check, if the setting is already set:
if (await db.Settings.FirstOrDefaultAsync(n => n.Code == settingName) is { } existingSetting)
{
settingValue = settingValue switch
{
bool => (T)(object)existingSetting.BoolValue,
string => (T)(object)existingSetting.TextValue,
int => (T)(object)existingSetting.IntegerValue,
Guid => (T)(object)existingSetting.GuidValue,
SettingDeepLMode or
SettingDeepLAction or
SettingGeneratorMode => (T)(object)existingSetting.IntegerValue,
_ => defaultValue,
};
return settingValue;
}
// Does not exist, so create it:
var setting = new Setting
{
Code = settingName,
};
switch (settingValue)
{
case bool:
setting.BoolValue = (bool)(object)settingValue;
break;
case string:
setting.TextValue = (string)(object)settingValue;
break;
case int:
setting.IntegerValue = (int)(object)settingValue;
break;
case Guid:
setting.GuidValue = (Guid)(object)settingValue;
break;
case SettingDeepLMode:
case SettingDeepLAction:
case SettingGeneratorMode:
setting.IntegerValue = (int)(object)settingValue;
break;
}
await db.Settings.AddAsync(setting);
await db.SaveChangesAsync();
return settingValue;
}
finally
{
CACHE_LOADED[settingName] = true;
CACHES[settingName] = settingValue!;
}
}
public static async Task SetSetting<T>(string settingName, T settingValue)
{
// Update the cache:
CACHES[settingName] = settingValue!;
CACHE_LOADED[settingName] = true;
// Get the database:
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
// Check, if the setting is already set:
if (await db.Settings.FirstOrDefaultAsync(n => n.Code == settingName) is { } existingSetting)
{
switch (settingValue)
{
case bool:
existingSetting.BoolValue = (bool)(object)settingValue;
break;
case string:
existingSetting.TextValue = (string)(object)settingValue;
break;
case int:
existingSetting.IntegerValue = (int)(object)settingValue;
break;
case Guid:
existingSetting.GuidValue = (Guid)(object)settingValue;
break;
case SettingDeepLMode:
case SettingDeepLAction:
case SettingGeneratorMode:
existingSetting.IntegerValue = (int)(object)settingValue;
break;
}
await db.SaveChangesAsync();
}
// Does not exist, so create it:
else
{
var setting = new Setting
{
Code = SettingNames.GENERATOR_DOTNET_ENABLED,
};
switch (settingValue)
{
case bool:
setting.BoolValue = (bool)(object)settingValue;
break;
case string:
setting.TextValue = (string)(object)settingValue;
break;
case int:
setting.IntegerValue = (int)(object)settingValue;
break;
case Guid:
setting.GuidValue = (Guid)(object)settingValue;
break;
case SettingDeepLMode:
case SettingDeepLAction:
case SettingGeneratorMode:
setting.IntegerValue = (int)(object)settingValue;
break;
}
await db.Settings.AddAsync(setting);
await db.SaveChangesAsync();
}
}
#endregion
#region DeepL Settings
#region DeepL Mode
private static SettingDeepLMode CACHE_DEEPL_MODE = SettingDeepLMode.DISABLED;
private static bool CACHE_DEEPL_MODE_IS_LOADED = false;
public static async Task SetDeepLMode(SettingDeepLMode mode)
{
// Convert the enum to its int value:
var intValue = (int)mode;
// Update the cache:
CACHE_DEEPL_MODE = mode;
CACHE_DEEPL_MODE_IS_LOADED = true;
// Get the database:
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
// Check, if the setting is already set:
if (await db.Settings.FirstOrDefaultAsync(n => n.Code == SettingNames.DEEPL_MODE) is {} existingSetting)
{
existingSetting.IntegerValue = intValue;
await db.SaveChangesAsync();
}
// Does not exist, so create it:
else
{
var setting = new Setting
{
Code = SettingNames.DEEPL_MODE,
IntegerValue = intValue,
};
await db.Settings.AddAsync(setting);
await db.SaveChangesAsync();
}
}
public static async Task SetDeepLMode(SettingDeepLMode mode) => await AppSettings.SetSetting(SettingNames.DEEPL_MODE, mode);
public static async Task<SettingDeepLMode> GetDeepLMode()
{
if (CACHE_DEEPL_MODE_IS_LOADED)
return CACHE_DEEPL_MODE;
// Get the database:
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
// Check, if the setting is already set:
if (await db.Settings.FirstOrDefaultAsync(n => n.Code == SettingNames.DEEPL_MODE) is { } existingSetting)
return (SettingDeepLMode) existingSetting.IntegerValue;
// Does not exist, so create it:
var setting = new Setting
{
Code = SettingNames.DEEPL_MODE,
IntegerValue = (int)SettingDeepLMode.DISABLED,
};
await db.Settings.AddAsync(setting);
await db.SaveChangesAsync();
var mode = (SettingDeepLMode) setting.IntegerValue;
CACHE_DEEPL_MODE = mode;
CACHE_DEEPL_MODE_IS_LOADED = true;
return mode;
}
public static async Task<SettingDeepLMode> GetDeepLMode() => await AppSettings.GetSetting(SettingNames.DEEPL_MODE, SettingDeepLMode.DISABLED);
#endregion
#region DeepL API Key
private static string CACHE_DEEPL_API_KEY = string.Empty;
private static bool CACHE_DEEPL_API_KEY_IS_LOADED = false;
public static async Task SetDeepLAPIKey(string apiKey)
{
// Update the cache:
CACHE_DEEPL_API_KEY = apiKey;
CACHE_DEEPL_API_KEY_IS_LOADED = true;
// Get the database:
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
// Check, if the setting is already set:
if (await db.Settings.FirstOrDefaultAsync(n => n.Code == SettingNames.DEEPL_API_KEY) is {} existingSetting)
{
existingSetting.TextValue = apiKey;
await db.SaveChangesAsync();
}
// Does not exist, so create it:
else
{
var setting = new Setting
{
Code = SettingNames.DEEPL_API_KEY,
TextValue = apiKey,
};
await db.Settings.AddAsync(setting);
await db.SaveChangesAsync();
}
}
public static async Task<string> GetDeepLAPIKey()
{
// Check the cache:
if (CACHE_DEEPL_API_KEY_IS_LOADED)
return CACHE_DEEPL_API_KEY;
// Get the database:
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
// Check, if the setting is already set:
if (await db.Settings.FirstOrDefaultAsync(n => n.Code == SettingNames.DEEPL_API_KEY) is { } existingSetting)
return existingSetting.TextValue;
// Does not exist, so create it:
var setting = new Setting
{
Code = SettingNames.DEEPL_API_KEY,
TextValue = string.Empty,
};
await db.Settings.AddAsync(setting);
await db.SaveChangesAsync();
var key = setting.TextValue;
CACHE_DEEPL_API_KEY = key;
CACHE_DEEPL_API_KEY_IS_LOADED = true;
return key;
}
public static async Task SetDeepLAPIKey(string apiKey) => await AppSettings.SetSetting(SettingNames.DEEPL_API_KEY, apiKey);
public static async Task<string> GetDeepLAPIKey() => await AppSettings.GetSetting(SettingNames.DEEPL_API_KEY, string.Empty);
#endregion
#region DeepL Action
private static SettingDeepLAction CACHE_DEEPL_ACTION = SettingDeepLAction.MANUAL;
private static bool CACHE_DEEPL_ACTION_IS_LOADED = false;
public static async Task SetDeepLAction(SettingDeepLAction action)
{
// Convert the enum to its int value:
var intValue = (int)action;
// Update the cache:
CACHE_DEEPL_ACTION = action;
CACHE_DEEPL_ACTION_IS_LOADED = true;
// Get the database:
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
// Check, if the setting is already set:
if (await db.Settings.FirstOrDefaultAsync(n => n.Code == SettingNames.DEEPL_ACTION) is {} existingSetting)
{
existingSetting.IntegerValue = intValue;
await db.SaveChangesAsync();
}
// Does not exist, so create it:
else
{
var setting = new Setting
{
Code = SettingNames.DEEPL_ACTION,
IntegerValue = intValue,
};
await db.Settings.AddAsync(setting);
await db.SaveChangesAsync();
}
}
public static async Task<SettingDeepLAction> GetDeepLAction()
{
// Check the cache:
if (CACHE_DEEPL_ACTION_IS_LOADED)
return CACHE_DEEPL_ACTION;
// Get the database:
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
// Check, if the setting is already set:
if (await db.Settings.FirstOrDefaultAsync(n => n.Code == SettingNames.DEEPL_ACTION) is { } existingSetting)
return (SettingDeepLAction) existingSetting.IntegerValue;
// Does not exist, so create it:
var setting = new Setting
{
Code = SettingNames.DEEPL_ACTION,
IntegerValue = (int)SettingDeepLAction.MANUAL,
};
await db.Settings.AddAsync(setting);
await db.SaveChangesAsync();
var action = (SettingDeepLAction) setting.IntegerValue;
CACHE_DEEPL_ACTION = action;
CACHE_DEEPL_ACTION_IS_LOADED = true;
return action;
}
public static async Task SetDeepLAction(SettingDeepLAction action) => await AppSettings.SetSetting(SettingNames.DEEPL_ACTION, action);
public static async Task<SettingDeepLAction> GetDeepLAction() => await AppSettings.GetSetting(SettingNames.DEEPL_ACTION, SettingDeepLAction.MANUAL);
#endregion
#region DeepL Source Culture
private static int CACHE_DEEPL_SOURCE_CULTURE = -1;
private static bool CACHE_DEEPL_SOURCE_CULTURE_IS_LOADED = false;
public static async Task SetDeepLSourceCultureIndex(int cultureIndex)
{
// Update the cache:
CACHE_DEEPL_SOURCE_CULTURE = cultureIndex;
CACHE_DEEPL_SOURCE_CULTURE_IS_LOADED = true;
// Get the database:
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
// Check, if the setting is already set:
if (await db.Settings.FirstOrDefaultAsync(n => n.Code == SettingNames.DEEPL_SOURCE_CULTURE) is {} existingSetting)
{
existingSetting.IntegerValue = cultureIndex;
await db.SaveChangesAsync();
}
// Does not exist, so create it:
else
{
var setting = new Setting
{
Code = SettingNames.DEEPL_SOURCE_CULTURE,
IntegerValue = cultureIndex,
};
await db.Settings.AddAsync(setting);
await db.SaveChangesAsync();
}
}
public static async Task<int> GetDeepLSourceCultureIndex()
{
// Check the cache:
if (CACHE_DEEPL_SOURCE_CULTURE_IS_LOADED)
return CACHE_DEEPL_SOURCE_CULTURE;
// Get the database:
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
// Check, if the setting is already set:
if (await db.Settings.FirstOrDefaultAsync(n => n.Code == SettingNames.DEEPL_SOURCE_CULTURE) is { } existingSetting)
return existingSetting.IntegerValue;
// Does not exist, so create it:
var setting = new Setting
{
Code = SettingNames.DEEPL_SOURCE_CULTURE,
IntegerValue = -1,
};
await db.Settings.AddAsync(setting);
await db.SaveChangesAsync();
var cultureIndex = setting.IntegerValue;
CACHE_DEEPL_SOURCE_CULTURE = cultureIndex;
CACHE_DEEPL_SOURCE_CULTURE_IS_LOADED = true;
return cultureIndex;
}
public static async Task SetDeepLSourceCultureIndex(int cultureIndex) => await AppSettings.SetSetting(SettingNames.DEEPL_SOURCE_CULTURE, cultureIndex);
public static async Task<int> GetDeepLSourceCultureIndex() => await AppSettings.GetSetting(SettingNames.DEEPL_SOURCE_CULTURE, -1);
#endregion
#endregion
#region Translation Settings
#region Culture Settings
#region List of culture indices
@ -432,4 +348,64 @@ public static class AppSettings
#endregion
#endregion
#region Generator Settings
#region Generator Mode
public static async Task<SettingGeneratorMode> GetGeneratorMode() => await AppSettings.GetSetting(SettingNames.GENERATOR_MODE, SettingGeneratorMode.MANUAL);
public static async Task SetGeneratorMode(SettingGeneratorMode mode) => await AppSettings.SetSetting(SettingNames.GENERATOR_MODE, mode);
#endregion
#region .NET Generator Enabled/Disabled
public static async Task<bool> GetGeneratorDotnetEnabled() => await AppSettings.GetSetting(SettingNames.GENERATOR_DOTNET_ENABLED, false);
public static async Task SetGeneratorDotnetEnabled(bool enabled) => await AppSettings.SetSetting(SettingNames.GENERATOR_DOTNET_ENABLED, enabled);
#endregion
#region .NET Generator Destination Path
public static async Task<string> GetGeneratorDotnetDestinationPath() => await AppSettings.GetSetting(SettingNames.GENERATOR_DOTNET_DESTINATION_PATH, string.Empty);
public static async Task SetGeneratorDotnetDestinationPath(string path) => await AppSettings.SetSetting(SettingNames.GENERATOR_DOTNET_DESTINATION_PATH, path);
#endregion
#region .NET Generator Namespace
public static async Task<string> GetGeneratorDotnetNamespace() => await AppSettings.GetSetting(SettingNames.GENERATOR_DOTNET_NAMESPACE, "I18N");
public static async Task SetGeneratorDotnetNamespace(string updatedNamespace) => await AppSettings.SetSetting(SettingNames.GENERATOR_DOTNET_NAMESPACE, updatedNamespace);
#endregion
#region .NET Generator Default Culture
public static async Task<int> GetGeneratorDotnetDefaultCultureIndex() => await AppSettings.GetSetting(SettingNames.GENERATOR_DOTNET_DEFAULT_CULTURE, 0);
public static async Task SetGeneratorDotnetDefaultCultureIndex(int updatedCulture) => await AppSettings.SetSetting(SettingNames.GENERATOR_DOTNET_DEFAULT_CULTURE, updatedCulture);
#endregion
#region Godot Generator Enabled/Disabled
public static async Task<bool> GetGeneratorGodotEnabled() => await AppSettings.GetSetting(SettingNames.GENERATOR_GODOT_ENABLED, false);
public static async Task SetGeneratorGodotEnabled(bool enabled) => await AppSettings.SetSetting(SettingNames.GENERATOR_GODOT_ENABLED, enabled);
#endregion
#region Godot Generator Destination Path
public static async Task<string> GetGeneratorGodotDestinationPath() => await AppSettings.GetSetting(SettingNames.GENERATOR_GODOT_DESTINATION_PATH, string.Empty);
public static async Task SetGeneratorGodotDestinationPath(string path) => await AppSettings.SetSetting(SettingNames.GENERATOR_GODOT_DESTINATION_PATH, path);
#endregion
#endregion
}

View File

@ -28,7 +28,7 @@ public static class DeepL
return new DeepLUsage(true, usage.Character!.Count, usage.Character.Limit);
}
catch (AuthorizationException e)
catch (AuthorizationException)
{
DEEPL_NOT_AVAILABLE = true;
return new DeepLUsage(false, 0, 1, true);
@ -63,7 +63,7 @@ public static class DeepL
return translation.Text;
}
catch (AuthorizationException e)
catch (AuthorizationException)
{
DEEPL_NOT_AVAILABLE = true;
return string.Empty;

View File

@ -0,0 +1,175 @@
using System.Text;
using DataModel.Database;
namespace Processor.Generators;
public class DotnetBigFile : IGenerator
{
private static readonly List<string> CULTURE_CODES = new();
private static int DEFAULT_CULTURE_INDEX = -1;
public async Task<ProcessorResult<long>> GenerateAsync()
{
const string filename = "I18N.cs";
var destPath = await AppSettings.GetGeneratorDotnetDestinationPath();
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)
CULTURE_CODES.Add(code);
DEFAULT_CULTURE_INDEX = await AppSettings.GetGeneratorDotnetDefaultCultureIndex();
DEFAULT_CULTURE_INDEX -= 1; // 1-based to 0-based
try
{
await using var fileStream = new FileStream(pathTemp, FileMode.CreateNew, FileAccess.Write, FileShare.None);
await using var writer = new StreamWriter(fileStream, Encoding.UTF8);
await writer.WriteLineAsync($"namespace {await AppSettings.GetGeneratorDotnetNamespace()};");
await this.CreateStaticClass(writer, "I18N", 0, async (streamWriter, indention) =>
{
var indentionString = this.AddIndention(indention);
var buildTime = DateTime.UtcNow;
await writer.WriteLineAsync($"{indentionString}public static readonly string BUILD_TIME = \"{buildTime:yyyy.MM.dd HH:mm:ss}\";");
await writer.WriteLineAsync($"{indentionString}public static readonly long BUILD_TIME_TICKS = {buildTime.Ticks};");
await writer.WriteLineAsync();
await writer.WriteLineAsync($"{indentionString}private static int PREVIOUS_CULTURE = -1;");
// Go through the first layer of sections:
var sections = await SectionProcessor.LoadLayer(0);
foreach (var section in sections)
await this.TransformSection(writer, indention, section);
});
}
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 string AddIndention(int indention) => new string(' ', indention * 3);
private async Task TransformSection(TextWriter writer, int indention, Section section)
{
await this.CreateStaticClass(writer, section.DataKey, indention, async (_, innerIndention) =>
{
var textElements = section.TextElements;
foreach (var textElement in textElements)
await this.TransformTextElement(writer, innerIndention, textElement);
var childSections = await SectionProcessor.GetChildSections(section.DataKey);
foreach (var childSection in childSections)
await this.TransformSection(writer, innerIndention, childSection);
});
}
private async Task TransformTextElement(TextWriter writer, int indention, TextElement textElement)
{
var indentionString = this.AddIndention(indention);
var indentionPropString = this.AddIndention(indention + 1);
var indentionPropInner1String = this.AddIndention(indention + 2);
var indentionPropInner2String = this.AddIndention(indention + 3);
var indentionPropInner3String = this.AddIndention(indention + 4);
await writer.WriteLineAsync($"{indentionString}private static string E_{textElement.Code}_CACHE = \"\";");
await writer.WriteLineAsync($"{indentionString}public static string E_{textElement.Code}");
await writer.WriteLineAsync($"{indentionString}{{");
await writer.WriteLineAsync($"{indentionPropString}get");
await writer.WriteLineAsync($"{indentionPropString}{{");
await writer.WriteLineAsync($"{indentionPropInner1String}var currentCulture = CultureInfo.CurrentCulture.Name;");
await writer.WriteLineAsync($"{indentionPropInner1String}if(PREVIOUS_CULTURE == currentCulture.GetHashCode())");
await writer.WriteLineAsync($"{indentionPropInner2String}return E_{textElement.Code}_CACHE;");
await writer.WriteLineAsync($"{indentionPropInner1String}else");
await writer.WriteLineAsync($"{indentionPropInner1String}{{");
await writer.WriteLineAsync($"{indentionPropInner2String}PREVIOUS_CULTURE = currentCulture.GetHashCode();");
for (var cultureIndex = 0; cultureIndex < CULTURE_CODES.Count; cultureIndex++)
{
if(cultureIndex == 0)
await writer.WriteLineAsync($"{indentionPropInner2String}if (currentCulture.StartsWith(\"{CULTURE_CODES[cultureIndex]}\", StringComparison.InvariantCultureIgnoreCase))");
else
await writer.WriteLineAsync($"{indentionPropInner2String}else if (currentCulture.StartsWith(\"{CULTURE_CODES[cultureIndex]}\", StringComparison.InvariantCultureIgnoreCase))");
await writer.WriteLineAsync($"{indentionPropInner2String}{{");
var cultureTranslation = textElement.Translations.FirstOrDefault(x => x.Culture == CULTURE_CODES[cultureIndex]);
var cultureText = cultureTranslation?.Text ?? string.Empty;
await writer.WriteLineAsync($"{indentionPropInner3String}var text = @\"{Utils.MadeVerbatimStringLiteral(cultureText)}\";");
await writer.WriteLineAsync($"{indentionPropInner3String}E_{textElement.Code}_CACHE = text;");
await writer.WriteLineAsync($"{indentionPropInner3String}return text;");
await writer.WriteLineAsync($"{indentionPropInner2String}}}");
}
// Add the default case:
await writer.WriteLineAsync($"{indentionPropInner2String}else");
await writer.WriteLineAsync($"{indentionPropInner2String}{{");
var defaultCultureTranslation = textElement.Translations.FirstOrDefault(x => x.Culture == CULTURE_CODES[DEFAULT_CULTURE_INDEX]);
var defaultCultureText = defaultCultureTranslation?.Text ?? string.Empty;
await writer.WriteLineAsync($"{indentionPropInner3String}var text = @\"{Utils.MadeVerbatimStringLiteral(defaultCultureText)}\";");
await writer.WriteLineAsync($"{indentionPropInner3String}E_{textElement.Code}_CACHE = text;");
await writer.WriteLineAsync($"{indentionPropInner3String}return text;");
await writer.WriteLineAsync($"{indentionPropInner2String}}}");
await writer.WriteLineAsync($"{indentionPropInner1String}}}");
await writer.WriteLineAsync($"{indentionPropString}}}");
await writer.WriteLineAsync($"{indentionString}}}");
await writer.WriteLineAsync();
}
private async Task CreateStaticClass(TextWriter writer, string name, int indention, Func<TextWriter, int, Task> content)
{
var indentionString = this.AddIndention(indention);
await writer.WriteLineAsync(indentionString);
await writer.WriteLineAsync($"{indentionString}public static class {name}");
await writer.WriteLineAsync($"{indentionString}{{");
await content(writer, indention + 1);
await writer.WriteLineAsync($"{indentionString}}}");
}
}

View File

@ -0,0 +1,41 @@
namespace Processor.Generators;
public static class Generator
{
private static readonly Dictionary<Type, IGenerator> GENERATORS = new();
private static readonly IGenerator VOID_GENERATOR = new VoidGenerator();
public static IGenerator Get(Type genType) => genType switch
{
Type.DOTNET => GENERATORS.ContainsKey(genType) ? GENERATORS[genType] : GENERATORS[genType] = new DotnetBigFile(),
_ => VOID_GENERATOR,
};
public static async Task<ProcessorResult<long>> TriggerAllAsync()
{
var dotnetEnabled = await AppSettings.GetGeneratorDotnetEnabled();
var godotEnabled = await AppSettings.GetGeneratorGodotEnabled();
long bytesWritten = 0;
if (dotnetEnabled)
{
var result = await Generator.Get(Type.DOTNET).GenerateAsync();
if(!result.Successful)
return result;
bytesWritten += result.Result;
}
if(godotEnabled)
{
var result = await Generator.Get(Type.GODOT).GenerateAsync();
if(!result.Successful)
return result;
bytesWritten += result.Result;
}
return new ProcessorResult<long>(bytesWritten);
}
}

View File

@ -0,0 +1,6 @@
namespace Processor.Generators;
public interface IGenerator
{
public Task<ProcessorResult<long>> GenerateAsync();
}

View File

@ -0,0 +1,9 @@
namespace Processor.Generators;
public enum Type
{
NONE,
DOTNET,
GODOT,
}

View File

@ -0,0 +1,6 @@
namespace Processor.Generators;
public class VoidGenerator : IGenerator
{
public Task GenerateAsync() => Task.CompletedTask;
}

View File

@ -198,4 +198,12 @@ public static class SectionProcessor
return $"Section's path: {path}";
}
public static async Task<List<Section>> GetChildSections(string sectionKey)
{
await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>();
var section = await db.Sections.FirstAsync(n => n.DataKey == sectionKey);
return await db.Sections.Where(n => n.Parent == section).ToListAsync();
}
}

View File

@ -124,7 +124,7 @@ public static class TextElementProcessor
// Save the changes:
await db.SaveChangesAsync();
}
catch (DbUpdateException updateException)
catch (DbUpdateException)
{
}
}

View File

@ -1,4 +1,5 @@
using System.Linq.Expressions;
using System.Text;
using Microsoft.EntityFrameworkCore;
namespace Processor;
@ -46,4 +47,25 @@ internal static class Utils
return code;
}
public static string MadeVerbatimStringLiteral(string text)
{
IEnumerable<char> ConvertAll(string source)
{
foreach(var c in source)
if(c == '"')
{
yield return '"';
yield return '"';
}
else
yield return c;
}
var sb = new StringBuilder();
foreach(var c in ConvertAll(text))
sb.Append(c);
return sb.ToString();
}
}

View File

@ -4,10 +4,26 @@ namespace UI_WinForms;
internal static class AppEvents
{
internal static void ResetAllSubscriptions()
{
WhenSettingsChanged = null;
WhenSectionChanged = null;
WhenTextElementChanged = null;
WhenTranslationChanged = null;
}
#region Event: Settings were
internal static event EventHandler? WhenSettingsChanged;
internal static void SettingsChanged() => WhenSettingsChanged?.Invoke(null, EventArgs.Empty);
#endregion
#region Event: Section was changed
// Section changed event which can be subscribed:
internal static event EventHandler<Section> WhenSectionChanged;
internal static event EventHandler<Section>? WhenSectionChanged;
// Method to raise the section changed event:
internal static void SectionChanged(Section section) => WhenSectionChanged?.Invoke(null, section);
@ -17,7 +33,7 @@ internal static class AppEvents
#region Event: Text element was changed
// Text element changed event which can be subscribed:
internal static event EventHandler<TextElement?> WhenTextElementChanged;
internal static event EventHandler<TextElement?>? WhenTextElementChanged;
// Method to raise the text element changed event:
internal static void TextElementChanged(TextElement? textElement) => WhenTextElementChanged?.Invoke(null, textElement);
@ -27,7 +43,7 @@ internal static class AppEvents
#region Translation was changed
// Translation changed event which can be subscribed:
internal static event EventHandler<Translation?> WhenTranslationChanged;
internal static event EventHandler<Translation?>? WhenTranslationChanged;
// Method to raise the translation changed event:
internal static void TranslationChanged(Translation? translation) => WhenTranslationChanged?.Invoke(null, translation);

View File

@ -16,6 +16,7 @@ public partial class Main : UserControl
if(result == DialogResult.Yes)
{
Program.RestartMainApp = true;
AppEvents.ResetAllSubscriptions();
this.ParentForm!.Close();
}
}

View File

@ -34,6 +34,7 @@
this.buttonAdd = new System.Windows.Forms.Button();
this.buttonRemove = new System.Windows.Forms.Button();
this.buttonRename = new System.Windows.Forms.Button();
this.buttonGenerate = new System.Windows.Forms.Button();
this.treeView = new System.Windows.Forms.TreeView();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.tableLayout.SuspendLayout();
@ -61,6 +62,7 @@
this.flowLayoutBottom.Controls.Add(this.buttonAdd);
this.flowLayoutBottom.Controls.Add(this.buttonRemove);
this.flowLayoutBottom.Controls.Add(this.buttonRename);
this.flowLayoutBottom.Controls.Add(this.buttonGenerate);
this.flowLayoutBottom.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutBottom.Location = new System.Drawing.Point(0, 445);
this.flowLayoutBottom.Margin = new System.Windows.Forms.Padding(0);
@ -115,6 +117,22 @@
this.buttonRename.UseVisualStyleBackColor = true;
this.buttonRename.Click += new System.EventHandler(this.buttonRename_Click);
//
// buttonGenerate
//
this.buttonGenerate.AutoSize = true;
this.buttonGenerate.Enabled = false;
this.buttonGenerate.FlatAppearance.BorderSize = 0;
this.buttonGenerate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.buttonGenerate.Image = global::UI_WinForms.Resources.Icons.icons8_code_512__2_;
this.buttonGenerate.Location = new System.Drawing.Point(201, 3);
this.buttonGenerate.Name = "buttonGenerate";
this.buttonGenerate.Size = new System.Drawing.Size(60, 60);
this.buttonGenerate.TabIndex = 3;
this.buttonGenerate.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText;
this.toolTip.SetToolTip(this.buttonGenerate, "Triggers all enabled generators");
this.buttonGenerate.UseVisualStyleBackColor = true;
this.buttonGenerate.Click += new System.EventHandler(this.buttonGenerate_Click);
//
// treeView
//
this.treeView.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
@ -159,5 +177,6 @@
private TreeView treeView;
private ToolTip toolTip;
private Button buttonRename;
private Button buttonGenerate;
}
}

View File

@ -1,13 +1,16 @@
using DataModel.Database;
using Processor;
using Processor.Generators;
using UI_WinForms.Dialogs;
using UI_WinForms.Resources;
using Timer = System.Timers.Timer;
namespace UI_WinForms.Components;
public partial class SectionTree : UserControl
{
private static readonly Dictionary<TreeNode, EventHandler<DataModel.Database.Translation?>> NODE_PROGRESS_HANDLERS = new();
private static readonly Dictionary<TreeNode, EventHandler<DataModel.Database.Translation?>?> NODE_PROGRESS_HANDLERS = new();
private readonly Timer generatorTimer;
public SectionTree()
{
@ -26,10 +29,39 @@ public partial class SectionTree : UserControl
// Set the image list to the tree view:
this.treeView.ImageList = imgList;
// The generator timer:
this.generatorTimer = new Timer
{
Enabled = false, // disable timer for now,
Interval = 6_000, // 6 second interval,
AutoReset = false, // runs only once
};
this.generatorTimer.Elapsed += async (sender, args) => await this.PerformGenerators();
// Subscribe to the load event:
this.Load += this.LoadNodes;
this.Load += (sender, args) => this.SetupGeneratorButton();
// Subscribe to all event for triggering the generators:
AppEvents.WhenTranslationChanged += (sender, translation) => this.GeneratorEvent();
AppEvents.WhenSettingsChanged += (sender, args) => this.GeneratorEvent();
}
private async void SetupGeneratorButton()
{
this.buttonGenerate.Enabled = false;
// Depend the generator button's visibility on the generator settings:
this.buttonGenerate.Enabled = await AppSettings.GetGeneratorDotnetEnabled() || await AppSettings.GetGeneratorGodotEnabled();
// Subscribe to the changed settings event:
AppEvents.WhenSettingsChanged += async (sender, args) =>
{
this.buttonGenerate.Enabled = await AppSettings.GetGeneratorDotnetEnabled() || await AppSettings.GetGeneratorGodotEnabled();
};
}
private async void LoadNodes(object? sender, EventArgs e)
{
if(this.DesignMode)
@ -277,4 +309,31 @@ public partial class SectionTree : UserControl
selectedNode.Text = alteredSection.Result!.Name;
selectedNode.Name = alteredSection.Result.DataKey; // [sic] name is the key
}
private async void buttonGenerate_Click(object sender, EventArgs e) => await this.PerformGenerators();
private async void GeneratorEvent()
{
if(await AppSettings.GetGeneratorMode() == SettingGeneratorMode.MANUAL)
return;
if (this.generatorTimer.Enabled)
this.generatorTimer.Stop();
this.generatorTimer.Start();
}
private async Task PerformGenerators()
{
if (this.buttonGenerate.InvokeRequired)
{
await this.buttonGenerate.Invoke(this.PerformGenerators);
return;
}
this.buttonGenerate.Enabled = false;
var result = await Generator.TriggerAllAsync();
result.ProcessError();
this.buttonGenerate.Enabled = true;
}
}

View File

@ -77,6 +77,8 @@ public sealed partial class Setting : UserControl
{
if(this.data.ChangeNeedsRestart)
this.needRestart = true;
AppEvents.SettingsChanged();
}
private void UpdateExplanation() => this.labelExplanation.Text = this.data.SettingExplanation();
@ -210,7 +212,7 @@ public sealed partial class Setting : UserControl
};
// Update the explanation text. Therefore, we need to get the setting object through the chain of parents:
var setting = (Setting) ((Control) sender).Parent.Parent.Parent;
var setting = (Setting) (((Control) sender!)!).Parent.Parent.Parent;
setting.UpdateExplanation();
};
@ -257,7 +259,6 @@ public sealed partial class Setting : UserControl
};
// Setup the change event handler:
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
dropdown.SelectedValueChanged += async (sender, args) => await AppSettings.SetDeepLAction(dropdown.SelectedIndex switch
{
0 => SettingDeepLAction.MANUAL,
@ -265,6 +266,7 @@ public sealed partial class Setting : UserControl
_ => SettingDeepLAction.MANUAL,
});
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
// Apply the desired layout:
dropdown.Dock = DockStyle.Fill;
@ -314,12 +316,12 @@ public sealed partial class Setting : UserControl
dropdown.SelectedIndex = currentCultureDropdownIndex;
// Setup the change event handler:
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
dropdown.SelectedValueChanged += async (sender, args) =>
{
if(dropdown.SelectedItem is ComboBoxItem selectedItem)
await AppSettings.SetDeepLSourceCultureIndex(selectedItem.CultureIndex);
};
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
// Apply the desired layout:
dropdown.Dock = DockStyle.Fill;
@ -388,14 +390,314 @@ public sealed partial class Setting : UserControl
cultureIndices.Remove(innerLoopIndex);
}
}
private static async Task<Setting> ShowGeneratorModeSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorMode();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator Mode",
ChangeNeedsRestart: false,
SettingExplanation: () => "The generator mode determines how the translation files are generated.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// We set up a combo box with the available actions:
var dropdown = new ComboBox();
dropdown.Items.Add("Automatic generation");
dropdown.Items.Add("Manual generation");
dropdown.SelectedIndex = currentSetting switch
{
SettingGeneratorMode.AUTOMATIC => 0,
SettingGeneratorMode.MANUAL => 1,
_ => 0,
};
// Setup the change event handler:
dropdown.SelectedValueChanged += async (sender, args) => await AppSettings.SetGeneratorMode(dropdown.SelectedIndex switch
{
0 => SettingGeneratorMode.AUTOMATIC,
1 => SettingGeneratorMode.MANUAL,
_ => SettingGeneratorMode.AUTOMATIC,
});
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
// Apply the desired layout:
dropdown.Dock = DockStyle.Fill;
dropdown.DropDownStyle = ComboBoxStyle.DropDownList;
return dropdown;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorDotnetEnabledSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorDotnetEnabled();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: .NET",
ChangeNeedsRestart: false,
SettingExplanation: () => "When enabled, .NET translation files are generated. Requires a .NET 6 or newer project.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up an checkbox:
var checkbox = new CheckBox();
checkbox.Checked = currentSetting;
checkbox.CheckedChanged += async (sender, args) => await AppSettings.SetGeneratorDotnetEnabled(checkbox.Checked);
checkbox.CheckedChanged += (sender, args) => changeTrigger();
checkbox.Text = "Enable .NET Generator";
// Apply the desired layout:
checkbox.Dock = DockStyle.Fill;
return checkbox;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorDotnetDestinationPathSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorDotnetDestinationPath();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: .NET Destination Path",
ChangeNeedsRestart: false,
SettingExplanation: () => "The destination path for the .NET translation files. You might use environment variables like %USERPROFILE%.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up a horizontal layout:
var layout = new TableLayoutPanel();
layout.ColumnCount = 2;
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 66F));
layout.RowCount = 1;
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
layout.Dock = DockStyle.Fill;
// Set up a textbox:
var textbox = new TextBox();
textbox.Text = currentSetting;
textbox.TextChanged += async (sender, args) => await AppSettings.SetGeneratorDotnetDestinationPath(textbox.Text);
textbox.TextChanged += (sender, args) => changeTrigger();
textbox.Dock = DockStyle.Fill;
textbox.Margin = new Padding(0, 13, 0, 13);
layout.Controls.Add(textbox, 0, 0);
// Set up a button:
var button = new Button();
button.Text = string.Empty;
button.Image = Icons.icons8_folder_tree_512;
button.FlatStyle = FlatStyle.Flat;
button.FlatAppearance.BorderSize = 0;
button.BackColor = Color.Empty;
button.UseVisualStyleBackColor = true;
button.Size = new Size(60, 60);
button.Click += (sender, args) =>
{
var dialog = new FolderBrowserDialog();
dialog.SelectedPath = textbox.Text;
dialog.InitialDirectory = textbox.Text;
dialog.Description = "Select the destination path for the .NET translation files.";
dialog.ShowNewFolderButton = true;
if (dialog.ShowDialog() == DialogResult.OK)
textbox.Text = dialog.SelectedPath;
};
button.Dock = DockStyle.Fill;
layout.Controls.Add(button, 1, 0);
return layout;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorDotnetNamespaceSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorDotnetNamespace();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: .NET Namespace",
ChangeNeedsRestart: false,
SettingExplanation: () => "The namespace for the .NET I18N files.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up a textbox:
var textbox = new TextBox();
textbox.Text = currentSetting;
textbox.TextChanged += async (sender, args) => await AppSettings.SetGeneratorDotnetNamespace(textbox.Text);
textbox.TextChanged += (sender, args) => changeTrigger();
textbox.Dock = DockStyle.Fill;
textbox.Margin = new Padding(0, 13, 0, 13);
return textbox;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorDotnetDefaultCultureSettingAsync()
{
var currentSourceCultureIndex = await AppSettings.GetGeneratorDotnetDefaultCultureIndex();
// We load the corresponding culture for that index. As dropdown items, we show
// all other available cultures:
var allCultures = await AppSettings.GetCultureInfos();
// Attention: We have to store the culture's index, because the index is not
// continuous and can change when the user adds or removes a culture!
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: .NET Default Culture",
ChangeNeedsRestart: false,
SettingExplanation: () => "The default culture for the .NET, which is used when no culture is specified or available.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
var dropdown = new ComboBox();
var currentCultureDropdownIndex = 0;
for (var n = 0; n < allCultures.Count; n++)
{
var cultureInfo = allCultures[n];
if(cultureInfo.Index == currentSourceCultureIndex)
currentCultureDropdownIndex = n;
dropdown.Items.Add(new ComboBoxItem($"{cultureInfo.Index}.: {cultureInfo.Code}", cultureInfo.Index));
}
dropdown.SelectedIndex = currentCultureDropdownIndex;
// Setup the change event handler:
dropdown.SelectedValueChanged += async (sender, args) =>
{
if(dropdown.SelectedItem is ComboBoxItem selectedItem)
await AppSettings.SetGeneratorDotnetDefaultCultureIndex(selectedItem.CultureIndex);
};
dropdown.SelectedValueChanged += (sender, args) => changeTrigger();
// Apply the desired layout:
dropdown.Dock = DockStyle.Fill;
dropdown.DropDownStyle = ComboBoxStyle.DropDownList;
return dropdown;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorGodotEnabledSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorGodotEnabled();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: Godot",
ChangeNeedsRestart: false,
SettingExplanation: () => "When enabled, Godot translation files are generated. Requires a Godot 3.5 or newer project.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up an checkbox:
var checkbox = new CheckBox();
checkbox.Checked = currentSetting;
checkbox.CheckedChanged += async (sender, args) => await AppSettings.SetGeneratorGodotEnabled(checkbox.Checked);
checkbox.CheckedChanged += (sender, args) => changeTrigger();
checkbox.Text = "Enable Godot Generator";
// Apply the desired layout:
checkbox.Dock = DockStyle.Fill;
return checkbox;
}
);
return new Setting(settingData);
}
private static async Task<Setting> ShowGeneratorGodotDestinationPathSettingAsync()
{
var currentSetting = await AppSettings.GetGeneratorGodotDestinationPath();
var settingData = new SettingUIData(
Icon: Icons.icons8_code_512,
SettingName: () => "Generator: Godot Destination Path",
ChangeNeedsRestart: false,
SettingExplanation: () => "The destination path for the Godot translation files. You might use environment variables like %USERPROFILE%.",
SettingExplanationLink: () => (string.Empty, string.Empty),
SetupDataControl: (changeTrigger) =>
{
// Set up a horizontal layout:
var layout = new TableLayoutPanel();
layout.ColumnCount = 2;
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 66F));
layout.RowCount = 1;
layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100F));
layout.Dock = DockStyle.Fill;
// Set up a textbox:
var textbox = new TextBox();
textbox.Text = currentSetting;
textbox.TextChanged += async (sender, args) => await AppSettings.SetGeneratorGodotDestinationPath(textbox.Text);
textbox.TextChanged += (sender, args) => changeTrigger();
textbox.Dock = DockStyle.Fill;
textbox.Margin = new Padding(0, 13, 0, 13);
layout.Controls.Add(textbox, 0, 0);
// Set up a button:
var button = new Button();
button.Text = string.Empty;
button.Image = Icons.icons8_folder_tree_512;
button.FlatStyle = FlatStyle.Flat;
button.FlatAppearance.BorderSize = 0;
button.BackColor = Color.Empty;
button.UseVisualStyleBackColor = true;
button.Size = new Size(60, 60);
button.Click += (sender, args) =>
{
var dialog = new FolderBrowserDialog();
dialog.SelectedPath = textbox.Text;
dialog.InitialDirectory = textbox.Text;
dialog.Description = "Select the destination path for the Godot translation files.";
dialog.ShowNewFolderButton = true;
if (dialog.ShowDialog() == DialogResult.OK)
textbox.Text = dialog.SelectedPath;
};
button.Dock = DockStyle.Fill;
layout.Controls.Add(button, 1, 0);
return layout;
}
);
return new Setting(settingData);
}
public static IEnumerable<Task<Setting>> GetAllSettings()
{
yield return ShowGeneratorGodotDestinationPathSettingAsync();
yield return ShowGeneratorGodotEnabledSettingAsync();
yield return ShowGeneratorDotnetDefaultCultureSettingAsync();
yield return ShowGeneratorDotnetNamespaceSettingAsync();
yield return ShowGeneratorDotnetDestinationPathSettingAsync();
yield return ShowGeneratorDotnetEnabledSettingAsync();
yield return ShowGeneratorModeSettingAsync();
yield return ShowDeepLSourceCultureSettingAsync();
foreach (var setting in ShowCultureSettingsAsync())
{
yield return setting;
}
yield return ShowDeepLUsageSettingAsync();
yield return ShowDeepLActionSettingAsync();

View File

@ -22,6 +22,9 @@ public sealed partial class Translation : UserControl
{
this.InitializeComponent();
this.Dock = DockStyle.Top;
this.saveTimer = new Timer();
this.translationTimer = new Timer();
}
public Translation(AppSettings.CultureInfo cultureInfo)
@ -121,7 +124,7 @@ public sealed partial class Translation : UserControl
}
}
private async void SaveChanges(object? sender, ElapsedEventArgs e)
private async void SaveChanges(object? sender, ElapsedEventArgs? e)
{
if (this.currentTranslationId > -1)
{
@ -135,7 +138,7 @@ public sealed partial class Translation : UserControl
this.isManualOnlyMode = this.checkBoxManual.Checked;
}
private async void TriggerTranslateNow(object? sender, ElapsedEventArgs e)
private async void TriggerTranslateNow(object? sender, ElapsedEventArgs? e)
{
if (this.currentTranslationId < 0 || this.isDeepLSourceCulture == false)
return;

View File

@ -6,7 +6,8 @@ public static class ExtensionsError
{
public static void ProcessError<TResult>(this ProcessorResult<TResult> result)
{
if (result.Successful) return;
if (result.Successful)
return;
MessageBox.Show(result.ErrorMessage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

View File

@ -140,6 +140,26 @@ namespace UI_WinForms.Resources {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap icons8_code_512 {
get {
object obj = ResourceManager.GetObject("icons8_code_512", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap icons8_code_512__2_ {
get {
object obj = ResourceManager.GetObject("icons8_code_512__2_", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
@ -180,6 +200,16 @@ namespace UI_WinForms.Resources {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap icons8_folder_tree_512 {
get {
object obj = ResourceManager.GetObject("icons8_folder_tree_512", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View File

@ -142,6 +142,12 @@
<data name="icons8_chat_bubble_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-chat-bubble-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="icons8_code_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-code-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="icons8_code_512__2_" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-code-512 (2).png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="icons8_collectibles_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-collectibles-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
@ -154,6 +160,9 @@
<data name="icons8_document_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-document-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="icons8_folder_tree_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-folder-tree-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="icons8_increase_512" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons8-increase-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB