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));
}
}