diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 02245fe..490362d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -98,6 +98,7 @@ jobs: shell: bash run: | cp -r PostCodeSerialMonitor/bin/${{ matrix.configuration }}/net9.0/${{ matrix.runtime }}/publish/* artifacts/${{ matrix.runtime }}/${{ matrix.configuration }}/ + cp PostCodeSerialMonitor/config.json artifacts/${{ matrix.runtime }}/${{ matrix.configuration }}/ - name: Upload artifacts uses: actions/upload-artifact@v4 diff --git a/PostCodeSerialMonitor/App.axaml.cs b/PostCodeSerialMonitor/App.axaml.cs index ff6d07c..56e9958 100644 --- a/PostCodeSerialMonitor/App.axaml.cs +++ b/PostCodeSerialMonitor/App.axaml.cs @@ -6,6 +6,8 @@ using PostCodeSerialMonitor.ViewModels; using PostCodeSerialMonitor.Views; using Microsoft.Extensions.DependencyInjection; +using PostCodeSerialMonitor.Services; +using System.Globalization; namespace PostCodeSerialMonitor; @@ -29,11 +31,11 @@ public override void OnFrameworkInitializationCompleted() // Creates a ServiceProvider containing services from the provided IServiceCollection var services = collection.BuildServiceProvider(); + var configService = services.GetRequiredService(); var mainWindowViewModel = services.GetRequiredService(); - //@todo Load language setting in cofig.json. - // - //Assets.Resources.Culture = new CultureInfo("en-US"); + // Load language setting in config.json. + Assets.Resources.Culture = new CultureInfo(configService.Config.Language); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { diff --git a/PostCodeSerialMonitor/Assets/Resources.Designer.cs b/PostCodeSerialMonitor/Assets/Resources.Designer.cs index 2861f1b..755ef01 100644 --- a/PostCodeSerialMonitor/Assets/Resources.Designer.cs +++ b/PostCodeSerialMonitor/Assets/Resources.Designer.cs @@ -627,6 +627,28 @@ public static string FailedOpenUrl { get { return ResourceManager.GetString("FailedOpenUrl", resourceCulture); } - } + } + + /// + /// In ViewModels/ConfigurationDialogViewModel.cs + /// + public static string RestartRequired + { + get + { + return ResourceManager.GetString("RestartRequired", resourceCulture); + } + } + + /// + /// In ViewModels/ConfigurationDialogViewModel.cs + /// + public static string LanguageChangedPleaseRestart + { + get + { + return ResourceManager.GetString("LanguageChangedPleaseRestart", resourceCulture); + } + } } -} \ No newline at end of file +} diff --git a/PostCodeSerialMonitor/Assets/Resources.pt-BR.resx b/PostCodeSerialMonitor/Assets/Resources.pt-BR.resx index 36d3f13..8195cca 100644 --- a/PostCodeSerialMonitor/Assets/Resources.pt-BR.resx +++ b/PostCodeSerialMonitor/Assets/Resources.pt-BR.resx @@ -369,4 +369,12 @@ Falha ao abrir URL: {0} In Views/MainWindow.axaml.cs + + Necessário reiniciar + In ViewModels/ConfigurationDialogViewModel.cs + + + O idioma foi alterado. Reinicie o aplicativo para que a alteração entre em vigor. + In ViewModels/ConfigurationDialogViewModel.cs + diff --git a/PostCodeSerialMonitor/Assets/Resources.resx b/PostCodeSerialMonitor/Assets/Resources.resx index ac64898..0336470 100644 --- a/PostCodeSerialMonitor/Assets/Resources.resx +++ b/PostCodeSerialMonitor/Assets/Resources.resx @@ -369,4 +369,12 @@ Failed to open URL: {0} In Views/MainWindow.axaml.cs + + Restart required + In ViewModels/ConfigurationDialogViewModel.cs + + + Language was changed. Please restart the application for it to take effect. + In ViewModels/ConfigurationDialogViewModel.cs + diff --git a/PostCodeSerialMonitor/PostCodeSerialMonitor.csproj b/PostCodeSerialMonitor/PostCodeSerialMonitor.csproj index a372915..47b46fe 100644 --- a/PostCodeSerialMonitor/PostCodeSerialMonitor.csproj +++ b/PostCodeSerialMonitor/PostCodeSerialMonitor.csproj @@ -37,6 +37,12 @@ + + + PreserveNewest + + + diff --git a/PostCodeSerialMonitor/ServiceCollectionExtensions.cs b/PostCodeSerialMonitor/ServiceCollectionExtensions.cs index 20a9a26..dceb8e2 100644 --- a/PostCodeSerialMonitor/ServiceCollectionExtensions.cs +++ b/PostCodeSerialMonitor/ServiceCollectionExtensions.cs @@ -28,13 +28,12 @@ public static void AddCommonServices(this IServiceCollection collection) // Build configuration var configuration = new ConfigurationBuilder() - .AddJsonFile("config.json", optional: true, reloadOnChange: true) + .AddJsonFile("config.json", optional: false, reloadOnChange: true) .Build(); // Configure options with validation - collection.Configure(configuration.GetSection(nameof(AppConfiguration))); collection.AddOptions() - .Bind(configuration.GetSection(nameof(AppConfiguration))) + .Bind(configuration.GetRequiredSection(nameof(AppConfiguration))) .Validate(x => { return x.FormatVersion == SUPPORTED_CONFIG_FORMAT_VERSION; }) diff --git a/PostCodeSerialMonitor/Services/ConfigurationService.cs b/PostCodeSerialMonitor/Services/ConfigurationService.cs index e027dd1..d49a31d 100644 --- a/PostCodeSerialMonitor/Services/ConfigurationService.cs +++ b/PostCodeSerialMonitor/Services/ConfigurationService.cs @@ -5,6 +5,8 @@ using PostCodeSerialMonitor.Models; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; +using System.Collections.Generic; +using System.Linq; namespace PostCodeSerialMonitor.Services; public class ConfigurationService @@ -30,12 +32,18 @@ public async Task SaveConfigurationAsync() { try { - var json = JsonSerializer.Serialize(_configurationMonitor.CurrentValue, new JsonSerializerOptions + var startupPath = AppContext.BaseDirectory?.TrimEnd(Path.DirectorySeparatorChar) + ?? throw new InvalidOperationException(); + + var newConfig = new Dictionary(){ + { nameof(AppConfiguration), _configurationMonitor.CurrentValue } + }; + var json = JsonSerializer.Serialize(newConfig, new JsonSerializerOptions { WriteIndented = true }); - await File.WriteAllTextAsync(_configFilePath, json); + await File.WriteAllTextAsync(Path.Join(startupPath, _configFilePath), json); _logger.LogInformation(Assets.Resources.ConfigurationSaved); } catch (Exception ex) diff --git a/PostCodeSerialMonitor/Utils/LocalizationUtils.cs b/PostCodeSerialMonitor/Utils/LocalizationUtils.cs new file mode 100644 index 0000000..054f982 --- /dev/null +++ b/PostCodeSerialMonitor/Utils/LocalizationUtils.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Globalization; +using System.Resources; +using PostCodeSerialMonitor.Assets; + +namespace PostCodeSerialMonitor.Utils; + +public static class LocalizationUtils +{ + public static IEnumerable GetAvailableCultures() + { + List result = new List() + { + // Prefill with the default culture info, as this won't be gathered by GetCultures + CultureInfo.GetCultureInfo("en-US") + }; + + ResourceManager rm = new ResourceManager(typeof(Resources)); + + CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures); + foreach (CultureInfo culture in cultures) + { + try + { + if (culture.Equals(CultureInfo.InvariantCulture)) continue; //do not use "==", won't work + + ResourceSet? rs = rm.GetResourceSet(culture, true, false); + if (rs != null) + result.Add(culture); + } + catch (CultureNotFoundException) + { + + } + } + return result; + } +} \ No newline at end of file diff --git a/PostCodeSerialMonitor/ViewModels/ConfigurationDialogViewModel.cs b/PostCodeSerialMonitor/ViewModels/ConfigurationDialogViewModel.cs index 4f7fbe8..a29dd6b 100644 --- a/PostCodeSerialMonitor/ViewModels/ConfigurationDialogViewModel.cs +++ b/PostCodeSerialMonitor/ViewModels/ConfigurationDialogViewModel.cs @@ -3,9 +3,14 @@ using CommunityToolkit.Mvvm.Input; using PostCodeSerialMonitor.Models; using PostCodeSerialMonitor.Services; +using PostCodeSerialMonitor.Utils; using System.Threading.Tasks; using Avalonia.Controls; using System; +using System.Collections.Generic; +using System.Globalization; +using MsBox.Avalonia; +using MsBox.Avalonia.Enums; namespace PostCodeSerialMonitor.ViewModels; @@ -32,11 +37,21 @@ public partial class ConfigurationDialogViewModel : ViewModelBase [ObservableProperty] private string fwUpdateUrl; - public ObservableCollection Languages { get; } = new(); + [ObservableProperty] + private ObservableCollection languages; [ObservableProperty] private string selectedLanguage; + public static ObservableCollection GetAvailableLanguages() + { + var languages = new ObservableCollection(); + var cultures = LocalizationUtils.GetAvailableCultures(); + foreach (CultureInfo culture in cultures) + languages.Add(culture.Name); + return languages; + } + public ConfigurationDialogViewModel(ConfigurationService configurationService) { _configurationService = configurationService; @@ -52,13 +67,14 @@ public ConfigurationDialogViewModel(ConfigurationService configurationService) SelectedLanguage = _originalConfiguration.Language; //Add available languages - Languages.Add("en-US"); - Languages.Add("pt-BR"); + Languages = GetAvailableLanguages(); } [RelayCommand] private async Task SaveAsync(Window window) { + bool languageChanged = _originalConfiguration.Language != SelectedLanguage; + await _configurationService.UpdateConfigurationAsync(config => { config.CheckForAppUpdates = CheckForAppUpdates; @@ -71,6 +87,13 @@ await _configurationService.UpdateConfigurationAsync(config => }); window.Close(); + + if (languageChanged) { + await MessageBoxManager + .GetMessageBoxStandard(Assets.Resources.RestartRequired, string.Format(Assets.Resources.LanguageChangedPleaseRestart), + ButtonEnum.Ok) + .ShowAsync(); + } } [RelayCommand] diff --git a/PostCodeSerialMonitor/config.json b/PostCodeSerialMonitor/config.json index 777aa08..6d73cf6 100644 --- a/PostCodeSerialMonitor/config.json +++ b/PostCodeSerialMonitor/config.json @@ -8,6 +8,7 @@ "CodesMetaBaseUrl": "https://errors.xboxresearch.com/", "FwUpdateUrl": "https://example.com/todo", "MetaStoragePath": "meta", + "Language": "en-US", "MetaJsonUrl": "https://errors.xboxresearch.com/meta.json" } } \ No newline at end of file