前面 WPF & Sivlerlight 多语言解决方案-实现本地化 对本地化语言资源编辑描述了一下, 说实话, 很麻烦. 经过一天摸索和翻阅文章, 找到了相对简单很多的多语言解决方案.
动态切换软件使用的语言, 是很多软件所使用的方式, 传统的Winform, Win32程序都需要有很多类库和语言资源解析类来完成界面上语言的切换. 在WPF里面,我们可以很方便的利用 动态资源(Dynamic resource)来完成此操作.
我的系统说明:
在我的系统是基于插件的开发框架,里面有多个project, 不能在某一个project中设置所有语言资源, 每个project都可能是独立运行的; 也就是,每个project里面都需要定义语言资源. 下面就说说我的思路. 其实搞成功了也是很简单的方法.
我们首先要有规则, 这个规则就是,每个project里面需要有统一的语言命名方式和文件命名方式, 看下面demo: 我每个项目都有LanCN.xaml 和 LanEN.xaml 这是分别定义中文和英文, 是每个需要用到语言资源的project里面都需要定义的.
具体语言内容和怎么使用字符串资源可以查看源码. 下面我来说说怎么简单的载入所有project中的字符串资源.
第一步. 设置默认和设计期语言资源
首先我们先看一下, MainApp.Controls.WinTest 这个窗口的xaml文件中引用字符串资源文件.
Window.Resources
1
<Window.Resources>
2
<ResourceDictionary>
3
<ResourceDictionary.MergedDictionaries>
4
<ResourceDictionary Source="/MainApp.Controls;component/LanCN.xaml" />
5
</ResourceDictionary.MergedDictionaries>
6
</ResourceDictionary>
7
</Window.Resources>
这里我们定义了引用, 注意引用格式, 再看一下MainApp里面的App.xaml中, 我同时也用到了另一个项目的语言资源(怎么使用另一个程序集的资源就是这么搞):
Application.Resources
1
<Application.Resources>
2
<ResourceDictionary>
3
<ResourceDictionary.MergedDictionaries>
4
<ResourceDictionary Source="/MainApp;Component/LanCN.xaml"/>
5
<ResourceDictionary Source="/MainApp.Controls;Component/LanCN.xaml"/>
6
</ResourceDictionary.MergedDictionaries>
7
</ResourceDictionary>
8
</Application.Resources>
这样我都使用了LanCN.xaml,也就是中文, 这些引用的目的是默认语言资源和设计器使用的.
第二步.运行期设置语言和资源
大家首先看一下Utils这个类
Utils 类
1
public class Utils
2

{
3
static List<string> AssemblyLans
{ get; set; }
4
/**//// <summary>
5
/// Loading language resource file
6
/// </summary>
7
/// <param name="app"></param>
8
public static void LoadLanguangeResource(System.Windows.Application app)
9
{
10
AssemblyLans = new List<string>();
11
Assembly[] ps = AppDomain.CurrentDomain.GetAssemblies();
12
foreach (Assembly items in ps)
13
{
14
if (items.GlobalAssemblyCache) continue;
15
try
16
{
17
string assembly = items.FullName.Split(',')[0];
18
string lanRes = string.Format("/{0};Component/Lan{1}.xaml", assembly, Language);
19
ResourceDictionary langRd = Application.LoadComponent(new Uri(lanRes, UriKind.RelativeOrAbsolute)) as ResourceDictionary;
20
21
app.Resources.MergedDictionaries.Add(langRd);
22
AssemblyLans.Add(assembly);
23
}
24
catch (Exception exp)
25
{
26
System.Diagnostics.Trace.WriteLine(exp.Message);
27
}
28
}
29
}
30
/**//// <summary>
31
/// clear default language resource
32
/// </summary>
33
/// <param name="ele"></param>
34
public static void ClearDefaultLan(FrameworkElement ele)
35
{
36
Assembly items = Assembly.GetCallingAssembly();
37
string assembly = items.FullName.Split(',')[0];
38
if (!AssemblyLans.Contains(assembly)) return;
39
if (ele.Resources.MergedDictionaries.Count > 0)
40
{
41
ele.Resources.MergedDictionaries.Clear();
42
}
43
}
44
public static string Language
45
{
46
get
47
{
48
string result = "";
49
try
50
{
51
result = ConfigurationManager.AppSettings["lan"];
52
}
53
catch
54
{
55
56
}
57
if (string.IsNullOrEmpty(result))
58
{
59
result = "en";
60
}
61
return result.ToUpper();
62
}
63
}
64
}
65
LoadLanguangeResource
是装载语言资源的方法, 这里是从配置文件中读取要取得的语言名.
大家注意这两句:
string lanRes = string.Format("/{0};Component/Lan{1}.xaml", assembly, Language);
ResourceDictionary langRd = Application.LoadComponent(new Uri(lanRes, UriKind.RelativeOrAbsolute)) as ResourceDictionary;
我这是从程序集中读取, 其实我们可以从外部文件或者URL来读取, 以方便修改.
ClearDefaultLan
是清除设计期的默认语言, 这里面我处理了一下,就是没有所指定的资源时候,用默认资源.
大家请看MainApp.Controls.WinTest的构造函数中:
InitializeComponent();
Utils.ClearDefaultLan(this);
这个Utils.ClearDefaultLan(this)一定要在InitializeComponent()之后调用, 没有初始化无效调用.
好了,这2个关键函数已经知道干什么了,我们再看 App.xaml.cs代码:
App.xaml.cs
private void OnStartup(Object sender, StartupEventArgs e)
{
LoadLanguage();
}
void LoadLanguage()
{
if (this.Resources.MergedDictionaries.Count > 0)
{
this.Resources.MergedDictionaries.Clear();
}
Controls.Utils.LoadLanguangeResource(this);
}
首先清除App全局语言资源, 然后装载所有的程序集语言资源. ok了, 大家下载源码修改App.config中语言配置跑跑看效果. 注意每个地方使用的资源(2个程序集中的).
