public interface ILocalizationProvider { object Localize(string key); IEnumerable<CultureInfo> Cultures { get; } }
public class ResxLocalizationProvider : ILocalizationProvider { private IEnumerable<CultureInfo> _cultures; public object Localize(string key) { return Strings.ResourceManager.GetObject(key); } public IEnumerable<CultureInfo> Cultures => _cultures ?? (_cultures = new List<CultureInfo> { new CultureInfo("ru-RU"), new CultureInfo("en-US"), }); }
public class LocalizationManager { private LocalizationManager() { } private static LocalizationManager _localizationManager; public static LocalizationManager Instance => _localizationManager ?? (_localizationManager = new LocalizationManager()); public event EventHandler CultureChanged; public CultureInfo CurrentCulture { get { return Thread.CurrentThread.CurrentCulture; } set { if (Equals(value, Thread.CurrentThread.CurrentUICulture)) return; Thread.CurrentThread.CurrentCulture = value; Thread.CurrentThread.CurrentUICulture = value; CultureInfo.DefaultThreadCurrentCulture = value; CultureInfo.DefaultThreadCurrentUICulture = value; OnCultureChanged(); } } public IEnumerable<CultureInfo> Cultures => LocalizationProvider?.Cultures ?? Enumerable.Empty<CultureInfo>(); public ILocalizationProvider LocalizationProvider { get; set; } private void OnCultureChanged() { CultureChanged?.Invoke(this, EventArgs.Empty); } public object Localize(string key) { if (string.IsNullOrEmpty(key)) return "[NULL]"; var localizedValue = LocalizationProvider?.Localize(key); return localizedValue ?? $"[{key}]"; } }
LocalizationManager.Instance.LocalizationProvider = new ResxLocalizationProvider();
public class KeyLocalizationListener : INotifyPropertyChanged { public KeyLocalizationListener(string key, object[] args) { Key = key; Args = args; LocalizationManager.Instance.CultureChanged += OnCultureChanged; } private string Key { get; } private object[] Args { get; } public object Value { get { var value = LocalizationManager.Instance.Localize(Key); if (value is string && Args != null) value = string.Format((string)value, Args); return value; } } public event PropertyChangedEventHandler PropertyChanged; private void OnCultureChanged(object sender, EventArgs eventArgs) { // PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value))); } ~KeyLocalizationListener() { LocalizationManager.Instance.CultureChanged -= OnCultureChanged; } }
public class BindingLocalizationListener { private BindingExpressionBase BindingExpression { get; set; } public BindingLocalizationListener() { LocalizationManager.Instance.CultureChanged += OnCultureChanged; } public void SetBinding(BindingExpressionBase bindingExpression) { BindingExpression = bindingExpression; } private void OnCultureChanged(object sender, EventArgs eventArgs) { try { // // BindingExpression?.UpdateTarget(); } catch { // ignored } } ~BindingLocalizationListener() { LocalizationManager.Instance.CultureChanged -= OnCultureChanged; } }
public class BindingLocalizationConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values == null || values.Length < 2) return null; var key = System.Convert.ToString(values[1] ?? ""); var value = LocalizationManager.Instance.Localize(key); if (value is string) { var args = (parameter as IEnumerable<object> ?? values.Skip(2)).ToArray(); if (args.Length == 1 && !(args[0] is string) && args[0] is IEnumerable) args = ((IEnumerable) args[0]).Cast<object>().ToArray(); if (args.Any()) return string.Format(value.ToString(), args); } return value; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotSupportedException(); } }
[ContentProperty(nameof(ArgumentBindings))] public class LocalizationExtension : MarkupExtension { private Collection<BindingBase> _arguments; public LocalizationExtension() { } public LocalizationExtension(string key) { Key = key; } /// <summary> /// /// </summary> public string Key { get; set; } /// <summary> /// /// </summary> public Binding KeyBinding { get; set; } /// <summary> /// /// </summary> public IEnumerable<object> Arguments { get; set; } /// <summary> /// /// </summary> public Collection<BindingBase> ArgumentBindings { get { return _arguments ?? (_arguments = new Collection<BindingBase>()); } set { _arguments = value; } } public override object ProvideValue(IServiceProvider serviceProvider) { if (Key != null && KeyBinding != null) throw new ArgumentException($" {nameof(Key)} {nameof(KeyBinding)}"); if (Key == null && KeyBinding == null) throw new ArgumentException($" {nameof(Key)} {nameof(KeyBinding)}"); if (Arguments != null && ArgumentBindings.Any()) throw new ArgumentException($" {nameof(Arguments)} {nameof(ArgumentBindings)}"); var target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget)); if (target.TargetObject.GetType().FullName == "System.Windows.SharedDp") return this; // , // BindingLocalizationListener if (KeyBinding != null || ArgumentBindings.Any()) { var listener = new BindingLocalizationListener(); // var listenerBinding = new Binding { Source = listener }; var keyBinding = KeyBinding ?? new Binding { Source = Key }; var multiBinding = new MultiBinding { Converter = new BindingLocalizationConverter(), ConverterParameter = Arguments, Bindings = { listenerBinding, keyBinding } }; // foreach (var binding in ArgumentBindings) multiBinding.Bindings.Add(binding); var value = multiBinding.ProvideValue(serviceProvider); // listener.SetBinding(value as BindingExpressionBase); return value; } // , KeyLocalizationListener if (!string.IsNullOrEmpty(Key)) { var listener = new KeyLocalizationListener(Key, Arguments?.ToArray()); // DependencyProperty DependencyObject Setter if ((target.TargetObject is DependencyObject && target.TargetProperty is DependencyProperty) || target.TargetObject is Setter) { var binding = new Binding(nameof(KeyLocalizationListener.Value)) { Source = listener, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged }; return binding.ProvideValue(serviceProvider); } // Binding, var targetBinding = target.TargetObject as Binding; if (targetBinding != null && target.TargetProperty != null && target.TargetProperty.GetType().FullName == "System.Reflection.RuntimePropertyInfo" && target.TargetProperty.ToString() == "System.Object Source") { targetBinding.Path = new PropertyPath(nameof(KeyLocalizationListener.Value)); targetBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; return listener; } // return listener.Value; } return null; } }
<TextBlock Text="{l:Localization Key=SomeKey}" />
or <TextBlock Text="{l:Localization SomeKey}" />
<TextBlock Text="{l:Localization KeyBinding={Binding SomeProperty}}" />
There are many scenarios for using localization by binding. For example, if it is necessary to display localized values ​​of some enumeration (Enum) in the drop-down list. <TextBlock> <TextBlock.Text> <l:Localization Key="SomeKey" Arguments="{StaticResource SomeArray}" /> </TextBlock.Text> </TextBlock>
<TextBlock> <TextBlock.Text> <l:Localization Key="SomeKey"> <Binding Source="{l:Localization SomeKey2}" /> <Binding Path="SomeProperty" /> </l:Localization> </TextBlock.Text> </TextBlock>
This localization option is useful when displaying validation messages (for example, a message about the minimum length of the input field).Source: https://habr.com/ru/post/274477/
All Articles