www.6799.com当地化入门

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类,那就造花费地化的实现方案完全两样。

www.6799.com 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”能源文件。最后目录结构如下:
www.6799.com 2

在zh-CN\Resources.resw和en-US\Resources.resw增添多少个新财富,分别是UsernameTextBox.Width和UsernameTextBox.Header:
www.6799.com 3

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

<TextBox x:Uid="UsernameTextBox"/>

运作后就可以知到UsernameTextBox的Header设置为”用户名”,Width为100。

在“设置\区域和言语”少校”English”设置为私下认可语言,再度运营应用可看到运维在盖尔语情况下的功用。
www.6799.com 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>

www.6799.com 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中一向引用。如项目中有如下两张图纸:
www.6799.com 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");

即使语法简单,但足以观望最大的主题材料是能源的名目未有智能感知和谬误提醒,那样使用财富很轻松出错。

www.6799.com 7

如上海教室所示,对不当的能源名称,ReSharper会有不当提醒,可是这种布局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;
}

www.6799.com 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>

www.6799.com 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用起来方便些):
www.6799.com 10

在修改能源文件的值后PublicResXFileCodeGenerator将活动创建对应的类并为每二个键值增加如下代码:

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

下一场将这些财富文件复制粘贴一份,将名称改为“原名+.+对应的言语+.resx”的格式,并且将里面包车型大巴值翻译成对应语言如下:
www.6799.com 11

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

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

这么核心的本地化就完事了。多数控件库都以选拔这种格局做本地化。除了字符串,resx能源文件还援救除字符串以外的能源,如图片、音频等。
www.6799.com 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属性,不是实例成员。幸运的是编写翻译一次这种不当提醒就能不复存在。
www.6799.com 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轻巧达成本地化:
www.6799.com 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"/>

www.6799.com 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,无需任何操作就能够平价地在先后集以内共享能源。
www.6799.com 16

3.7 管理能源文件

比起能源词典,财富文件还会有贰个极大的优势正是便于处理。德姆o中唯有壹个名字Labels的财富文件,实际项目中得以按职能或模块分别创设相应的财富文件,解决了能源词典重名、相互覆盖、智能感知列表过长等主题材料。此外笔者引入应用VS的扩张程序ResXManager管理全部财富文件。
www.6799.com 17

它能够在一个UI里处理全体语言的财富文件,十分的大地方便人民群众了能源文件的施用。
www.6799.com 18

3.8 ReSharper支持

对Resx财富文件,ReSharper也提供了了不起的支撑。

当必要为某些能源修改Key时,能够按“能源文件名称”+”.”+”Key”来全局替换,经常那样已经够用放心。ReSharper更进一步,它提供了重命名功用。如若要将Labels的财富English重名称叫为Englishs,能够先在Labels.Designer.cs重命名,然后采纳“Apply
rename refactoring”选项:
www.6799.com 19

那会儿全数引用,包含XAML都已使用新的称号:
www.6799.com 20

而是最后仍需和睦出手在财富文件编辑器中期维修改Key。

除此之外,要是在XAML中选取了不当的Key,ReSharper也可能有荒唐提醒:
www.6799.com 21

在一些场面,ReShaper还可利用“Move To Resource”成效:
www.6799.com 22
www.6799.com 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上理应利用相对布局而非绝对布局、字体选拔等,这里不再累赘。

亟待留意的是上述三种方案都不适用于CLPAJERO属性,那也是怎么小编间接重申UIElement的性质最佳是注重属性的原故之一。

如有错漏请建议。

5. 参考

WPF
全世界化和本地化概述
.aspx)
Silverlight
布署和本地化
.aspx)
WPFLocalizationExtension
WPF Localization Guidance
XAML
Resources

CultureInfo
.aspx)
Supported
languages

6. 源码

LocalizationDemo