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:
commit
cf3791ed70
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RiderMarkupStore">
|
||||
<option name="version" value="-2154046885505616848" />
|
||||
</component>
|
||||
</project>
|
@ -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>
|
||||
|
@ -0,0 +1,7 @@
|
||||
namespace DataModel.Database;
|
||||
|
||||
public enum SettingGeneratorMode
|
||||
{
|
||||
AUTOMATIC,
|
||||
MANUAL,
|
||||
}
|
@ -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";
|
||||
}
|
@ -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
|
||||
}
|
@ -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;
|
||||
|
175
I18N Commander/Processor/Generators/DotnetBigFile.cs
Normal file
175
I18N Commander/Processor/Generators/DotnetBigFile.cs
Normal 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}}}");
|
||||
}
|
||||
}
|
41
I18N Commander/Processor/Generators/Generator.cs
Normal file
41
I18N Commander/Processor/Generators/Generator.cs
Normal 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);
|
||||
}
|
||||
}
|
6
I18N Commander/Processor/Generators/IGenerator.cs
Normal file
6
I18N Commander/Processor/Generators/IGenerator.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Processor.Generators;
|
||||
|
||||
public interface IGenerator
|
||||
{
|
||||
public Task<ProcessorResult<long>> GenerateAsync();
|
||||
}
|
9
I18N Commander/Processor/Generators/Type.cs
Normal file
9
I18N Commander/Processor/Generators/Type.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Processor.Generators;
|
||||
|
||||
public enum Type
|
||||
{
|
||||
NONE,
|
||||
|
||||
DOTNET,
|
||||
GODOT,
|
||||
}
|
6
I18N Commander/Processor/Generators/VoidGenerator.cs
Normal file
6
I18N Commander/Processor/Generators/VoidGenerator.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Processor.Generators;
|
||||
|
||||
public class VoidGenerator : IGenerator
|
||||
{
|
||||
public Task GenerateAsync() => Task.CompletedTask;
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -124,7 +124,7 @@ public static class TextElementProcessor
|
||||
// Save the changes:
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateException updateException)
|
||||
catch (DbUpdateException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -16,6 +16,7 @@ public partial class Main : UserControl
|
||||
if(result == DialogResult.Yes)
|
||||
{
|
||||
Program.RestartMainApp = true;
|
||||
AppEvents.ResetAllSubscriptions();
|
||||
this.ParentForm!.Close();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
BIN
I18N Commander/UI WinForms/Resources/icons8-code-512 (2).png
Normal file
BIN
I18N Commander/UI WinForms/Resources/icons8-code-512 (2).png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
BIN
I18N Commander/UI WinForms/Resources/icons8-code-512.png
Normal file
BIN
I18N Commander/UI WinForms/Resources/icons8-code-512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
BIN
I18N Commander/UI WinForms/Resources/icons8-folder-tree-512.png
Normal file
BIN
I18N Commander/UI WinForms/Resources/icons8-folder-tree-512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Loading…
Reference in New Issue
Block a user