WPF 高级本地化






4.93/5 (10投票s)
这是“高级WPF本地化”的另一种选择,它增加了文本大小写和复数化的显示功能。
引言
本文介绍了一个项目,该项目在原始文章《高级WPF本地化》的基础上增加了一些增强功能:它增加了指定大小写和复数化的能力。
背景
我曾在一个项目中使用这个Localization
项目进行本地化。问题在于,在不同的地方使用了相同的文本,但在某些情况下文本是大写的,而在其他情况下不是。通常,英文名称用于资源名称。不幸的是,即使大小写不同,也无法为两个不同的资源使用相同的名称。有趣的是,大小写必须与资源关联的名称匹配。为了解决这个问题,我增强了原始值,使其能够将大小写指定为ExtensionMethod
上的一个属性。我使用了一个枚举来指定允许的不同大小写(无、大写、小写),这意味着智能感知会起作用。这很好地解决了我们的问题。
后来我想到也可以包含复数化。在我们的应用程序中,我们确实有一个方法来进行复数化,我曾考虑过包含那段代码,但后来发现了PluralizationServices
,它位于System.Data.Entity.Design
命名空间
中。该服务有一些限制,所以你可能想使用不同的方法。
在此期间,我对代码进行了一些清理。
新代码
只需少量代码即可为现有项目添加这两项功能。在派生的MarkupExtension
类
LocExtension
中,需要添加两个属性,并为每个属性定义一个枚举。
public CaseEnum Case { get; set; }
public enum CaseEnum
{
None = 0, Upper, Lower
}
public PluralizationEnum Pluralization { get; set; }
public enum PluralizationEnum
{
None = 0, Plural, Singular
}
还需要将这两个属性添加到用作不同TargetProperty
类型基类的abstract
LocalizedProperty
类
中。然后在LocExtension
的ProvideValue
方法中,只需将LocalizedProperty
类
中的属性设置为与LocExtension
类
中的值匹配即可。
然后,在LocalizedProperty
类
的GetValue
方法中,只需相应地修改生成的string
,然后在类型确实是string
时返回该值。
internal object GetValue()
{
var localizedValue = GetLocalizedValue();
var converter = Property.Converter;
if (converter != null)
{
localizedValue = converter.Convert(
localizedValue,
Property.GetValueType(),
Property.ConverterParameter,
Property.GetCulture()
);
}
return AdjustForCase(AdjustForPluralization(localizedValue));
}
private object AdjustForCase(object localizedValue)
{
var strValue = localizedValue as string;
if (strValue == null) return localizedValue;
switch (Property.Case)
{
case LocExtension.CaseEnum.None:
return strValue;
case LocExtension.CaseEnum.Upper:
return strValue.ToUpper();
case LocExtension.CaseEnum.Lower:
return strValue.ToLower();
default:
throw new ArgumentOutOfRangeException();
}
}
private object AdjustForPluralization(object localizedValue)
{
var strValue = localizedValue as string;
if (strValue == null) return localizedValue;
switch (Property.Pluralization)
{
case LocExtension.PluralizationEnum.None:
return strValue;
case LocExtension.PluralizationEnum.Singular:
return strValue.ToSingular();
case LocExtension.PluralizationEnum.Plural:
return strValue.ToPlural();
default:
throw new ArgumentOutOfRangeException();
}
}
需要注意的是,localizedValue
使用了object
类型,因为这个值实际上可能不是字符串。用于大小写转换和复数化的两个方法都会先检查localizedValue
是否为string
,然后再进行处理。
添加到这个项目中的唯一其他东西是一个静态类,用于包含复数化的扩展方法。
public static class PluralizationExtensions
{
private static PluralizationService _pluralizationService;
private static PluralizationService PluralizationService => _pluralizationService
?? (_pluralizationService = PluralizationService.CreateService(CultureInfo.CurrentCulture));
public static string ToPlural(this string value)
{
if (String.IsNullOrEmpty(value)) throw new ArgumentException("Value is required", nameof(value));
return PluralizationService.IsPlural(value) ? value : PluralizationService.Pluralize(value);
}
public static string ToSingular(this string value)
{
if (String.IsNullOrEmpty(value)) throw new ArgumentException("Value is required", nameof(value));
return PluralizationService.IsSingular(value) ? value : PluralizationService.Singularize(value);
}
}
这个类
可以独立使用。
又一个附加功能
我实际上也为这个类添加了一个功能。它可能不是必需的,但我确实使用了它。这是一个static
Loc
类,它允许使用相同的键string
访问相同的值。
public static class Loc
{
public static object GetValue(string value)
{
var resourceManager = LocalizationManager.DefaultResourceManager;
if (resourceManager == null) return $"[{value}]";
var uiCulture = Thread.CurrentThread.CurrentCulture;
var returnValue = resourceManager.GetObject(value, uiCulture);
return returnValue ?? $"[{value}]";
}
}
我还将解决方案更新到了框架版本4.6.1,并用条件运算符和一些较新的C# 6.0特性替换了许多代码。
使用代码
原始文章可以参考以了解代码的原始功能。本文仅涵盖了新增功能,即用于指定代码的大小写和复数化的新增元素。
这个代码片段展示了如何指定文本应为大写并进行复数化。
<TextBlock Grid.Row="0"
Grid.Column="0"
Style="{StaticResource Label}"
Text="{Loc Label_CodeBehind_Callback, Case=Upper, Pluralization=Plural}" />
Case
和Pluralization
参数都是可选的,如果不希望使用此功能,可以省略。两者都在代码中指定为枚举。
public enum CaseEnum
{
None = 0, Upper, Lower
}
public enum PluralizationEnum
{
None = 0, Plural, Singular
}
示例
这是与原始代码中相同的示例,但进行了一些更改。一种是包含“Callback:”的控件在XAML中指定了Case
和Pluralization
,如上面的TextBlock
代码所示。二是Label_CodeBehind_Callback
在Resources.resx
文件中的“Callback:”末尾的冒号(“:”)已删除。这是因为冒号(“:”)会干扰PluralizationService
的复数化。PluralizationService
不处理冒号,因此为了演示该功能,必须删除冒号。
历史
- 16/06/16:初始版本
- 16/06/17:清理