1. 前言
WPF的本地化是个很广阔的效劳,小编做过的WPF程序超过四分之二都落到实处了本地化(不管最终有未有利用)。常常本地化有以下几点供给:
- 在先后运营时依据CultureInfo.CurrentUICulture或配备项显示对应语言的UI。
- 在程序运维时方可动态切换UI语言(没有须求重启程序)。
- 制作对应分歧语言的安装包。
- 通过下载语言包完结二种语言的本地化。
在那之中独有首先点是必需的。
其次点最棒也足以兑现,相当多时候切换语言只为了看看有个别专门的学业术语在克罗地亚共和国(Republic of Croatia)语中的原著是何许,可能权且打字与印刷个保加梅里达语报表,日常利用可能用汉语,用户不想为了这一点重启程序。
其三点和第四点即使很常见,但作者一贯没落成过,毕竟文字能源(有时还应该有一些些图片)占用的空间不会太多,大多数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类,那就导致当地化的落到实处方案完全差别。
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”资源文件。最终目录结构如下:
在zh-CN\Resources.resw和en-US\Resources.resw增加四个新财富,分别是UsernameText博克斯.Width和UsernameTextBox.Header:
在XAML中增加三个TextBox,设置x:Uid为UsernameTextBox,x:Uid将XAML元素和财富文件中的能源拓展关联:
<TextBox x:Uid="UsernameTextBox"/>
运作后就能够看到UsernameTextBox的Header设置为”用户名”,Width为100。
在“设置\区域和言语”准将”English”设置为私下认可语言,再次运维应用可知到运转在斯拉维尼亚语境况下的成效。
这么主题的本地化效能就达成了。这种本地化格局有如下优点:
- 简言之快捷,轻便上手
- 语法轻巧,无需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>
这段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中一贯引用。如项目中有如下两张图纸:
在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");
就算语法轻便,但足以看出最大的主题材料是能源的称号未有智能感知和不当提醒,那样使用财富很轻便出错。
如上海教室所示,对错误的能源名称,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;
}
只在装置页面及菜单这几个在切换语言时不会另行加载的UI上选择Binding,另外地方不改变,那样简单的动态切换语言就落到实处了。运维结果如上,能够看出TextBox右键菜单仍未切换语言,须求再一次开动。
UWP暗中认可只安装Computer对应的言语,那样能够省去安装空间,但影响到动态切换语言的功力,要化解那几个标题得以参谋以下内容(作者未曾证实过):[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)
。
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>
只必要如此写就可以赢得完整的规划时希图,不过照旧不曾减轻智能感知和谬误提醒这四个问题。
在那几个方案上也可回顾地贯彻动态切换语言。
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用起来方便些):
在改造财富文件的值后PublicResXFileCodeGenerator将电动创建对应的类并为每三个键值增多如下代码:
/// <summary>
/// 查找类似 Address 的本地化字符串。
/// </summary>
public static string Address {
get {
return ResourceManager.GetString("Address", resourceCulture);
}
}
然后将这些资源文件复制粘贴一份,将名称改为“原名+.+对应的言语+.resx”的格式,并且将里面的值翻译成对应语言如下:
在UI上使用x:Static绑定到相应的能源:
<DataGridTextColumn Header="{x:Static local:Labels.Username}"/>
那般基本的本地化就到位了。很多控件库都以利用这种办法做本地化。除了字符串,resx能源文件还扶助除字符串以外的财富,如图片、音频等。
只是那个方案只兑现了最主旨的本地化,何况最大的标题是只帮忙直接接纳字符串,不帮忙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自个儿。
- 开采“增加新项”对话框,选中“财富文件(.resw)”,在“名称”文本框上校文件名称改为“Labels.resx”,点击“增多”。
- 在“化解方案能源管理器”选中“Labels.resx”,邮件张开“属性”视图,“生成操作”接纳“嵌入的财富”。
- 将“Labels.resx”复制为“Labels.zh-CN.resx”,展开“Labels.zh-CN.resx”,“访谈修饰符”改为“无代码生成”。
-
在“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当然也足以采用这种方法。
第一, 创设三个类包装能源文件生成的类(在这一个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属性,不是实例成员。幸运的是编写翻译一次这种张冠李戴提示就能够不复存在。
将调用格局改为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轻便达成本地化:
本地化的宗旨仍有大多内容,那篇小说只筹算介绍入门知识,更深透的知识能够参照下边给出的链接。
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"/>
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. 源码
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,不需求任何操作就足以一本万利地在先后集以内分享能源。
3.7 管理能源文件
比起财富词典,资源文件还会有二个比十分大的优势正是轻松管理。德姆o中独有二个名字Labels的能源文件,实际项目中得以按职能或模块分别创建相应的财富文件,化解了能源词典重名、互相覆盖、智能感知列表过长等主题材料。其它作者引入应用VS的扩展程序ResXManager管理全数财富文件。
它能够在二个UI里管理全数语言的财富文件,比比较大地方便了财富文件的应用。
3.8 ReSharper支持
对Resx财富文件,ReSharper也提供了优异的支撑。
当须要为有个别财富修改Key时,能够按“财富文件名称”+”.”+”Key”来全局替换,日常那样已经足足放心。ReSharper更进一竿,它提供了重命名效用。借使要将Labels的能源English重名称叫为Englishs,能够先在Labels.Designer.cs重命名,然后采纳“Apply
rename refactoring”选项:
这会儿全数引用,包罗XAML都已运用新的名称:
但是最后仍需自身动手在财富文件编辑器中期维修改Key。
除去,假若在XAML中应用了不当的Key,ReSharper也可以有荒唐提醒:
在少数场所,ReShaper还可采用“Move To Resource”效用:
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讴歌ZDX属性,那也是干吗本身直接重申UIElement的属性最佳是依据属性的由来之一。
如有错漏请提议。
5. 参考
WPF
环球化和本地化概述.aspx)
Silverlight
计划和本地化.aspx)
WPFLocalizationExtension
WPF Localization Guidance
XAML
Resources
CultureInfo
类.aspx)
Supported
languages