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,29 +7,120 @@ namespace Processor; | ||||
| 
 | ||||
| public static class AppSettings | ||||
| { | ||||
|     #region DeepL Settings | ||||
|     #region Common DB Code | ||||
| 
 | ||||
|     #region DeepL Mode | ||||
|     private static readonly Dictionary<string, object> CACHES = new(); | ||||
|     private static readonly Dictionary<string, bool> CACHE_LOADED = new(); | ||||
| 
 | ||||
|     private static SettingDeepLMode CACHE_DEEPL_MODE = SettingDeepLMode.DISABLED; | ||||
|     private static bool CACHE_DEEPL_MODE_IS_LOADED = false; | ||||
|      | ||||
|     public static async Task SetDeepLMode(SettingDeepLMode mode) | ||||
|     private static async Task<T> GetSetting<T>(string settingName, T defaultValue) | ||||
|     { | ||||
|         // Convert the enum to its int value: | ||||
|         var intValue = (int)mode; | ||||
|         // 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: | ||||
|         CACHE_DEEPL_MODE = mode; | ||||
|         CACHE_DEEPL_MODE_IS_LOADED = true; | ||||
|         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 == SettingNames.DEEPL_MODE) is {} existingSetting) | ||||
|         if (await db.Settings.FirstOrDefaultAsync(n => n.Code == settingName) is { } existingSetting) | ||||
|         { | ||||
|             existingSetting.IntegerValue = intValue; | ||||
|             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(); | ||||
|         } | ||||
|          | ||||
| @ -38,253 +129,78 @@ public static class AppSettings | ||||
|         { | ||||
|             var setting = new Setting | ||||
|             { | ||||
|                 Code = SettingNames.DEEPL_MODE, | ||||
|                 IntegerValue = intValue, | ||||
|                 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(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static async Task<SettingDeepLMode> GetDeepLMode() | ||||
|     { | ||||
|         if (CACHE_DEEPL_MODE_IS_LOADED) | ||||
|             return CACHE_DEEPL_MODE; | ||||
|     #endregion    | ||||
|      | ||||
|         // Get the database: | ||||
|         await using var db = ProcessorMeta.ServiceProvider.GetRequiredService<DataContext>(); | ||||
|     #region DeepL Settings | ||||
| 
 | ||||
|         // Check, if the setting is already set: | ||||
|         if (await db.Settings.FirstOrDefaultAsync(n => n.Code == SettingNames.DEEPL_MODE) is { } existingSetting) | ||||
|             return (SettingDeepLMode) existingSetting.IntegerValue; | ||||
|     #region DeepL Mode | ||||
| 
 | ||||
|         // Does not exist, so create it: | ||||
|         var setting = new Setting | ||||
|         { | ||||
|             Code = SettingNames.DEEPL_MODE, | ||||
|             IntegerValue = (int)SettingDeepLMode.DISABLED, | ||||
|         }; | ||||
|     public static async Task SetDeepLMode(SettingDeepLMode mode) => await AppSettings.SetSetting(SettingNames.DEEPL_MODE, mode); | ||||
| 
 | ||||
|         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) => await AppSettings.SetSetting(SettingNames.DEEPL_API_KEY, apiKey); | ||||
| 
 | ||||
|     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<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) => await AppSettings.SetSetting(SettingNames.DEEPL_ACTION, action); | ||||
| 
 | ||||
|     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<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) => await AppSettings.SetSetting(SettingNames.DEEPL_SOURCE_CULTURE, cultureIndex); | ||||
| 
 | ||||
|     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<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,8 +29,37 @@ 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) | ||||
| @ -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; | ||||
| @ -389,13 +391,313 @@ public sealed partial class Setting : UserControl | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     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