WPF 国际化(全球化)管理

resx资源文件

单个resx扩展

复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Markup;


    /// <summary>
    /// XAML 用法:
    /// xmlns:ext="clr-namespace:自己的命名空间.Resources"
    /// {ext:Localize MainPage_Menu_Start} 
    /// Model用法:
    /// LocalizeExtension.Instance["MainPage_Menu_DataPacking"];
    /// </summary>
    internal sealed class LocalizeExtension : MarkupExtension, INotifyPropertyChanged
    {
        public static LocalizeExtension Instance { get; } = new();

        public static void ChangeLanguage(CultureInfo ci)
        {
            Resources.Langs.Lang.Culture = ci;
            OnLanguageChanged?.Invoke();
        }

        public static event Action? OnLanguageChanged;

        private string Key { get; }

        public string Result => GetString(Key);
        public string this[string key] => GetString(key);

        public static string GetString(string key)
        {
            return Resources.Langs.Lang.ResourceManager.GetString(key, Resources.Langs.Lang.Culture)?.Replace("\\n", "\n") ?? $"#{key}#";
        }

        private LocalizeExtension()
        {
            Key = string.Empty;
        }

        public LocalizeExtension(string key)
        {
            Key = key;

            OnLanguageChanged += () => {
                OnPropertyChanged(nameof(Result));
            };
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var binding = new Binding(nameof(Result))
            {
                Source = this,
                Mode = BindingMode.OneWay
            };
            return binding.ProvideValue(serviceProvider);
        }

        public event PropertyChangedEventHandler? PropertyChanged;

        private void OnPropertyChanged([CallerMemberName] string? propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

多个resx资源扩展

复制代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Windows.Data;
using System.Windows.Markup;


{
   /// <summary>
/// XAML 用法:
/// xmlns:ext="clr-namespace:自己的命名空间.Resources"
/// 1:{ext:Localize Key=Main_Title, Source=GUI}
/// 2:{ext:Localize MainPage_Menu_Start}    --默认资源组(Lang)
/// Model用法:
/// 1:LocalizeExtension.Instance["MainPage_Menu_DataPacking"];
/// 2:LocalizeExtension.Instance["GUI", nameof(Layout.Main_Nav_Title)];
/// </summary>
public sealed class LocalizeExtension : MarkupExtension, INotifyPropertyChanged
{
    public static LocalizeExtension Instance { get; } = new LocalizeExtension();

    public static event Action? OnLanguageChanged;
  
    private const string DefaultSource = "Lang";
  
    private static readonly Dictionary<string, System.Resources.ResourceManager> ResourceManagers =
        new(StringComparer.OrdinalIgnoreCase)
        {
            ["Lang"] = Lang.ResourceManager,
            ["GUI"] = Layout.ResourceManager,
        };
   
    public LocalizeExtension(string key)
    {
        Key = key;
        Source = DefaultSource;
        OnLanguageChanged += RaiseResultChanged;
    }
    
    public LocalizeExtension()
    {
        Key = string.Empty;
        Source = DefaultSource;
        OnLanguageChanged += RaiseResultChanged;
    }
    public string Key { get; set; } = string.Empty;

    public string Source { get; set; } = DefaultSource;

    public string this[string key] => GetString(key, DefaultSource);
    
    public string this[string source, string key] => GetString(key, source);

    public string Result => GetString(Key, Source);

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var pvt = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        var targetObject = pvt?.TargetObject;
        var targetProperty = pvt?.TargetProperty;
       
        // targetObject 是 Binding,必须返回"对象",不能返回 BindingExpression
        if (targetObject is Binding)
        {
            return this;
        }

        // 正常给 DependencyProperty 赋值,返回内部绑定实现动态刷新
        if (targetObject is DependencyObject && targetProperty is DependencyProperty)
        {
            var binding = new Binding(nameof(Result))
            {
                Source = this,
                Mode = BindingMode.OneWay
            };
            return binding.ProvideValue(serviceProvider);
        }
        return Result;
    }
   
    public static void ChangeLanguage(CultureInfo culture)
    {
        Lang.Culture = culture;
        Layout.Culture = culture;
        OnLanguageChanged?.Invoke();
    }
 
    public static string GetString(string key, string? source = null)
    {
        if (string.IsNullOrWhiteSpace(key))
            return string.Empty;
        var src = string.IsNullOrWhiteSpace(source) ? DefaultSource : source;
        if (!ResourceManagers.TryGetValue(src!, out var rm))
            return $"#InvalidSource:{src}#{key}#";
      
        var value = rm.GetString(key, Lang.Culture);
        return value?.Replace("\\n", "\n") ?? $"#{src}:{key}#";
    }
   
    public static void RegisterSource(string source, System.Resources.ResourceManager manager)
    {
        if (string.IsNullOrWhiteSpace(source))
            throw new ArgumentException("source is required.", nameof(source));
        ResourceManagers[source] = manager ?? throw new ArgumentNullException(nameof(manager));
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    private void RaiseResultChanged()
    {
        OnPropertyChanged(nameof(Result));
    }

    private void OnPropertyChanged([CallerMemberName] string? propName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    }
}
相关推荐
happyprince34 分钟前
11-Hugging Face Transformers 分布式与并行系统深度分析
分布式·c#·wpf
加号32 小时前
【WPF】 基于 Canvas 读取并渲染 DXF 文件的技术指南
c#·wpf
AC赳赳老秦5 小时前
用 OpenClaw 整理团队技术分享:自动提取 PPT 内容、生成文字稿、同步到知识库
开发语言·python·自动化·powerpoint·wpf·deepseek·openclaw
闪电悠米8 小时前
黑马点评-秒杀优化-03_blocking_queue_async_order
数据库·分布式·oracle·junit·wpf·lua
kingwebo'sZone10 小时前
WPF 在(WrapPanel父级使用可以自动换行)每个 TextBlock 显示一行数据(竖排,垂直)
wpf
闪电悠米1 天前
黑马点评-秒杀优化-02_lua_precheck
开发语言·redis·分布式·缓存·junit·wpf·lua
FuckPatience1 天前
WPF 获取一个控件某个依赖属性的默认绑定方式
wpf
加号31 天前
【WPF】 ListView 数据绑定:从列表呈现到复杂交互的完整实践
wpf·交互
闪电悠米2 天前
黑马点评-Redisson-01_why_redisson
java·服务器·网络·数据库·缓存·wpf
小满Autumn2 天前
CommunityToolkit.Mvvm 架构笔记:现代 MVVM、源生成器与工程化实践
笔记·架构·c#·.net·wpf·mvvm