Skip to content

Instantly share code, notes, and snippets.

@canton7
Last active September 24, 2017 07:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save canton7/e4d250ec9fa625913efe to your computer and use it in GitHub Desktop.
Save canton7/e4d250ec9fa625913efe to your computer and use it in GitHub Desktop.
using System;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
namespace LocalizationDemo.Localization
{
/// <summary>
/// Localization converter which takes a static key and is applied to a single value
/// </summary>
public class StaticKeySingleValueConverter : IValueConverter
{
/// <summary>
/// Gets or sets the key to use to look up a localized string
/// </summary>
public string Key { get; set; }
/// <summary>
/// Gets or sets an optional converter to apply to the value
/// </summary>
public IValueConverter Converter { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (this.Key == null)
throw new InvalidOperationException("Key must not be null");
var convertedValue = (this.Converter == null) ? value : this.Converter.Convert(value, targetType, parameter, culture);
return Localizer.Translate(this.Key, convertedValue);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
/// <summary>
/// Localization converter which takes a static key and is applied to multiple values
/// </summary>
public class StaticKeyMultipleValuesConverter : IMultiValueConverter
{
/// <summary>
/// Gets or sets the key to use to look up a localized string
/// </summary>
public string Key { get; set; }
/// <summary>
/// Gets or sets an optional converter to apply to the values. May return a scalar or an array
/// </summary>
public IMultiValueConverter Converter { get; set; }
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (this.Key == null)
throw new InvalidOperationException("Key must not be null");
if (this.Converter == null)
return Localizer.Translate(this.Key, values);
var convertedValues = this.Converter.Convert(values, targetType, parameter, culture);
return Localizer.Translate(this.Key, convertedValues as object[] ?? new object[] { convertedValues });
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
/// <summary>
/// Localization converter which is applied to a key binding
/// </summary>
public class BoundKeyNoValuesConverter : IValueConverter
{
/// <summary>
/// Gets or sets an optional converter to apply to the key binding first
/// </summary>
public IValueConverter Converter { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var stringValue = (this.Converter == null) ? value as string : this.Converter.Convert(value, targetType, parameter, culture) as string;
return (stringValue != null) ? Localizer.Translate(stringValue) : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
/// <summary>
/// Localization converter which is applied to a MultiBinding of { Key Binding, Value Binding, [Value Binding [...]] }
/// </summary>
public class BoundKeyWithValuesConverter : IMultiValueConverter
{
/// <summary>
/// Gets or sets an optional converter to apply to the value bindings (not the key binding)
/// </summary>
public IMultiValueConverter ValuesConverter { get; set; }
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
// The first item is the key. The rest are the values
if (values.Length < 1)
return null;
var key = values[0] as string;
if (key == null)
return null;
var parameters = values.Skip(1).ToArray();
if (this.ValuesConverter == null)
return Localizer.Translate(key, parameters);
var convertedParameters = this.ValuesConverter.Convert(parameters, targetType, parameter, culture);
return Localizer.Translate(key, convertedParameters as object[] ?? new object[] { convertedParameters });
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
using LocalizationDemo.Properties;
using System;
using System.Threading;
namespace LocalizationDemo.Localization
{
public static class Localizer
{
public static string Translate(string key, params object[] parameters)
{
var culture = Thread.CurrentThread.CurrentUICulture;
var format = Resources.ResourceManager.GetString(key, culture);
if (format == null)
return "!" + key + (parameters.Length > 0 ? ":" + String.Join(",", parameters) : "") + "!";
return String.Format(culture, format, parameters);
}
public static string Format(string format, params object[] parameters)
{
return String.Format(Thread.CurrentThread.CurrentCulture, format, parameters);
}
}
}
using System;
using System.Windows.Data;
using System.Windows.Markup;
namespace LocalizationDemo.Localization
{
public class LocExtension : MarkupExtension
{
/// <summary>
/// Gets or sets the key to use to look up the appropriate value to display.
/// </summary>
/// <remarks>
/// Either this or <see cref="KeyBinding"/> must be set.
/// </remarks>
public string Key { get; set; }
/// <summary>
/// Gets or sets the key binding to use the look up the appropriate value to display.
/// </summary>
/// <remarks>
/// The binding is evaluated, and the result used as the key.
/// Either this or <see cref="Key"/> must be set.
/// </remarks>
public Binding KeyBinding { get; set; }
/// <summary>
/// Gets or sets an optional binding to use to supply a single parameter to substitute into the value to display.
/// </summary>
/// <remarks>
/// This or <see cref="ParamBindings"/> may be set, but not both.
/// </remarks>
public Binding ParamBinding { get; set; }
/// <summary>
/// Gets or set an optional MultiBinding to use to supply multiple parameters to substitute into the value to display.
/// </summary>
/// <remarks>
/// This or <see cref="ParamBinding"/> may be set, but not both.
/// </remarks>
public MultiBinding ParamBindings { get; set; }
public LocExtension()
{
}
public LocExtension(string key)
{
this.Key = key;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (this.Key == null && this.KeyBinding == null)
throw new ArgumentException("Either Key or KeyBinding must be set");
if (this.Key != null && this.KeyBinding != null)
throw new ArgumentException("Either Key or KeyBinding must be set, but not both");
if (this.ParamBinding != null && this.ParamBindings != null)
throw new ArgumentException("ParamBinding and ParamBindings may not be set at the same time");
// Most of these conditions are redundent, according to the assertions above. However I'll still state them,
// for clarity.
// A static key, and no values
if (this.Key != null && this.KeyBinding == null && this.ParamBinding == null && this.ParamBindings == null)
{
// Just returning a string!
return Localizer.Translate(this.Key);
}
// A static key, and a single value
if (this.Key != null && this.KeyBinding == null && this.ParamBinding != null && this.ParamBindings == null)
{
var converter = new StaticKeySingleValueConverter() { Key = this.Key, Converter = this.ParamBinding.Converter };
this.ParamBinding.Converter = converter;
return this.ParamBinding.ProvideValue(serviceProvider);
}
// A static key, and multiple values
if (this.Key != null && this.KeyBinding == null && this.ParamBinding == null && this.ParamBindings != null)
{
var converter = new StaticKeyMultipleValuesConverter() { Key = this.Key, Converter = this.ParamBindings.Converter };
this.ParamBindings.Converter = converter;
return this.ParamBindings.ProvideValue(serviceProvider);
}
// A bound key, no values
if (this.Key == null && this.KeyBinding != null && this.ParamBinding == null && this.ParamBindings == null)
{
var converter = new BoundKeyNoValuesConverter() { Converter = this.KeyBinding.Converter };
this.KeyBinding.Converter = converter;
return this.KeyBinding.ProvideValue(serviceProvider);
}
// A bound key, and one value
if (this.Key == null && this.KeyBinding != null && this.ParamBinding != null && this.ParamBindings == null)
{
var converter = new BoundKeyWithValuesConverter();
var multiBinding = new MultiBinding() { Converter = converter };
multiBinding.Bindings.Add(this.KeyBinding);
multiBinding.Bindings.Add(this.ParamBinding);
return multiBinding.ProvideValue(serviceProvider);
}
// A bound key, and multiple values
if (this.Key == null && this.KeyBinding != null && this.ParamBinding == null && this.ParamBindings != null)
{
var converter = new BoundKeyWithValuesConverter() { ValuesConverter = this.ParamBindings.Converter };
this.ParamBindings.Bindings.Insert(0, this.KeyBinding);
this.ParamBindings.Converter = converter;
return this.ParamBindings.ProvideValue(serviceProvider);
}
throw new Exception("Should never get here");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment