本地化入门

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增加多少个新能源,分别是UsernameTextBox.Width和UsernameTextBox.Header:
图片 3

在XAML中增加叁个Text博克斯,设置x:Uid为UsernameText博克斯,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

如上海教室所示,对不当的财富名称,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;
}

图片 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值为
#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我们族的一员。

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”来全局替换,常常那样已经丰盛放心。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奥迪Q7属性,那也是为啥作者平昔强调UIElement的属性最佳是依据属性的因由之一。

如有错漏请提出。

5. 参考

WPF
举世化和本地化概述
.aspx)
Silverlight
陈设和本地化
.aspx)
WPFLocalizationExtension
WPF Localization Guidance
XAML
Resources

CultureInfo
.aspx)
Supported
languages

6. 源码

LocalizationDemo

相关文章

admin

网站地图xml地图