From 6650549ed7a3d8b548155db3e1e49eaa68d410c2 Mon Sep 17 00:00:00 2001 From: Jack <3486688394@qq.com> Date: Thu, 23 Jan 2025 22:53:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E5=9B=BD=E9=99=85?= =?UTF-8?q?=E5=8C=96=E6=94=AF=E6=8C=81=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- JackCraft.I18N/Converters/I18NConverter.cs | 19 ++++++++ JackCraft.I18N/Converters/I18NKeyConverter.cs | 22 +++++++++ .../Converters/I18NValueConverter.cs | 17 +++++++ JackCraft.I18N/I18NBinding.cs | 23 +++++++++ JackCraft.I18N/I18NConfig.cs | 12 +++++ JackCraft.I18N/I18NExtension.cs | 15 ++++++ JackCraft.I18N/I18NManager.cs | 48 +++++++++++++++++++ JackCraft.I18N/JackCraft.I18N.csproj | 4 ++ 8 files changed, 160 insertions(+) create mode 100644 JackCraft.I18N/Converters/I18NConverter.cs create mode 100644 JackCraft.I18N/Converters/I18NKeyConverter.cs create mode 100644 JackCraft.I18N/Converters/I18NValueConverter.cs create mode 100644 JackCraft.I18N/I18NBinding.cs create mode 100644 JackCraft.I18N/I18NConfig.cs create mode 100644 JackCraft.I18N/I18NExtension.cs create mode 100644 JackCraft.I18N/I18NManager.cs diff --git a/JackCraft.I18N/Converters/I18NConverter.cs b/JackCraft.I18N/Converters/I18NConverter.cs new file mode 100644 index 0000000..3f29d8b --- /dev/null +++ b/JackCraft.I18N/Converters/I18NConverter.cs @@ -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 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(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); + } +} \ No newline at end of file diff --git a/JackCraft.I18N/Converters/I18NKeyConverter.cs b/JackCraft.I18N/Converters/I18NKeyConverter.cs new file mode 100644 index 0000000..61fb947 --- /dev/null +++ b/JackCraft.I18N/Converters/I18NKeyConverter.cs @@ -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; + } +} \ No newline at end of file diff --git a/JackCraft.I18N/Converters/I18NValueConverter.cs b/JackCraft.I18N/Converters/I18NValueConverter.cs new file mode 100644 index 0000000..64786b8 --- /dev/null +++ b/JackCraft.I18N/Converters/I18NValueConverter.cs @@ -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; + } +} \ No newline at end of file diff --git a/JackCraft.I18N/I18NBinding.cs b/JackCraft.I18N/I18NBinding.cs new file mode 100644 index 0000000..1e91511 --- /dev/null +++ b/JackCraft.I18N/I18NBinding.cs @@ -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 }); + } +} \ No newline at end of file diff --git a/JackCraft.I18N/I18NConfig.cs b/JackCraft.I18N/I18NConfig.cs new file mode 100644 index 0000000..4265a8c --- /dev/null +++ b/JackCraft.I18N/I18NConfig.cs @@ -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; +} \ No newline at end of file diff --git a/JackCraft.I18N/I18NExtension.cs b/JackCraft.I18N/I18NExtension.cs new file mode 100644 index 0000000..67fe230 --- /dev/null +++ b/JackCraft.I18N/I18NExtension.cs @@ -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); + } +} \ No newline at end of file diff --git a/JackCraft.I18N/I18NManager.cs b/JackCraft.I18N/I18NManager.cs new file mode 100644 index 0000000..25a74bb --- /dev/null +++ b/JackCraft.I18N/I18NManager.cs @@ -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(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; + } +} \ No newline at end of file diff --git a/JackCraft.I18N/JackCraft.I18N.csproj b/JackCraft.I18N/JackCraft.I18N.csproj index 00e99c8..40898b0 100644 --- a/JackCraft.I18N/JackCraft.I18N.csproj +++ b/JackCraft.I18N/JackCraft.I18N.csproj @@ -7,4 +7,8 @@ enable + + + +