因公司業(yè)務(wù)需要,需要將原有的ERP系統(tǒng)加上支持繁體語(yǔ)言,但不能改變?cè)械木幋a方式,即:普通程序員感受不到編碼有什么不同。經(jīng)過(guò)我與幾個(gè)同事的多番溝通,確定了以下兩種方案:
方案一:在窗體基類中每次加載并顯示窗體時(shí),會(huì)自動(dòng)遞歸遍歷含文本顯示的控件(Button,CheckBox,GroupBox,Label,LinkLabel,TextBox,StatusStrip,TabPage,ToolStrip,RadioButton,DateTimePicker,DataGridView,CheckedListBox,TreeView,MenuStrip),并根據(jù)不同的控件類型的文本屬性調(diào)用簡(jiǎn)繁轉(zhuǎn)換方法進(jìn)行轉(zhuǎn)換并重新設(shè)置新的相應(yīng)文本屬性的內(nèi)容(比如:繁體內(nèi)容)
優(yōu)點(diǎn):編碼簡(jiǎn)單,對(duì)普通程序員的編碼無(wú)影響(除窗體類的基類由Form類變成MyStyleFormBase類);
缺點(diǎn):因每次打開(kāi)窗體都需要遍歷控件并進(jìn)行簡(jiǎn)繁轉(zhuǎn)換,如果界面上的控件較多,則可能導(dǎo)致打開(kāi)窗體較慢,影響用戶體驗(yàn),且子控件的文本內(nèi)容改變時(shí)需程序員手動(dòng)通知,無(wú)法自動(dòng)感知并轉(zhuǎn)換。
具體實(shí)現(xiàn)思路如下:
一.對(duì)Form類進(jìn)行二次封裝(繼承),定義一個(gè)MyStyleFormBase類,并在里面加入每次加載并顯示窗體類型時(shí),會(huì)自動(dòng)遞歸遍歷含文本顯示的控件,并根據(jù)不同的控件類型的文本屬性調(diào)用簡(jiǎn)繁轉(zhuǎn)換方法進(jìn)行轉(zhuǎn)換并重新設(shè)置新的相應(yīng)文本屬性的內(nèi)容,這樣當(dāng)所有的窗體都繼承MyStyleFormBase類時(shí),均默認(rèn)就實(shí)現(xiàn)了遍歷與轉(zhuǎn)換的過(guò)程,程序員無(wú)需再次編碼,甚至都無(wú)需知道存在遍歷與轉(zhuǎn)換的過(guò)程,從而提高了代碼的復(fù)用性,具體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
public class MyStyleFormBase : Form { public MyStyleFormBase() { if (!Thread.CurrentThread.CurrentUICulture.Name.Equals( "zh-CHS" , StringComparison.OrdinalIgnoreCase)) //如果是簡(jiǎn)體,則無(wú)需轉(zhuǎn)換 { base .TextChanged += MyStyleFormBase_TextChanged; base .Shown += MyStyleFormBase_Shown; } } private void MyStyleFormBase_TextChanged( object sender, EventArgs e) { this .Text = LanguageHelper.GetLanguageText( this .Text); } private void MyStyleFormBase_Shown( object sender, EventArgs e) { LanguageHelper.SetControlLanguageText( this ); base .ControlAdded += MyStyleFormBase_ControlAdded; } private void MyStyleFormBase_ControlAdded( object sender, ControlEventArgs e) { LanguageHelper.SetControlLanguageText(e.Control); } /// <summary> /// 強(qiáng)制通知子控件改變消息 /// </summary> /// <param name="target"></param> protected virtual void PerformChildrenChange(Control target) { LanguageHelper.SetControlLanguageText(target); } /// <summary> /// 彈出消息框 /// </summary> /// <param name="text"></param> /// <param name="caption"></param> /// <param name="buttons"></param> /// <param name="icon"></param> /// <param name="defaultButton"></param> /// <returns></returns> protected DialogResult MessageBoxShow( string text, string caption, MessageBoxButtons buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.None, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) { return MessageBox.Show(LanguageHelper.GetLanguageText(text), LanguageHelper.GetLanguageText(caption), buttons, icon, defaultButton); } } |
代碼邏輯簡(jiǎn)要說(shuō)明:
1.當(dāng)當(dāng)前UI的文化區(qū)域不為中文簡(jiǎn)體時(shí)(因?yàn)楸境绦虮旧矶际腔诤?jiǎn)體開(kāi)發(fā)的),就訂閱窗體顯示事件Shown及窗體標(biāo)題改變事件TextChanged,作用:當(dāng)窗體顯示時(shí),則會(huì)遍歷控件并轉(zhuǎn)換為繁體,當(dāng)標(biāo)題的文本改變時(shí),也會(huì)自動(dòng)轉(zhuǎn)換為繁體;
2.當(dāng)窗體顯示后訂閱窗體的控件增加事件ControlAdded,作用:當(dāng)窗體顯示后,若后續(xù)存在代碼增加控件時(shí),會(huì)自動(dòng)將控件及其子控件進(jìn)行繁體的轉(zhuǎn)換,保證一個(gè)都不漏;
3.增加一個(gè)消息提示框方法,目的是彈出消息窗口前能夠?qū)⒑?jiǎn)體文本轉(zhuǎn)換成繁體文本;
4.增加一個(gè)強(qiáng)制通知子控件改變消息的方法PerformChildrenChange,當(dāng)某個(gè)控件的文本內(nèi)容或增加子控件發(fā)生時(shí),由于窗體本身無(wú)法捕獲到,故需要調(diào)用該方法來(lái)遍歷與轉(zhuǎn)換子控件的文本內(nèi)容;(感覺(jué)這里不太好,但目前沒(méi)有更好的辦法,如果大家有更好的辦法,歡迎留言評(píng)論)
二、LanguageHelper:語(yǔ)方轉(zhuǎn)換公共類(目前僅支持簡(jiǎn)繁轉(zhuǎn)換,依賴于:ChineseConverter.dll)代碼如下:
由于代碼過(guò)長(zhǎng),請(qǐng)點(diǎn)擊下載
該類邏輯很簡(jiǎn)單,就是從一個(gè)父控件開(kāi)始,遍歷所有的子控件,并根據(jù)不同的控件類型將控件相應(yīng)的文本內(nèi)容轉(zhuǎn)換成簡(jiǎn)體或繁體,調(diào)用方法:SetControlLanguageText
以上二步就實(shí)現(xiàn)了多語(yǔ)言的支持了(準(zhǔn)確的說(shuō)是簡(jiǎn)繁轉(zhuǎn)換),應(yīng)用到項(xiàng)目中很簡(jiǎn)單,只需將窗體默認(rèn)的基類Form改成:MyStyleFormBase即可,如:public partial class FormTest : MyStyleFormBase
方案二:由控件依據(jù)當(dāng)前區(qū)域信息+緩存語(yǔ)言字典直接實(shí)現(xiàn)各控件自行轉(zhuǎn)換
優(yōu)點(diǎn):無(wú)需遍歷,各控件自行根據(jù)區(qū)域信息自支轉(zhuǎn)換,因此效率較高,對(duì)普通程序員的編碼無(wú)影響(除窗體類的基類由Form類變成MyStyleFormBase類外,還需要使用支持多語(yǔ)言的控件,這些控件均由普通控件二次封裝得來(lái),保留原有的所有屬性及事件);
缺點(diǎn):需將所有帶文本顯示的控件(如:Button,CheckBox,GroupBox,Label,LinkLabel,TextBox,StatusStrip,TabPage,ToolStrip,RadioButton,DateTimePicker,DataGridView,CheckedListBox,TreeView)均進(jìn)行二次封裝,控件統(tǒng)一命名為:MyStyleXXX
涉及的控件較多,編碼相對(duì)復(fù)雜;
具體實(shí)現(xiàn)思路如下:
一.對(duì)Form類進(jìn)行二次封裝(繼承),定義一個(gè)MyStyleFormBase類,里面加入對(duì)窗體標(biāo)題進(jìn)行修改時(shí),能自動(dòng)進(jìn)行多語(yǔ)言轉(zhuǎn)換功能,具體代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
public partial class MyStyleFormBase : Form { public MyStyleFormBase() { base .TextChanged += MyStyleFormBase_TextChanged; } private void MyStyleFormBase_TextChanged( object sender, EventArgs e) { if (!Common.IsChsLanguage()) { this .Text = LanguageHelper.GetLanguageText( this .Text); } } /// <summary> /// 彈出消息框 /// </summary> /// <param name="text"></param> /// <param name="caption"></param> /// <param name="buttons"></param> /// <param name="icon"></param> /// <param name="defaultButton"></param> /// <returns></returns> protected DialogResult MessageBoxShow( string text, string caption = "提示" , MessageBoxButtons buttons = MessageBoxButtons.OK, MessageBoxIcon icon = MessageBoxIcon.None, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) { if (!Common.IsChsLanguage()) { text = LanguageHelper.GetLanguageText(text); caption = LanguageHelper.GetLanguageText(caption); } return MessageBox.Show(text, caption, buttons, icon, defaultButton); } } |
代碼邏輯很簡(jiǎn)單,就是訂閱一個(gè)Form.TextChanged事件,以便當(dāng)根據(jù)IsChsLanguage(判斷是否為簡(jiǎn)體模式)判斷不是簡(jiǎn)體時(shí),則需進(jìn)行Form.Text轉(zhuǎn)換
二.定義多語(yǔ)言支持普通控件及容器控件接口(IMultiLanguageControl、IMultiLanguageContainerControl),具體代碼如下:(此處僅是為了作一個(gè)規(guī)范,支持手動(dòng)設(shè)置轉(zhuǎn)換控件的文本內(nèi)容)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
/// <summary> /// 支持多語(yǔ)言普通控件(無(wú)子控件) /// </summary> public interface IMultiLanguageControl { string DefaultLangText { get ; } string CurrentLangText { get ; set ; } } /// <summary> /// 支持多語(yǔ)言容器控件(包含子控件) /// </summary> public interface IMultiLanguageContainerControl { Dictionary< object , string > DefaultLangTexts { get ; } Dictionary< object , string > CurrentLangTexts { get ; set ; } Control this [ string ctrlName] { get ; set ; } void SetItemCurrentLangText( string ctrlName, string langText); event EventHandler<ChildrenAddedEventArgs> ChildrenChanged; } public class ChildrenAddedEventArgs : EventArgs { public Dictionary< object , string > LangTexts { get ; private set ; } public ChildrenAddedEventArgs() { LangTexts = new Dictionary< object , string >(); } public ChildrenAddedEventArgs(Dictionary< object , string > langTexts) { this .LangTexts = langTexts; } public string this [ object key] { get { return LangTexts[key]; } set { LangTexts[key] = value; } }} |
三、實(shí)現(xiàn)支持多語(yǔ)言普通控件:基于原有標(biāo)準(zhǔn)控件(Button,CheckBox,GroupBox,Label,LinkLabel,TextBox,RadioButton,DateTimePicker)進(jìn)行二次封裝,實(shí)現(xiàn)IMultiLanguageControl接口,各控件代碼如下:
以下是MyStyleButton定義代碼,MyStyleCheckBox、MyStyleGroupBox、MyStyleLabel、MyStyleLinkLabel、MyStyleTextBox、MyStyleRadioButton里面的實(shí)現(xiàn)代碼均相同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
public partial class MyStyleButton : MyButton, IMultiLanguageControl { static Dictionary< string , string > LanDict = new Dictionary< string , string >(); public MyStyleButton() { } public override string Text { get { if (!DesignMode && System.Threading.Thread.CurrentThread.CurrentUICulture.Name != "zh-CHS" ) { if (LanDict.ContainsKey(DefaultLangText)) { return CurrentLangText; } else { string langText = LanguageHelper.GetLanguageText( base .Text); LanDict[ base .Text] = langText; return langText; } } return base .Text; } set { base .Text = value; } } [Browsable( false )] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string DefaultLangText { get { return base .Text; } } [Browsable( false )] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string CurrentLangText { get { try { return LanDict[DefaultLangText]; } catch (Exception) { return "" ; } } set { if (System.Threading.Thread.CurrentThread.CurrentUICulture.Name != "zh-CHS" ) { if (LanDict.ContainsKey(DefaultLangText)) { LanDict[DefaultLangText] = value; } else { LanDict.Add(DefaultLangText, value); } } } } } |
二次封裝這些控件的目的是:1.暴露統(tǒng)一的屬性,便于直接遍歷并賦值(需手動(dòng)改變文本內(nèi)容語(yǔ)言的情況);2.當(dāng)文本內(nèi)容發(fā)生改變時(shí),能夠根據(jù)語(yǔ)言緩存字典,快速直接的自我簡(jiǎn)繁轉(zhuǎn)換,無(wú)需再次遍歷;
四、實(shí)現(xiàn)支持多語(yǔ)言容器控件:基于原有標(biāo)準(zhǔn)控件(StatusStrip,TabPage,ToolStrip,DataGridView,CheckedListBox,TreeView)進(jìn)行二次封裝,實(shí)現(xiàn)IMultiLanguageContainerControl接口,各控件代碼如下:
MyStyleDataGridView:
由于代碼過(guò)長(zhǎng),請(qǐng)點(diǎn)擊下載
MyStyleTabControl:
由于代碼過(guò)長(zhǎng),請(qǐng)點(diǎn)擊下載
二次封裝這些控件的目的是:1.暴露統(tǒng)一的屬性,便于直接遍歷并賦值(僅當(dāng)直接改變文本內(nèi)容語(yǔ)言時(shí)需要);2.當(dāng)文本內(nèi)容或子控件文本內(nèi)容或新增子控件發(fā)生改變時(shí),能夠根據(jù)語(yǔ)言緩存字典,快速直接的自我簡(jiǎn)繁轉(zhuǎn)換,無(wú)需再次遍歷;
五.LanguageHelper:語(yǔ)方轉(zhuǎn)換公共類,與方案一原理相同,但相對(duì)方案一要簡(jiǎn)單很多,代碼如下:
由于代碼過(guò)長(zhǎng),請(qǐng)點(diǎn)擊下載
Common.IsChsLanguage方法定義如下:
1
2
3
4
5
6
7
|
public static bool IsChsLanguage() { return System.Threading.Thread.CurrentThread.CurrentUICulture.Name.Equals( "zh-CHS" , StringComparison.OrdinalIgnoreCase); } |
多語(yǔ)言支持的容器類控件的實(shí)現(xiàn)難點(diǎn)是:捕獲子控件文本內(nèi)容的改變,由于沒(méi)有現(xiàn)成的事件或方法,故需要通過(guò)其它的途徑來(lái)實(shí)現(xiàn)文本內(nèi)容改時(shí)能夠進(jìn)行處理。
以上就是本文的全部?jī)?nèi)容,有人可能會(huì)說(shuō),為何不采用資源文件的形式,原因文章一開(kāi)頭就說(shuō)明了,是在原有的系統(tǒng)上,且不能改變?cè)械木幋a風(fēng)格,故才花了這么大的力氣來(lái)實(shí)現(xiàn)這個(gè)簡(jiǎn)繁轉(zhuǎn)換的功能,我公司經(jīng)領(lǐng)導(dǎo)確認(rèn)最終采用的方案二。文中若有不足,歡迎交流,謝謝!
注:控件的實(shí)現(xiàn)代碼都貼出來(lái)了,大家若需要的話,可以直接COPY走,另外為了系統(tǒng)安全,簡(jiǎn)繁體的系統(tǒng)截圖我就不貼出來(lái)了,大家可以自行測(cè)試。
原文鏈接:http://www.cnblogs.com/zuowj/p/5878228.html