Win10的SDK正式版已经发布了,"UAP"的名称改成了"UWP",微软改名部好忙啊。随便他了。今天想试试正式版的SDK,升级一下Currency Exchanger,在处理多语言的时候,发现Multilingual App Toolkit 3.0已经不能用在VS2015里了,需要更新。因此把这部分单独再说一下。
VS2015需要安装最新的Multilingual App Toolkit 4.0 beta,下载地址: https://visualstudiogallery.msdn.microsoft.com/6dab9154-a7e1-46e4-bbfa-18b5e81df520?SRC=VSIDE
也可以在VS2015的扩展和更新里安装,注意要安装4.0版本的,不然不能在VS2015里用:
我还是习惯使用MVVM-Sidekick框架来做,VS扩展插件也可以在VS2015的扩展和更新里安装:
新建一个Win10的UWP项目,基于MVVM-Sidekick模板:
新建项目后,需要编译一下,Nuget会自动添加所需引用:
为了国际范,可以把默认语言改为英语。打开Package.appxmanifest,修改默认语言为en-US:
安装多语言工具包后在工具菜单点击Multilingual App Toolkit,启用多语言支持:
此时貌似什么也没发生,然后我又使劲用力多点了好几次,仍然没有任何反应。因为底下会报错:
提示没有找到本地资源文件。这就是4.0与旧版本的不同之处,之前启用多语言支持后会自动添加资源文件,但4.0必须手动添加了。
在项目中添加一个文件夹命名为Strings,在其中添加一个默认语言的文件夹,如果默认语言设置为en-US,则添加的文件名也为en-US,然后再添加一个资源文件,文件名为Resources.resw:
然后再启用多语言支持,就可以了:
右键单击项目,添加语言:
添加几种语言,比如中文简体和繁体:
多语言工具包会添加一个名为MultilingualResources的文件夹,里面添加了两个文件:
这就是对应语言的翻译文件,其实是一个xml文件,可以将此文件发送给帮助翻译的人,翻译好后再导入进来就行了。
打开默认语言的资源,如en-US目录下的Resources.resw,添加几个资源:
注意,AppName.Text命名是这样的,如果有一个TextBlock控件要显示应用名称,那此控件的<span style="font-size:10pt;">x:Uid</span>属性要设置为AppName,这样就可以找到其Text值从而显示对应语言的应用名称。同样的,可以添加一个AppName.Width来区分不同语言下的控件宽度。
重新编译一下项目。
打开MultilingualResources文件夹里的xlf文件进行翻译:
可以点击这个按钮自动调用bing进行翻译:
翻译完后不要忘记保存。
然后重新编译项目,多语言工具包会自动填充每种语言的Resources.resw文件:
下面该画界面了。在页面中找到 pageTitle 控件,添加一个属性:
x : Uid ="AppName"
把 Text ="{ Binding Title }" 删掉 ,现在是这样子:
然后运行一下试试:
虽然默认语言设置的是en-US,但因为本地计算机是使用的zh-CN,所以已经调用了中文的字符来显示。
现在部署到手机上试试。注意要将生成x86改成ARM。
手机上必须先添加英文和中文繁体语言包。把手机切换到en-US语言,运行一下:
已经根据设置的语言改变了。
除了在XAML页面中直接设置x:Uid属性,还可以在后台代码中使用多语言资源。我在之前一篇blog里介绍了自己实现类似WP8中AppResources的方式,经过某位高手指点,加上Cache后会提高性能,因此进行了一点改进。
添加一个 AppResources .cs 文件,输入以下代码:
public static class AppResources { private static ResourceLoader CurrentResourceLoader { get { return loader ?? (loader = ResourceLoader.GetForCurrentView()); } } private static ResourceLoader loader; private static Dictionary<string, string> ResourceCache = new Dictionary<string, string>(); public static string GetString(string key) { string result; if (ResourceCache.TryGetValue(key, out result)) { return result; } result = CurrentResourceLoader.GetString(key); ResourceCache[key] = result; return result; } public static string Introduction { get { return GetString("Introduction"); } } }
打开MainPage_Model.cs,使用propvm添加一个属性:
public string Introduction { get { return _IntroductionLocator(this).Value; } set { _IntroductionLocator(this).SetValueAndTryNotify(value); } } #region Property string Introduction Setup protected Property<string> _Introduction = new Property<string> { LocatorFunc = _IntroductionLocator }; static Func<BindableBase, ValueContainer<string>> _IntroductionLocator = RegisterContainerLocator<string>("Introduction", model => model.Initialize("Introduction", ref model._Introduction, ref _IntroductionLocator, _IntroductionDefaultValueFactory)); static Func<string> _IntroductionDefaultValueFactory = () => default(string); #endregion
在vm的构造函数中赋值:
public MainPage_Model() { Introduction = AppResources.Introduction; }
在MainPage.xaml中添加一个TextBlock:
< TextBlock Grid.Row ="2" Text ="{ Binding Introduction }" />
将Text属性绑定到VM的属性上。
然后运行:
英文设置下:
这样在后台代码中也可以用了。其实在代码中也可以直接使用 AppResources .GetString( " Introduction " ) , 封装一下只是为了防止写错。