浅谈灵活的WPF程序多语言支持
创始人
2024-04-17 03:10:52
0

微软的WPF程序多语言支持官方解决方案:使用Resource,并把Resource按语言编译成独立DLL,程序会根据系统当前语言设置,自动加载最合适的资源。(这种方法灵活性较差,而且不能满足多样的需求,于是网上各种多语言方案纷至沓来。)这里有一篇对官方方案的进一步解释。

使用XML保存语言文件:放进来只是因为网上的确有这么个解释方案,虽然没有什么实用价值……,Resource本来就是XML,还用自己定义一个XML,还XMLDataProvider,还XML-based Data Binding,看着都累……
使用Project Resource的:和上面的类似,不过把字符串全放在Project Resource里,然后用ObjectDataProvider,然后也是使用Data Binding。

Assembly自带语言:每个Assembly里放上支持的所有语言,使用配置文件设置软件语言,比微软的方案更进一步,但是WPF程序多语言支持问题也还是存在的。

上面所有的方案都没有同时解决下面这两个问题:

运行时切换语言。

加入新语言,而不需要重新编译软件。


下面,就来介绍一种更灵活的,解决了上面两个问题的WPF程序多语言支持方案。

基本方式还是使用Resource,只不过Resource是运行时才加载进来的。解决方案的结构如下图所示。

解决方案的结构

图1. 解决方案的结构

其中各个语言文件的资源文件放在Resources/Langs文件夹中,这些资源文件不会被编译到Assembly中,编译之后的文件结构如下图所示,语言文件被原样复制到Output文件夹中。

编译后的文件结构

图2. 编译后的文件结构

先来看看程序的运行效果,再来看代码会比较直观一些。

英文界面

图3. 英文界面

汉语界面

图4. 汉语界面

下面就是这个界面的代码。

  1. MainWindow  
  2.  x:Class="Localization.DemoWindow" 
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  5.     xmlns:c="clr-namespace:Localization.Backend.Commands" 
  6.     Title="{DynamicResource MainWindowTitle}" 
  7.     Width="230" Height="150"> 
  8.      LastChildFill="False"> 
  9.          DockPanel.Dock="Top"> 
  10.              
  11.                  Member="c:LanguageCommands.OpenLanguageBinding"/> 
  12.             Menu.CommandBindings> 
  13.              Header="{DynamicResource LanguageMenuHeader}"> 
  14.                  Header="{DynamicResource EnglishMenuHeader}" 
  15.                           Click="OnLoadEnglishClick"/> 
  16.                  Header="{DynamicResource ChineseMenuHeader}" 
  17.                           Click="OnLoadChineseClick" /> 
  18.                  
  19.                  Command="c:LanguageCommands.OpenLanguage" 
  20.                           Header="{DynamicResource OpenLanguageFileMenuHeader}"/> 
  21.             MenuItem> 
  22.         Menu> 
  23.     DockPanel> 
  24. Window> 

所有的界面上的文字,都使用DynamicResource引用资源文件中的字符串。资源文件的格式如下(英文资源文件示例):

  1.  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  2.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  3.     xmlns:s="clr-namespace:System;assembly=mscorlib"> 
  4.      x:Key="MainWindowTitle">Localization Demos:String> 
  5.      x:Key="LanguageMenuHeader">_Languages:String> 
  6.      x:Key="EnglishMenuHeader">_Englishs:String> 
  7.      x:Key="ChineseMenuHeader">汉语(_C)s:String> 
  8.      x:Key="OpenLanguageFileMenuHeader">_Open Language Files:String> 
  9. ResourceDictionary> 

语言文件没有编译到Assembly中,使用起来就有些不太一样。下面是App.xaml文件中设置Application的默认加载语言的方式。

  1.  x:Class="Localization.App" 
  2.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  3.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  4.     StartupUri="UI\DemoWindow.xaml"> 
  5.      
  6.          
  7.              
  8.                  Source="pack://siteOfOrigin:,,,/Resources/Langs/en-US.xaml"/> 
  9.             ResourceDictionary.MergedDictionaries> 
  10.         ResourceDictionary> 
  11.     Application.Resources> 
  12. Application> 

前面的内容基本上没有什么和别的方案不一样的地方,下面才是最重要的一点,就是如何运行时切换语言的呢?答案就是,只要把上面代码里的ResourceDictionary替换掉就OK了,界面会自动刷新。下面就是实现替换功能的代码。  

  1. public class LanguageHelper  
  2.     {  
  3.         ///  
  4.         ///   
  5.         /// summary> 
  6.         ///  name="languagefileName">param> 
  7.         public static void LoadLanguageFile(string languagefileName)  
  8.         {  
  9.             Application.Current.Resources.MergedDictionaries[0] = new ResourceDictionary()  
  10.             {  
  11.                 Source = new Uri(languagefileName, UriKind.RelativeOrAbsolute)  
  12.             };  
  13.         }  
  14.     } 

参数languagefileName可以是文件的绝对路径,如:C:\en-US.xaml或是和App.xaml里一样的相对路径。顺便解释一下,那个“pack://siteOfOrigin:,,,”无非就是当前执行程序的所在目录。

以目前的测试结果来看,即使界面上有大量的细粒度文字。切换语言的速度也是一瞬间的事儿,如果慢,也是因为xaml文件过大,读文件用了不少时间。

WPF程序多语言支持缺陷

其实这才是最重要的,很多文章介绍一项技术的时候都会把这个技术夸得天花乱坠,却对潜在的缺陷或问题避而不谈。

缺陷就在于,不是所有的东西都是可以运行是更新的。比如***一个菜单项是用Command实现的,如下代码所示:

  1.  Command="c:LanguageCommands.OpenLanguage" 
  2.  Header="{DynamicResource OpenLanguageFileMenuHeader}"/> 

RoutedUICommand本身就已经定义了Text属性用来显示在界面上,完全没有必要为使用了这个Command的MenuItem设置Header属性。但是这里为什么还是设置了呢?因为目前还没有找到简单的方案改变Command的Text后能自动地更新界面。因为Command的Text属性不是一个Dependency Property。为了自动更新界面,不得不为MenuItem设置Header属性。

【编辑推荐】

  1. Visual Studio 2010截图曝光 以WPF开发UI
  2. 为WPF项目创建单元测试
  3. 详解Silverlight和WPF互相扩展
  4. 教你如何理解WPF中的Template类
  5. 详谈WPF开发中的数据虚拟化

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...
2012年第四季度互联网状况报... [[71653]]  北京时间4月25日消息,据国外媒体报道,全球知名的云平台公司Akamai Te...