本地化入门

1. 前言

WPF的当地化是个很分布的功能,小编做过的WPF程序超越3/5都落成了本地化(不管最后有未有利用)。平时本地化有以下几点需要:

  • 在程序运营时遵照CultureInfo.CurrentUICulture或布署项突显对应语言的UI。
  • 在程序运营时得以动态切换UI语言(没有需求重启程序)。
  • 构建对应差异语言的安装包。
  • 经过下载语言包实现二种语言的本地化。

在那之中唯有首先点是不能缺少的。
其次点最佳也得以完结,多数时候切换语言只为了看看某些职业术语在阿尔巴尼亚语中的原版的书文是怎么,只怕权且打字与印刷个英文报表,平常选取依旧用普通话,用户不想为了那点重启程序。
其三点和第肆点即使很宽泛,但自己向来没完结过,究竟文字能源(临时还会有微量图形)占用的空中不会太多,大多数WPF程序都不曾大到需求思量安装包大小,全数语言的财富总体打包进3个安装包就足以了。

WPF本地化本领很成熟,也许有二种方案,微软在MSDN给出了详细的牵线WPF
举世化和本地化概述
.aspx),还应该有壹份古老的文书档案WPF
Localization
Guidance
,整整66页,里面详细介绍了种种WPF本地化的体制。

本文只介绍两种完毕上述第3、贰点需要的方案。

1. 前言

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

二. 选用财富词典

2. 行使resw能源文件贯彻本地化

在以前的XAML平台,resx财富文件是1种很便利的本地化方案,但在UWP中微软又再一次推荐x:Uid方案,暗中认可的能源文件也改为resw能源文件。纵然后缀名只差了二个字母,但利用办法完全分化。最关键的界别是resw能源文件不会创设对应的Designer.cs类,那就变成本地化的兑现方案完全不一样。

lovebet爱博体育 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;

那般本地化的功能就形成了。

2.1 在XAML中贯彻当地化

在XAML中落到实处本地化的长河很轻便。首先在档次中新建”strings”文件夹,在”strings”文夹下开创”en-US”和”zh-CN”文件夹,并在七个文本夹中分别拉长”Resources.resw”能源文件。最后目录结构如下:
lovebet爱博体育 2

在zh-CN\Resources.resw和en-US\Resources.resw增添三个新能源,分别是UsernameTextBox.Width和UsernameTextBox.Header:
lovebet爱博体育 3

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

<TextBox x:Uid="UsernameTextBox"/>

运维后就能够看出UsernameText博克斯的Header设置为”用户名”,Width为100。

在“设置\区域和言语”上将”English”设置为暗中同意语言,再度运转应用可知到运营在印度语印尼语碰到下的效果。
lovebet爱博体育 4

这么核心的本地化功效就落到实处了。这种本地化格局有如下优点:

  • 粗略飞速,轻松上手
  • 语法轻易,不必要Binding等知识
  • 能够钦赐任意属性进行业地化
  • 支持CLR属性

除了,上一篇文章提到的ResXManager也支撑Resw能源文件,还是可以够动用多语言应用工具包对财富文件进行管理,新浪的那篇文章页对那一个工具实行了详尽介绍:
Win10 UWP
开辟种类:使用多语言工具包让应用支撑多语言

依旧参照他事他说加以考察那一个摄像:
Windows 10 Apps Designing for Global
Customers

二.2 动态切换语言

实质上上述方案已落实了动态切换语言。
XAML能源的引用原则是就地原则,这一个周围不止指VisualTree上的周围,还指时间上的内外。后增多进资源词典的能源将替换在此之前的同名能源。使用DynamicResource而不是StaticResource,正是为着在财富被沟通时能实时更改UI的来得。

二.二 关联到其余财富文件

UI成分暗中认可与Resources.resw举办关联,借使急需和其余能源文件涉及,能够拉长能源文件的路子。如须求与/OtherResources.resw中的能源事关,x:Uid的语法如下:

x:Uid="/OtherResources/AddressTextBox"

2.三 设计时补助

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>

lovebet爱博体育 5

这段XAML只是为着加强统一图谋时体验,未有也能透过编写翻译。

2.三 附加属性的本地化

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

UsernameTextBox.Grid.Row

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

ShowMessageButton.[using:LocalizationDemoUwp]ButtonEx.Content

奇怪的是,就好像此直接运转应用会报错。唯有利用这一个能源的UI元素已经有其一附加属性的值工夫符合规律运维,简单的讲就是急需随意为那几个附加属性设置八个值:

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

二.肆 在代码里拜访能源

在代码中做客能源比较麻烦,须求知道财富的称呼,而且从不智能感知,假使财富词典由第一方类库提供就能够更麻烦。

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

二.四 别的财富的本地化

除去字符串能源,别的资源的本地化格局无需设置x:Uid,只须求创设对应语言的目录结构及命名就能够在XAML中一向引用。如项目中有如下两张图片:
lovebet爱博体育 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.伍 在代码里拜访财富

在代码中做客财富的代码如下:

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

纵然语法轻便,但足以看来最大的主题材料是财富的名称没有智能感知和不当提醒,那样使用财富很轻松出错。

lovebet爱博体育 7

如上海教室所示,对错误的财富名称,ReSharper会有不当提醒,可是这种布局ResourceLoader的艺术已经被标志为Deprecated并提示使用GetForCurrentView获取ResourceLoader,而选用GetForCurrentView的情况下ReSharper又没错误提醒。不知道ReSharper什么日期工夫援救在GetForCurrentView的办法下显得错误提醒(笔者设置的ReSharper已是最新的20一七.2)。

二.陆 在程序集以内共享能源

上面有提过,在获得第1方类库中某些能源极度烦劳,不仅仅如此,连得到第一方类库中的财富词典名称都13分难为。小编建议在类库中定义如下的类,可以给开荒者提供一些利于:

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

二.6 存在的标题

本条本地化方案即便轻松,但自己认为很难使用,因为那几个方案存在相当多主题材料。

先是是安顿性时援救,对本地化来讲,设计时扶助爱抚含有三有个别:

  • 在编写XAML时方可拿走资源的智能感知
  • 有总体的筹算视图
  • 在不一样语言之间切换

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

第一点,在Fall Creators Update
(1629玖)此前,没有,设计视图一片空白。也足以不管写一些剧情(如TextBox x:Uid="UsernameTextBox" Header="(here is header)")以帮忙设计。但在XAML中写的别的内容都大概被能源文件覆盖,无论是公事依然大小、对齐格局或任何具备属性对XAML的编辑来讲都以不可控的,不到骨子里运转时根本不清楚UI的末梢效果,那就很考验本地化人员和测试职员。在Fall
Creators
Update未来终于能够在筹算视图看到本地化的成效,那不得不说是巨大的迈入。

其叁点,近日来看做不到。

除此以外,财富管理也是个很麻烦的标题。同3个字符串,固然要对应TextBlock.Text、ContentControl.Content、TextBox.Header,那样就供给多少个能源,变成了冗余,而大气的冗余最终会形成错误。

总的来讲,那几个本地化方案有为数非常多标题,即便这么些方案是微软推举的。既然是微软推荐的,应该是支撑最佳的,大概是本身的用法不对?

接下去在那几个方案的基础上做些改造,希望得以让当地化越来越好用。

2.7 总结

财富词典是完毕本地化的1种很广阔的点子,它有如下优点:

  • 简短易用,而且便于精通。
  • 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及部分体系组件生效,只会影响之后创建的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;
}

lovebet爱博体育 8

只在设置页面及菜单那几个在切换语言时不会再度加载的UI上采取Binding,其余地方不改变,那样归纳的动态切换语言就落到实处了。运转结果如上,能够观望TextBox右键菜单仍未切换语言,须要再次开动。

UWP暗许只安装Computer对应的语言,那样能够节省安装空间,但影响到动态切换语言的成效,要化解那么些主题素材得以参照以下内容(笔者从未注脚过):[localization

3. 行使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>

lovebet爱博体育 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用起来方便些):
lovebet爱博体育 10

在修改能源文件的值后PublicResXFileCodeGenerator将自行创立对应的类并为每一个键值加多如下代码:

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

然后将以此财富文件复制粘贴一份,将名称改为“原名+.+对应的言语+.resx”的格式,并且将在那之中的值翻译成对应语言如下:
lovebet爱博体育 11

在UI上使用x:Static绑定到相应的能源:

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

这样中央的本地化就完了了。诸多控件库都以行使这种方法做本地化。除了字符串,resx能源文件还辅助除字符串以外的能源,如图片、音频等。
lovebet爱博体育 12

只是那一个方案只兑现了最宗旨的本地化,而且最大的难点是只协助直接运用字符串,不援助TypeConverter,乃至也不补助除字符串以外的其他XAML内置类型.aspx)(即Boolea,Char,Decimal,Single,Double,Int1陆,Int3贰,Int6四,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:
“#8捌FF0000”不是性质“Background”的有效值。

如此那般能源文件的实用性大减价扣。当然,那个方案也不援助动态切换语言。

伍. 行使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财富文件了。完毕本地化的代码和上1篇文章中介绍的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我们族的1员。

三.二 动态切换语言

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>

lovebet爱博体育,末段在XAML中那样绑定:

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

如此那般语法复杂一些,但也是有点不清便宜:

  • 支撑TypeConverter,那样就可以运用除String以外的任何项目。
  • 支撑Binding的别样作用,如IValueConverter。

麻烦的是,WPF仿佛不是很喜爱这种办法,VisualStudio会提醒这种错误,究竟能源文件中的属性都以static属性,不是实例成员。幸运的是编写翻译贰遍这种不当提醒就能流失。
lovebet爱博体育 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财富文件用得最顺手,毕竟那些方案小编1度用了累累年(在silverlight中不得不用那些方案)。具体应用哪个方案分裂。

亟待重申的是resx并不能完全替代resw方案,好多时候要求混合使用,举例使用的Display
Name能够选拔resw轻便完毕本地化:
lovebet爱博体育 14

本地化的主旨仍有为数十分多内容,那篇小说只准备介绍入门知识,更加深刻的知识能够参照上边给出的链接。

三.三 设计时帮助

贯彻当地化的一个很麻烦的政工是怎么在设计视图看到各类语言下的机能。在选用能源词典的方案中是通过在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的言语,在VS20一7中连编写翻译都没有需求就能够转移规划视图的言语。

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

lovebet爱博体育 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 在代码里拜访财富

在代码里拜访财富文件的能源11分粗略:

MessageBox.Show(Labels.SwitchLanguage);

8. 源码

GitHub –
LocalizationDemo

三.五 在代码里替换能源

财富文件要促成那些需求就一些都不佳玩了,至少本身从没在事实上中国人民解放军海军工程大学业作中做过。最大的难点是能源文件生成的类中的属性是静态属性,而且惟有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();
}

叁.陆 在先后集以内共享能源

只要求将财富文件的拜访修饰符改为public,无需任何操作就足以壹本万利地在先后集以内共享能源。
lovebet爱博体育 16

三.七 管理能源文件

比起能源词典,财富文件还会有一个比十分的大的优势就是便于管理。德姆o中只有二个名字Labels的能源文件,实际项目中可以按职能或模块分别成立相应的财富文件,消除了能源词典重名、互相覆盖、智能感知列表过长等主题素材。别的笔者引入应用VS的恢弘程序ResXManager管理全部财富文件。
lovebet爱博体育 17

它能够在一个UI里管理全部语言的能源文件,非常大地方便人民群众了财富文件的施用。
lovebet爱博体育 18

3.8 ReSharper支持

对Resx财富文件,ReSharper也提供了大好的援助。

当须求为有个别财富修改Key时,能够按“能源文件名称”+”.”+”Key”来全局替换,常常那样已经够用放心。ReSharper更进一步,它提供了重命名功能。纵然要将Labels的财富English重名叫为Englishs,能够先在Labels.Designer.cs重命名,然后选用“Apply
rename refactoring”选项:
lovebet爱博体育 19

那时全体引用,包涵XAML都已利用新的名号:
lovebet爱博体育 20

可是最终仍需本身入手在能源文件编辑器中期维修改Key。

除此而外,如若在XAML中央银行使了不当的Key,ReSharper也可以有荒唐提醒:
lovebet爱博体育 21

在有个别场面,ReShaper还可选拔“Move To Resource”作用:
lovebet爱博体育 22
lovebet爱博体育 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

相关文章