(原创) C# Winform界面的多语言处理方式(使用XML文件,支持菜单栏)

上个月遇到了一个项目,需要进行多语言处理,然而扒了很多多语言处理的帖子,基本上就是两种做法,第一种是使用vs自带的多语言处理方法,第二种是使用XML文档来实现多语言,我看了一下各有千秋。我只简单说下第一种方法,重点说明第二种方法,不想看第一种方法的可以跳过。

第一种 使用本地资源.resx文件方法

进入正题,首先我们创建一个界面,如下所示就可以:
在这里插入图片描述
接下来在 设计->Language下选择想要翻译的语言,这里以英语为例,
在这里插入图片描述
选择语言后,Localizable会自动变为true,当前页面会变为Form1.cs[设计 - 英语],然后将界面中文翻译为英文即可。
在这里插入图片描述
当我们切换完语言后,需要软件记住当前切换语言,下次打开时就不用切换语言了。在App.config中添加当前语言的类型,没有App.config文件的话,就自己添加一个应用程序配置文件,
在这里插入图片描述
接下来就是多语言处理方法了,创建一个多语言处理的帮助类,将多语言有关方法都写在这个类里面,方便调用。

	/// <summary>
    /// 多语言处理类
    /// </summary>
    public static class MultiLanguage
    {
        /// <summary>
        /// 设置多语言处理方法
        /// </summary>
        /// <param name="language"></param>
        /// <param name="form"></param>
        public static void SetLanguage(string language, Form form)
        {
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(language);
            if (form != null)
            {
                ComponentResourceManager resources = new ComponentResourceManager(form.GetType());
                resources.ApplyResources(form, "$this");
                AppLanguage(form, resources);
            }
        }
        /// <summary>
        /// 循环遍历控件设置多语言
        /// </summary>
        /// <param name="control"></param>
        /// <param name="resource"></param>
        private static void AppLanguage(Control control, ComponentResourceManager resource)
        {
            if (control is MenuStrip)   //对MenuStrip单独处理
            {
                resource.ApplyResources(control, control.Name);
                MenuStrip ms = (MenuStrip)control;
                if (ms.Items.Count > 0)
                {
                    foreach (ToolStripMenuItem item in ms.Items)
                    {
                        StripAppLanguage(item, resource);
                    }
                }
            }
            if (control is StatusStrip) //对StatusStrip单独处理
            {
                resource.ApplyResources(control, control.Name);
                StatusStrip ss = (StatusStrip)control;
                if (ss.Items.Count > 0)
                {
                    foreach (ToolStripItem item in ss.Items)
                    {
                        resource.ApplyResources(item, item.Name);
                    }
                }
            }
           //*********************
           //其他一些没有翻译的控件多语言处理方法
           //*********************
            foreach (Control c in control.Controls) //普通控件多语言处理
            {
                resource.ApplyResources(c, c.Name);
                AppLanguage(c, resource);
            }
        }
        /// <summary>
        /// 对MenuStrip菜单多语言进行单独处理
        /// </summary>
        /// <param name="item"></param>
        /// <param name="resource"></param>
        private static void StripAppLanguage(ToolStripMenuItem item, ComponentResourceManager resource)
        {
            if (item is ToolStripMenuItem)
            {
                resource.ApplyResources(item, item.Name);
                ToolStripMenuItem tsmi = item;
                if (tsmi.DropDownItems.Count > 0)
                {
                    foreach (ToolStripMenuItem c in tsmi.DropDownItems)
                    {
                        StripAppLanguage(c, resource);
                    }
                }
            }
        }
        /// <summary>
        /// 当前多语言选择
        /// </summary>
        public static EnumLanguage Language { get; set; }
    }
    public enum EnumLanguage
    {
        [Description("中文")]
        Chinese,
        [Description("英文")]
        English
    }
        

好了,接下来就可以添加界面加载事件和两个按钮多语言切换事件了

        private void Form1_Load(object sender, EventArgs e)
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            if (config.AppSettings.Settings["DefaultLanguage"].Value == EnumLanguage.Chinese.ToString())
            {
                MultiLanguage.Language = EnumLanguage.Chinese;
                MultiLanguage.SetLanguage("zh-CN", this);
            }
            else
            {
                MultiLanguage.Language = EnumLanguage.English;
                MultiLanguage.SetLanguage("en", this);
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            MultiLanguage.SetLanguage("zh-CN", this);
            MultiLanguage.Language = EnumLanguage.Chinese;
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            config.AppSettings.Settings["DefaultLanguage"].Value = MultiLanguage.Language.ToString();
            config.Save();
        }
        private void button2_Click(object sender, EventArgs e)
        {
            MultiLanguage.SetLanguage("en", this);
            MultiLanguage.Language = EnumLanguage.English;
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            config.AppSettings.Settings["DefaultLanguage"].Value = MultiLanguage.Language.ToString();
            config.Save();
        }

当当,多语言切换完成了,是不是很简单,当然这只是翻译了界面上的中文,代码中的中文可是不会被翻译的,不要忘了给代码中的中文添加多语言处理,判断逻辑也很简单,如下所示,

		if (MultiLanguage.Language == EnumLanguage.Chinese)
	       MessageBox.Show("正在导出数据, 请稍等......");
	    else
	       MessageBox.Showe("Exporting data, please wait......");

好了,这种方法是不是简单易学,但是,有些繁琐,如果界面少了还好,界面多了就会很麻烦,需要把所有界面都翻译一遍,如果再添加一种语言,所有界面还要再翻译一遍,工作量大到你怀疑人生有木有。所以这种方法适合单页面,或者页面比较少的项目,如果页面很多,语言种类也多,就非常不推荐使用这种方法了,我们需要考虑其他方法了,就是我下面要说的第二种方法。

第二种 使用XML文档方法

这种方法是采用XML文档来记录key-value的值,每一种语言对应一个XML文档,语言切换时只需根据key值来寻找对应的value,就可以实现多语言的切换了。
让我们进入正题,还是先创建一个项目,界面如下:
在这里插入图片描述
如方法1里面创建一个App.config文件记录当前多语言类型。然后创建一个Languages文件夹,用来单独存放多语言的xml文档,如下图所示,将界面上的中文部分全部放到xml文档中,name是控件的Name名称,标签中的中文是控件的Text内容。
在这里插入图片描述
英文部分我就不贴了,跟这个一样,只是把标签中的中文翻译成英文就行了,如果还要添加一种中文繁体语言,就再添加一个xml文档,把上面的简体中文翻译为繁体中文。
好了,翻译完了,我们现在要进行多语言处理了,创建一个MultiLanguage多语言处理类,代码有点长,我先说下思路,首先是读取对应语言的xml文档,将键值对读取出来,然后遍历界面所有控件,根据控件名称给控件Text赋值,这样就完成了多语言的切换,具体代码如下:

		private static Dictionary<string, string> DicLanguage = new Dictionary<string, string>();
		//读取对应语言的xml文档
        private static Dictionary<string, string> ReadXMLText(string frmName, string language)
        {
            try
            {
                Dictionary<string, string> DicLang = new Dictionary<string, string>();
                XmlDocument doc = new XmlDocument();
                string path = AppDomain.CurrentDomain.BaseDirectory + "Languages\\" + language + ".xml";
                if (File.Exists(path))
                    doc.Load(path);
                else
                    return null;
                XmlElement root = doc.DocumentElement;
                XmlNodeList nodeList = root.SelectNodes("Form[Name='" + frmName + "']/Controls/Control");
                foreach (XmlNode node in nodeList)
                {
                    DicLang.Add(node.Attributes["name"].Value, node.InnerText);
                }
                return DicLang;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        //设置界面的多语言
        public static void SetLanguage(Form form)
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            string languageType = config.AppSettings.Settings["Language"].Value;
            DicLanguage = ReadXMLText(form.Name, languageType);
            if (DicLanguage == null) return;
            form.Text = GetLanguage(form.Name);
            SetMenuLanguage(form);
            SetControlsLanguage(form.Controls);
        }
        //根据控件的名称来寻找控件的Text内容
        private static string GetLanguage(string name)
        {
            if (DicLanguage.ContainsKey(name))
                return DicLanguage[name];
            else
                return null;
        }
        //设置一些特殊控件的多语言
        private static void SetMenuLanguage(Form form)
        {
            FieldInfo[] fieldInfos = form.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
            for (int i = 0; i < fieldInfos.Length; i++)
            {
                switch (fieldInfos[i].FieldType.Name)
                {
                    case "MenuStrip":
                        {
                            MenuStrip menuStrip = (MenuStrip)fieldInfos[i].GetValue(form);
                            foreach (ToolStripMenuItem menuItem in menuStrip.Items)
                            {
                                GetSetMenuStripItems(menuItem);
                            }
                            break;
                        }
                    case "ContextMenuStrip":
                        {
                            ContextMenuStrip menuStrip = (ContextMenuStrip)fieldInfos[i].GetValue(form);
                            foreach (ToolStripMenuItem menuItem in menuStrip.Items)
                            {
                                GetSetMenuStripItems(menuItem);
                            }
                            break;
                        }
                    case "ToolStrip":
                        {
                            ToolStrip menuStrip = (ToolStrip)fieldInfos[i].GetValue(form);
                            foreach (ToolStripItem item in menuStrip.Items)
                            {
                                string text = GetLanguage(item.Name);
                                if (!string.IsNullOrEmpty(text)) item.Text = text;
                            }
                            break;
                        }
                    case "StatusStrip":
                        {
                            StatusStrip statusStrip = (StatusStrip)fieldInfos[i].GetValue(form);
                            foreach (ToolStripItem item in statusStrip.Items)
                            {
                                string text = GetLanguage(item.Name);
                                if (!string.IsNullOrEmpty(text)) item.Text = text;
                            }
                            break;
                        }
                }
            }
        }
        private static void GetSetMenuStripItems(ToolStripMenuItem menuItem)
        {
            string text = GetLanguage(menuItem.Name);
            if (!string.IsNullOrEmpty(text)) menuItem.Text = text;
            foreach (ToolStripMenuItem item in menuItem.DropDownItems)
            {
                text = GetLanguage(item.Name);
                if (!string.IsNullOrEmpty(text)) item.Text = text;
                if (item.DropDownItems != null) GetSetMenuStripItems(item);
            }
        }
        //设置普通控件的多语言
        private static void SetControlsLanguage(Control.ControlCollection controls)
        {
            foreach (Control item in controls)
            {
                string text = GetLanguage(item.Name);
                if (!string.IsNullOrEmpty(text)) item.Text = text;
                if (item.Controls.Count > 0)
                    SetControlsLanguage(item.Controls);
            }
        }        

设置完成后,就轮到添加界面加载事件和语言切换事件了,中文按钮是button1,英文按钮是button2,

		private void Form1_Load(object sender, EventArgs e)
        {
            MultiLanguage.SetLanguage(this);
        }
        private void button1_Click(object sender, EventArgs e)
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            config.AppSettings.Settings["Language"].Value = EnumLanaguage.Chinese.ToString();
            config.Save();
            MultiLanguage.SetLanguage(this);
        }
        private void button2_Click(object sender, EventArgs e)
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            config.AppSettings.Settings["Language"].Value = EnumLanaguage.English.ToString();
            config.Save();
            MultiLanguage.SetLanguage(this);
        }

做完这些就可以实现界面的多语言切换了,各位小伙伴学会了吗。可能有人要问了,代码中的某些字符串在加载时才显示到界面,有办法进行多语言处理吗?当然是有的,你可以像第一种方法里面那样处理,判断当前语言,如果是中文就显示中文,如果是英文就显示英文。那还有更简单的方法吗,当然也是有的,在Languages文件夹里面创建一个其他的xml文件,名字随意,我这里叫OtherLanguage.xml,在里面添加你代码中要进行多语言处理的字符串,如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<OtherLanguage>
  <Text name="Determine" ch-z="确定" en="Determine" />
  <Text name="Cancel" ch-z="取消" en="Cancel" />
</OtherLanguage>

name是key值,ch-z是简体中文,en是英语,在使用的时候调用key值,就能显示对应的多语言内容。调用方法如下:

        public static string GetOtherLanguage(string name)
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            string languageType = config.AppSettings.Settings["Language"].Value;
            string value = "";
            XmlDocument doc = new XmlDocument();
            string path = AppDomain.CurrentDomain.BaseDirectory + "Languages\\OtherLanguage.xml";
            if (File.Exists(path))
                doc.Load(path);
            else
                return null;
            XmlElement root = doc.DocumentElement;
            XmlNodeList nodeList = root.SelectNodes("/OtherLanguage/Text");
          	foreach (XmlNode node in nodeList)
            {
                if (node.Attributes["name"].Value == name)
                {
                    if(languageType == EnumLanaguage.Chinese.ToString())
                        value = node.Attributes["ch-z"].Value;
                    else
                        value = node.Attributes["en"].Value;
                }
            }
            return value;
        }

怎么使用那,很简单,调用该方法,输入OtherLanguage里面的key值也就是name的值,就能找出对应的语言内容,如下所示,取消按钮是button3:

	 	private void button3_Click(object sender, EventArgs e)
       	{
            if (button3.Text == MultiLanguage.GetOtherLanguage("Cancel"))
            {
                button3.Text = MultiLanguage.GetOtherLanguage("Determine");
            }
            else
            {
                button3.Text = MultiLanguage.GetOtherLanguage("Cancel");
            }
        }

好了,给大家看下最终的结果吧
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这种方法虽说有些复杂,可是对于多页面,多语言类型来说,相对于第一种方法,已经非常简单了,最多就是翻译比较麻烦。好了,文章就到这里了,希望能帮助到大家,如果有疑问和错误的地方,请私信指出,如果对你有帮助,请点赞支持一波,不胜感激。
源代码放到这里了,有需要的可以去看看

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值