在Windows应用程序中,实现多语言的需求基本上就是设计资源文件的过程,主要涉及到以下几种资源的处理:
1)窗体及其控件资源,包括窗体标题、控件文本、控件布局等;
2)各种图片资源中,涉及到有文本显示的图片;
3)运行过程、用户交互过程中的提示信息等;
下面以中英文两种语言设计为例,简单介绍下整个过程:
一、首先确定默认的语言种类。
VS.Net2005中,资源文件是以resx为扩展名的。其中:仅以resx为扩展名的是默认的本地化资源,而有语言后缀的为
特定种类的资源文件。比如:
*.resx -- 表示默认的(Default)本地化资源文件;
*.en.resx -- 表示英语资源文件;
*.zh-CN.resx -- 表示简体中文资源文件;
.Net中的本地化功能按顺序会首先加载默认的资源文件,然后再根据当前线程对应的语言加载特定语种的资源文件。可以将默认资源文件中包含的是公共部分资源,而特定语言的资源文件中包含的是个性化的资源。这里,我们将中文作为默认资源进行设计。确定默认语言不需要做任何操作,只是表示在默认的资源中包含的就是我们中文设计的内容。
二、窗体资源设计
1、首先设计中文格式的窗体,包括控件布局设计依据窗体代码等,待功能基本完成后即可开始多语言的设计工作。
2、在解决方案资源管理器中,双击该窗体(如:Form1)的资源文件Form1.resx,可以看到里面基本上没有定义任何资源信息。这时,切换到窗体设计器上选择该窗体,将其Localizable属性设置为true,这时,再打开Form1.resx,会发现其中多了很多资源定义,包括窗体、控件的一些可本地化属性。
3、修改窗体的Language属性,将(Default)改为英语,这时,窗体设计器的后面会显示[英语],表示当前你设计的是英语状态下的表单,剩下的工作仅需要将原有中文的地方修改为英文,并重新根据变化后的文字长度调整布局。这时,你会发现在解决方案资源管理器中,Form1下面多了个Form1.en.resx的文件,这正是与英文配套的资源。今后需要修改哪种语言中的资源时,仅需要按本步骤重新选取窗体的语言种类就能可视化的进行调整,当然你也可以直接修改对应语种的resx文件中具体的资源项。
三、Resources.resx文件的设计
1、找到项目Properties目录下的Resources.resx文件,并改名为Resources.en.resx。
2、窗体上用到的图片、图标资源等,系统默认存放在Resources.resx中。若某些图片上包含了文字,则需要重新做一个英文语种的图片。然后将这套英文的图片放到项目的Resources目录下新建的en目录中,双击Resources.en.resx。在资源管理界面中,将需要替换的资源移除,再加入对应的,并保证前后的资源名一致。所有图片替换完成后保存即可。
3、资源管理界面上切换至字符串类型,根据需要将那些过程信息内容定义一个名称并分配资源值。如某个MessageBox.Show()中的字符串为“网络已断开”,我们可以将其在Resources.resx中定义一个资源,名为Messgae_ShowNetworkDisconnected,值设为“网络已断开”;同时,在Resources.en.resx中定义同样的资源变量,只不过值设置为英文信息“Network is Disconnected”。如下图:
代码则如下方式修改:
view plaincopy to clipboardprint?
...
private void Show()
{
if(linked)
MessageBox.Show("网络已断开");
...
}
修改后代码:
private void Show()
{
if(linked)
MessageBox.Show(Resources.Messgae_ShowNetworkDisconnected);
...
}
4、最后完成语言切换的代码。
假定语言的切换需要通过菜单触发,或其他控件去处理,具体实现自己考虑,这里不多讲,只需要认为某处有个Language的变量即可,切换语言也就是改变这个变量的值。
剩下来的工作,先定义一个属性CurrentCulture来获取上述的Language变量值以获取本地语言设置,具体怎么取假设由GetOptions()的方法实现,我放到自定义的CommonUtils类中。另外,创建一个ReloadSystemConfig() 的方法用于加载配置后将Resources.resx对应的语言设置为CurrentCulture即可。
view plaincopy to clipboardprint?
public class CommonUtils
{
...
/// <summary>
/// 根据系统设置获取当前的语言类型
/// </summary>
public static System.Globalization.CultureInfo CurrentCulture
{
get
{
if (generationOptions == null || currentOptions.Language == "")
{
return new System.Globalization.CultureInfo("zh-CN");
}
else
{
return new System.Globalization.CultureInfo(currentOptions.Language);
}
}
}
/// <summary>
/// 重新加载系统配置信息
/// </summary>
public static void ReloadSystemConfig()
{
//获取当前的设置项
currentOptions = GetOptions();
//设定语言类别
Resources.Culture = CurrentCulture;
...
}
...
}
除此之外,要改变Form中资源则需要在各Form的构造函数代码或FormLoad事件中增加System.Threading.Thread.CurrentThread.CurrentUICulture = CommonUtil.CurrentCulture,并重新为窗体所有控件ApplyResouces()即可,建议创建一个Form的基类,如BaseForm,在其中增加这部分代码,这样继承自它的子窗体就不用再做任何处理了。
view plaincopy to clipboardprint?
public class BaseForm
{
public BaseForm()
{
...
//获取语言
System.Threading.Thread.CurrentThread.CurrentUICulture = CommonUtil.CurrentCulture;
//重新加载资源
this.ApplyResource();
}
/// <summary>
/// 应用资源
/// ApplyResources 的第一个参数为要设置的控件
/// 第二个参数为在资源文件中的ID,默认为控件的名称
/// </summary>
private void ApplyResource()
{
foreach (Control ctl in Controls)
{
currentFormResManager.ApplyResources(ctl, ctl.Name);
}
currentFormResManager.ApplyResources(this, "$this");
}
...
}
public class FormConfig: BaseForm
{
...
}
OK,整个工作就算完成了。
几点需要注意的:
1、待系统功能基本完善后再开始多语言的工作,否则当你频繁的调整某项功能时,经常需要切换不同的语言同步变
化该窗体的资源。
2、可新建一个TextResources.resx来存放与文本信息有关的资源,不一定只能使用系统创建的Resources.resx文件
,当然在语言切换时,别忘记同时也需要将TextResources管理器的语言进行设置。
3、窗体资源设计时,若该窗体由父类窗体继承的,可能切换某种语言设计后再切回(Default)时,某些属性会丢失。
我遇到的情况是父类窗体设置的BackgroundImage丢失了,查看该窗体的*.Designer.cs文件时,发现系统自动生成了
一行this.BackgroundImage = null; 手工去掉即可。
参考文章:
http://blog.csdn.net/lihongzhai/archive/2006/11/19/1396287.aspx
http://www.microsoft.com/china/MSDN/library/netFramework/netframework/issuesBasicInstincts.mspx?
mfr=true