最近在做一個小程序,要求實現(xiàn)對多語言界面顯示支持功能,并且,界面顯示內(nèi)容用戶能夠自己設(shè)置。
初步設(shè)計用INI文件來配置顯示內(nèi)容,換一種語言的配置文件,就能夠更換整個系統(tǒng)的顯示語言??紤]到系統(tǒng)規(guī)模很小,周期又短,不想用太復(fù)雜的方案來解決這個問題,當(dāng)參考了很多網(wǎng)上類似的設(shè)計和代碼,發(fā)現(xiàn)都不是很滿意。
主要問題在于:絕大多數(shù)基于INI文件配置這種簡單應(yīng)有實現(xiàn)的代碼,都是針對組件ID固定加載,寫死了組件的ID號,比如: 以下是引用片段:
strCaption = fileManager.GetString(section,"IDC_Stc_ListStudent","");
SetDlgItemText(IDC_Stc_ListStudent,strCaption);
strCaption = fileManager.GetString(section,"IDC_Stc_AllContent","");
SetDlgItemText(IDC_Stc_AllContent,strCaption);
這樣:界面組件越多,加載代碼越長;每新增一個顯示窗口,又必須復(fù)制、粘貼類似的代碼,根據(jù)組件ID常量值來修改相關(guān)的加載項,很是不爽!
初步設(shè)想是:設(shè)計統(tǒng)一、通用的窗口組件Caption設(shè)置方法,對給定的Frame或Dialog等Window容器組件內(nèi)的所以組件進(jìn)行遍歷,當(dāng)增、減顯示組件不對語言包加載代碼產(chǎn)生影響,達(dá)到自適應(yīng)界面組件語言包加載效果。
這樣就產(chǎn)生一個新問題:語言包配置文件中的Caption值如何跟相關(guān)的組件正確地一一對應(yīng)?
好友文國慶建議:用XML文件來定義這種對應(yīng)關(guān)系。這個想法觸動了我:反正就是一個[Key,Value]的數(shù)據(jù),就用已經(jīng)實現(xiàn)的INI配置文件也可以啊。于是所有問題解決!
具體設(shè)計是:語言包配置文件就直接設(shè)置成組件ID與組件顯示信息的Hash表,Key = Value的形式,比如:BtnOK組件的ControlID為“1003”,中文顯示Caption為“登錄”,語言包配置內(nèi)容就是“1003=登錄”。
語言包的加載過程為2步實現(xiàn):
首先,從語言包配置文件中,讀取所有配置的ID、Caption條目到Vector或者Array中。
其次,在遍歷指定窗口中所有組件時,每發(fā)現(xiàn)一個組件,就用其ID在已經(jīng)加載的語言包數(shù)組中查找,找到就用配置的值修改組件Caption屬性;找不到,就認(rèn)為是不需要動態(tài)配置,不做處理。
配置文件實例:
配置項解釋:Section:[Login Dialog]:界面窗口;等號左邊:窗口中需要設(shè)置其Caption屬性的組件ID;等號左邊:窗口中需要設(shè)置其Caption屬性的組件Caption值;
[Login Dialog]
1001 = 用戶帳號
1002 = 用戶密碼
1017 = 登 錄
1018 = 退 出
語言包配置信息加載代碼:
以下是引用片段:
BOOL CLanguageManager::loadFromFile()
...{
BOOL bRead=FALSE;
int i;
ItemContext temp;
CStringArray itemBuf,valueBuf;
bRead = fileManager.GetSectionValues("Main Window",itemBuf,valueBuf);
if(bRead)
...{
for(i=0;i
...{
temp.uCtrlID = atoi(itemBuf.GetAt(i));
temp.strContext = valueBuf.GetAt(i);
m_vtContexts.push_back(temp);
}
}
itemBuf.RemoveAll();
valueBuf.RemoveAll();
bRead = fileManager.GetSectionValues("Login Dialog",itemBuf,valueBuf);
if(bRead)
...{
for(i=0;i
...{
temp.uCtrlID = atoi(itemBuf.GetAt(i));
temp.strContext = valueBuf.GetAt(i);
m_vtContexts.push_back(temp);
}
}
return bRead;
}
初步設(shè)計用INI文件來配置顯示內(nèi)容,換一種語言的配置文件,就能夠更換整個系統(tǒng)的顯示語言??紤]到系統(tǒng)規(guī)模很小,周期又短,不想用太復(fù)雜的方案來解決這個問題,當(dāng)參考了很多網(wǎng)上類似的設(shè)計和代碼,發(fā)現(xiàn)都不是很滿意。
主要問題在于:絕大多數(shù)基于INI文件配置這種簡單應(yīng)有實現(xiàn)的代碼,都是針對組件ID固定加載,寫死了組件的ID號,比如: 以下是引用片段:
strCaption = fileManager.GetString(section,"IDC_Stc_ListStudent","");
SetDlgItemText(IDC_Stc_ListStudent,strCaption);
strCaption = fileManager.GetString(section,"IDC_Stc_AllContent","");
SetDlgItemText(IDC_Stc_AllContent,strCaption);
這樣:界面組件越多,加載代碼越長;每新增一個顯示窗口,又必須復(fù)制、粘貼類似的代碼,根據(jù)組件ID常量值來修改相關(guān)的加載項,很是不爽!
初步設(shè)想是:設(shè)計統(tǒng)一、通用的窗口組件Caption設(shè)置方法,對給定的Frame或Dialog等Window容器組件內(nèi)的所以組件進(jìn)行遍歷,當(dāng)增、減顯示組件不對語言包加載代碼產(chǎn)生影響,達(dá)到自適應(yīng)界面組件語言包加載效果。
這樣就產(chǎn)生一個新問題:語言包配置文件中的Caption值如何跟相關(guān)的組件正確地一一對應(yīng)?
好友文國慶建議:用XML文件來定義這種對應(yīng)關(guān)系。這個想法觸動了我:反正就是一個[Key,Value]的數(shù)據(jù),就用已經(jīng)實現(xiàn)的INI配置文件也可以啊。于是所有問題解決!
具體設(shè)計是:語言包配置文件就直接設(shè)置成組件ID與組件顯示信息的Hash表,Key = Value的形式,比如:BtnOK組件的ControlID為“1003”,中文顯示Caption為“登錄”,語言包配置內(nèi)容就是“1003=登錄”。
語言包的加載過程為2步實現(xiàn):
首先,從語言包配置文件中,讀取所有配置的ID、Caption條目到Vector或者Array中。
其次,在遍歷指定窗口中所有組件時,每發(fā)現(xiàn)一個組件,就用其ID在已經(jīng)加載的語言包數(shù)組中查找,找到就用配置的值修改組件Caption屬性;找不到,就認(rèn)為是不需要動態(tài)配置,不做處理。
配置文件實例:
配置項解釋:Section:[Login Dialog]:界面窗口;等號左邊:窗口中需要設(shè)置其Caption屬性的組件ID;等號左邊:窗口中需要設(shè)置其Caption屬性的組件Caption值;
[Login Dialog]
1001 = 用戶帳號
1002 = 用戶密碼
1017 = 登 錄
1018 = 退 出
語言包配置信息加載代碼:
以下是引用片段:
BOOL CLanguageManager::loadFromFile()
...{
BOOL bRead=FALSE;
int i;
ItemContext temp;
CStringArray itemBuf,valueBuf;
bRead = fileManager.GetSectionValues("Main Window",itemBuf,valueBuf);
if(bRead)
...{
for(i=0;i
...{
temp.uCtrlID = atoi(itemBuf.GetAt(i));
temp.strContext = valueBuf.GetAt(i);
m_vtContexts.push_back(temp);
}
}
itemBuf.RemoveAll();
valueBuf.RemoveAll();
bRead = fileManager.GetSectionValues("Login Dialog",itemBuf,valueBuf);
if(bRead)
...{
for(i=0;i
...{
temp.uCtrlID = atoi(itemBuf.GetAt(i));
temp.strContext = valueBuf.GetAt(i);
m_vtContexts.push_back(temp);
}
}
return bRead;
}