C#的Winform多语言实现(resx文件)
?使用resx文件實現Winform多語言切換,本博文提供的代碼可以實現簡體中文、繁體中文、英文的切換。如果需要增加其它語言的切換,只需要編寫相應的語言的resx文件即可。 并且,當修改了語言之后,會更新所有打開的窗口。先貼幾張圖展示一下效果。
程序下載:點擊打開鏈接
http://download.csdn.net/detail/softimite_zifeng/9731575
1. 簡體中文
2. 繁體中文
3. 英文
下面子豐介紹一下實現的過程:
1. 為每個窗口創建相應語言的resx文件。子豐以英文為例,右鍵->添加->新建項->資源文件,文件名為窗口名.en-US,如上面的兩個窗口,分別為LoginForm.en-US.resx和PasswordForm.en-US.resx。簡體中文為LoginForm.zh-CN.resx和PasswordForm.zh-CN.resx,繁體中文為LoginForm.zh-CHT.resx和PasswordForm.zh-CHT.resx。下面給出LoginForm.en-US.resx文件的截圖。
2. 在項目的Properties的Settings.settings中添加變量DefaultLanguage,用于保存當前設置的默認語言。當下次啟動程序時,會讀取該變量,從而將程序的語言設置為上次程序關閉時的語言。
3. 創建一個靜態類(MultiLanguage.cs)用于編寫與切換語言相關的變量和代碼。
(1)變量DefaultLanguage,用于保存當前默認語言
//當前默認語言
public static string DefaultLanguage = "zh-CN";
(2)函數SetDefaultLanguage修改當前默認語言
/// <summary>
/// 修改默認語言
/// </summary>
/// <param name="lang">待設置默認語言</param>
public static void SetDefaultLanguage(string lang)
{
? ? System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo(lang);
? ? DefaultLanguage = lang;
? ? Properties.Settings.Default.DefaultLanguage = lang;
? ? Properties.Settings.Default.Save();
}
(3)函數LoadLanguage用于加載語言或切換語言
/// <summary>
/// 加載語言
/// </summary>
/// <param name="form">加載語言的窗口</param>
/// <param name="formType">窗口的類型</param>
public static void LoadLanguage(Form form, Type formType)
{
? ? if (form != null)
? ? {
? ? ? ? System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(formType);
? ? ? ? resources.ApplyResources(form, "$this");
? ? ? ? Loading(form, resources);
? ? }
}
?
/// <summary>
/// 加載語言
/// </summary>
/// <param name="control">控件</param>
/// <param name="resources">語言資源</param>
private static void Loading(Control control, System.ComponentModel.ComponentResourceManager resources)
{
? ? if (control is MenuStrip)
? ? {
? ? ? ? //將資源與控件對應
? ? ? ? resources.ApplyResources(control, control.Name);
? ? ? ? MenuStrip ms = (MenuStrip)control;
? ? ? ? if (ms.Items.Count > 0)
? ? ? ? {
? ? ? ? ? ? foreach (ToolStripMenuItem c in ms.Items)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? //遍歷菜單
? ? ? ? ? ? ? ? Loading(c, resources);
? ? ? ? ? ? }
? ? ? ? }
? ? }
?
? ? foreach (Control c in control.Controls)
? ? {
? ? ? ? resources.ApplyResources(c, c.Name);
? ? ? ? Loading(c, resources);
? ? }
}
?
/// <summary>
/// 遍歷菜單
/// </summary>
/// <param name="item">菜單項</param>
/// <param name="resources">語言資源</param>
private static void Loading(ToolStripMenuItem item, System.ComponentModel.ComponentResourceManager resources)
{
? ? if (item is ToolStripMenuItem)
? ? {
? ? ? ? resources.ApplyResources(item, item.Name);
? ? ? ? ToolStripMenuItem tsmi = (ToolStripMenuItem)item;
? ? ? ? if (tsmi.DropDownItems.Count > 0)
? ? ? ? {
? ? ? ? ? ? foreach (ToolStripMenuItem c in tsmi.DropDownItems)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? Loading(c, resources);
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
4. 在主窗口的Load事件中讀取Properties.Settings.Default.DefaultLanguage,并將ComboBox賦值為當前默認語言,即簡體中文、繁體中文或英文。
private void LoginForm_Load(object sender, EventArgs e)
{
? ? //設置combobox的值
? ? string language = Properties.Settings.Default.DefaultLanguage;
? ? if (language == "zh-CN")
? ? {
? ? ? ? languageTxt.Text = "簡體中文(默認)";
? ? }
? ? else if (language == "zh-CHT")
? ? {
? ? ? ? languageTxt.Text = "繁體中文";
? ? }
? ? else if (language == "en-US")
? ? {
? ? ? ? languageTxt.Text = "English";
? ? }
}
5. 在每個窗口的Load事件中調用函數MultiLanguage.LoadLanguage,使窗口在出現時即顯示為當前默認語言。
private void PasswordForm_Load(object sender, EventArgs e)
{
? ? //加載語言
? ? MultiLanguage.LoadLanguage(this, typeof(PasswordForm));
}
6. 編寫用于切換語言的ComboBox的SelectedIndexChanged事件,使得當用戶選擇對應的語言時,程序會切換到該語言。
//切換語言
private void languageTxt_SelectedIndexChanged(object sender, EventArgs e)
{
? ? languageTxt.Enabled = false;
? ? if (languageTxt.Text == "簡體中文(默認)")
? ? {
? ? ? ? //修改默認語言
? ? ? ? MultiLanguage.SetDefaultLanguage("zh-CN");
? ? ? ? //對所有打開的窗口重新加載語言
? ? ? ? foreach (Form form in Application.OpenForms)
? ? ? ? {
? ? ? ? ? ? LoadAll(form);
? ? ? ? }
? ? }
? ? else if (languageTxt.Text == "繁體中文")
? ? {
? ? ? ? //修改默認語言
? ? ? ? MultiLanguage.SetDefaultLanguage("zh-CHT");
? ? ? ? //對所有打開的窗口重新加載語言
? ? ? ? foreach (Form form in Application.OpenForms)
? ? ? ? {
? ? ? ? ? ? LoadAll(form);
? ? ? ? }
? ? }
? ? else if (languageTxt.Text == "English")
? ? {
? ? ? ? //修改默認語言
? ? ? ? MultiLanguage.SetDefaultLanguage("en-US");
? ? ? ? //對所有打開的窗口重新加載語言
? ? ? ? foreach (Form form in Application.OpenForms)
? ? ? ? {
? ? ? ? ? ? LoadAll(form);
? ? ? ? }
? ? }
? ? languageTxt.Enabled = true;
}
?
private void LoadAll(Form form)
{
? ? if (form.Name == "LoginForm")
? ? {
? ? ? ? MultiLanguage.LoadLanguage(form, typeof(LoginForm));
? ? }
? ? else if (form.Name == "PasswordForm")
? ? {
? ? ? ? MultiLanguage.LoadLanguage(form, typeof(PasswordForm));
? ? }
}
?
?
//***********
國際化就是要實現多語種的界面切換。首先,我們不可能用if else等語句來根據選擇的不同語種對所有的控件一個一個的設值,這樣太麻煩了。.Net提供了國際化相關的支持,主要放在System.Globalization命名空間下。下面是一個簡單的實現,麻雀雖小,五臟俱全。
這個程序是最近寫的一個程序,就在這基礎上進行改造,關鍵是弄懂原理。
1> 首先要加入Resource文件
在VS工程-->添加新項目里加入三個resource文件,Resource文件的作用就是存放我們的界面控件的顯示字符串。這里我們要實現3種語言的切換,所有加入了3個,分別命名為:Resource.en-US.resx,Resource.zh-CN.resx,Resource.ja-JP.resx。注意命名規則第一部分要相同,第二部分是不同語言的culture name,我定義的就是英語,中文,日文。
2> 在這3個文件中定義界面相關的字符串信息。
注意定義的名字在3個文件中要一致,否則找不到。
Resource.en-US.resx
tsmi_language_Name?Language
tsmi_japanese_Name?Japanese
tsmi_english_Name?English
tsmi_close_Name?Close
tsmi_chiniese_Name?Chinese
Resource.zh-CN.resx
tsmi_language_Name?語言
tsmi_chiniese_Name?中文
tsmi_english_Name?英文
tsmi_japanese_Name?日文
tsmi_close_Name?退出
Resource.ja-JP.resx
tsmi_language_Name?言語
tsmi_chiniese_Name?中國語
tsmi_english_Name?英語
tsmi_japanese_Name?日本語
tsmi_close_Name?閉じる
3> 利用ResourceManager類進行讀取。
ResourceManager會根據不同的cultrue來讀不同的resource文件,所以,實現的關鍵就是根據不同的語言來改變當前程序線程的cultrue就可以達到目地。而對于界面控件Text的賦值代碼將是不變的,當新增加一種語言是,也就是再加一個resource文件,對代碼的改動幾乎沒有影響。
基本代碼:
Resource的讀取類
[csharp]?view plaincopy
//***********************異常
今天在測試一個工程的時候,突然遇到了這樣一個問題:
?
錯誤信息:System.Resources.MissingManifestResourceException: 未能找到任何適合于指定的區域或非特定區域性的資源。請確保在編譯時已將“****.****.Resource.resources”正確嵌入或鏈接到程序集"****",或者確保所有需要的附屬程序集都可加載并已進行了完全簽名。
在網上搜索了N久都沒看到幾篇解決的文章,最后在不懈的努力下終于解決了,所以決定寫下解決方法方便以后遇到同樣問題的朋友:
其實這個錯誤的主要問題就是沒有找到需要的資源文件(該文件為Resources.resx),
引用該文件的地方就是
System.Resources.ResourceManager manager = new System.Resources.ResourceManager("×××.Resources", typeof(Resources).Assembly);
而導致錯誤的原因就是"×××.Resources"的配置錯誤
解決方法:首先查看工程中時候存在Resources.resx相關的文件,
找到它在工程中的位置(不如說一般都是在:工程名.Properties 命名空間下),
最后更改配置為new System.Resources.ResourceManager("工程名.Properties.Resources", typeof(Resources).Assembly);
續:
我這里在舉個詳細的例子,以便能夠更明白哈
首先,一個容器(不管是Form,或是Panel也好),如果與其配套一個資源文件(以后綴名為.resx),則這2個文件應是在同一個命名空間下,才能相互使用
舉個最特殊的例子
比如說一個工程名叫Test.Tname
其下有一個文件夾叫aaa(文件夾名字隨便,沒有關系)
文件夾aaa下有一個類文件叫Form1.cs,其命名空間為:Test.Tname(注意:命名空間才是重要的位置信息)
現在也有一個資源文件叫Form1.resx
(默認此資源文件是沒有問題的,但是在特別的情況下,此文件就不會再正確的位置,導致出現如題的異常信息,比如說我反編譯一個工程,自動生成的資源文件的位置就有問題)。
在Form1.cs中有句代碼是需要資源文件的
ResourceManager manager = new ResourceManager(typeof(Test.Tname.Form1));
這里就注意了,如果Form1.cs類文件與Form1.resx資源文件是分開的話,
那么Form1.resx資源文件應放在哪個地方,程序才能找到他呢?
首先我們看哈Form1.cs類文件的命名空間為Test.Tname。
而資源文件Form1.resx中并沒有命名空間的描述,所以只有靠位置來表示
再看下我們的工程名稱:Test.Tname很好,它跟Form1.cs類文件的命名空間相同
所以我們就把Form1.resx資源文件放在工程的根目錄下面
問題解決了,呵呵
其實我覺得最重要的問題就是類文件中可以有namespace來描述位置
而資源文件中并沒有這行代碼,只能靠真正的位置,這才是關鍵
總結
以上是生活随笔為你收集整理的C#的Winform多语言实现(resx文件)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《千只鹤》:面对爱,我们永远还行走在成长
- 下一篇: VUE.JS 组件化开发实践