划重点:在网上查了很多资料,一个很重要的点基本上没有人提出来,要使用.net4.0及以上啊。。。否则都是扯淡。
代码还是那个代码,.net4.0以下根本就不起作用。
1. 学习过程:修改窗口的localizable=true; Language=你要添加的语言。VS会帮我们自动添加一个对应的语言资源文件。
这时候修改窗体的text为繁体,打开Fom1.zh_TW.resx, 会发现里面有一条 名称和值的对应信息:$this.Text: 測試窗口。
查看构造函数:
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
resources.ApplyResources(this, "$this");
原先的this.Text='测试窗口',变成了resources.ApplyResources(this, "$this");
这个是一个很合理的逻辑,我在开始查资料,知道会形成多个资源文件的时候,就想应该是存在一种快速切换资源的做法。
网上的很多代码是这样的:
public Form_实验管理()
{
InitializeComponent();
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
ApplyResource(); //修改控件的语言显示
}
private void ApplyResource()
{
System.ComponentModel.ComponentResourceManager res = new ComponentResourceManager(typeof(Form_实验管理));
foreach (Control ctl in Controls)
{
res.ApplyResources(ctl, ctl.Name);
}
this.ResumeLayout(false);
this.PerformLayout();
res.ApplyResources(this, "$this");
}
这个我隐隐觉得不对劲,还需要自己每个窗口去写循环?但是因为一开始我用的.net2.0, 上面的方法不起作用,我以为是我没弄对,后来使用下面代码的时候也不起作用,我就觉得应该要使用更高版本的框架,改为.net4.0后,生效了。
两种方法都生效,但是上面这个代码明显比较繁琐。
反复强调:在网上看到使用高版本特性的方法说明时不带版本,或者不带引用,这点很讨厌,自己也要注意这点。
2. 实际使用:这个方法很简单,直接让.net自己去加载对应的语言资源文件就好了。
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("zh-TW");
这句话放在哪里呢,我需要整个程序都切换语言,通过配置文件一开始就设定好语言,不需要随时切换语言,所以我放在了登录窗口的load事件里面。
private void Login_Load(object sender, EventArgs e)
{
string lan = "";
if (MConfig.Language == "臺灣繁體")
{
lan = "zh-TW";
}
if (MConfig.Language == "UsEnglish")
{
lan = "en-US";
}
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(lan);
}
3. 翻译工作:一个程序有几十个窗口,几百几千个控件,如何快速的完成其他语言录入工作?
3.1 每一个窗口名称,控件名称都要有对应语言的翻译,然后要加入到资源文件。如果我们在可视化界面上一个个控件进行修改,要有个翻译坐在旁边,不断的翻译,然后我们录入,工作量庞大,效率低。
打开资源文件看了下。原始的resx是这样的
可以清楚的看到,排除带>>符号的,剩下的就是窗口和的控件Text,或者自定义的字段。
在界面上将英文的窗口text改为Test,查看en-Us.resx的内容,发现里面的内容是这样的。
从原始resx里面复制button1.Text到en-Us并修改值为按钮1button,运行结果显示成功。
3.2 于是将form1.resx的文件内容复制到excel,去除带>>的,发给翻译,让翻译对照软件窗口,将对应的值全部改成对应的语言,完成后我们从excel直接复制到对应的资源文件中,工作就完成了。
2018-9-10号补充:我的程序窗口巨多,工作量有点大。而且上面的方法不利于后续程序更改,控件有变化的话就需要重新发资源文件进行更新。
想了一个比较傻瓜化的方法,类似上面的资源文件,在窗口加载时从资源文件获取对应的语言。这里需要自定义基础Form控件,在load时间中加载其他语言,其他窗口全部继承此控件。
CSV文件,客户随时可以添加中文和其他语言的对照关系。客户在界面上看到某个不对的翻译时,随时可以对CSV文件进行更改或者添加。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace HSJ_p
{
public partial class MBaseForm : Form
{
public MBaseForm()
{
InitializeComponent();
}
/// <summary>
/// 加载的时候替换相应的语言
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MBaseForm_Load(object sender, EventArgs e)
{
if (HSJ_p.Data.SysParameterItem.LanguageResources == null || HSJ_p.Data.SysParameterItem.LanguageResources.Columns.Count == 0) return;
if (HSJ_p.Data.MConfig.Language != "简体中文")
{
GetLanguageText(this);
}
}
private void GetLanguageText<T>(T obj)
{
try
{
if (typeof(Form) == typeof(T).BaseType
|| typeof(Control) == typeof(T))
{
Control c = (Control)(object)obj;
DataRow[] drs = HSJ_p.Data.SysParameterItem.LanguageResources.Select(string.Format("简体中文='{0}'", c.Text), "");
if (drs.Length > 0)
{
c.Text = drs[0][HSJ_p.Data.MConfig.Language].ToString();
}
if (c.Controls.Count > 0)
{
foreach (Control c1 in c.Controls)
{
GetLanguageText(c1);
}
}
}
//注意有些控件不是control类型的
if (typeof(ToolStrip) == obj.GetType().BaseType
|| typeof(ToolStrip) == obj.GetType())
{
ToolStrip c = (ToolStrip)(object)obj;
DataRow[] drs = HSJ_p.Data.SysParameterItem.LanguageResources.Select(string.Format("简体中文='{0}'", c.Text), "");
if (drs.Length > 0)
{
c.Text = drs[0][HSJ_p.Data.MConfig.Language].ToString();
}
if (c.Items.Count > 0)
{
foreach (ToolStripItem c1 in c.Items)
{
GetLanguageText(c1);
}
}
}
if (typeof(MenuStrip) == obj.GetType().BaseType
|| typeof(MenuStrip) == obj.GetType())
{
MenuStrip c = (MenuStrip)(object)obj;
DataRow[] drs = HSJ_p.Data.SysParameterItem.LanguageResources.Select(string.Format("简体中文='{0}'", c.Text), "");
if (drs.Length > 0)
{
c.Text = drs[0][HSJ_p.Data.MConfig.Language].ToString();
}
if (c.Items.Count > 0)
{
foreach (ToolStripMenuItem c1 in c.Items)
{
GetLanguageText(c1);
}
}
}
if (typeof(ToolStripItem) == obj.GetType().BaseType
|| typeof(ToolStripItem) == obj.GetType())
{
ToolStripItem c = (ToolStripItem)(object)obj;
DataRow[] drs = HSJ_p.Data.SysParameterItem.LanguageResources.Select(string.Format("简体中文='{0}'", c.Text), "");
if (drs.Length > 0)
{
c.Text = drs[0][HSJ_p.Data.MConfig.Language].ToString();
}
}
if (typeof(ToolStripMenuItem) == obj.GetType().BaseType
|| typeof(ToolStripMenuItem) == obj.GetType())
{
ToolStripMenuItem c = (ToolStripMenuItem)(object)obj;
DataRow[] drs = HSJ_p.Data.SysParameterItem.LanguageResources.Select(string.Format("简体中文='{0}'", c.Text), "");
if (drs.Length > 0)
{
c.Text = drs[0][HSJ_p.Data.MConfig.Language].ToString();
}
if (c.DropDownItems.Count > 0)
{
foreach (ToolStripItem c1 in c.DropDownItems)
{
GetLanguageText(c1);
}
}
}
if (typeof(DataGridView) == obj.GetType().BaseType
|| typeof(DataGridView) == obj.GetType())
{
DataGridView c = (DataGridView)(object)obj;
foreach (DataGridViewColumn col in c.Columns )
{
DataRow[] drs = HSJ_p.Data.SysParameterItem.LanguageResources.Select(string.Format("简体中文='{0}'", col.HeaderText), "");
if (drs.Length > 0)
{
col.HeaderText = drs[0][HSJ_p.Data.MConfig.Language].ToString();
}
}
}
}
catch(Exception ex)
{
}
}
}