轉載請註明原文網址:
http://www.cnblogs.com/xianyunhe/archive/2011/09/02/2163842.html
目前很多軟件都是要出口到多個國家,因此,爲軟件提供多國語言支持就成爲了一個基本條件。爲軟件提供多國語言的支持的具體實現方法有很多,但基本原理都差不多,就是實現代碼和語言包的獨立,代碼根據設定的語言選擇語言包。
其中,MFC的資源文件就提供了對多國不同語言的支持功能,如果使用MFC開發,直接用資源文件自帶的多國語言支持,可以省去不少的麻煩。
下面就介紹給MFC程序添加中英文的支持,開發環境爲VS2010。
1. 新建工程
新建了一個對話框工程,工程名稱爲MultiLanguages,默認語言選擇是“中文”。
2. 添加多國語言的資源
在創建工程後,工程會添加默認的資源,如主對話框,都是“中文”資源。現在我們需要添加相應的英文的資源文件。
爲主窗口IDD_MULTILANGUAGES添加英文資源的方法爲:
(1) 打開Resource View窗口。
(2) 右鍵IDD_MULTILANGUAGES,點擊彈出菜單中的“Insert Copy”菜單,如下圖所示。
(3) 彈出窗口資源複製語言選擇窗口,選擇語言爲“英語(美國)”,如下圖所示。
(4) 點擊OK,即完成英文版對話框的添加。完成添加後,IDD_MULTILANGUAGES就對應於兩個不同語言版本的對話框了,如下圖所示。
使用同樣的方法,也可以爲其他資源添加多國語言版本的支持。主要需要多國版本需要支持的有對話框、菜單和字符串。
添加多國語言的資源後,要對這些資源進行不同語言的定製,根據資源對應的語言,設置對話框和控件的標題等。
3. Locale
程序的語言選擇跟操作系統語言(System Locale)、用戶設置語言(User Locale)和線程語言(Thread Locale)有關。程序運行時,是根據線程語言來選擇資源的。如果程序中未對線程語言進行設置,線程語言默認採用用戶設置語言。設置線程語言的函數是SetThreadLocale。
設置線程語言爲“中文”的代碼如下:
SetThreadLocale(MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT));
設置線程語言爲“英語(美國)”的代碼如下:
SetThreadLocale(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT));
設置線程語言要在對話框創建之前,否則無法更改對話框的資源。可以在CMultiLanguagesApp::InitInstance函數中的對話框初始化之前添加線程語言設置,分別設置爲中文和英文語言,就可以查看到對話框界面的不同。
4. 字符串處理
程序的多國語言的支持,不僅包括界面的多國語言支持,也要包括各類字符串的多國語言支持,如彈出的提示信息。因此,在彈出提示信息時,也要爲提示信息創建多個語言版本,並根據當前線程的語言來選擇不同的提示信息。
例子:實現不同語言版本中按鈕的點擊次數的統計。
(1) 在String Table中分別添加中英文的IDS_STRING_SAMPLE資源,內容如下表所示。
中文 |
這個一箇中文提示信息。\n點擊次數:%d。 |
英文 |
This is a prompt message in English.\nClick Times:%d. |
(2) 在主窗口控件中添加一個控件Button1,控件的中文名爲“提示”,英文名稱爲“Prompt”。爲該控件添加一個左鍵單擊消息響應函數,該函數的內容如下:
void CMultiLanguagesDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
static int s_iClickTime = 0;
s_iClickTime++;
CString strPrompt = _T("");
CString strFormat = _T("");
strFormat.LoadString(IDS_STRING_SAMPLE);
strPrompt.Format(strFormat, s_iClickTime);
AfxMessageBox(strPrompt);
}
(3) 分別在CMultiLanguagesApp::InitInstance添加設置線程語言爲中文和英文的代碼,然後多次點擊按鈕進行測試。
中文版本彈出的提示框如下圖所示:
英文版本彈出的提示框如下圖所示:
5. 語言切換
窗口在初始化時候就導入了資源文件,在通過SetThreadLocale更換了線程語言後,窗口的資源並不會更改,必須要通過代碼來重新裝載資源。因爲窗口中存在多種與線程語言相關的資源,重新啓動軟件一種叫快捷的更新語言環境的方法。
例:通過菜單來進行語言切換,切換語言後重啓軟件。
(1) 爲程序添加中英文菜單選項ID_LANGUAGE_SWITCH,併爲該菜單添加消息響應函數,其中,m_bRestartFlag使用判斷關閉窗口時是否需要重啓程序的標識。代碼如下。
void CMultiLanguagesDlg::OnLanguageSwitch()
{
// TODO: Add your command handler code here
// 讀取當前線程的語言,並根據當前線程語言進行語言切換
LCID lcidNew = GetThreadLocale();
if (LANG_ENGLISH == PRIMARYLANGID(LANGIDFROMLCID(lcidNew)))
{
lcidNew = MAKELCID(MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED), SORT_DEFAULT);
}
else
{
lcidNew = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT);
}
// 把語言設置寫入配置文件
CFile file;
file.Open(_T("Language.ini"), CFile::modeWrite | CFile::modeCreate | CFile::typeBinary);
file.Write(&lcidNew, sizeof(lcidNew));
file.Close();
// 關閉窗口
m_bRestartFlag = TRUE;
PostMessage(WM_CLOSE, 0, 0);
}
(2) 在關閉窗口時,重啓動該程序。即在窗口響應WM_CLOSE時,重啓程序。代碼如下:
void CMultiLanguagesDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
// 判斷是否需要重新啓動窗口
if (m_bRestartFlag)
{
CString strFileName = _T("");
GetModuleFileName(NULL, strFileName.GetBuffer(MAX_PATH), MAX_PATH);
ShellExecute(NULL, _T(""), strFileName, NULL, NULL, SW_SHOWNORMAL);
strFileName.ReleaseBuffer();
}
CDialogEx::OnClose();
}
(3) 在啓動軟件時,根據當前軟件的配置文件中語言來設置線程語言,即在CMultiLanguagesApp::InitInstance函數中創建對話框之前設置線程語言,代碼如下:
// 判斷你是否存在配置文件,如果存在,從配置文件中讀取語言設置
CString strFileName = _T("Language.ini");
if (PathFileExists(strFileName))
{
LCID lcidThread = 0;
CFile file;
file.Open(strFileName, CFile::modeRead | CFile::typeBinary);
file.Read(&lcidThread, sizeof(LCID));
file.Close();
SetThreadLocale(lcidThread);
}
(4) 通過點擊菜單來測試軟件的語言切換。
6. MessageBox的問題
由於MessageBox中的按鈕的語言是跟操作系統相關的,要想實現MessageBox按鈕的多語言化是很有一定難度的。我現在還沒有查到好的解決方法,很多網友的建議是拋棄MessageBox,自己建立對話框。
7. 源代碼
源代碼的下載鏈接如下:
http://files.cnblogs.com/xianyunhe/MultiLanguages.rar
8. 相關函數和類型
與本地化相關的函數和類型如下:
GetSystemDefaultLCID
GetSystemDefaultLocaleName
GetUserDefaultLCID
GetUserDefaultLocaleName
SetThreadLocale
GetThreadLocale
MAKELCID
MAKELANGID
LCIDToLocalName
LocalNameToLCID
LANGIDFROMLCID
PRIMARYLANGID
LCID
LANGID
LANG_CHINESE 0x04
LANG_ENGLISH 0x09