C#实现动态多语言界面程序

       一直想做一个多语言的程序,研究了一下.net的本地化方法,觉得做起来比较麻烦,而且不能快速切换,就自己琢磨着写一个。
以我做的一个C# winform 项目为例。
       首先设计多语言文件,这里我用XML来保存,基本结构如下。
 1<?xml version = "1.0" encoding = "GB2312"?>
 2<AirControl language="简体中文">
 3    <Menu>
 4        <Project>
 5            <Item id="0" key="MenuProject" value="项目(&amp;P)" />
 6            <Item id="1" key="MenuProjectItem1" value="新建(&amp;N)" />
 7            <Item id="2" key="MenuProjectItem2" value="打开(&amp;O)" />
 8            <Item id="3" key="MenuProjectItem3" value="保存(&amp;S)" />
 9            <Item id="5" key="MenuProjectItem5" value="退出(&amp;X)" />
10        </Project>
11        <Manage>
12            <Item id="0" key="MenuManage" value="管理(&amp;M)" />
13            <Item id="1" key="MenuManageItem1" value="登录(&amp;I)" />
14            <Item id="2" key="MenuManageItem2" value="注销(&amp;O)" />
15            <Item id="3" key="MenuManageItem3" value="修改密码(&amp;C)" />
16            <Item id="4" key="MenuManageItem4" value="用户管理(&amp;U)" />
17        </Manage>
18        <Help>
19            <Item id="0" key="MenuHelp" value="帮助(&amp;H)" />
20            <Item id="1" key="MenuHelpItem1" value="帮助内容(&amp;H)" />
21            <Item id="2" key="MenuHelpItem2" value="关于(&amp;A)" />
22        </Help>
23    </Menu>
24    <Toolbar>
25        <Statusbar>
26            <Item id="1" key="StatusItem1" value="用户名: " />
27            <Item id="2" key="StatusItem2" value="用户组: " />
28            <Item id="3" key="StatusItem3" value="上次登录时间: " />
29            <Item id="4" key="StatusItem4" value="本次登录时间:" />
30        </Statusbar>
31    </Toolbar>
32    <Form>
33        <MainForm>
34            <Item id="0" key="MainForm" value="xx" />
35            <Item id="1" key="buttonGo" value="开始" />
36            <Item id="2" key="buttonStop" value="停止" />        
37            <Item id="3" key="groupBox1" value="用户信息" />
38            <Item id="4" key="groupBox2" value="常规数据" />    
39        </MainForm>
40        <UserLoginForm>
41            <Item id="0" key="UserLoginForm" value="用户登录" />
42            <Item id="1" key="labelTitle"  value="xx" />
43            <Item id="2" key="labelUsername" value="用户名" />
44            <Item id="3" key="labelPassword" value="密码" />
45            <Item id="4" key="buttonLogin" value="登录" />
46        </UserLoginForm>
47        <ChangePasswordForm>
48            <Item id="0" key="ChangePasswordForm" value="修改密码" />
49            <Item id="1" key="label1" value="原密码" />
50            <Item id="2" key="label2" value="新密码" />
51            <Item id="3" key="label3" value="再输入" />
52            <Item id="4" key="buttonConfirm" value="确认" />
53            <Item id="5" key="buttonCancel" value="取消" />
54        </ChangePasswordForm>
55    </Form>
56    <Dialog>
57        <Title>
58            <Item id="0" key="0001" value="xx" />
59            <Item id="1" key="0002" value="添加测试" />
60            <Item id="2" key="0003" value="添加用户" />
61            <Item id="3" key="0004" value="修改密码" />
62        </Title>
63        <Message>
64            <Item id="0" key="0000" value="一切正常" />
65            <Item id="1" key="2001" value="用户名或密码错误" />
66            <Item id="5" key="2002" value="密码不一致" />
67            <Item id="6" key="2003" value="用户名已存在" />
68            <Item id="7" key="2004" value="添加用户成功" />            
69        </Message>            
70    </Dialog>
71</AirControl>
        这里是语言文件的局部,主体分为四个部分,Menu, Toolbar, Form 和 Dialog,分别对应菜单,工具栏,窗体和对话框的显示字符串。
在Form里面,其每个子树分别对应一个窗体。XML每项有三个域,id 这个只是用来标号,程序中为用,key,value形成一个字典,key是控件
的名称,value是控件的text。在Dialog中key用数字编号。
   做其他语言文件时,只用将value里面的值改成对应的语言即可。
     当然,我们也不一定用XML来写语言文件,简单的ini文件也行。我现在觉得在一般的中小型程序中用XML,出于一个最基本的目的就是装B。

        下面设计读取这个XML的类,
  1using System;
  2using System.Collections.Generic;
  3using System.Linq;
  4using System.Text;
  5using System.Xml;
  6
  7namespace AirLibrary
  8{
  9    /// <summary>
 10    /// 本地化类
 11    /// </summary>

 12    public static class Localization
 13    {
 14        Property //Property
 18
 19        Attribute //Attribute
 25
 26        Method //Method
 66
 67        Function //Function
116
117        Property //Property
158    }

159}

160
        这里我使用静态类来读取和保存,这样效率相对会高一些。读取XML时,我使用的是XmlReader,它使用流式读取,速度也比较快。
        Forms, Menu, Toolbar, Dialog几个属性分别对应XML中的子树,使用.net中的Dictionary范型,Forms嵌套了一层Dictionary。
Load方法是加载语言文件,readLanguage 和paraseXML 函数对XML进行解析,并保存字符串到对应的属性中。
        AddForm这个方法是将每个窗体的动态的添加到forms 里面。
        在程序开始main 函数中,首先调用AddForm方法,添加所有窗体。
       
 1         // 添加所有窗体用于本地化(按XML中顺序)
 2         private static void AddForm()
 3         {
 4             Localization.AddForm("MainForm");
 5             Localization.AddForm("UserLoginForm");
 6             Localization.AddForm("UserManageForm");
 7             Localization.AddForm("ChangePasswordForm");
 8         }
   然后加载语言文件。
1  if (!Localization.Load("zh"))
2             {
3                 MessageBox.Show("无法加载语言配置文件, 将显示英文.""错误", MessageBoxButtons.OK,
4                     MessageBoxIcon.Exclamation);
5                 Localization.HasLang = false;
6             }
7             else
8                 Localization.HasLang = true;

       在每个Form的Load事件中初始化每个控件的Text。
1 if (Localization.HasLang)
2         RefreshLanguage();

// 更新窗体语言
public static void RefreshLanguage(Form form)
{          
     form.Text 
= Localization.Forms[form.Name][form.Name];
     SetControlsLanguage(form, Localization.Forms[form.Name]);
}

         递归更新每个控件Text
 1 /// <summary>
 2 /// 设置control子控件语言
 3 /// </summary>
 4 /// <param name="control">父控件</param>
 5 /// <param name="obj">语言字典</param>
 6 public static void SetControlsLanguage(Control control, Dictionary<stringstring> obj)
 7 {
 8      foreach (Control ctrl in control.Controls)
 9      {
10         // set the control which one's key in the dictionary
11         string text = "";
12         if (obj.TryGetValue(ctrl.Name, out text))
13               ctrl.Text = text;
14 
15         if (ctrl.HasChildren)
16               SetControlsLanguage(ctrl, obj);
17       }
18 }
  
         另外主窗体的Menu和Toolbar,我采用以下的方法更新。
 1 // Refresh the menu language
 2 foreach (ToolStripMenuItem topItem in MainMenuStrip.Items)
 3 {
 4       topItem.Text = Localization.Menu[topItem.Name];
 5       foreach (ToolStripItem item in topItem.DropDownItems)
 6       {
 7             if (item is ToolStripMenuItem)
 8             {
 9                  string text = "";
10                  if (Localization.Menu.TryGetValue(item.Name, out text))
11                       item.Text = text;
12             }
13       }
14 }
15 
16 // Refresh the statusbar language
17 foreach (ToolStripItem item in mainStatus.Items)
18 {
19      string text = "";
20      if (Localization.Toolbar.TryGetValue(item.Name, out text))
21              item.Text = text;
22 }
           Dialog就直接调用Localization中的Dialog属性即可。
           需要转变为不同语言时只需要再调用一次Localization.Load方法。
        
小结:
       这种实现多语言界面的方式我思考了很久,也在网上查了一些资料,最后设计了这样一种方式,XML中利用字典来记录控件的语言
在添加,读取时非常方便,Localization类做成静态类,在运行时就相当于一个常量,没有构造函数这样的开销,整个界面也可以再运行时
直接改变界面语言。
       当然这种方法不一定是最好的, 如果有更好的方法欢迎指点。
posted @ 2009-08-20 10:55  下下签  阅读(11559)  评论(17编辑  收藏  举报
Copyright © 2009 Powered by 下下签