一种灵活的WPF程序多国语言支持

35 篇文章 1 订阅

http://www.cnblogs.com/nankezhishi/archive/2009/07/17/WPFLocalization.html

一种灵活的WPF程序多国语言支持

软件开发常常会被要求支持多国语言。而且想要软件有更多的受众,做好本地化无疑是必然的选择。对于WPF程序而言,支持多语言的方式实在是多种多样。

  1. 微软的官方解决方案:使用Resource,并把Resource按语言编译成独立DLL,程序会根据系统当前语言设置,自动加载最合适的资源。(这种方法灵活性较差,而且不能满足多样的需求,于是网上各种多语言方案纷至沓来。)这里有一篇对官方方案的进一步解释
  2. 使用XML保存语言文件:放进来只是因为网上的确有这么个解释方案,虽然没有什么实用价值……,Resource本来就是XML,还用自己定义一个XML,还XMLDataProvider,还XML-based Data Binding,看着都累……
  3. 使用Project Resource的:和上面的类似,不过把字符串全放在Project Resource里,然后用ObjectDataProvider,然后也是使用Data Binding。
  4. Assembly自带语言:每个Assembly里放上支持的所有语言,使用配置文件设置软件语言,比微软的方案更进一步,但是问题也还是存在的。

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

  1. 运行时切换语言。
  2. 加入新语言,而不需要重新编译软件。

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

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

 

图1. 解决方案的结构

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

 

图2. 编译后的文件结构

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

 

图3. 英文界面

 

图4. 汉语界面

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

MainWindow

 

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

复制代码
< ResourceDictionary  xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s
="clr-namespace:System;assembly=mscorlib" >
    
< s:String  x:Key ="MainWindowTitle" > Localization Demo </ s:String >
    
< s:String  x:Key ="LanguageMenuHeader" > _Language </ s:String >
    
< s:String  x:Key ="EnglishMenuHeader" > _English </ s:String >
    
< s:String  x:Key ="ChineseMenuHeader" > 汉语(_C) </ s:String >
    
< s:String  x:Key ="OpenLanguageFileMenuHeader" > _Open Language File </ s:String >
</ ResourceDictionary >
复制代码

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

复制代码
< Application  x:Class ="Localization.App"
    xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri
="UI\DemoWindow.xaml" >
    
< Application.Resources >
        
< ResourceDictionary >
            
< ResourceDictionary.MergedDictionaries >
                
< ResourceDictionary  Source ="pack://siteOfOrigin:,,,/Resources/Langs/en-US.xaml" />
            
</ ResourceDictionary.MergedDictionaries >
        
</ ResourceDictionary >
    
</ Application.Resources >
</ Application >
复制代码

 

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

复制代码
     public   class  LanguageHelper
    {
        
///   <summary>
        
///  
        
///   </summary>
        
///   <param name="languagefileName"></param>
         public   static   void  LoadLanguageFile( string  languagefileName)
        {
            Application.Current.Resources.MergedDictionaries[
0 =   new  ResourceDictionary()
            {
                Source 
=   new  Uri(languagefileName, UriKind.RelativeOrAbsolute)
            };
        }
    }
复制代码

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

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

缺陷

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

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

<MenuItem Command="c:LanguageCommands.OpenLanguage"

 Header="{DynamicResource OpenLanguageFileMenuHeader}"/>

 

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

 

2012/3/18  update:

 完整的代码可以从这里下载到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值