1. 前言

WPF的当地化是个很广阔的机能,我做过的WPF程序超越百分之五十都实现了本地化(不管最终有未有应用)。经常本地化有以下几点供给:

  • 在程序运维时依据CultureInfo.CurrentUICulture或配备项显示对应语言的UI。
  • 在程序运转时得以动态切换UI语言(没有须求重启程序)。
  • 制作对应不一致语言的安装包。
  • 通过下载语言包达成各个语言的本地化。

内部唯有首先点是不可缺少的。
其次点最佳也得以兑现,许多时候切换语言只为了看看有些职业术语在立陶宛语中的原来的书文是怎么着,大概一时半刻打字与印刷个英文报表,日常接纳可能用汉语,用户不想为了那点重启程序。
其三点和第四点就算很广泛,但自身平素没完成过,究竟文字能源(有的时候还会有少些图形)占用的上空不会太多,大部分WPF程序都尚未大到要求考虑安装包大小,全体语言的财富总体打包进多个安装包就足以了。

WPF本地化本事很干练,也是有二种方案,微软在MSDN给出了详细的介绍WPF
全世界化和本地化概述.aspx),还会有一份古老的文书档案WPF
Localization
Guidance,整整66页,里面详细介绍了各个WPF本地化的体制。

正文只介绍三种达成上述第1、2点急需的方案。

1. 前言

上一篇小说介绍了各个WPF本地化的入门知识,这篇小说介绍UWP本地化的入门知识。

正文将钻探在WPF中一种相比较有利的本地化方法。

2. 行使能源词典

2. 采用resw财富文件落实本地化

在在此以前的XAML平台,resx能源文件是一种很低价的本地化方案,但在UWP中微软又重新推荐x:Uid方案,暗许的能源文件也成为resw财富文件。尽管后缀名只差了二个假名,但利用办法完全差异。最关键的分别是resw能源文件不会创制对应的Designer.cs类,那就导致本地化的实现方案完全分化。

必威中文官网 1

鉴于在项目中要落到实处本地化,所以自身在网络查找有关的缓和方案。通过一多元科学切磋,发掘达成本地化的秘技重要有以下三种:

2.1 基本原理

对WPF开垦者来讲,财富词典鲜明不会目生。可是在财富词典里应用string大概比较少。

<Window x:Class="LocalizationDemoWpf.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:LocalizationDemoWpf"
        mc:Ignorable="d" 
        xmlns:system="clr-namespace:System;assembly=mscorlib"
        Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <system:String x:Key="Chinese">中文</system:String>
    </Window.Resources>
    <Grid>
        <TextBlock Text="{DynamicResource Chinese}"/>
    </Grid>
</Window>

如以上代码所示,在XAML中定义string财富要求先引进xmlns:system="clr-namespace:System;assembly=mscorlib"取名空间,之后再选拔DynamicResource援引那一个财富。不要选拔StaticResource,那样没有办法做到动态切换语言。

要利用财富词典完成本地化,须要先创建所需语言的xaml,小编在DEMO中成立了en-us.xaml和zh-cn.xaml三个财富词典,里面的盈盈的能源结构相同(指数量和Key同样):

<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"
                    xmlns:local="clr-namespace:LocalizationDemoWpf">
    <system:String x:Key="SwitchLanguage">切换语言</system:String>
    <system:String x:Key="Chinese">中文</system:String>
    <system:String x:Key="English">英文</system:String>
    <system:String x:Key="Username">用户名</system:String>
    <system:String x:Key="Sex">性别</system:String>
    <system:String x:Key="Address">地址</system:String>
    <SolidColorBrush x:Key="Background" Color="#88FF0000"/>
</ResourceDictionary>

在先后运行时依照CultureInfo.CurrentUICulture或配备项选取相应的财富词典,使用MergedDictionaries的法子加载到程序的能源聚合中:

var culture = ReadCultureFromConfig();
var cultureInfo = new System.Globalization.CultureInfo(culture);
Thread.CurrentThread.CurrentUICulture = cultureInfo;
Thread.CurrentThread.CurrentCulture = cultureInfo;


ResourceDictionary dictionary = new ResourceDictionary { Source = new Uri($@"Resources\{culture}.xaml", UriKind.RelativeOrAbsolute) };
Application.Current.Resources.MergedDictionaries[0] = dictionary;

如此当地化的坚守就完毕了。

2.1 在XAML中贯彻本地化

在XAML中落到实处当地化的长河很简单。首先在档案的次序中新建”strings”文件夹,在”strings”文夹下创办”en-US”和”zh-CN”文件夹,并在八个公文夹中分头拉长”Resources.resw”能源文件。最终目录结构如下:
必威中文官网 2

在zh-CN\Resources.resw和en-US\Resources.resw增添两个新能源,分别是UsernameTextBox.Width和UsernameTextBox.Header:
必威中文官网 3

在XAML中增加三个TextBox,设置x:Uid为UsernameTextBox,x:Uid将XAML成分和能源文件中的财富进行关联:

<TextBox x:Uid="UsernameTextBox"/>

运营后就能够知到UsernameText博克斯的Header设置为”用户名”,Width为100。

在“设置\区域和语言”团长”English”设置为私下认可语言,再度运维应用可阅览运行在爱尔兰语蒙受下的职能。
必威中文官网 4

如此那般基本的本地化功效就完成了。这种本地化格局有如下优点:

  • 简轻巧单高效,轻便上手
  • 语法简单,无需Binding等学问
  • 能够内定率性属性进行本地化
  • 支持CLR属性

除开,上一篇小说提到的ResXManager也帮忙Resw财富文件,还是能够运用多语言应用工具包对能源文件实行政管理制,博客园的那篇小说页对那个工具进行了详尽介绍:
Win10 UWP
开拓种类:使用多语言工具包让应用支撑多语言

抑或参照他事他说加以考察那几个摄像:
Windows 10 Apps Designing for Global
Customers

  1. 由此编写翻译项目以设置 x:Uid 并使用 LocBaml 工具完毕;
  2. 通过 DynamicResource 实现;
  3. 透过 Resx 文件落到实处

2.2 动态切换语言

骨子里上述方案已落到实处了动态切换语言。
XAML财富的援引原则是前后原则,这几个周围不唯有指VisualTree上的不远处,还指时间上的周围。后增多进能源词典的财富将替换在此之前的同名财富。使用DynamicResource而不是StaticResource,便是为了在能源被调换时能实时改变UI的显示。

2.2 关联到任何能源文件

UI成分暗许与Resources.resw举办关联,假如急需和别的资源文件涉及,能够加上财富文件的路线。如须要与/OtherResources.resw中的财富事关,x:Uid的语法如下:

x:Uid="/OtherResources/AddressTextBox"

中间第一种是法定介绍.aspx)的诀窍,思索到贯彻步骤略为复杂性,所以直接忽略;

2.3 设计时帮忙

VisualStudio的XAML设计时帮衬对开荒WPF程序至关心注重要,对本地化来讲,设计时支持重视涵盖3片段:

  • 在编写XAML时方可博得能源的智能感知
  • 有总体的宏图视图
  • 在差异语言之间切换

利用财富词典达成本地化,只需在App.xaml中联合对应的财富词典就可以获得完整的设计时帮忙。

<Application x:Class="LocalizationDemoWpf.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:LocalizationDemoWpf"
             xmlns:resource="clr-namespace:LocalizationDemoWpf.Resource;assembly=LocalizationDemoWpf.Resource"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/LocalizationDemoWpf;component/Resources/zh-cn.xaml"/>
                <!--<ResourceDictionary Source="/LocalizationDemoWpf;component/Resources/en-us.xaml"/>-->
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

必威中文官网 5

这段XAML只是为了增长规划时体验,没有也能通过编写翻译。

2.3 附加属性的本地化

对系统提供的增大属性,能源的名称语法如下:

UsernameTextBox.Grid.Row

对自定义附加属性,语法稍微复杂一些:

ShowMessageButton.[using:LocalizationDemoUwp]ButtonEx.Content

奇异的是,就那样一向运维应用会报错。只有利用那个能源的UI成分已经有那个附加属性的值技巧健康运维,轻易的话便是需求随意为那几个附加属性设置二个值:

<Button Margin="5" x:Uid="ShowMessageButton"  local:ButtonEx.Content="ssssss"/>

第三种艺术的贯彻,首如果在先后中增添 Resource Dictionary
类型的公文,并在里头放入本地化财富字符串;在 XAML 代码中,直接利用
{DynamicResource XXXX} 来完毕;这种办法比较便利,可是它也可能有四个缺陷:

2.4 在代码里拜访能源

在代码中做客财富相比麻烦,需求掌握能源的名目,而且从不智能感知,假使能源词典由第三方类库提供就能够更麻烦。

var message = TryFindResource("SwitchLanguage") as string;
if (string.IsNullOrWhiteSpace(message) == false)
    MessageBox.Show(message);

2.4 其余财富的本地化

除了那么些之外字符串能源,其余能源的本地化情势无需设置x:Uid,只须求创建对应语言的目录结构及命名就足以在XAML中一贯援用。如项目中有如下两张图片:
必威中文官网 6

在XAML中得以一贯通过Images/Flag.png援引。路线中的”zh-CN”、”en-US”称为能源限定符,用于协助多样展现比例、UI
语言、高相比较度设置等,具体可参看Load images and assets tailored for
scale, theme, high contrast, and
others

  • 在 XAML 中,援用 DynamicResource 的品质必须为借助属性,不然会出错;
  • 在 C# 代码中引用稍微有一些麻烦,需求从 Resource Dictionary
    中获得并转化为字符串

2.5 在代码里替换财富

private void OnReplaceString(object sender, RoutedEventArgs e)
{
    _totalReplace++;
    string content = "Replace " + _totalReplace;
    Resources["StringToReplace"] = content;
}

如上所示,在代码中替换资源十分简便,然则这种简易也推动了资源不可控的难题。

2.5 在代码里拜访财富

在代码中走访能源的代码如下:

var resourceLoader = ResourceLoader.GetForCurrentView();
var currentLanguage = resourceLoader.GetString("CurrentLanguage");
resourceLoader = ResourceLoader.GetForCurrentView("OtherResources");
var message = resourceLoader.GetString("Message");

地点的代码中,currentLanguage从暗中同意的财富文件Resources.resw中获取,resourceLoader
无需钦定能源文件的称号;而message
则从OtherResources.resw获取,resourceLoader 供给钦赐能源文件的称呼。

如必要利用别的类库中的能源,代码如下:

resourceLoader = ResourceLoader.GetForCurrentView("LocalizationDemoUwp.ResourceLibrary/Resources");
currentLanguage = resourceLoader.GetString("CurrentLanguage");

虽说语法轻松,但足以见见最大的主题材料是能源的名称未有智能感知和不当提示,那样使用财富很轻巧失误。

必威中文官网 7

如上海教室所示,对不当的财富名称,ReSharper会有不当提示,可是这种布局ResourceLoader的法门已经被标识为Deprecated并指示使用GetForCurrentView获取ResourceLoader,而选择GetForCurrentView的动静下ReSharper又尚未错误提醒。不领会ReSharper什么日期手艺支撑在GetForCurrentView的艺术下显得错误提醒(作者设置的ReSharper已是最新的2017.2)。

里面第一点能够说是沉重缺陷,作者曾经在品种中增多了三个第三方控件,其 Header
属性并不是依据属性,所以不能够使用这种办法;不是依据属性,当然,也就更不可能利用绑定(Binding)来设置了。

2.6 在先后集以内分享能源

上边有提过,在获得第三方类库中有些财富极度烦劳,不止如此,连获得第三方类库中的能源词典名称都非凡麻烦。作者提议在类库中定义如下的类,能够给开拓者提供部分有益于:

public static class Resources
{
    public static Uri EnglishResourceUri { get; } =
        new Uri("/LocalizationDemoWpf.Resource;component/Resource.en-us.xaml", UriKind.RelativeOrAbsolute);

    public static Uri ChineseResourceUri { get; } =
        new Uri("/LocalizationDemoWpf.Resource;component/Resource.zh-cn.xaml", UriKind.RelativeOrAbsolute);
}

2.6 存在的难题

以此本地化方案固然轻松,但本人觉着很难使用,因为那么些方案存在重重主题素材。

第一是安排性时扶助,对本地化来讲,设计时补助注重含有3部分:

  • 在编写XAML时得以博得能源的智能感知
  • 有完整的规划视图
  • 在差异语言之间切换

第一点,未有,而且写错属性名称还不会在编写翻译时报错,而是用最严寒的方式表现:运转时崩溃。

其次点,在Fall Creators Update
(16299)从前,没有,设计视图一片空白。也能够不管写一些内容(如TextBox x:Uid="UsernameTextBox" Header="(here is header)")以匡助设计。但在XAML中写的任何内容都恐怕被能源文件覆盖,无论是公事照旧大小、对齐方式或别的具备属性对XAML的编者来讲都是不可控的,不到骨子里运转时根本不清楚UI的最后效果,那就很考验本地化职员和测验职员。在Fall
Creators
Update今后终于能够在策画视图看到本地化的机能,那不得不说是巨大的发展。

其三点,近来来看做不到。

除此以外,能源管理也是个很费劲的主题素材。同三个字符串,假若要对应TextBlock.Text、ContentControl.Content、TextBox.Header,那样就须要四个能源,变成了冗余,而恢宏的冗余最后会导致错误。

总的看,那个本地化方案有多数难点,就算这几个方案是微软推荐的。既然是微软推荐的,应该是支撑最棒的,只怕是本人的用法不对?

接下去在那些方案的底蕴上做些改换,希望得以让本地化越来越好用。

就此,之后尝试了第两种艺术——使用 resx
文件,事实上,那是一种相比较传统的、且广泛的法子,说它古板,是因为在
WinForm 中就足以这么做;说它布满,是因为在 ASP.net MVC
中也能够那样做;并且,在 UWP
中的实现格局也与此有一些类似。能够说,基本上基于 .NET
的次第平台都以以这种或看似这种格局来促开销地化的。并且,事件作证,这种方法实在是丰盛合适的,也很好用,在
XAML 代码和 C# 代码中均能够十一分有益的利用。 

2.7 总结

财富词典是完毕本地化的一种很遍及的艺术,它有如下优点:

  • 简短易用,而且便于驾驭。
  • XAML语法简单。
  • 能源得以是除string以外的等级次序,如SolidColorBrush。

但这种方法的症结也不在少数:

  • 不便管理,一旦能源过多,重名、互相覆盖、智能感知列表过长等题材将相当的大地震慑开辟,就连有限支撑差别语言间能源词典里的能源数量同样都很费劲。
  • 在先后集以内难以分享,引用很简短,但鉴于尚未智能感知将很难使用,而且不相同程序集以内的能源同名更麻烦追踪。

除此以外,在动态切换语言上还留存有的标题。上面这段XAML就无法做到动态切换语言:

<DataGrid Grid.Row="1" Margin="5">
    <DataGrid.Columns>
        <DataGridTextColumn Header="{DynamicResource Username}"/>
        <DataGridTextColumn Header="{DynamicResource Sex}"/>
        <DataGridTextColumn Header="{DynamicResource Address}" Width="*"/>
    </DataGrid.Columns>
</DataGrid>

在DataGridColumn的Header上做动态切换语言,必要写成DataTemplate的点子:

<DataGrid Grid.Row="2" Margin="5">
    <DataGrid.Columns>
        <DataGridTextColumn >
            <DataGridTextColumn.HeaderTemplate>
                <DataTemplate >
                    <TextBlock Text="{DynamicResource Username}"/
                </DataTemplate>
            </DataGridTextColumn.HeaderTemplate>
        </DataGridTextColumn>
        <DataGridTextColumn >
            <DataGridTextColumn.HeaderTemplate>
                <DataTemplate >
                    <TextBlock Text="{DynamicResource Sex}"/>
                </DataTemplate>
            </DataGridTextColumn.HeaderTemplate>
        </DataGridTextColumn>
        <DataGridTextColumn Width="*">
            <DataGridTextColumn.HeaderTemplate>
                <DataTemplate >
                    <TextBlock Text="{DynamicResource Address}"/>
                </DataTemplate>
            </DataGridTextColumn.HeaderTemplate>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

3. 动态切换语言

不是小编太执着动态切换语言,是测量试验员真的喜欢这一个职能,因为不用重启应用就足以测量检验到持有语言的UI。

UWP提供了ApplicationLanguages.PrimaryLanguageOverride属性用于转移语言首选项,即能够更改使用的语言,用法如下:

Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride = "zh-CN";

本条更换是永世的,但不会对目前UI及部分系统组件生效,只会潜移默化之后创建的UI成分。改造ApplicationLanguages.PrimaryLanguageOverride,会异步地接触ResourceContext.QualifierValues的MapChanged事件,能够监听那几个事件并更新UI。那样就能够完结轻便的动态切换语言功用。

DynamicResources.cs

public class DynamicResources : INotifyPropertyChanged
{
    public DynamicResources()
    {
        _defaultContextForCurrentView = ResourceContext.GetForCurrentView();

        _defaultContextForCurrentView.QualifierValues.MapChanged += async (s, m) =>
        {
            await MainPage.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                OnPropertyChanged("");
            });
        };
    }

    private ResourceContext _defaultContextForCurrentView;

    public string Main
    {
        get { return ResourceManager.Current.MainResourceMap.GetValue("DynamicResources/Main", _defaultContextForCurrentView).ValueAsString; }
    }

    public string Settings
    {

        get { return ResourceManager.Current.MainResourceMap.GetValue("DynamicResources/Settings", _defaultContextForCurrentView).ValueAsString; }
    }

    public string RestartNote
    {
        get { return ResourceManager.Current.MainResourceMap.GetValue("DynamicResources/RestartNote", _defaultContextForCurrentView).ValueAsString; }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

SettingView.xaml

<Page.Resources>
    <local:DynamicResources x:Key="DynamicResources"/>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
        <ListView x:Name="LanguageListView" Margin="10">
            <ListViewItem Tag="zh-Hans-CN" Content="中文"/>
            <ListViewItem Tag="en-US" Content="English"/>
        </ListView>
        <TextBlock x:Name="NoteElement" Foreground="#FFF99F00" Margin="20,10" Visibility="Collapsed"
                   Text="{Binding RestartNote,Source={StaticResource DynamicResources}}"
                   />
    </StackPanel>
</Grid>

SettingView.xaml.cs

private async void OnLanguageListViewSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var item = LanguageListView.SelectedItem as ListViewItem;
    if (item == null)
        return;

    ApplicationLanguages.PrimaryLanguageOverride = item.Tag as string;
    _hasChangedLanguage = true;
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, ShowNoteElement);
}

private void ShowNoteElement()
{
    NoteElement.Visibility = Visibility.Visible;
    var appView = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView();
    appView.Title = (LanguageListView.SelectedItem as ListViewItem)?.Content as string;
}

必威中文官网 8

只在设置页面及菜单这个在切换语言时不会再一次加载的UI上采纳Binding,此外地点不改变,那样轻巧的动态切换语言就贯彻了。运营结果如上,能够看看TextBox右键菜单仍未切换语言,供给重新起动。

UWP暗许只安装Computer对应的言语,那样能够节省安装空间,但潜移默化到动态切换语言的功效,要化解这些主题素材可以参照以下内容(笔者未曾证实过):[localization

  • How to always install all localized resources in Windows Store UWP app
  • Stack
    Overflow]()

动用 ResX 文件落实 

它的操作步骤大约如下:

  1. 创立贰个 WPF 项目;

  2. 在主窗口中加多几个必要当地化其故事情节的控件,如 TextBlock、Button等;

  3. 展现此项指标 Properties 文件夹,这里一度有一个私下认可的
    Resources.resx,在里头增多本地化字符串;

  4. 将其复制,并粘贴到前段时间岗位,将新文件改名称叫Resources.en-US.resx,并修改当中的地头化字符串为相应的语言值;

申明:这里大家加多了对俄语语言的本地化,至于扶助什么语言的本地化,能够参照他事他说加以考察那篇作品
Supported
languages,关于语言相配可参谋那篇小说
Manage language and
region,固然这两篇文章是针对
UWP 的,然而原则上,对于 WPF 也是适用的;

  1. 将上述三个 resx 文件的 Access Modifier 修改为 Public,暗许值是
    Internal;如下图:

必威中文官网 9

 接下来就是哪些行使了:

  1. 在 Xaml 中加多命名空间引用:

    xmlns:loc=”clr-namespace:WpfLocalizationTest.Properties”

  2. 利用 {x:Static} 标识引用资源,如下:

  3. 比如急需在代码中援引,也极其轻便:

    var homePage = Properties.Resources.Main_Menu_Home;

经测验,这种形式也协理 速龙liSense(智能提醒),如下图:

必威中文官网 10

假若您没见到智能提示,能够先编写翻译项目。

此时,有三种方法能够测量试验本地化效果,第一种办法是在调节面板中更换操作系统的语言,第三种艺术是透过代码改造CurrentUICulture;这里大家选用后者,在 App.xaml.cs 中增多如下代码:

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
        }

运营后就足以看看测量试验结果了。 

3. 使用Resx能源文件

4. 获取完整的统筹视图

在Fall Creators
Update以前为了拿走设计时视图能够选取索引器。十分少有时机在C#中用到索引器,XAML中也十分少用到Binding到字符串索引的语法,就是那八个作用在本地化中帮了大忙。

public class ResourcesStrings
{
    public string this[string key]
    {
        get
        {
            return ResourceLoader.GetForViewIndependentUse().GetString(key);
        }
    }
}

<Page.Resources>
    <local:ResourcesStrings x:Key="S"/>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="{Binding Source={StaticResource S},Path=[MainTitle]}" />
</Grid>

必威中文官网 11

只需求如此写就能够获得完全的规划时试图,但是依然不曾化解智能感知和不当提示那多个难题。

在那个方案上也可总结地促成动态切换语言。

public class ApplicationResources : INotifyPropertyChanged
{
    public ApplicationResources()
    {
        DynamicResources = new DynamicResourcesStrings();
        Resources = new ResourcesStrings();
        Current = this;
    }

    public static ApplicationResources Current { get; private set; }

    public event PropertyChangedEventHandler PropertyChanged;

    public DynamicResourcesStrings DynamicResources { get; }

    public ResourcesStrings Resources { get; }

    public string Language
    {
        get
        {
            return ApplicationLanguages.PrimaryLanguageOverride;
        }
        set
        {

            if (ApplicationLanguages.PrimaryLanguageOverride == value)
                return;

            ApplicationLanguages.PrimaryLanguageOverride = value;
            if (MainPage.Current != null )
                MainPage.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { OnPropertyChanged(""); });
        }
    }

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

<ListViewItem Content="{Binding Source={StaticResource R},Path=DynamicResources[Main]}"/>

不晓得为什么,在VisualStudio上有时不可能获得设计时视图,全部文字都浮现为”Item”。

在大型项目中动用 

地方是在 德姆o
中显得怎么样本地化应用,那么在大型项目中是什么来行使这种方法啊?以下简要介绍一下,能够供仿效:

1.
在消除方案中开创二个类库项目(或在已有档案的次序中举行三番五次操作),此项指标用处主假诺作能源用;

  1. 在里头创造 Localization
    文件夹,在那个文件夹下能够再次创下制针对种种模块的子文件夹,然后在此创造resx 文件、增多本地化字符串并复制。文件结构如下:

必威中文官网 12

  1. 要在主程序中央银行使,情势和大家在 德姆o
    中涉嫌的是大同小异的。首先在主程序项目中增加对新成立项指标引用,然后在 XAML
    中增加命名空间和相关代码:

    xmlns:loc2=”clr-namespace:App.Resources.Localization.MainModule;assembly=App.Resources”

3.1 基本原理

比起财富词典,小编更爱好使用Resx能源文件,可是这种艺术语法复杂一些,而且也可能有无数小标题。
在VisualStudio中成立后缀名称为resx的财富文件并开采,可在以下UI编辑财富文件的值(将拜访修饰符改为public用起来方便些):
必威中文官网 13

在改换财富文件的值后PublicResXFileCodeGenerator将活动创造对应的类并为每五个键值加多如下代码:

/// <summary>
///   查找类似 Address 的本地化字符串。
/// </summary>
public static string Address {
    get {
        return ResourceManager.GetString("Address", resourceCulture);
    }
}

接下来将这么些财富文件复制粘贴一份,将名称改为“原名+.+对应的言语+.resx”的格式,并且将当中的值翻译成对应语言如下:
必威中文官网 14

在UI上使用x:Static绑定到对应的财富:

<DataGridTextColumn Header="{x:Static local:Labels.Username}"/>

那样基本的本地化就做到了。诸多控件库都以选用这种艺术做本地化。除了字符串,resx能源文件还帮助除字符串以外的财富,如图片、音频等。
必威中文官网 15

只是这一个方案只兑现了最基本的本地化,而且最大的主题材料是只帮助直接运用字符串,不帮衬TypeConverter,以致也不协理除字符串以外的任何XAML内置类型.aspx)(即Boolea,Char,Decimal,Single,Double,Int16,Int32,Int64,TimeSpan,Uri,Byte,Array等体系)。比方使用Label.resx中名字为Background值为
#8八千0FF 的字符串为Grid.Background完结本地化:

Labels.designer.resx

/// <summary>
///   查找类似 #880000FF 的本地化字符串。
/// </summary>
public static string Background {
    get {
        return ResourceManager.GetString("Background", resourceCulture);
    }
}

MainWindow.xaml

<Grid  Background="{x:Static local:Labels.Background}"/>

运行时报错:ArgumentException:
“#88FF0000”不是性质“Background”的有效值。

那般能源文件的实用性大打折扣。当然,那么些方案也不帮衬动态切换语言。

5. 使用resx能源文件

既然UWP是XAML我们族的一份子,那么应该也得以接纳resx能源文件落到实处本地化,毕竟生成resx对应代码的是PublicResXFileCodeGenerator,而不是UWP自个儿。

  1. 开发“增加新项”对话框,选中“财富文件(.resw)”,在“名称”文本框上将文件名称改为“Labels.resx”,点击“增添”。
  2. 在“消除方案财富管理器”选中“Labels.resx”,邮件展开“属性”视图,“生成操作”选取“嵌入的财富”。
  3. 将“Labels.resx”复制为“Labels.zh-CN.resx”,展开“Labels.zh-CN.resx”,“访问修饰符”改为“无代码生成”。
  4. 在“AssemblyInfo.cs”增添如下代码:

    [assembly: NeutralResourcesLanguage("en-US")]
    

那样就能够在UWP中利用resx能源文件了。达成当地化的代码和上一篇小说中牵线的WPF本地化方案差不离。

public class ApplicationResources : INotifyPropertyChanged
{
    public static ApplicationResources Current { get; private set; }

    public ApplicationResources()
    {
        Labels = new Labels();
        if (string.IsNullOrWhiteSpace(ApplicationLanguages.PrimaryLanguageOverride) == false)
            Language = ApplicationLanguages.PrimaryLanguageOverride;
        else
            Language = Windows.System.UserProfile.GlobalizationPreferences.Languages.FirstOrDefault();

        Current = this;
    }

    public Labels Labels { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    }

    private string _language;

    /// <summary>
    /// 获取或设置 Language 的值
    /// </summary>
    public string Language
    {
        get { return _language; }
        set
        {
            if (_language == value)
                return;

            _language = value;
            Labels.Culture = new System.Globalization.CultureInfo(_language);
            ApplicationLanguages.PrimaryLanguageOverride = _language;
            OnPropertyChanged("");
        }
    }
}

利用体验和WPF中的resx本地化方案差不离,设计时帮忙差非常少周到,包涵智能感知和不当提示,然则如故不能够减轻系统组件中的本地化难点(如TextBox右键菜单)。此外,编写翻译时会报错:带有输出类型“appcontainerexe”的门类不帮衬生成操作“EmbeddedResource”。化解方案是不在UWP应用类型中加多resx能源文件,而在类库中增添resx财富文件,那样连错误都不报了。

不理解Xamarin.Forms是还是不是也足以如此落成,毕竟它也是XAML我们族的一员。

更有益于的办法 

如若软件中有雅量的文本需求本地化,那么在 resx
文件中的能源项将会要命多,那时,要在三个乃至更加多财富文件中加上、删除、相比、检查项目时,将会十三分不便。有未有更利于的办法吧?这里推荐三个VS Extension: ResX Manager

必威中文官网 16

它可以十一分低价地管理当前减轻方案中的 Resx
文件以及个中的能源项,安装后,在 VS 湖南中华南理管理高校程公司具菜单中得以张开,分界面如下:

必威中文官网 17

内需小心的是,要是要增加新财富项时,必须在左边手仅选拔对象能源文件。它的有血有肉用法,不属于本文探究的限定,假如大家有要求理解,能够搜寻相关课程。同理可得,通过这几个插件,能够特别方便地开创、删除、管理地点化文本。

3.2 动态切换语言

在Silverlight.aspx)中已未有了x:Static的绑定方式,改为运用Binding完结本地化,那样固然语法复杂一些,但更为实用。WPF当然也得以利用这种方法。

率先, 创设三个类包装能源文件生成的类(在这些德姆o中是Labels):

public class ApplicationResources
{
    public ApplicationResources()
    {
        Labels = new Labels();
    }

    public Labels Labels { get; set; }
}

下一场在App.xaml大校那个类作为能源丰裕到能源聚集中,为了现在选用的语法轻易些,作者一般将Key获得极粗略:

<Application x:Class="LocalizationDemoWpfUsingResource.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:LocalizationDemoWpfUsingResource"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <local:ApplicationResources x:Key="R"  />
    </Application.Resources>
</Application>

聊到底在XAML中如此绑定:

<DataGridTextColumn Header="{Binding Labels.Username, Source={StaticResource R}}"/>

这么语法复杂一些,但也可能有过多好处:

  • 援助TypeConverter,那样就足以行使除String以外的任何项目。
  • 支撑Binding的别的效用,如IValueConverter。

艰苦的是,WPF仿佛不是很喜欢这种办法,VisualStudio会提醒这种不当,毕竟能源文件中的属性都以static属性,不是实例成员。幸运的是编写翻译三次这种错误提示就能没有。
必威中文官网 18

将调用格局改为Binding今后就能够实现动态切换语言了。由于UI通过Binding获取财富文件的内容,能够透过INotifyPropertyChanged公告UI更新。将ApplicationResources
更动一下:

public class ApplicationResources : INotifyPropertyChanged
{
    public static ApplicationResources Current { get; private set; }

    public ApplicationResources()
    {
        Current = this;
        Labels = new Labels();
    }

    public Labels Labels { get; set; }



    public event PropertyChangedEventHandler PropertyChanged;

    public  void ChangeCulture(System.Globalization.CultureInfo cultureInfo)
    {
        Thread.CurrentThread.CurrentUICulture = cultureInfo;
        Thread.CurrentThread.CurrentCulture = cultureInfo;
        Labels.Culture = cultureInfo;

        if (Current != null)
            Current.RaiseProoertyChanged();
    }

    public void RaiseProoertyChanged()
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(""));
    }
}

近年来得以简轻松单地切换语言了。

var culture = ReadCultureFromConfig();
var cultureInfo = new System.Globalization.CultureInfo(culture);
ApplicationResources.Current.ChangeCulture(cultureInfo);

6. 结语

商讨了这么多resw能源文件的方案,结果或许resx财富文件用得最顺手,终究那个方案作者已经用了成都百货成百上千年(在silverlight中只可以用那一个方案)。具体应用哪个方案差异。

须求重申的是resx并不能够一心代表resw方案,繁多时候供给混合使用,举例使用的Display
Name能够动用resw轻松实现本地化:
必威中文官网 19

当地化的主旨仍有十分多内容,那篇小说只策画介绍入门知识,越来越深远的知识能够参谋下边给出的链接。

总结

从而,通过本文所提议的 Resx 文件本地化方案再加 ResXManager
扩展,你就能够一本万利地在你的
WPF项目中实现本地化了。假诺您有更加好的提议或意见,请留言交换。

 

参谋小说:

WPF Globalization and Localization
Overview
.aspx)

How to: Localize an
Application

Supported
languages

Manage language and
region

WPF
Localization

Localizing WPF Applications using
Locbaml

 

源码下载

3.3 设计时扶助

完成本地化的三个很麻烦的事体是什么在规划视图看到各样语言下的机能。在使用财富词典的方案中是通过在App.xaml中联合对应的能源词典:

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="/LocalizationDemoWpf;component/Resources/zh-cn.xaml"/>
    <!--<ResourceDictionary Source="/LocalizationDemoWpf;component/Resources/en-us.xaml"/>-->
</ResourceDictionary.MergedDictionaries>

在能源文件的方案中,须要在ApplicationResources中增添三个特性:

private string _language;

/// <summary>
/// 获取或设置 Language 的值
/// </summary>
public string Language
{
    get { return _language; }
    set
    {
        if (_language == value)
            return;

        _language = value;
        var cultureInfo = new CultureInfo(value);
        Thread.CurrentThread.CurrentUICulture = cultureInfo;
        Thread.CurrentThread.CurrentCulture = cultureInfo;
        Labels.Culture = cultureInfo;

        RaiseProoertyChanged();
    }
}

此后在App.xaml中就足以经过更改这些性情来改换布置时的UI的语言,在VS2017中连编写翻译都不需求就足以改换规划视图的语言。

<local:ApplicationResources x:Key="R"  Language="zh-CN"/>

必威中文官网 20

7. 参考

Guidelines for globalization – UWP app developer Microsoft
Docs
Localize strings in your UI and app package manifest – UWP app
developer Microsoft
Docs
Load images and assets tailored for scale, theme, high contrast, and
others – UWP app developer Microsoft
Docs
急速入门:翻译 UI 资源(XAML)
c# – UWP Resource file for languages is not deployed correctly – Stack
Overflow
localization – How to always install all localized resources in Windows
Store UWP app – Stack
Overflow
Win10 UWP 开采类别:使用多语言工具包让应用支撑多语言 – yan_xiaodi –
博客园
Windows 10 Apps Designing for Global
Customers

3.4 在代码里拜访能源

在代码里拜访能源文件的财富特别简短:

MessageBox.Show(Labels.SwitchLanguage);

8. 源码

GitHub –
LocalizationDemo

3.5 在代码里替换财富

财富文件要贯彻这几个必要就一些都不佳玩了,至少我从没在事实上中国人民解放军海军事工业程大学业作中做过。最大的难点是财富文件生成的类中的属性是静态属性,而且唯有getter方法:

public static string StringToReplace {
    get {
        return ResourceManager.GetString("StringToReplace", resourceCulture);
    }
}

我们也足以创立三个派生类,强行替换对应的习性:

public class ExtendLabels : Labels
{
    /// <summary>
    /// 获取或设置 StringToReplace 的值
    /// </summary>
    public new string StringToReplace { get; set; }
}

下一场替换ApplicationResources中的Labels,并且触发PropertyChanged。也才这样会刷新全体UI上的字符串等财富,只为了替换两个字符财富代价有一些大,辛亏一般的话并不会太开支质量。

private void OnReplaceString(object sender, RoutedEventArgs e)
{
    _totalReplace++;
    string content = Labels.StringToReplace + " " + _totalReplace;
    if (_extendLabels == null)
        _extendLabels = new ExtendLabels();

    _extendLabels.StringToReplace = content;
    ApplicationResources.Current.Labels = _extendLabels;
    ApplicationResources.Current.RaiseProoertyChanged();
}

3.6 在程序集以内共享能源

只须要将能源文件的访问修饰符改为public,无需任何操作就足以方便地在先后集以内分享财富。
必威中文官网 21

3.7 管理能源文件

比起财富词典,资源文件还大概有八个十分的大的优势就是轻便管理。德姆o中唯有一个名字Labels的能源文件,实际项目中得以按职能或模块分别创建相应的能源文件,化解了能源词典重名、相互覆盖、智能感知列表过长等主题素材。别的小编推荐应用VS的扩展程序ResXManager管理全部财富文件。
必威中文官网 22

它能够在四个UI里管理全体语言的能源文件,一点都不小地方便人民群众了资源文件的利用。
必威中文官网 23

3.8 ReSharper支持

对Resx财富文件,ReSharper也提供了四角俱全的支撑。

当须求为某些财富修改Key时,能够按“财富文件名称”+”.”+”Key”来全局替换,经常那样已经够用放心。Re夏普er更进一步,它提供了重命名功用。假如要将Labels的能源English重名字为为Englishs,能够先在Labels.Designer.cs重命名,然后使用“Apply
rename refactoring”选项:
必威中文官网 24

那儿全体引用,包含XAML都已采取新的称谓:
必威中文官网 25

可是最终仍需和煦动手在财富文件编辑器中修改Key。

除此而外,若是在XAML中应用了不当的Key,ReSharper也会有错误提醒:
必威中文官网 26

在一些场馆,ReShaper还可采用“Move To Resource”功效:
必威中文官网 27
必威中文官网 28

3.9 总结

使用Resx财富文件贯彻本地化有如下优点:

  • 财富管理有利于。
  • 轻巧在代码中动用。
  • 轻便在程序集以内分享。
  • 援助TypeConverter,那样就足以选拔除String以外的任何门类。
  • 支撑Binding的其他功用,如IValueConverter。
  • 包容性好,Silverlight及之后的XAML工夫都足以应用。
  • 其三方工具帮衬。
  • 支撑图片、音频等财富。

症结如下:

  • XAML语法相对复杂。
  • 不可能直接行使于TypeConverter不补助的项目,比如LinearGradientBrush。

虽说不能够一贯辅助LinearGradientBrush,但也不是全然未有议程,只是复杂了广大,如分别对LinearGradientBrush的GradientStop做本地化:

<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="Black" Offset="0"/>
    <GradientStop Color="{Binding Source={StaticResource R},Path=Labels.Background}" Offset="1"/>
</LinearGradientBrush>

4. 结语

那篇文章只介绍了当地化的入门知识,别的还也可能有相当多本地化的大旨,如验证消息中的本地化未有提到。别的,本地化还是能使用x:Uid情势或WPFLocalizeExtension等艺术落成,这里就不详细介绍。
WPF
环球化和当地化概述.aspx)里有介绍部分本地化的最好做法,如UI上应该利用相对布局而非相对布局、字体选用等,这里不再累赘。

须求小心的是上述三种方案都不适用于CLTiguan属性,那也是干什么笔者一向重申UIElement的天性最棒是依靠属性的来头之一。

如有错漏请建议。

5. 参考

WPF
整个世界化和当地化概述.aspx)
Silverlight
安排和本地化.aspx)
WPFLocalizationExtension
WPF Localization Guidance
XAML
Resources
CultureInfo
类.aspx)
Supported
languages

6. 源码

LocalizationDemo

相关文章