本地化入门

1. 前言

WPF的本地化是个很宽泛的成效,小编做过的WPF程序大多数都达成了本地化(不管最后有未有接纳)。日常本地化有以下几点要求:

  • 在程序运行时依照葡京会,CultureInfo.CurrentUICulture或配备项展现对应语言的UI。
  • 在程序运维时能够动态切换UI语言(无需重启程序)。
  • 创立对应不一样语言的安装包。
  • 因而下载语言包完结三种语言的本地化。

中间唯有首先点是少不了的。
其次点最棒也能够达成,很多时候切换语言只为了看看某些专业术语在菲律宾语中的原来的文章是哪些,大概一时半刻打字与印刷个英文报表,平常使用还是用中文,用户不想为了这一点重启程序。
其三点和第5点即使很宽泛,但自小编平昔没实现过,究竟文字能源(有时还有微量图纸)占用的半空中不会太多,大多数WPF程序都未有大到需求思量安装包大小,全体语言的财富总体打包进一个安装包就可以了。

WPF本地化技术很干练,也有两种方案,微软在MSDN给出了详尽的介绍WPF
环球化和本地化概述
.aspx),还有一份古老的文书档案WPF
Localization
Guidance
,整整66页,里面详细介绍了各个WPF本地化的编写制定。

本文只介绍三种完毕上述第三、二点须求的方案。

1. 前言

上1篇作品介绍了种种WPF本地化的入门知识,那篇小说介绍UWP本地化的入门知识。

二. 用到能源词典

二. 应用resw财富文件贯彻本地化

在此前的XAML平台,resx能源文件是一种很便宜的本地化方案,但在UWP中微软又重新推荐x:Uid方案,私下认可的财富文件也成为resw财富文件。即便后缀名只差了一个假名,但运用办法完全两样。最重点的区分是resw财富文件不会创设对应的Designer.cs类,那就导致当地化的兑现方案完全差别。

葡京会 1

二.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;

那般本地化的法力就形成了。

贰.一 在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"/>

运作后即可看到UsernameTextBox的Header设置为”用户名”,Width为100。

在“设置\区域和言语”军长”English”设置为默许语言,再度运维应用可观看运营在立陶宛(Lithuania)语环境下的效应。
葡京会 4

如在那之中央的当地化功用就落实了。这种本地化情势有如下优点:

  • 简单易行高效,不难上手
  • 语法简单,不要求Binding等文化
  • 能够钦命任意属性进行当地化
  • 支持CLR属性

除了,上1篇小说提到的ResXManager也扶助Resw能源文件,还足以选择多语言应用工具包对财富文件进行保管,搜狐的那篇文章页对那一个工具进行了详实介绍:
Win十 UWP
开发种类:使用多语言工具包让应用支撑多语言

可能参考那个摄像:
Windows 10 Apps Designing for Global
Customers

二.二 动态切换语言

其实上述方案已落实了动态切换语言。
XAML财富的引用原则是周边原则,那么些周围不仅指VisualTree上的就近,还指时间上的就近。后添加进财富词典的能源将替换以前的同名能源。使用DynamicResource而不是StaticResource,正是为着在资源被交流时能实时变更UI的来得。

二.2 关联到别的国资本源文件

UI成分暗中认可与Resources.resw实行关联,假使需求和其余国资本源文件涉及,能够添加财富文件的门路。如须要与/OtherResources.resw中的财富事关,x:Uid的语法如下:

x:Uid="/OtherResources/AddressTextBox"

二.三 设计时匡助

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只是为了拉长设计时体验,未有也能通过编写翻译。

二.3 附加属性的本地化

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

UsernameTextBox.Grid.Row

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

ShowMessageButton.[using:LocalizationDemoUwp]ButtonEx.Content

奇怪的是,就那样直接运转应用会报错。唯有利用那个财富的UI成分已经有其一附加属性的值才能常常运作,不难的话就是内需随便为这么些附加属性设置1个值:

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

2.四 在代码里拜访财富

在代码中走访财富相比劳苦,要求掌握财富的称谓,而且尚未智能感知,假若能源词典由第1方类库提供就会更麻烦。

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

2.四 别的资源的本地化

除此之外字符串能源,别的财富的本地化格局不供给设置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

二.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.二)。

二.6 在先后集以内共享能源

地点有提过,在收获第1方类库中有个别财富13分劳神,不仅如此,连获得第2方类库中的能源词典名称都不行劳动。笔者建议在类库中定义如下的类,能够给开发者提供一些有益:

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);
}

二.陆 存在的题材

以此本地化方案纵然简易,但自笔者觉着很难使用,因为这些方案存在不少标题。

先是是统一筹划时协理,对本地化来说,设计时协理重点涵盖三局地:

  • 在编写XAML时方可拿走能源的智能感知
  • 有整机的安排视图
  • 在分歧语言之间切换

第贰点,未有,而且写错属性名称还不会在编写翻译时报错,而是用最严寒的办法彰显:运转时崩溃。

其次点,在Fall Creators Update
(1629九)在此之前,未有,设计视图一片空白。也能够不管写一些剧情(如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。

但那种办法的短处也不在少数:

  • 难以管理,一旦能源过多,重名、相互覆盖、智能感知列表过长等难题将非常大地影响开发,就连保障不相同语言间资源词典里的能源数量一样都很麻烦。
  • 在程序集以内难以共享,引用相当粗略,但出于并未有智能感知将很难使用,而且差异程序集以内的财富同名更难以跟踪。

除此以外,在动态切换语言上还设有1些难题。下边那段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及1些系统组件生效,只会潜移默化之后创造的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暗许只安装总结机对应的言语,这样能够节省安装空间,但影响到动态切换语言的机能,要消除那个标题能够参考以下内容(我未有注脚过):[localization

三. 用到Resx财富文件

四. 收获完全的安排性视图

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

三.一 基本原理

比起财富词典,笔者更爱好使用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,Int1陆,Int3二,Int6四,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:
“#8八FF0000”不是性质“Background”的有效值。

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

5. 行使resx能源文件

既然UWP是XAML大家族的1份子,那么应该也得以选拔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本地化方案差不离,设计时协助差不多无所不包,包蕴智能感知和谬误提示,然则照旧不能够消除系统组件中的当地化难题(如Text博克斯右键菜单)。别的,编写翻译时会报错:带有输出类型“appcontainerexe”的品类不帮忙生成操作“EmbeddedResource”。消除方案是不在UWP应用类型中添加resx财富文件,而在类库中添加resx财富文件,那样连错误都不报了。

不知晓Xamarin.Forms是或不是也得以如此完毕,毕竟它也是XAML大家族的壹员。

三.二 动态切换语言

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.三 设计时帮衬

落到实处本地化的二个很麻烦的业务是什么样在设计视图看到各类语言下的效益。在运用财富词典的方案中是经过在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

Win十 UWP 开发类别:使用多语言工具包让应用支撑多语言 – yan_xiaodi –
博客园

Windows 10 Apps Designing for Global
Customers

三.四 在代码里拜访财富

在代码里拜访能源文件的能源格外简便:

MessageBox.Show(Labels.SwitchLanguage);

8. 源码

GitHub –
LocalizationDemo

三.五 在代码里替换财富

财富文件要促成那一个需求就一些都不好玩了,至少自身从未在实际工作中做过。最大的难点是财富文件生成的类中的属性是静态属性,而且唯有getter方法:

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

我们也足以创立3个派生类,强行替换对应的品质:

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();
}

三.6 在先后集以内共享能源

只必要将财富文件的造访修饰符改为public,无需任何操作就足以一本万利地在程序集以内共享能源。
葡京会 16

三.7 管理财富文件

比起财富词典,资源文件还有3个相当的大的优势正是不难管理。德姆o中唯有一个名字Labels的财富文件,实际项目中能够按职能或模块分别创立相应的能源文件,消除了财富词典重名、相互覆盖、智能感知列表过长等题材。其它我推荐应用VS的扩展程序ResXManager管理全数财富文件。
葡京会 17

它能够在二个UI里管理全部语言的财富文件,不小地惠及了财富文件的应用。
葡京会 18

3.8 ReSharper支持

对Resx财富文件,ReSharper也提供了卓越的扶助。

当须要为某些能源修改Key时,可以按“能源文件名称”+”.”+”Key”来全局替换,平日那样已经丰盛放心。ReSharper更进一步,它提供了重命名作用。若是要将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的个性最好是凭借属性的来头之1。

如有错漏请提议。

5. 参考

WPF
满世界化和本地化概述
.aspx)
Silverlight
计划和本地化
.aspx)
WPFLocalizationExtension
WPF Localization Guidance
XAML
Resources

CultureInfo
.aspx)
Supported
languages

6. 源码

LocalizationDemo

相关文章

admin

网站地图xml地图