feat: 完成国际化支持库

This commit is contained in:
2025-01-23 22:53:28 +08:00
parent 5f62df1ef6
commit 6650549ed7
8 changed files with 160 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
using System.Globalization;
using Avalonia.Data.Converters;
namespace JackCraft.I18N.Converters;
internal class I18NConverter(I18NBinding binding, object[] bindingValues) : IMultiValueConverter
{
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
{
if (values.Count < 2 || values[0] is not CultureInfo)
return null;
if (binding.KeyConverter.Convert(values[1], null!, null, culture) is not string key)
return values[1];
var value = I18NConfig.Manager.Get<object>(key, values[0] as CultureInfo);
if (value is string str && bindingValues.Length > 0)
value = string.Format(str, bindingValues);
return binding.ValueConverter.Convert(value, null!, null, culture);
}
}

View File

@@ -0,0 +1,22 @@
using System.Globalization;
using Avalonia.Data.Converters;
namespace JackCraft.I18N.Converters;
internal class I18NKeyConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return value switch
{
Enum e => value.GetType().Name + "." + e,
string str => str,
_ => null
};
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return null;
}
}

View File

@@ -0,0 +1,17 @@
using System.Globalization;
using Avalonia.Data.Converters;
namespace JackCraft.I18N.Converters;
internal class I18NValueConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return value;
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return null;
}
}

View File

@@ -0,0 +1,23 @@
using Avalonia.Data;
using Avalonia.Data.Converters;
using JackCraft.I18N.Converters;
namespace JackCraft.I18N;
internal class I18NBinding : MultiBinding
{
public readonly IValueConverter KeyConverter;
public readonly IValueConverter ValueConverter;
public I18NBinding(string key, params dynamic[] values)
{
Mode = BindingMode.OneWay;
TargetNullValue = key;
FallbackValue = key;
Converter = new I18NConverter(this, values);
KeyConverter = new I18NKeyConverter();
ValueConverter = new I18NValueConverter();
Bindings.Add(new Binding { Source = I18NConfig.Manager, Path = nameof(I18NConfig.Manager.Culture) });
Bindings.Add(new Binding { Source = key });
}
}

View File

@@ -0,0 +1,12 @@
using System.Globalization;
using System.Reflection;
namespace JackCraft.I18N;
internal static class I18NConfig
{
public static I18NManager Manager { get; set; } = null!;
public static string BaseName { get; set; } = string.Empty;
public static Assembly Assembly { get; set; } = typeof(I18NConfig).Assembly;
public static CultureInfo Culture { get; set; } = CultureInfo.InvariantCulture;
}

View File

@@ -0,0 +1,15 @@
using Avalonia.Markup.Xaml;
namespace JackCraft.I18N;
public class I18NExtension(string key, params object[] values) : MarkupExtension
{
public I18NExtension(string key) : this(key, [])
{
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return new I18NBinding(key, values);
}
}

View File

@@ -0,0 +1,48 @@
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
namespace JackCraft.I18N;
public sealed class I18NManager : INotifyPropertyChanged
{
public I18NManager(string baseName, Assembly assembly)
{
I18NConfig.BaseName = baseName;
I18NConfig.Assembly = assembly;
I18NConfig.Manager = this;
}
public CultureInfo Culture
{
get => I18NConfig.Culture;
set
{
if (Equals(value, I18NConfig.Culture)) return;
I18NConfig.Culture = value;
OnPropertyChanged();
}
}
public static string BaseName => I18NConfig.BaseName;
public static Assembly Assembly => I18NConfig.Assembly;
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public T? Get<T>(string key, CultureInfo? culture = null, params object?[] values)
{
culture ??= Culture;
var resourceManager = new ResourceManager(BaseName, Assembly);
var resourceSet = resourceManager.GetResourceSet(culture, true, true);
var obj = resourceSet?.GetObject(key);
if (obj is string str && values.Length > 0) return (dynamic)string.Format(str, values);
if (obj != null) return (dynamic)obj;
return default;
}
}

View File

@@ -7,4 +7,8 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.3"/>
</ItemGroup>
</Project>