Skip to content

Commit 0464f1b

Browse files
authored
Merge pull request #9 from xboxoneresearch/feat/localization
feat: Finishing touches on localization implementation
2 parents 9ad3805 + a391b91 commit 0464f1b

11 files changed

Lines changed: 129 additions & 13 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ jobs:
9898
shell: bash
9999
run: |
100100
cp -r PostCodeSerialMonitor/bin/${{ matrix.configuration }}/net9.0/${{ matrix.runtime }}/publish/* artifacts/${{ matrix.runtime }}/${{ matrix.configuration }}/
101+
cp PostCodeSerialMonitor/config.json artifacts/${{ matrix.runtime }}/${{ matrix.configuration }}/
101102
102103
- name: Upload artifacts
103104
uses: actions/upload-artifact@v4

PostCodeSerialMonitor/App.axaml.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
using PostCodeSerialMonitor.ViewModels;
77
using PostCodeSerialMonitor.Views;
88
using Microsoft.Extensions.DependencyInjection;
9+
using PostCodeSerialMonitor.Services;
10+
using System.Globalization;
911

1012
namespace PostCodeSerialMonitor;
1113

@@ -29,11 +31,11 @@ public override void OnFrameworkInitializationCompleted()
2931
// Creates a ServiceProvider containing services from the provided IServiceCollection
3032
var services = collection.BuildServiceProvider();
3133

34+
var configService = services.GetRequiredService<ConfigurationService>();
3235
var mainWindowViewModel = services.GetRequiredService<MainWindowViewModel>();
3336

34-
//@todo Load language setting in cofig.json.
35-
//
36-
//Assets.Resources.Culture = new CultureInfo("en-US");
37+
// Load language setting in config.json.
38+
Assets.Resources.Culture = new CultureInfo(configService.Config.Language);
3739

3840
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
3941
{

PostCodeSerialMonitor/Assets/Resources.Designer.cs

Lines changed: 24 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PostCodeSerialMonitor/Assets/Resources.pt-BR.resx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,4 +369,12 @@
369369
<value>Falha ao abrir URL: {0}</value>
370370
<comment>In Views/MainWindow.axaml.cs</comment>
371371
</data>
372+
<data name="RestartRequired" xml:space="preserve">
373+
<value>Necessário reiniciar</value>
374+
<comment>In ViewModels/ConfigurationDialogViewModel.cs</comment>
375+
</data>
376+
<data name="LanguageChangedPleaseRestart" xml:space="preserve">
377+
<value>O idioma foi alterado. Reinicie o aplicativo para que a alteração entre em vigor.</value>
378+
<comment>In ViewModels/ConfigurationDialogViewModel.cs</comment>
379+
</data>
372380
</root>

PostCodeSerialMonitor/Assets/Resources.resx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,4 +369,12 @@
369369
<value>Failed to open URL: {0}</value>
370370
<comment>In Views/MainWindow.axaml.cs</comment>
371371
</data>
372+
<data name="RestartRequired" xml:space="preserve">
373+
<value>Restart required</value>
374+
<comment>In ViewModels/ConfigurationDialogViewModel.cs</comment>
375+
</data>
376+
<data name="LanguageChangedPleaseRestart" xml:space="preserve">
377+
<value>Language was changed. Please restart the application for it to take effect.</value>
378+
<comment>In ViewModels/ConfigurationDialogViewModel.cs</comment>
379+
</data>
372380
</root>

PostCodeSerialMonitor/PostCodeSerialMonitor.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
</Compile>
3838
</ItemGroup>
3939

40+
<ItemGroup>
41+
<None Update="config.json">
42+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
43+
</None>
44+
</ItemGroup>
45+
4046
<ItemGroup>
4147
<PackageReference Include="Avalonia" Version="11.3.0" />
4248
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.1.5" />

PostCodeSerialMonitor/ServiceCollectionExtensions.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,12 @@ public static void AddCommonServices(this IServiceCollection collection)
2828

2929
// Build configuration
3030
var configuration = new ConfigurationBuilder()
31-
.AddJsonFile("config.json", optional: true, reloadOnChange: true)
31+
.AddJsonFile("config.json", optional: false, reloadOnChange: true)
3232
.Build();
3333

3434
// Configure options with validation
35-
collection.Configure<AppConfiguration>(configuration.GetSection(nameof(AppConfiguration)));
3635
collection.AddOptions<AppConfiguration>()
37-
.Bind(configuration.GetSection(nameof(AppConfiguration)))
36+
.Bind(configuration.GetRequiredSection(nameof(AppConfiguration)))
3837
.Validate(x => {
3938
return x.FormatVersion == SUPPORTED_CONFIG_FORMAT_VERSION;
4039
})

PostCodeSerialMonitor/Services/ConfigurationService.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
using PostCodeSerialMonitor.Models;
66
using Microsoft.Extensions.Options;
77
using Microsoft.Extensions.Logging;
8+
using System.Collections.Generic;
9+
using System.Linq;
810

911
namespace PostCodeSerialMonitor.Services;
1012
public class ConfigurationService
@@ -30,12 +32,18 @@ public async Task SaveConfigurationAsync()
3032
{
3133
try
3234
{
33-
var json = JsonSerializer.Serialize(_configurationMonitor.CurrentValue, new JsonSerializerOptions
35+
var startupPath = AppContext.BaseDirectory?.TrimEnd(Path.DirectorySeparatorChar)
36+
?? throw new InvalidOperationException();
37+
38+
var newConfig = new Dictionary<string, AppConfiguration>(){
39+
{ nameof(AppConfiguration), _configurationMonitor.CurrentValue }
40+
};
41+
var json = JsonSerializer.Serialize(newConfig, new JsonSerializerOptions
3442
{
3543
WriteIndented = true
3644
});
3745

38-
await File.WriteAllTextAsync(_configFilePath, json);
46+
await File.WriteAllTextAsync(Path.Join(startupPath, _configFilePath), json);
3947
_logger.LogInformation(Assets.Resources.ConfigurationSaved);
4048
}
4149
catch (Exception ex)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System.Collections.Generic;
2+
using System.Globalization;
3+
using System.Resources;
4+
using PostCodeSerialMonitor.Assets;
5+
6+
namespace PostCodeSerialMonitor.Utils;
7+
8+
public static class LocalizationUtils
9+
{
10+
public static IEnumerable<CultureInfo> GetAvailableCultures()
11+
{
12+
List<CultureInfo> result = new List<CultureInfo>()
13+
{
14+
// Prefill with the default culture info, as this won't be gathered by GetCultures
15+
CultureInfo.GetCultureInfo("en-US")
16+
};
17+
18+
ResourceManager rm = new ResourceManager(typeof(Resources));
19+
20+
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
21+
foreach (CultureInfo culture in cultures)
22+
{
23+
try
24+
{
25+
if (culture.Equals(CultureInfo.InvariantCulture)) continue; //do not use "==", won't work
26+
27+
ResourceSet? rs = rm.GetResourceSet(culture, true, false);
28+
if (rs != null)
29+
result.Add(culture);
30+
}
31+
catch (CultureNotFoundException)
32+
{
33+
34+
}
35+
}
36+
return result;
37+
}
38+
}

PostCodeSerialMonitor/ViewModels/ConfigurationDialogViewModel.cs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
33
using CommunityToolkit.Mvvm.Input;
44
using PostCodeSerialMonitor.Models;
55
using PostCodeSerialMonitor.Services;
6+
using PostCodeSerialMonitor.Utils;
67
using System.Threading.Tasks;
78
using Avalonia.Controls;
89
using System;
10+
using System.Collections.Generic;
11+
using System.Globalization;
12+
using MsBox.Avalonia;
13+
using MsBox.Avalonia.Enums;
914

1015
namespace PostCodeSerialMonitor.ViewModels;
1116

@@ -32,11 +37,21 @@ public partial class ConfigurationDialogViewModel : ViewModelBase
3237
[ObservableProperty]
3338
private string fwUpdateUrl;
3439

35-
public ObservableCollection<string> Languages { get; } = new();
40+
[ObservableProperty]
41+
private ObservableCollection<string> languages;
3642

3743
[ObservableProperty]
3844
private string selectedLanguage;
3945

46+
public static ObservableCollection<string> GetAvailableLanguages()
47+
{
48+
var languages = new ObservableCollection<string>();
49+
var cultures = LocalizationUtils.GetAvailableCultures();
50+
foreach (CultureInfo culture in cultures)
51+
languages.Add(culture.Name);
52+
return languages;
53+
}
54+
4055
public ConfigurationDialogViewModel(ConfigurationService configurationService)
4156
{
4257
_configurationService = configurationService;
@@ -52,13 +67,14 @@ public ConfigurationDialogViewModel(ConfigurationService configurationService)
5267
SelectedLanguage = _originalConfiguration.Language;
5368

5469
//Add available languages
55-
Languages.Add("en-US");
56-
Languages.Add("pt-BR");
70+
Languages = GetAvailableLanguages();
5771
}
5872

5973
[RelayCommand]
6074
private async Task SaveAsync(Window window)
6175
{
76+
bool languageChanged = _originalConfiguration.Language != SelectedLanguage;
77+
6278
await _configurationService.UpdateConfigurationAsync(config =>
6379
{
6480
config.CheckForAppUpdates = CheckForAppUpdates;
@@ -71,6 +87,13 @@ await _configurationService.UpdateConfigurationAsync(config =>
7187
});
7288

7389
window.Close();
90+
91+
if (languageChanged) {
92+
await MessageBoxManager
93+
.GetMessageBoxStandard(Assets.Resources.RestartRequired, string.Format(Assets.Resources.LanguageChangedPleaseRestart),
94+
ButtonEnum.Ok)
95+
.ShowAsync();
96+
}
7497
}
7598

7699
[RelayCommand]

0 commit comments

Comments
 (0)