前面 WPF & Sivlerlight 多语言解决方案-实现本地化 对本地化语言资源编辑描述了一下, 说实话, 很麻烦. 经过一天摸索和翻阅文章, 找到了相对简单很多的多语言解决方案.
动态切换软件使用的语言, 是很多软件所使用的方式, 传统的Winform, Win32程序都需要有很多类库和语言资源解析类来完成界面上语言的切换. 在WPF里面,我们可以很方便的利用 动态资源(Dynamic resource)来完成此操作.
我的系统说明:
在我的系统是基于插件的开发框架,里面有多个project, 不能在某一个project中设置所有语言资源, 每个project都可能是独立运行的; 也就是,每个project里面都需要定义语言资源. 下面就说说我的思路. 其实搞成功了也是很简单的方法.
我们首先要有规则, 这个规则就是,每个project里面需要有统一的语言命名方式和文件命名方式, 看下面demo: 我每个项目都有LanCN.xaml 和 LanEN.xaml 这是分别定义中文和英文, 是每个需要用到语言资源的project里面都需要
    
前面 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个程序集中的).
 
