c# 程式多語言切換嘗試
劃重點:在網上查了很多資料,一個很重要的點基本上沒有人提出來,要使用.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)
{
}
}
}