Skip to content

Commit ba82a55

Browse files
committed
use DynamicLocalization
1 parent 2dbb3d8 commit ba82a55

25 files changed

Lines changed: 197 additions & 1213 deletions

File tree

Demo/AutoSettingUI.Avalonia.CrossPlatform.Demo/AutoSettingUI.Avalonia.CrossPlatform.Demo/App.axaml.cs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,80 @@
1+
using System;
2+
using System.Linq;
13
using Avalonia;
24
using Avalonia.Controls.ApplicationLifetimes;
35
using Avalonia.Data.Core;
46
using Avalonia.Data.Core.Plugins;
5-
using System.Linq;
67
using Avalonia.Markup.Xaml;
78
using AutoSettingUI.Avalonia.CrossPlatform.Demo.ViewModels;
89
using AutoSettingUI.Avalonia.CrossPlatform.Demo.Views;
9-
using AutoSettingUI.Core.Registry;
10-
10+
using Microsoft.Extensions.DependencyInjection;
11+
using DynamicLocalization.Core;
12+
using DynamicLocalization.Core.Providers;
13+
using AutoSettingUI.Avalonia.CrossPlatform.Demo.Resources;
1114

1215
namespace AutoSettingUI.Avalonia.CrossPlatform.Demo;
1316

1417
public partial class App : Application
1518
{
19+
public IServiceProvider Services { get; private set; } = null!;
20+
21+
public new static App Current => (App)Application.Current!;
22+
1623
public override void Initialize()
1724
{
1825
AvaloniaXamlLoader.Load(this);
1926
}
2027

2128
public override void OnFrameworkInitializationCompleted()
2229
{
30+
Services = ConfigureServices();
31+
2332
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
2433
{
25-
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
26-
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
2734
DisableAvaloniaDataAnnotationValidation();
2835

2936
desktop.MainWindow = new MainWindow
3037
{
31-
DataContext = new MainViewModel()
38+
DataContext = Services.GetRequiredService<MainViewModel>()
3239
};
3340
}
3441
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
3542
{
3643
singleViewPlatform.MainView = new MainView
3744
{
38-
DataContext = new MainViewModel()
45+
DataContext = Services.GetRequiredService<MainViewModel>()
3946
};
4047
}
4148

4249
base.OnFrameworkInitializationCompleted();
4350
}
4451

52+
private static IServiceProvider ConfigureServices()
53+
{
54+
var services = new ServiceCollection();
55+
56+
services.AddSingleton<ICultureService>(sp =>
57+
{
58+
var cultureService = new CultureService();
59+
var resxProvider = new ResxLocalizationProvider();
60+
resxProvider.Initialize(new ResxLocalizationProviderOptions
61+
{
62+
ResourceType = typeof(Strings)
63+
});
64+
cultureService.RegisterProvider(resxProvider);
65+
return cultureService;
66+
});
67+
68+
services.AddSingleton<MainViewModel>();
69+
70+
return services.BuildServiceProvider();
71+
}
72+
4573
private void DisableAvaloniaDataAnnotationValidation()
4674
{
47-
// Get an array of plugins to remove
4875
var dataValidationPluginsToRemove =
4976
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
5077

51-
// remove each entry found
5278
foreach (var plugin in dataValidationPluginsToRemove)
5379
{
5480
BindingPlugins.DataValidators.Remove(plugin);

Demo/AutoSettingUI.Avalonia.CrossPlatform.Demo/AutoSettingUI.Avalonia.CrossPlatform.Demo/AutoSettingUI.Avalonia.CrossPlatform.Demo.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
2929
</PackageReference>
3030
<PackageReference Include="CommunityToolkit.Mvvm"/>
31+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
3132
</ItemGroup>
3233

3334
<ItemGroup>

Demo/AutoSettingUI.Avalonia.CrossPlatform.Demo/AutoSettingUI.Avalonia.CrossPlatform.Demo/ViewModels/MainViewModel.cs

Lines changed: 6 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -3,89 +3,51 @@
33
using CommunityToolkit.Mvvm.ComponentModel;
44
using CommunityToolkit.Mvvm.Input;
55
using AutoSettingUI.Avalonia.CrossPlatform.Demo.Models;
6-
using AutoSettingUI.Avalonia.CrossPlatform.Demo.Resources;
7-
using AutoSettingUI.Core.Interfaces;
8-
using AutoSettingUI.Core.Services;
96
using Avalonia;
107
using Avalonia.Styling;
8+
using DynamicLocalization.Core;
119

1210
namespace AutoSettingUI.Avalonia.CrossPlatform.Demo.ViewModels;
1311

14-
/// <summary>
15-
/// Main view model for the Avalonia cross-platform demo application.
16-
/// Demonstrates dynamic language switching, theme management, and settings panel features.
17-
/// </summary>
1812
public partial class MainViewModel : ViewModelBase
1913
{
20-
/// <summary>
21-
/// Collection of setting objects to display in the settings panel.
22-
/// Each object represents a different settings category.
23-
/// </summary>
2414
[ObservableProperty]
2515
private ObservableCollection<object> _targets = new();
2616

27-
/// <summary>
28-
/// The title displayed at the top of the settings panel.
29-
/// </summary>
3017
[ObservableProperty]
3118
private string _title = "Settings";
3219

33-
/// <summary>
34-
/// Controls whether the navigation sidebar is visible.
35-
/// </summary>
3620
[ObservableProperty]
3721
private bool _showNavigation = true;
3822

39-
/// <summary>
40-
/// Width of the navigation sidebar in pixels.
41-
/// </summary>
4223
[ObservableProperty]
4324
private double _navigationWidth = 200;
4425

45-
/// <summary>
46-
/// Toggles between default and custom styled views.
47-
/// </summary>
4826
[ObservableProperty]
4927
private bool _isCustomView = false;
5028

51-
/// <summary>
52-
/// Settings for extended UI controls demonstration.
53-
/// </summary>
5429
[ObservableProperty]
5530
private ExtendedControlsSettings _extendedSettings = new();
5631

57-
/// <summary>
58-
/// Settings for theme selection.
59-
/// </summary>
6032
[ObservableProperty]
6133
private ThemeSettings _themeSettings = new();
6234

63-
/// <summary>
64-
/// Localization service for dynamic language switching.
65-
/// </summary>
6635
[ObservableProperty]
67-
private ILocalizationService? _localizationService;
36+
private ICultureService _localizationService;
6837

69-
/// <summary>
70-
/// Current language code (e.g., "en", "zh-CN").
71-
/// Used to highlight the active language button.
72-
/// </summary>
7338
[ObservableProperty]
7439
private string _currentLanguage = "en";
7540

76-
/// <summary>
77-
/// Dynamic text for the view toggle button.
78-
/// </summary>
7941
public string ViewModeText => IsCustomView ? "Switch to Default View" : "Switch to Custom View";
8042

8143
partial void OnIsCustomViewChanged(bool value)
8244
{
8345
OnPropertyChanged(nameof(ViewModeText));
8446
}
8547

86-
public MainViewModel()
48+
public MainViewModel(ICultureService localizationService)
8749
{
88-
LocalizationService = new ResxLocalizationService(Strings.ResourceManager);
50+
LocalizationService = localizationService;
8951

9052
Targets.Add(ThemeSettings);
9153
Targets.Add(ExtendedSettings);
@@ -96,9 +58,6 @@ public MainViewModel()
9658
ThemeSettings.PropertyChanged += OnThemeSettingsChanged;
9759
}
9860

99-
/// <summary>
100-
/// Handles theme changes and applies them to the application.
101-
/// </summary>
10261
private void OnThemeSettingsChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
10362
{
10463
if (e.PropertyName == nameof(ThemeSettings.SelectedTheme))
@@ -116,80 +75,51 @@ private void OnThemeSettingsChanged(object? sender, System.ComponentModel.Proper
11675
}
11776
}
11877

119-
/// <summary>
120-
/// Adds a new ApplicationSettings instance to the targets collection.
121-
/// </summary>
12278
[RelayCommand]
12379
private void AddApp()
12480
{
12581
Targets.Add(new ApplicationSettings() { AppName = "New App", Version = "2.0.0" });
12682
}
12783

128-
/// <summary>
129-
/// Adds a new UserPreferences instance to the targets collection.
130-
/// </summary>
13184
[RelayCommand]
13285
private void AddUser()
13386
{
13487
Targets.Add(new UserPreferences() { Language = "Spanish", FontSize = 16 });
13588
}
13689

137-
/// <summary>
138-
/// Adds a new NetworkSettings instance to the targets collection.
139-
/// </summary>
14090
[RelayCommand]
14191
private void AddNetworkConfig()
14292
{
14393
Targets.Add(new NetworkSettings() { Port = 8080 });
14494
}
14595

146-
/// <summary>
147-
/// Toggles between default and custom styled settings panel views.
148-
/// </summary>
14996
[RelayCommand]
15097
private void ToggleView()
15198
{
15299
IsCustomView = !IsCustomView;
153100
}
154101

155-
/// <summary>
156-
/// Toggles the visibility of the navigation sidebar.
157-
/// </summary>
158102
[RelayCommand]
159103
private void ToggleNavigation()
160104
{
161105
ShowNavigation = !ShowNavigation;
162106
}
163107

164-
/// <summary>
165-
/// Switches the application language to English.
166-
/// </summary>
167108
[RelayCommand]
168109
private void SwitchToEnglish()
169110
{
170-
LocalizationService?.SetCulture("en");
111+
LocalizationService.SetCulture("en");
171112
CurrentLanguage = "en";
172113
}
173114

174-
/// <summary>
175-
/// Switches the application language to Chinese (Simplified).
176-
/// </summary>
177115
[RelayCommand]
178116
private void SwitchToChinese()
179117
{
180-
LocalizationService?.SetCulture("zh-CN");
118+
LocalizationService.SetCulture("zh-CN");
181119
CurrentLanguage = "zh-CN";
182120
}
183121
}
184122

185-
/// <summary>
186-
/// Value converter that highlights the currently selected language button.
187-
/// Returns Bold font weight for the active language, Normal for others.
188-
/// </summary>
189-
/// <example>
190-
/// Usage in XAML:
191-
/// TextBlock FontWeight="{Binding CurrentLanguage, Converter={StaticResource LanguageToFontWeightConverter}, ConverterParameter=en}"
192-
/// </example>
193123
public class LanguageToFontWeightConverter : global::Avalonia.Data.Converters.IValueConverter
194124
{
195125
public object? Convert(object? value, Type targetType, object? parameter, System.Globalization.CultureInfo culture)

Demo/AutoSettingUI.Avalonia.CrossPlatform.Demo/Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<PackageVersion Include="Avalonia.Android" Version="11.2.7" />
1818

1919
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.3.2" />
20+
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
2021

2122
<PackageVersion Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.1" />
2223
</ItemGroup>

Demo/AutoSettingUI.Ursa.Demo/App.axaml.cs

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
1+
using System;
2+
using System.Linq;
13
using Avalonia;
24
using Avalonia.Controls.ApplicationLifetimes;
35
using Avalonia.Data.Core;
46
using Avalonia.Data.Core.Plugins;
5-
using System.Linq;
67
using Avalonia.Markup.Xaml;
7-
using AutoSettingUI.Core.Registry;
8-
using AutoSettingUI.Generated;
98
using AutoSettingUI.Ursa.Demo.ViewModels;
109
using AutoSettingUI.Ursa.Demo.Views;
10+
using Microsoft.Extensions.DependencyInjection;
11+
using DynamicLocalization.Core;
12+
using DynamicLocalization.Core.Providers;
13+
using AutoSettingUI.Ursa.Demo.Resources;
1114

1215
namespace AutoSettingUI.Ursa.Demo;
1316

1417
public partial class App : Application
1518
{
19+
public IServiceProvider Services { get; private set; } = null!;
20+
21+
public new static App Current => (App)Application.Current!;
22+
1623
public override void Initialize()
1724
{
1825
AvaloniaXamlLoader.Load(this);
@@ -22,26 +29,45 @@ public override void OnFrameworkInitializationCompleted()
2229
{
2330
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
2431
{
25-
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
26-
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
2732
DisableAvaloniaDataAnnotationValidation();
2833

34+
Services = ConfigureServices();
35+
2936
desktop.MainWindow = new MainWindow
3037
{
31-
DataContext = new MainWindowViewModel(),
38+
DataContext = Services.GetRequiredService<MainWindowViewModel>(),
3239
};
3340
}
3441

3542
base.OnFrameworkInitializationCompleted();
3643
}
3744

45+
private static IServiceProvider ConfigureServices()
46+
{
47+
var services = new ServiceCollection();
48+
49+
services.AddSingleton<ICultureService>(sp =>
50+
{
51+
var cultureService = new CultureService();
52+
var resxProvider = new ResxLocalizationProvider();
53+
resxProvider.Initialize(new ResxLocalizationProviderOptions
54+
{
55+
ResourceType = typeof(Strings)
56+
});
57+
cultureService.RegisterProvider(resxProvider);
58+
return cultureService;
59+
});
60+
61+
services.AddSingleton<MainWindowViewModel>();
62+
63+
return services.BuildServiceProvider();
64+
}
65+
3866
private void DisableAvaloniaDataAnnotationValidation()
3967
{
40-
// Get an array of plugins to remove
4168
var dataValidationPluginsToRemove =
4269
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
4370

44-
// remove each entry found
4571
foreach (var plugin in dataValidationPluginsToRemove)
4672
{
4773
BindingPlugins.DataValidators.Remove(plugin);

Demo/AutoSettingUI.Ursa.Demo/AutoSettingUI.Ursa.Demo.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
4848
</PackageReference>
4949
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1"/>
50+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
5051
<PackageReference Include="Irihi.Ursa" Version="1.13.0" />
5152
<PackageReference Include="Irihi.Ursa.Themes.Semi" Version="1.13.0" />
5253
<PackageReference Include="Semi.Avalonia" Version="11.2.1.10" />

0 commit comments

Comments
 (0)