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的类,
复制代码
  1 using  System;
  2 using  System.Collections.Generic;
  3 using  System.Linq;
  4 using  System.Text;
  5 using  System.Xml;
  6
  7 namespace  AirLibrary
  8 {
  9    /// <summary>
 10    /// 本地化类
 11    /// </summary>

 12    public static class Localization
 13    {
 14        #region Property
 15        public static string Lang getprivate set; }
 16        public static bool HasLang getset; }        
 17        #endregion
 //Property
 18
 19        #region Attribute
 20        private static Dictionary<string, Dictionary<stringstring>> forms = new Dictionary<string, Dictionary<stringstring>>();
 21        private static Dictionary<stringstring> menu = new Dictionary<stringstring>();
 22        private static Dictionary<stringstring> toolbar = new Dictionary<stringstring>();
 23        private static Dictionary<stringstring> dialog = new Dictionary<stringstring>();
 24        #endregion
 //Attribute
 25
 26        #region Method
 27        public static void AddForm(string formName)
 28        {
 29            forms.Add(formName, new Dictionary<stringstring>());
 30            //formMap.Add(formName, count++);
 31        }

 32
 33        /// <summary>
 34        /// 加载语言文件
 35        /// </summary>
 36        /// <param name="lang">语言</param>
 37        /// <returns></returns>

 38        public static bool Load(string lang)
 39        {
 40            string path = "";
 41            Localization.Lang = "English";
 42
 43            menu.Clear();
 44            toolbar.Clear();
 45            dialog.Clear();
 46            exception.Clear();
 47            foreach (Dictionary<stringstring> form in forms.Values)
 48                form.Clear();
 49            
 50            switch (lang)
 51            {
 52                case "zh":                   
 53                    path = @"resources/lang-zh.xml";
 54                    break;
 55                case "en":                  
 56                    path = @"resources/lang-en.xml";
 57                    break;
 58                default:                    
 59                    path = @"resources/lang-zh.xml";
 60                    break;
 61            }

 62
 63            return readLanguage(path);
 64        }

 65        #endregion
 //Method
 66
 67        #region Function
 68        private static bool readLanguage(string path)
 69        {
 70            // Read the language file
 71            XmlReader reader;
 72            try
 73            {
 74                reader = XmlReader.Create(path);
 75            }

 76            catch (Exception)
 77            {
 78                return false;
 79            }

 80
 81            // Begin to parase
 82            try
 83            {
 84                reader.ReadToFollowing("AirControl");
 85                Localization.Lang = reader.GetAttribute("language");
 86
 87                paraseXml(reader, "Menu", menu);
 88                paraseXml(reader, "Toolbar", toolbar);
 89  
 90                foreach (string formName in forms.Keys)
 91                {
 92                    paraseXml(reader, formName, forms[formName]);
 93                }

 94                paraseXml(reader, "Dialog", dialog);               
 95            }

 96            catch (Exception)
 97            {
 98                return false;
 99            }

100            return true;
101        }

102
103        private static void paraseXml(XmlReader reader, string item, Dictionary<stringstring> obj)
104        {
105            // Get the attribute key & value 
106            reader.ReadToFollowing(item);
107
108            XmlReader subreader = reader.ReadSubtree();
109            while (subreader.Read())
110            {
111                if (subreader.NodeType == XmlNodeType.Element && subreader.Name == "Item")
112                    obj.Add(subreader.GetAttribute("key"), subreader.GetAttribute("value"));
113            }

114        }

115        #endregion
 //Function
116
117        #region Property
118        public static Dictionary<stringstring> Menu
119        {
120            get
121            {
122                return menu;
123            }

124            private set
125            { }
126        }

127
128        public static Dictionary<stringstring> Toolbar
129        {
130            get
131            {
132                return toolbar;
133            }

134            private set
135            { }
136        }

137
138        public static Dictionary<string, Dictionary<stringstring>> Forms
139        {
140            get
141            {
142                return forms;
143            }

144            private set
145            { }
146        }

147 
148        public static Dictionary<stringstring> Dialog
149        {
150            get
151            {
152                return dialog;
153            }

154            private set
155            { }
156        }

157        #endregion
 //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 < string string >  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类做成静态类,在运行时就相当于一个常量,没有构造函数这样的开销,整个界面也可以再运行时
直接改变界面语言。
       当然这种方法不一定是最好的, 如果有更好的方法欢迎指点。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值