65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 高级本地化

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.93/5 (10投票s)

2016年6月16日

CPOL

3分钟阅读

viewsIcon

20894

downloadIcon

230

这是“高级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 中。然后在LocExtensionProvideValue方法中,只需将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}" />

CasePluralization参数都是可选的,如果不希望使用此功能,可以省略。两者都在代码中指定为枚举。

  public enum CaseEnum
  {
   None = 0, Upper, Lower
  }

  public enum PluralizationEnum
  {
   None = 0, Plural, Singular
  }

示例

这是与原始代码中相同的示例,但进行了一些更改。一种是包含“Callback:”的控件在XAML中指定了CasePluralization,如上面的TextBlock代码所示。二是Label_CodeBehind_CallbackResources.resx文件中的“Callback:”末尾的冒号(“:”)已删除。这是因为冒号(“:”)会干扰PluralizationService的复数化。PluralizationService不处理冒号,因此为了演示该功能,必须删除冒号。

历史

  • 16/06/16:初始版本
  • 16/06/17:清理
© . All rights reserved.