1. 前言

WPF的本地化是个很广泛的出力,笔者做过的WPF程序当先二分之一都落到实处了当地化(不管最终有未有利用)。平时本地化有以下几点须要:

  • 在程序运行时依照CultureInfo.CurrentUICulture或安顿项呈现对应语言的UI。
  • 在程序运转时方可动态切换UI语言(没有须要重启程序)。
  • 塑造对应分歧语言的安装包。
  • 通过下载语言包达成各类语言的本地化。

内部唯有首先点是少不了的。
其次点最佳也能够完毕,比相当多时候切换语言只为了看看某些职业术语在英语中的最早的作品是什么,也许权且打字与印刷个葡萄牙共和国语报表,经常使用依旧用汉语,客户不想为了那点重启程序。
其三点和第四点就算很宽泛,但本人一贯没落成过,毕竟文字财富(不经常还恐怕有微量图纸)占用的半空中不会太多,大多数WPF程序都未有大到必要思量安装包大小,全数语言的财富总体打包进叁个安装包就足以了。

WPF本地化才能很干练,也可能有三种方案,微软在MSDN给出了详细的牵线WPF
整个世界化和当地化概述
.aspx),还会有一份古老的文书档案WPF
Localization
Guidance
,整整66页,里面详细介绍了各个WPF本地化的编写制定。

本文只介绍二种实现上述第1、2点必要的方案。

1. 前言

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

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加多四个新能源,分别是UsernameText博克斯.Width和UsernameTextBox.Header:
图片 3

在XAML中加多叁个TextBox,设置x:Uid为UsernameTextBox,x:Uid将XAML成分和财富文件中的能源扩充关联:

<TextBox x:Uid="UsernameTextBox"/>

运作后就可以看到UsernameTextBox的Header设置为”顾客名”,Width为100。

在“设置\区域和语言”军长”English”设置为暗许语言,再度运维应用可看出运营在印度语印尼语景况下的功能。
图片 4

那般基本的本地化功用就贯彻了。这种本地化格局有如下优点:

  • 简短便捷,轻易上手
  • 语法简单,没有要求Binding等知识
  • 能够内定放肆属性举办本地化
  • 支持CLR属性

除去,上一篇文章提到的ResXManager也帮忙Resw能源文件,还足以接纳多语言使用工具包对财富文件实行保管,和讯的这篇文章页对这一个工具实行了详尽介绍:
Win10 UWP
开拓连串:使用多语言工具包让应用支撑多语言

也许参考那么些录制:
Windows 10 Apps Designing for Global
Customers

2.2 动态切换语言

实则上述方案已完毕了动态切换语言。
XAML能源的援用原则是周围原则,那一个左近不仅仅指VisualTree上的内外,还指时间上的内外。后增添进财富词典的财富将替换以前的同名财富。使用DynamicResource并不是StaticResource,正是为了在财富被替换时能实时退换UI的突显。

2.2 关联到任何能源文件

UI成分暗中认可与Resources.resw举行关联,尽管急需和别的国资本源文件涉及,可以加上财富文件的路径。如须要与/OtherResources.resw中的能源事关,x:Uid的语法如下:

x:Uid="/OtherResources/AddressTextBox"

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"/>

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

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

如上海教室所示,对错误的财富名称,Re夏普er会有荒唐提示,可是这种结构ResourceLoader的不二等秘书技已经被标志为Deprecated并提示使用GetForCurrentView获取ResourceLoader,而利用GetForCurrentView的气象下ReSharper又从未不当提醒。不理解ReSharper什么日期技艺援助在GetForCurrentView的办法下显得错误提醒(小编设置的ReSharper已是最新的2017.2)。

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,那样就须求四个财富,形成了冗余,而大气的冗余最后会招致错误。

总的看,那些本地化方案有广大主题材料,就算这几个方案是微软推荐的。既然是微软引荐的,应该是永葆最佳的,只怕是自个儿的用法不对?

接下去在这一个方案的功底上做些退换,希望得以让本地化更加好用。

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

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>

图片 9

只要求这么写就能够拿走完全的宏图时筹算,可是仍旧尚未减轻智能感知和错误提醒那八个难题。

在那么些方案上也可总结地贯彻动态切换语言。

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”。

3.1 基本原理

比起财富词典,小编更欣赏使用Resx能源文件,不过这种措施语法复杂一些,而且也可以有过多小难题。
在VisualStudio中创建后缀名称叫resx的能源文件并开垦,可在以下UI编辑财富文件的值(将做客修饰符改为public用起来方便些):
图片 10

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

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

下一场将那个资源文件复制粘贴一份,将名称改为“原名+.+对应的言语+.resx”的格式,並且将里面包车型地铁值翻译成对应语言如下:
图片 11

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

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

这么基本的本地化就完事了。相当多控件库都以行使这种格局做本地化。除了字符串,resx能源文件还帮忙除字符串以外的财富,如图片、音频等。
图片 12

然则那个方案只兑现了最中央的本地化,并且最大的标题是只扶助直接动用字符串,不补助TypeConverter,乃至也不帮衬除字符串以外的别的XAML内置类型.aspx)(即Boolea,Char,Decimal,Single,Double,Int16,Int32,Int64,TimeSpan,Uri,Byte,Array等门类)。例如使用Label.resx中名字为Background值为
#870000FF 的字符串为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大家族的一员。

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属性,不是实例成员。幸运的是编写翻译三回这种错误提醒就能够磨灭。
图片 13

将调用格局改为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轻易达成本地化:
图片 14

本地化的宗旨仍有众多内容,这篇文章只筹算介绍入门知识,更深远的知识能够参见上面给出的链接。

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"/>

图片 15

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,没有要求任何操作就能够一本万利地在前后相继集以内分享能源。
图片 16

3.7 管理能源文件

比起能源词典,能源文件还大概有贰个十分大的优势正是便于管理。德姆o中独有贰个名字Labels的财富文件,实际项目中得以按职能或模块分别建构相应的能源文件,化解了能源词典重名、相互覆盖、智能感知列表过长等主题材料。别的我推荐使用VS的恢弘程序ResXManager管理全体财富文件。
图片 17

它能够在一个UI里管理全数语言的能源文件,非常大地便民了财富文件的采用。
图片 18

3.8 ReSharper支持

对Resx能源文件,ReSharper也提供了卓越的援助。

当须求为有个别资源修改Key时,能够按“财富文件名称”+”.”+”Key”来全局替换,平日那样已经够用放心。Re夏普er更上一层楼,它提供了重命名功用。如果要将Labels的能源English重名叫为Englishs,能够先在Labels.Designer.cs重命名,然后使用“Apply
rename refactoring”选项:
图片 19

此刻全数援引,包罗XAML都已采取新的称谓:
图片 20

然而最终仍需本人入手在资源文件编辑器中修改Key。

除了,假如在XAML中选择了不当的Key,ReSharper也可能有错误提醒:
图片 21

在有个别场馆,ReShaper还可选择“Move To Resource”作用:
图片 22
图片 23

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上应有采用相对布局而非绝对布局、字体选用等,这里不再累赘。

内需注意的是上述三种方案都不适用于CL昂科拉属性,那也是为啥本身直接重申UIElement的习性最佳是借助属性的原由之一。

如有错漏请提出。

5. 参考

WPF
全球化和当地化概述
.aspx)
Silverlight
铺排和本地化
.aspx)
WPFLocalizationExtension
WPF Localization Guidance
XAML
Resources

CultureInfo
.aspx)
Supported
languages

6. 源码

LocalizationDemo