在进行WPF项目开发时,本地化是一个不可忽视的重要环节。本篇文章将介绍如何在WPF项目中指定文本的大小写和复数形式,以满足不同语言环境下的显示需求。
在参与一个使用WPF进行开发的项目时,遇到了一个本地化的问题。项目中相同的文本在不同的地方被使用,但有时需要大写,有时不需要。通常情况下,资源的名称是以英文命名的。不幸的是,即使大小写不同,也不能为两个不同的资源使用相同的名称。有趣的是,大小写必须与资源名称匹配。为了解决这个问题,增强了原始代码,使其能够指定大小写作为属性。
后来,考虑将复数形式也加入到项目中。在应用程序中,已经有了一个进行复数形式转换的方法。考虑将这段代码加入,但后来发现了PluralizationServices
类,它位于System.Data.Entity.Design
命名空间中。尽管这个服务有一些限制,但可能需要使用不同的解决方案。
为了给现有项目添加这两个功能,只需要添加少量的代码。在派生的MarkupExtension
类LocExtension
中,需要添加两个属性,并为每个属性创建一个枚举:
public enum CaseEnum { None = 0, Upper, Lower }
public enum PluralizationEnum { None = 0, Plural, Singular }
还需要将这两个属性添加到用作不同TargetProperty
类型的基类的抽象LocalizedProperty
类中。然后在LocExtension
类的ProvideValue
方法中,只需要将LocalizedProperty
类的属性设置为与LocExtension
类中的值相匹配即可。
接下来,只需要在LocalizedProperty
类的GetValue
方法中,根据需要修改生成的字符串,然后返回值(如果类型实际上是字符串):
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));
}
需要注意的是,使用object
作为localizedValue
的类型,因为该值实际上可能不是字符串。每个用于大写和小写转换的方法首先检查localizedValue
是否为字符串,然后再进行处理。
实际上,为这个类添加了一个特性。这可能不是必需的,但确实使用了它。这是一个静态的Loc
类,它使用相同的键字符串访问相同的值:
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 }
这个示例与原始代码中的示例相同,但做了一些改动。一个是在XAML中指定了Case
和Pluralization
的控件,如上面的TextBlock
代码所示。第二个是在Resources.resx
文件中,"Callback:"的末尾的冒号(":")已经被移除。这是因为冒号(":")会干扰PluralizationService
进行复数形式的处理。PluralizationService
不处理冒号,所以为了演示这个功能,必须移除它。