上面几个小节通过示例介绍了如何引用资源以及设置应用语言来显示不同语言的信息,这些示例都只是添加了简体中文和英语两种语言来显示资源,而在一些复杂的应用程序中,字符串资源可能会被定义成多种语言,文件资源也可能为了根据不同的环境显示不同的效果而在程序中存储多种版本,这时应用程序就需要根据使用情况选取最匹配的资源作为应用的首选资源,本小节将通过示例模拟应用选取匹配资源的过程。
1.匹配规则
在应用程序运行时,应用对资源的选取受许多方面的因素的影响,例如系统的语言、屏幕的大小、分辨率和对比度等。应用程序的资源管理系统将根据应用的上下文环境对资源候选项进行排序,选取最匹配的候选项作为应用的首选资源。
例如应用选取的资源类型为字符串资源,资源的值通过五种语言来表示,这五种语言分别为英语(英国)、英语(美国)、法语(法国)、法语(加拿大)和简体中文(中国),这五种语言所对应的语言标识符分别为:en-GB、en-US、fr-FR、fr-CA和zh-CN。
在应用中添加一个ComboBox下拉列表框控件,分别将上面介绍的五种语言加入到列表框当中,用户可以通过此列表框在应用中选取任意一种语言来作为应用的首选语言。当用户选定一种语言作为应用的首选语言后。程序可以通过应用的资源管理器根据用户选择语言的标识符和系统的语言首选项标识符对所提供的资源候选项进行匹配并排序,从中选出最适合的资源。
资源管理器的匹配规则会首先判断应用程序当前的首选语言标识符的前缀,对所有的资源候选项进行匹配,从中选择前缀相同的资源候选项进行优先考虑,如果前缀相同再使用语言标识符的后缀对前缀匹配的资源候选项进行区分和排序。下面再在所有的资源候选项当中查找与当前系统的语言首选项相匹配的资源候选项进行排序,匹配的规则与应用的首选语言标识符匹配规则一样,先匹配资源候选项的前缀再匹配资源候选项的后缀,如果资源候选项的语言标识符从前缀就开始无法与当前的应用及系统语言匹配则代表此资源候选项完全不匹配,按此规则最后形成一个从高到底的资源候选项匹配序列。
下面假设系统的语言首选项为中文(简体),资源候选项为之前所介绍的五种语言,那么对于选取应用首选语言为“英语(英国)”的应用而言,通过规则匹配将得到以下顺序的资源候选项匹配序列:英语(英国)、英语(美国)、简体中文(中国)、法语(法国)和法语(加拿大)。
原因是,英语(英国)资源候选项的标识符是en-GB,它和当前应用所设置的首选语言在语言及区域两个前后缀上完全匹配,所以被排在了第一位,英语(美国)资源候选项的标识符是en-US与当前应用首选语言在语言上匹配但是在区域上不匹配,所以被排在了第二位。接下来由于系统的语言首选项为中文(简体),所以简体中文(中国)资源候选项从系统的语言首选项角度来说也是匹配的,但是却在这五种资源候选项当中排第三位,这是由于系统级别的语言首选项的优先级别要低于应用程序本身所设置的首选语言,而排列末尾的“法语(法国)”和“法语(加拿大)”的标识符前缀为fr,它们与英语(英国)所代表的en-GB语言标识符从前缀比较上就已经不相同,所以表示法语的两种语言是完全不匹配的。下面通过代码演示上述过程。
2.匹配示例
新建一个Windows应用商店的空白应用程序项目,并命名为SelectMatchResources。在项目中新建一个名为“Strings”的文件夹,在“Strings”文件夹下新建一个名为“dimensions”的子文件夹,在“dimensions”文件夹中添加5个资源文件并在资源文件中添加资源值,最终的资源文件名及其中的资源值,如表18-1所示。
表18-1 dimensions文件夹下的5个资源文件及资源文件中的资源
资源文件名 | 资源名称 | 资源值 |
dimensions.lang-en-GB | LanguageOnly | 英语资源(英国) |
dimensions.lang-en-US | LanguageOnly | 英语资源(美国) |
dimensions.lang-fr-FR | LanguageOnly | 法语资源(法国) |
dimensions.lang-fr-CA | LanguageOnly | 法语资源(加拿大) |
dimensions.lang-zh-CN | LanguageOnly | 简体中文资源(中国) |
本示例以“英语资源(英国)”的形式表示字符串资源的值,方便读者可以直观的看到在应用程序中资源候选项的匹配情况。
双击打开MainPage.xaml文件,在Grid元素中添加一个ComboBox控件、一个Button按钮和两个TextBlock文本块。在ComboBox控件中添加五个ComboBoxItem列表项,分别用来显示英语(英国)、英语(美国)、法语(法国)、法语(加拿大)和简体中文(中国)五种语言选项,并分别设置这五个列表项的Tag属性值为五种语言对应的标识符。然后设置ComboBox控件的SelectedValuePath属性的值为Tag,表示在后台代码中使用SelectedValue属性将获取到Tag属性的值。接下来设置Button按钮的Content属性值为“显示候选资源信息”,此按钮用于获取候选资源匹配列表并将其显示在一个TextBlock文本块中,另一个文本块则用来显示“选择应用语言”提示信息,代码如下所示:
<ComboBox SelectedValuePath="Tag" SelectedIndex="0" Name="LanguageComboBox" Margin="360,122,787,599">
<ComboBoxItem Tag="en-GB">英语(英国)</ComboBoxItem>
<ComboBoxItem Tag="en-US">英语(美国)</ComboBoxItem>
<ComboBoxItem Tag="fr-FR">法语(法国)</ComboBoxItem>
<ComboBoxItem Tag="fr-CA">法语(加拿大)</ComboBoxItem>
<ComboBoxItem Tag="zh-CN">简体中文(中国)</ComboBoxItem>
</ComboBox>
<Button Name="ShowCandidateResources" Content="显示候选资源信息" FontSize="20" Click="ShowCandidateResources_Click" Margin="612,118,0,594" Width="223" Height="56" />
<TextBlock Margin="360,225,0,0" HorizontalAlignment="Left" Name="CandidateResources" FontSize="20" Height="412" TextWrapping="Wrap" VerticalAlignment="Top" Width="648"/>
<TextBlock HorizontalAlignment="Left" Margin="514,63,0,0" TextWrapping="Wrap" Text="选择应用语言" FontSize="25" VerticalAlignment="Top" Height="34" Width="157"/>
这时运行此页面,单击ComboBox控件的文本框,可展开下拉列表查看5种语言选项,如图18-31所示。在后台添加代码以后,可以选择列表中的一种语言作为应用的首选语言,然后单击“显示候选资源信息”按钮查看资源候选项匹配列表信息。
图18-31 选择应用语言界面
下面在MainPage.xaml.cs文件中添加单击“显示候选资源信息”按钮后的事件处理方法ShowCandidateResources_Click,此方法用于显示资源候选项匹配列表信息,代码如下所示:
using Windows.ApplicationModel.Resources.Core;
private void ShowCandidateResources_Click(object sender, RoutedEventArgs e)
{
//新建一个ResourceContext类的对象context,用于存储应用的上下文环境
var context = new ResourceContext();
//定义selectedLanguage变量存储选择语言所对应的Tag属性值
var selectedLanguage = LanguageComboBox.SelectedValue;
context.QualifierValues["Language"] = selectedLanguage.ToString();
//调用SearchResource方法用于在项目中查找资源
SearchResource(context, "LanguageOnly");
}
上面的代码首先新建了一个ResourceContext类的对象context,用于存储应用的上下文环境。然后定义一个selectedLanguage变量用于存储在ComboBox下拉列表中选择项的语言标记信息。接着调用ToString方法把selectedLanguage变量转化为字符串,将其以键值对形式保存在context对象的QualifierValues属性的"Language"键中。最后以context对象和资源名称"LanguageOnly"作为参数调用SearchResource方法,用于在项目中查找资源候选项。下面来看一下SearchResource方法的实现代码。
在SearchResource方法中添加了查找资源的过程,代码如下所示:
void SearchResource(ResourceContext context, string resourceId)
{
//定义一个dimensionMap对象用于访问资源文件
ResourceMap dimensionMap = ResourceManager.Current.MainResourceMap.GetSubtree("dimensions");
//声明一个NamedResource类的对象namedResource
NamedResource namedResource;
if (dimensionMap.TryGetValue(resourceId, out namedResource))
{
var resourceCandidates = namedResource.ResolveAll(context);
//调用ShowCandidates方法显示候选资源
ShowCandidates(resourceId, resourceCandidates);
}
}
上面的代码新建了一个ResourceMap类的对象dimensonMap,以项目中资源文件名的前半部分“dimensions”作为参数调用ResourceManager类的Current成员中的MainResourcesMap成员所提供的GetSubtree方法,将返回结果赋给resourceStringMap对象。这样resourceStringMap对象便可以访问文件名前半部分为“dimensions”的资源文件。
声明一个NamedResource类的对象namedResource用于获取字符串资源的值。然后使用SearchResource方法的参数resourceId作为调用dimensionMap对象的TryGetValue方法的第一个参数,第二个为引用参数,用于将获取的资源值赋给namedResource。TryGetValue方法返回一个bool类型的值,当nameResource对象不为空时返回值True,则以context对象作为参数调用namedResource对象的ResolveAll方法,将所有候选资源项按优先顺序存储在resourceCandidates对象中,然后以SearchResource方法的参数resourceId和resourceCandidates对象作为参数调用ShowCandidates方法来显示候选资源的相关信息。下面再来看一下ShowCandidates方法的实现代码。
在ShowCandidates方法很简单,只是通过遍历的方法将各个候选资源名称、语言代码和是否匹配应用等信息显示在界面上,代码如下所示:
void ShowCandidates(string resourceId, IReadOnlyList<ResourceCandidate> resourceCandidates)
{
string outText = "资源名称: " + resourceId + "\r\n";
int number = 1;
//遍历resourceCandidates对象中的候选资源
foreach (var candidate in resourceCandidates)
{
var value = candidate.ValueAsString;
outText += " 候选资源 " + number.ToString() + ":" + value + "\r\n";
foreach (var qualifier in candidate.Qualifiers)
{
//将语言的标识符、是否匹配应用等信息显示出来
var qualifierValue = qualifier.QualifierValue;
outText += " 语言标识符: " + qualifierValue + "\r\n";
outText += " 是否匹配应用: 匹配 (" + qualifier.IsMatch.ToString() + ") " + "默认语言 (" + qualifier.IsDefault.ToString() + ")" + "\r\n";
}
number++;
}
CandidateResources.Text += outText + "\r\n";
}
运行程序,在应用界面中选择英语(英国)作为应用的首选语言,单击“显示候选资源信息”按钮,会看到资源候选项对应语言的匹配顺序为“英语(英国)”、“英语(美国)”、“简体中文(中国)”、“法语(法国)”和“法语(加拿大)”,效果如图18-32所示。
图18-32 选取匹配语言
从图18-32可以看到,应用对这些资源候选项的匹配顺序就是本小节开始讲述的规则,候选资源1:英语资源(英国)为应用的首选资源项。以上就是资源匹配的相关知识点。为了巩固本章所学知识,下节为读者总结一个全球化示例。