最近遇到一个项目,客户是国外的,开发上位机程序是在中国。需支持中英文多语言切换。
多语言切换思路:
使用不同的xml配置文件来映射不同的语言,窗体加载时从默认语言DefaultLanguage.xml中读取配置,比如中文语言 对应Chinese.xml
英文语言 对应English.xml
比如一个Button控件 btnLogin,因某个窗体的某一个控件的变量名是绝对唯一的
我们可以通过键值对字典来进行处理,键名都是控件的变量名称,值为控件的文本内容
中文语言在Chinese.xml 设置Name="btnLogin" Text="登录"
英文语言在English.xml 设置Name="btnLogin" Text="Login"
我们以登录窗体FormLogin和主窗体FormMain为例,来进行多语言切换显示。
新建windows窗体应用程序MultiLanguageDemo,将默认的Form1修改为FormLogin
第一步,Language配置文件
在项目MultiLanguageDemo上新建文件夹Language,在Language文件夹下新建三个xml配置文件Chinese.xml,DefaultLanguage.xml,English.xml并将其【复制到输出目录】设置为【始终复制】
①Chinese.xml文件内容
<?xml version="1.0" encoding="utf-8" ?>
<Root Language="Chinese">
<Form>
<FormName Name="MultiLanguageDemo.FormLogin" Text="登录"></FormName>
<Controls>
<Control Name="label1" Text="语言"/>
<Control Name="label2" Text="账号"/>
<Control Name="label3" Text="密码"/>
<Control Name="chkRememberUserName" Text="记住账号"/>
<Control Name="chkDisplayPassword" Text="显示密码"/>
<Control Name="btnLogin" Text="登录"/>
<Control Name="btnClose" Text="关闭"/>
</Controls>
</Form>
<Form>
<FormName Name="MultiLanguageDemo.FormMain" Text="主页"></FormName>
<Controls>
<Control Name="label1" Text="这是主界面"/>
<Control Name="groupBox1" Text="操作按钮"/>
<Control Name="btnRun" Text="运行"/>
<Control Name="btnStop" Text="停止"/>
</Controls>
</Form>
</Root>
②DefaultLanguage.xml文件内容
<?xml version="1.0" standalone="yes"?>
<Root Language="Default Language">
<DefaultLanguage>Chinese</DefaultLanguage>
</Root>
③English.xml文件内容
<?xml version="1.0" encoding="utf-8" ?>
<Root Language="English">
<Form>
<FormName Name="MultiLanguageDemo.FormLogin" Text="Login Page"></FormName>
<Controls>
<Control Name="label1" Text="Language"/>
<Control Name="label2" Text="UserName"/>
<Control Name="label3" Text="Password"/>
<Control Name="chkRememberUserName" Text="Remember User Name"/>
<Control Name="chkDisplayPassword" Text="Show Password"/>
<Control Name="btnLogin" Text="Login"/>
<Control Name="btnClose" Text="Close"/>
</Controls>
</Form>
<Form>
<FormName Name="MultiLanguageDemo.FormMain" Text="Main Page"></FormName>
<Controls>
<Control Name="label1" Text="This is the homepage"/>
<Control Name="groupBox1" Text="operating button"/>
<Control Name="btnRun" Text="Run"/>
<Control Name="btnStop" Text="Stop"/>
</Controls>
</Form>
</Root>
第二步,关键辅助类MultiLanguageUtil
用于读取默认语言并根据选择的语言设置窗体以及该窗体的所有控件的文本内容
MultiLanguageUtil.cs源程序如下
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml;
namespace MultiLanguageDemo
{
/// <summary>
/// 多语言切换辅助类:
/// 思路:使用不同的xml配置文件来映射不同的语言,窗体加载时从默认语言DefaultLanguage.xml中读取配置
/// 中文语言 对应Chinese.xml
/// 英文语言 对应English.xml
/// 比如一个Button控件 btnLogin,因控件的变量名是绝对唯一的
/// 我们可以通过键值对字典来进行处理,键名都是控件的变量名称,值为控件的文本内容
/// 中文语言在Chinese.xml 设置Name="btnLogin" Text="登录"
/// 英文语言在English.xml 设置Name="btnLogin" Text="Login"
/// </summary>
public class MultiLanguageUtil
{
/// <summary>
/// 获取默认语言,从 Language\DefaultLanguage.xml 配置文件中读取
/// </summary>
/// <returns></returns>
public static string GetDefaultLanguage()
{
string defaultLanguage = "English";
XmlReader reader = new XmlTextReader($"{AppDomain.CurrentDomain.BaseDirectory}Language\\DefaultLanguage.xml");
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNode root = doc.DocumentElement;
//默认语言节点
XmlNode node = root.SelectSingleNode("DefaultLanguage");
if (node != null)
{
defaultLanguage = node.InnerText;
}
reader.Close();
reader.Dispose();
return defaultLanguage;
}
/// <summary>
/// 设置默认语言
/// </summary>
/// <param name="defaultLanguage"></param>
public static void SetDefaultLanguage(string defaultLanguage)
{
DataSet ds = new DataSet();
ds.ReadXml($"{AppDomain.CurrentDomain.BaseDirectory}Language\\DefaultLanguage.xml");
DataTable dt = ds.Tables["Root"];
dt.Rows[0]["DefaultLanguage"] = defaultLanguage;
ds.AcceptChanges();
ds.WriteXml($"{AppDomain.CurrentDomain.BaseDirectory}Language\\DefaultLanguage.xml");
}
/// <summary>
/// 读取默认语言配置,将【key=控件名称,value=语言描述】添加到字典集合中
/// </summary>
/// <param name="formName"></param>
/// <param name="language"></param>
/// <returns></returns>
public static Dictionary<string, string> ReadXMLText(Form form, string language)
{
string formName = form.GetType().ToString();
try
{
Dictionary<string, string> dict = new Dictionary<string, string>();
//判断是否存在该语言的配置文件
if (!System.IO.File.Exists($"{AppDomain.CurrentDomain.BaseDirectory}Language\\{language}.xml"))
{
return dict;
}
XmlReader reader = new XmlTextReader($"{AppDomain.CurrentDomain.BaseDirectory}Language\\{language}.xml");
XmlDocument doc = new XmlDocument();
doc.Load(reader);
XmlNode root = doc.DocumentElement;
//获取XML文件中对应该窗口的内容
XmlNode nodeFind = root.SelectSingleNode($"Form/FormName[@Name='{formName}']");
if(nodeFind == null)
{
//如果没有配置该窗体的语言描述,就返回空
return dict;
}
//添加窗体到字典中
dict.Add(formName, nodeFind.SelectSingleNode("@Text").InnerText);
XmlNodeList nodeList = nodeFind.ParentNode.SelectNodes("Controls/Control");
foreach (XmlNode node in nodeList)
{
//修改内容为控件的Text值
XmlNode node1 = node.SelectSingleNode("@Name");
XmlNode node2 = node.SelectSingleNode("@Text");
if (node1 != null)
{
dict.Add(node1.InnerText, node2.InnerText);
}
}
reader.Close();
reader.Dispose();
return dict;
}
catch
{
return null;
}
}
/// <summary>
/// 设置窗体以及该窗体的所有控件的文本内容
/// </summary>
/// <param name="form">窗体</param>
/// <param name="dict">键值对字典,键为控件名称,值为控件文本</param>
public static void SetTextContentForAllControls(Form form, Dictionary<string, string> dict)
{
string formName = form.GetType().FullName;
if (dict.ContainsKey(formName))
{
//设置窗体的文本内容
form.Text = dict[formName];
}
//设置所有控件的文本内容:只考虑已配置的控件 并且 在字典中存在的控件名称
for (int i = 0; i < dict.Count; i++)
{
KeyValuePair<string, string> keyValuePair = dict.ElementAt(i);
Control[] controls = form.Controls.Find(keyValuePair.Key, true);
if (controls != null && controls.Length > 0)
{
controls[0].Text = keyValuePair.Value;
}
}
}
/// <summary>
/// 设置窗体以及该窗体的所有控件的文本内容
/// </summary>
/// <param name="form">窗体</param>
/// <param name="language">语言标识:中文Chinese,英文English</param>
public static void SetTextContentForAllControls(Form form, string language)
{
Dictionary<string, string> dict = ReadXMLText(form, language);
SetTextContentForAllControls(form, dict);
}
}
}
第三步,登录窗体FormLogin和主窗体FormMain设计以及加载指定语言的文本
①窗体FormLogin设计器 FormLogin.Designer.cs代码如下:
namespace MultiLanguageDemo
{
partial class FormLogin
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows 窗体设计器生成的代码
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.cboLanguage = new System.Windows.Forms.ComboBox();
this.label2 = new System.Windows.Forms.Label();
this.chkRememberUserName = new System.Windows.Forms.CheckBox();
this.btnLogin = new System.Windows.Forms.Button();
this.txtUserName = new System.Windows.Forms.TextBox();
this.label3 = new System.Windows.Forms.Label();
this.txtPassword = new System.Windows.Forms.TextBox();
this.chkDisplayPassword = new System.Windows.Forms.CheckBox();
this.btnClose = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(10, 16);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(29, 12);
this.label1.TabIndex = 0;
this.label1.Text = "语言";
//
// cboLanguage
//
this.cboLanguage.FormattingEnabled = true;
this.cboLanguage.Location = new System.Drawing.Point(77, 13);
this.cboLanguage.Name = "cboLanguage";
this.cboLanguage.Size = new System.Drawing.Size(283, 20);
this.cboLanguage.TabIndex = 1;
this.cboLanguage.SelectedIndexChanged += new System.EventHandler(this.cboLanguage_SelectedIndexChanged);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(10, 56);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(29, 12);
this.label2.TabIndex = 2;
this.label2.Text = "账号";
//
// chkRememberUserName
//
this.chkRememberUserName.AutoSize = true;
this.chkRememberUserName.Location = new System.Drawing.Point(366, 58);
this.chkRememberUserName.Name = "chkRememberUserName";
this.chkRememberUserName.Size = new System.Drawing.Size(72, 16);
this.chkRememberUserName.TabIndex = 3;
this.chkRememberUserName.Text = "记住账号";
this.chkRememberUserName.UseVisualStyleBackColor = true;
//
// btnLogin
//
this.btnLogin.Location = new System.Drawing.Point(207, 133);
this.btnLogin.Name = "btnLogin";
this.btnLogin.Size = new System.Drawing.Size(75, 23);
this.btnLogin.TabIndex = 4;
this.btnLogin.Text = "登录";
this.btnLogin.UseVisualStyleBackColor = true;
this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click);
//
// txtUserName
//
this.txtUserName.Location = new System.Drawing.Point(77, 53);
this.txtUserName.Name = "txtUserName";
this.txtUserName.Size = new System.Drawing.Size(283, 21);
this.txtUserName.TabIndex = 5;
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(10, 96);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(29, 12);
this.label3.TabIndex = 6;
this.label3.Text = "密码";
//
// txtPassword
//
this.txtPassword.Location = new System.Drawing.Point(77, 93);
this.txtPassword.Name = "txtPassword";
this.txtPassword.PasswordChar = '*';
this.txtPassword.Size = new System.Drawing.Size(283, 21);
this.txtPassword.TabIndex = 7;
//
// chkDisplayPassword
//
this.chkDisplayPassword.AutoSize = true;
this.chkDisplayPassword.Location = new System.Drawing.Point(366, 98);
this.chkDisplayPassword.Name = "chkDisplayPassword";
this.chkDisplayPassword.Size = new System.Drawing.Size(72, 16);
this.chkDisplayPassword.TabIndex = 8;
this.chkDisplayPassword.Text = "显示密码";
this.chkDisplayPassword.UseVisualStyleBackColor = true;
this.chkDisplayPassword.CheckedChanged += new System.EventHandler(this.chkDisplayPassword_CheckedChanged);
//
// btnClose
//
this.btnClose.Location = new System.Drawing.Point(308, 133);
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(75, 23);
this.btnClose.TabIndex = 9;
this.btnClose.Text = "关闭";
this.btnClose.UseVisualStyleBackColor = true;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// FormLogin
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(562, 194);
this.Controls.Add(this.btnClose);
this.Controls.Add(this.chkDisplayPassword);
this.Controls.Add(this.txtPassword);
this.Controls.Add(this.label3);
this.Controls.Add(this.txtUserName);
this.Controls.Add(this.btnLogin);
this.Controls.Add(this.chkRememberUserName);
this.Controls.Add(this.label2);
this.Controls.Add(this.cboLanguage);
this.Controls.Add(this.label1);
this.Name = "FormLogin";
this.Text = "多语言切换示例";
this.Load += new System.EventHandler(this.FormLogin_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox cboLanguage;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.CheckBox chkRememberUserName;
private System.Windows.Forms.Button btnLogin;
private System.Windows.Forms.TextBox txtUserName;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox txtPassword;
private System.Windows.Forms.CheckBox chkDisplayPassword;
private System.Windows.Forms.Button btnClose;
}
}
②窗体FormLogin.cs源程序如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MultiLanguageDemo
{
public partial class FormLogin : Form
{
public FormLogin()
{
InitializeComponent();
cboLanguage.Items.AddRange(new string[]
{
"中文",
"English"
});
cboLanguage.SelectedIndex = 0;
}
private void btnClose_Click(object sender, EventArgs e)
{
Application.Exit();
}
FormMain formMain;
private void btnLogin_Click(object sender, EventArgs e)
{
//设置默认语言
MultiLanguageUtil.SetDefaultLanguage(cboLanguage.SelectedIndex == 0 ? "Chinese" : "English");
if (formMain == null || formMain.IsDisposed)
{
formMain = new FormMain();
formMain.Show();
}
else
{
formMain.Activate();
}
}
private void chkDisplayPassword_CheckedChanged(object sender, EventArgs e)
{
if (chkDisplayPassword.Checked)
{
txtPassword.PasswordChar = '\0';
}
else
{
txtPassword.PasswordChar = '*';
}
}
private void FormLogin_Load(object sender, EventArgs e)
{
string language = MultiLanguageUtil.GetDefaultLanguage();
MultiLanguageUtil.SetTextContentForAllControls(this, language);
if (language == "Chinese")
{
cboLanguage.SelectedIndex = 0;
}
else if (language == "English")
{
cboLanguage.SelectedIndex = 1;
}
}
private void cboLanguage_SelectedIndexChanged(object sender, EventArgs e)
{
string language = string.Empty;
if (cboLanguage.SelectedIndex == 0)
{
language = "Chinese";
}
else if (cboLanguage.SelectedIndex == 1)
{
language = "English";
}
//过滤掉未选中语言
if (cboLanguage.SelectedIndex >= 0)
{
MultiLanguageUtil.SetTextContentForAllControls(this, language);
}
}
}
}
③窗体设计器FormMain.Designer.cs源程序如下
namespace MultiLanguageDemo
{
partial class FormMain
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.btnRun = new System.Windows.Forms.Button();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.btnStop = new System.Windows.Forms.Button();
this.groupBox1.SuspendLayout();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Font = new System.Drawing.Font("宋体", 20F);
this.label1.Location = new System.Drawing.Point(149, 52);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(147, 27);
this.label1.TabIndex = 0;
this.label1.Text = "这是主界面";
//
// btnRun
//
this.btnRun.Font = new System.Drawing.Font("宋体", 15F);
this.btnRun.Location = new System.Drawing.Point(117, 29);
this.btnRun.Name = "btnRun";
this.btnRun.Size = new System.Drawing.Size(75, 50);
this.btnRun.TabIndex = 1;
this.btnRun.Text = "运行";
this.btnRun.UseVisualStyleBackColor = true;
//
// groupBox1
//
this.groupBox1.Controls.Add(this.btnStop);
this.groupBox1.Controls.Add(this.btnRun);
this.groupBox1.Font = new System.Drawing.Font("宋体", 15F);
this.groupBox1.Location = new System.Drawing.Point(75, 152);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(339, 100);
this.groupBox1.TabIndex = 2;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "操作按钮";
//
// btnStop
//
this.btnStop.Font = new System.Drawing.Font("宋体", 15F);
this.btnStop.Location = new System.Drawing.Point(229, 29);
this.btnStop.Name = "btnStop";
this.btnStop.Size = new System.Drawing.Size(75, 50);
this.btnStop.TabIndex = 2;
this.btnStop.Text = "停止";
this.btnStop.UseVisualStyleBackColor = true;
//
// FormMain
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(653, 382);
this.Controls.Add(this.groupBox1);
this.Controls.Add(this.label1);
this.Name = "FormMain";
this.Text = "主界面";
this.Load += new System.EventHandler(this.FormMain_Load);
this.groupBox1.ResumeLayout(false);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button btnRun;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.Button btnStop;
}
}
④窗体FormMain.cs源程序如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MultiLanguageDemo
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
}
private void FormMain_Load(object sender, EventArgs e)
{
string language = MultiLanguageUtil.GetDefaultLanguage();
MultiLanguageUtil.SetTextContentForAllControls(this, language);
}
}
}
第四步,程序运行多语言切换如图: