WPF中的多语言支持

22

你能推荐一个好的方式来实现WPF应用程序的多语言系统吗?我现在使用的方法涉及XML、类和XAML扩展。它在大多数情况下都运行良好,但当我必须处理动态标签或一般的动态文本时,它需要额外的努力。我希望让程序员只在主要问题上工作,并忘记语言问题。

4个回答

39

按照以下步骤进行操作:

1) 将所有String片段放在单独的资源文件中。

例如:StringResources.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">

    <!-- String resource that can be localized -->
    <system:String x:Key="All_Vehicles">All Vehicles</system:String>

</ResourceDictionary>

2) 为每种语言创建副本,并将它们(翻译后的副本)添加到合并的字典中。别忘了加上国家的 ISO 代码,以便更方便地处理。

例如: App.xaml

<Application x:Class="WpfStringTables.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
    <Application.Resources>
        <ResourceDictionary >
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="StringResources.de-DE.xaml" />
                <ResourceDictionary Source="StringResources.nl-NL.xaml" />
                <ResourceDictionary Source="StringResources.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

将使用最后一个包含字符串的资源文件替换代码中的文本部分。

3a) 使用 String 表中的文本部分:

示例:Window1.xaml

<Window x:Class="WpfStringTables.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
    <Grid>
        <Button Margin="51,82,108,129" Name="AllVehiclesButton" 
                Content="{StaticResource All_Vehicles}"/>
    </Grid>
</Window>

3b) 从代码中加载资源(仅在不想通过 XAML 设置时使用此代码):

void PageLoad()
{
  string str = FindResource("All_Vehicles").ToString();
}

4) 在应用程序启动时切换到新的文化:

App.xaml.cs 中的代码片段:

public static void SelectCulture(string culture)    
{      
    if (String.IsNullOrEmpty(culture))
        return;

    //Copy all MergedDictionarys into a auxiliar list.
    var dictionaryList = Application.Current.Resources.MergedDictionaries.ToList();

    //Search for the specified culture.     
    string requestedCulture = string.Format("StringResources.{0}.xaml", culture);
    var resourceDictionary = dictionaryList.
        FirstOrDefault(d => d.Source.OriginalString == requestedCulture);

    if (resourceDictionary == null)
    {
        //If not found, select our default language.             
        requestedCulture = "StringResources.xaml";
        resourceDictionary = dictionaryList.
            FirstOrDefault(d => d.Source.OriginalString == requestedCulture);
    }

    //If we have the requested resource, remove it from the list and place at the end.     
    //Then this language will be our string table to use.      
    if (resourceDictionary != null)
    {
        Application.Current.Resources.MergedDictionaries.Remove(resourceDictionary);
        Application.Current.Resources.MergedDictionaries.Add(resourceDictionary);
    }

    //Inform the threads of the new culture.     
    Thread.CurrentThread.CurrentCulture = new CultureInfo(culture);
    Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);

}

喜欢你的建议。需要添加的内容: 我认为我们可以通过使用 {StaticResource resKey} 使应用程序在运行时可切换。 - Nam G VU
5
实际上,只需在使用资源的地方指定 {DynamicResource resKey},然后在运行时,随时调用上面的 SelectCulture(culture) 方法,它将动态地更新所有字符串到新的文化。不要使用这种方式:string str = FindResource("All_Vehicles").ToString(); 而应该使用:Application.Current.Resources["All_Vehicles"] as string。 - Curtis
在执行期间有没有任何方法可以更改它? - albatross
您可以在运行时调用该方法,例如在单击带有国旗的按钮后。 - Andre van Heerwaarde
如果您正在构建一个大型应用程序,并且希望从WPF、ASP.NET或其他类库引用相同的文件,则在我看来,这是一个更好的解决方案:https://dev59.com/tnRC5IYBdhLWcg3wOOP1#35813707 - CularBytes

17

我正在使用WPF本地化扩展。这是一种非常简单的方法,可以将DependencyObject上的任何类型的DependencyProperty本地化。

  • 处于真正稳定的状态
  • 支持类似绑定写法,例如:Text = {LocText ResAssembly:ResFile:ResKey}
  • 支持.resx回退机制(例如,en-us -> en -> 独立文化)
  • 支持强制区域设置(例如,“这必须始终是英语”)
  • 适用于普通依赖属性
  • 适用于控件模板
  • 可以在XAML中使用(确实 :P),而无需添加任何命名空间
  • 可以在代码后台中使用,将本地化值绑定到动态生成的控件上
  • 实现了INotifyPropertyChanged以进行高级用途
  • 支持字符串格式化,例如:"this is the '{0}' value"
  • 支持前缀和后缀值(目前使用LocText扩展)
  • 在生产系统中使用(例如我的公共关系产品)
  • 运行时切换语言不影响时间片
  • 可以与任何资源文件(.resx)一起使用,跨所有程序集(包括运行时动态加载的程序集)
  • 不需要任何初始化过程(例如“调用xyz来注册特殊本地化字典”)
  • 在设计时可用(MS Expression Blend,MS Visual Studio 2008(正常和SP1)
  • 可以在设计时更改选择的语言
  • 可以本地化任何数据类型,只要存在其转换器(TypeConverter)(扩展了LocalizeExtension
  • 内置对Text、大写Text、小写TextImageBrushDoubleThickness的支持
  • 不会影响任何内存泄漏
  • 保留UID属性不变
  • 提供一个SpecificCulture用作IFormatProvider(例如,(123.20).ToString(LocalizeDictionary.SpecificCulture) = "123.20"或者"123,20"
  • 提供一些功能来检查和在代码中获取资源值
  • 不会修改Thread.CurrentCulture或者Thread.CurrentUICulture(可以轻松更改)

6
没有关于如何使用这个的文档或教程? - L-Four
1
现在提供文档 http://wpflocalizeextension.codeplex.com/documentation - SeriousM

1

Josh Smith撰写了一篇深入教程,介绍了他的首选方法:在WPF中创建国际化向导

这可能会指向一个大的重新设计(它是一个MVVM解决方案),但出于其他原因使用MVVM似乎也是值得的。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接