[WPF]本地化入门。[UWP]本地化入门。

我做过的WPF程序大部分都实现了本地化(不管最终有没有用到),这篇文章介绍UWP本地化的入门知识

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中上加一个TextBox,设置x:Uid为UsernameTextBox,x:Uid将XAML元素和资源文件被之资源进行关联:

<TextBox x:Uid="UsernameTextBox"/>

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

在“设置\区域及语言”中将”English”设置为默认语言,再次运行应用可观看运行在英语环境下之效应。
澳门蒲京 4

如此这般中心的本地化功能就落实了。这种本地化方式来如下优点:

  • 简简单单便捷,容易达成亲手
  • 语法简单,不欲Binding等文化
  • 好指定任意属性进行本地化
  • 支持CLR属性

而外,上平等首文章提到的ResXManager也支撑Resw资源文件,还足以运用多语言使用工具确保对资源文件进行管理,博客园的当下首文章页对之家伙进行了详尽介绍:
Win10 UWP
开发系列:使用多语言工具包让应用支撑多语言

要么参考这视频:
Windows 10 Apps Designing for Global
Customers

2.2 动态切换语言

其实上述方案已兑现了动态切换语言。
XAML资源的援原则是就地原则,这个附近不仅指VisualTree上的就近,还因日及之内外。后上加进资源词典的资源以替换之前的同名资源。使用DynamicResource而不是StaticResource,就是以以资源给调换时能够实时变更UI的显示。

2.2 关联到外资源文件

UI元素默认与Resources.resw进行关联,如果要与外资源文件涉及,可以加上资源文件的路线。如得与/OtherResources.resw中之资源事关,x:Uid的语法如下:

x:Uid="/OtherResources/AddressTextBox"

2.3 设计时支持

VisualStudio的XAML设计时支持对开发WPF程序要,对本地化来说,设计时支持至关重要含有3有的:

  • 于编写XAML时好得资源的智能感知
  • 出整机的筹划视图
  • 每当不同语言里切换

动资源词典实现本地化,只需要以App.xaml中集合对应之资源词典即可获取完全的计划时支持。

<Application x:Class="LocalizationDemoWpf.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:LocalizationDemoWpf"
             xmlns:resource="clr-namespace:LocalizationDemoWpf.Resource;assembly=LocalizationDemoWpf.Resource"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/LocalizationDemoWpf;component/Resources/zh-cn.xaml"/>
                <!--<ResourceDictionary Source="/LocalizationDemoWpf;component/Resources/en-us.xaml"/>-->
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

澳门蒲京 5

这段XAML只是以增强规划时体验,没有啊能经过编译。

2.3 附加属性的本地化

针对系统提供的叠加属性,资源的名目语法如下:

UsernameTextBox.Grid.Row

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

ShowMessageButton.[using:LocalizationDemoUwp]ButtonEx.Content

奇怪的是,就这样直接运行应用会报错。只有使这资源的UI元素已经来其一附加属性的价值才能够正常运转,简单来说就是是要随便为是附加属性设置一个价值:

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

2.4 在代码里拜访资源

以代码中访问资源比较辛苦,需要理解资源的名,而且尚未智能感知,如果资源词典由第三方类库提供就见面重累。

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

2.4 其它资源的本地化

除此之外字符串资源,其它资源的本地化方式不欲设置x:Uid,只待树立对许语言的目结构和命名就可在XAML中一直引用。如项目受到产生如下两摆图片:
澳门蒲京 6

以XAML中好直接通过Images/Flag.png引用。路径中之”zh-CN”、”en-US”称为资源限定符,用于支持多来得比例、UI
语言、高对比度设置等,具体但参考Load images and assets tailored for
scale, theme, high contrast, and
others

2.5 在代码里替换资源

private void OnReplaceString(object sender, RoutedEventArgs e)
{
    _totalReplace++;
    string content = "Replace " + _totalReplace;
    Resources["StringToReplace"] = content;
}

假若达到所示,在代码中替换资源十分概括,不过这种简单吗带来了资源不可控的题目。

2.5 在代码里拜访资源

于代码中访问资源的代码如下:

var resourceLoader = ResourceLoader.GetForCurrentView();
var currentLanguage = resourceLoader.GetString("CurrentLanguage");
resourceLoader = ResourceLoader.GetForCurrentView("OtherResources");
var message = resourceLoader.GetString("Message");

点的代码中,currentLanguage从默认的资源文件Resources.resw中落,resourceLoader
无需指定资源文件的名号;而message
则于OtherResources.resw获取,resourceLoader 需要指定资源文件的称呼。

如得利用其他类库中的资源,代码如下:

resourceLoader = ResourceLoader.GetForCurrentView("LocalizationDemoUwp.ResourceLibrary/Resources");
currentLanguage = resourceLoader.GetString("CurrentLanguage");

虽语法简单,但好观看最可怜的题目是资源的名目没有智能感知与错误提示,这样用资源异常易出错。

澳门蒲京 7

如若齐图所示,对不当的资源名称,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默认只安装计算机对应之语言,这样好节省安装空间,但潜移默化及动态切换语言的效能,要解决这个题材得以参照以下内容(我从未征了):[localization

  • How to always install all localized resources in Windows Store UWP app
  • Stack
    Overflow](https://stackoverflow.com/questions/40957295/how-to-always-install-all-localized-resources-in-windows-store-uwp-app)

  • 抱完全的计划性视图


于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. 利用Resx资源文件

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.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值为
#880000FF 的字符串为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”的有效值。

然资源文件之实用性大打折扣。当然,这个方案吗不支持动态切换语言。

6. 结语

切磋了这般多resw资源文件之方案,结果或者resx资源文件用得极其顺手,毕竟这方案我早就用了众年(在silverlight中不得不用是方案)。具体用谁方案不同。

得强调的凡resx并无克全代表resw方案,很多时光用混合使用,例如利用之Display
Name可以下resw轻松实现本地化:
澳门蒲京 13

本地化的主题仍有许多情节,这篇文章就打算介绍入门知识,更尖锐之学问可以参见下面被来之链接。

3.2 动态切换语言

在Silverlight.aspx)中曾经没有了x:Static的绑定方式,改吗利用Binding实现本地化,这样虽然语法复杂一些,但越来越实用。WPF当然为可采取这种方法。

首先, 创建一个好像包装资源文件生成的近乎(在斯Demo中是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属性,不是实例成员。幸运的凡编译一次等这种似是而非提示就会收敛。
澳门蒲京 14

用调用方式改变吧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);

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

8. 源码

GitHub –
LocalizationDemo

3.4 在代码里拜访资源

在代码里看资源文件之资源十分简练:

MessageBox.Show(Labels.SwitchLanguage);

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 管理资源文件

比较由资源词典,资源文件还有一个老死之优势就是易管理。Demo中独发一个名字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上应当利用相对布局要休绝对布局、字体选择相当,这里不再累赘。

欲留意的是上述两栽方案还无适用于CLR属性,这吗是为什么我一直强调UIElement的习性最好是据属性的因由之一。

苟产生澳门蒲京错漏请指出。

5. 参考

WPF
全球化及本地化概述.aspx)
Silverlight
部署以及本地化.aspx)
WPFLocalizationExtension
WPF Localization Guidance
XAML
Resources
CultureInfo
类.aspx)
Supported
languages

6. 源码

LocalizationDemo