一种灵活的WPF程序多国语言支持
2009-07-17 00:07
465 查看
软件开发常常会被要求支持多国语言。而且想要软件有更多的受众,做好本地化无疑是必然的选择。对于WPF程序而言,支持多语言的方式实在是多种多样。
微软的官方解决方案:使用Resource,并把Resource按语言编译成独立DLL,程序会根据系统当前语言设置,自动加载最合适的资源。(这种方法灵活性较差,而且不能满足多样的需求,于是网上各种多语言方案纷至沓来。)这里有一篇对官方方案的进一步解释。
使用XML保存语言文件:放进来只是因为网上的确有这么个解释方案,虽然没有什么实用价值……,Resource本来就是XML,还用自己定义一个XML,还XMLDataProvider,还XML-based Data Binding,看着都累……
使用Project Resource的:和上面的类似,不过把字符串全放在Project Resource里,然后用ObjectDataProvider,然后也是使用Data Binding。
Assembly自带语言:每个Assembly里放上支持的所有语言,使用配置文件设置软件语言,比微软的方案更进一步,但是问题也还是存在的。
上面所有的方案都没有同时解决下面这两个问题:
运行时切换语言。
加入新语言,而不需要重新编译软件。
下面,就来介绍一种更灵活的,解决了上面两个问题的多语言支持方案。
基本方式还是使用Resource,只不过Resource是运行时才加载进来的。解决方案的结构如下图所示。
MainWindow
<Window x:Class="Localization.DemoWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:Localization.Backend.Commands"
Title="{DynamicResource MainWindowTitle}"
Width="230" Height="150">
<DockPanel LastChildFill="False">
<Menu DockPanel.Dock="Top">
<Menu.CommandBindings>
<x:Static Member="c:LanguageCommands.OpenLanguageBinding"/>
</Menu.CommandBindings>
<MenuItem Header="{DynamicResource LanguageMenuHeader}">
<MenuItem Header="{DynamicResource EnglishMenuHeader}"
Click="OnLoadEnglishClick"/>
<MenuItem Header="{DynamicResource ChineseMenuHeader}"
Click="OnLoadChineseClick" />
<Separator/>
<MenuItem Command="c:LanguageCommands.OpenLanguage"
Header="{DynamicResource OpenLanguageFileMenuHeader}"/>
</MenuItem>
</Menu>
</DockPanel>
</Window>
所有的界面上的文字,都使用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:
完整的代码可以从这里下载到。
微软的官方解决方案:使用Resource,并把Resource按语言编译成独立DLL,程序会根据系统当前语言设置,自动加载最合适的资源。(这种方法灵活性较差,而且不能满足多样的需求,于是网上各种多语言方案纷至沓来。)这里有一篇对官方方案的进一步解释。
使用XML保存语言文件:放进来只是因为网上的确有这么个解释方案,虽然没有什么实用价值……,Resource本来就是XML,还用自己定义一个XML,还XMLDataProvider,还XML-based Data Binding,看着都累……
使用Project Resource的:和上面的类似,不过把字符串全放在Project Resource里,然后用ObjectDataProvider,然后也是使用Data Binding。
Assembly自带语言:每个Assembly里放上支持的所有语言,使用配置文件设置软件语言,比微软的方案更进一步,但是问题也还是存在的。
上面所有的方案都没有同时解决下面这两个问题:
运行时切换语言。
加入新语言,而不需要重新编译软件。
下面,就来介绍一种更灵活的,解决了上面两个问题的多语言支持方案。
基本方式还是使用Resource,只不过Resource是运行时才加载进来的。解决方案的结构如下图所示。
MainWindow
<Window x:Class="Localization.DemoWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:Localization.Backend.Commands"
Title="{DynamicResource MainWindowTitle}"
Width="230" Height="150">
<DockPanel LastChildFill="False">
<Menu DockPanel.Dock="Top">
<Menu.CommandBindings>
<x:Static Member="c:LanguageCommands.OpenLanguageBinding"/>
</Menu.CommandBindings>
<MenuItem Header="{DynamicResource LanguageMenuHeader}">
<MenuItem Header="{DynamicResource EnglishMenuHeader}"
Click="OnLoadEnglishClick"/>
<MenuItem Header="{DynamicResource ChineseMenuHeader}"
Click="OnLoadChineseClick" />
<Separator/>
<MenuItem Command="c:LanguageCommands.OpenLanguage"
Header="{DynamicResource OpenLanguageFileMenuHeader}"/>
</MenuItem>
</Menu>
</DockPanel>
</Window>
所有的界面上的文字,都使用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:
完整的代码可以从这里下载到。
相关文章推荐
- 一种灵活的WPF程序多国语言支持
- WPF一种灵活的程序多国语言支持
- 浅谈灵活的WPF程序多语言支持
- 如何用最简单的方法让WPF程序支持多国语言,并且语言文字用户可以随意编辑?
- 怎样在程序中利用C++支持多国语言(一种解决方案)
- EasyJWeb中灵活的多国语言支持
- 怎样编写支持多国语言的程序, 让它能够根据所运行的操作系统自动显示相应的文字。
- 在程序中利用C++支持多国语言
- EasyJWeb中灵活的多国语言支持
- C#多国语言支持的WinForm程序开发
- EasyJWeb中灵活的多国语言支持
- EasyJWeb中灵活的多国语言支持
- EasyJWeb中灵活的多国语言支持
- EasyJWeb中灵活的多国语言支持
- 怎样编写支持多国语言的程序, 让它能够根据所运行的操作系统自动显示相应的文字。
- EasyJWeb中灵活的多国语言支持
- C#多国语言支持的WinForm程序开发(转)
- WPF应用程序支持多国语言解决方案
- 终极实现WPF应用程序支持多国语言解决方案的源码下载
- EasyJWeb中灵活的多国语言支持