私は最近、クライアントが外国で、ホストコンピュータプログラムが中国で開発されているプロジェクトに遭遇しました。中国語と英語の多言語切り替えをサポートする必要があります。
多言語切り替えのアイデア:
異なる言語をマップするには、異なる XML 構成ファイルを使用します。フォームが読み込まれると、構成はデフォルト言語 DefaultLanguage.xml から読み取られます。たとえば、中国語は Chinese.xml に対応し、英語は English.xml に対応し
ます
。たとえば、ボタン コントロール btnLogin、ウィンドウ本体内の特定のコントロールの変数名は完全に一意です。
キーと値のペアの辞書を通じて処理できます。キー名はコントロールの変数名であり、値はコントロールのテキスト コンテンツです。
中国語の場合は、 Chinese.xml で Name="btnLogin" を設定します。 Text="Login"
英語の場合は、English.xml で Name="btnLogin" Text="Login" を設定します。
複数の言語を切り替える例として、ログイン フォーム FormLogin とメイン フォーム FormMain を取り上げます。
新しい Windows フォーム アプリケーション MultiLanguageDemo を作成し、デフォルトの Form1 を FormLogin に変更します。
最初のステップ、言語設定ファイル
プロジェクト MultiLanguageDemo に新しいフォルダー Language を作成し、Language フォルダーの下に 3 つの新しい 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>
2 番目のステップ、主要な補助クラス 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);
}
}
}
3 番目のステップは、ログイン フォーム 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);
}
}
}
4 番目のステップでは、プログラムは図に示すように多言語切り替えを実行します。