此隨筆中主要內容來自http://blog.csdn.net/china_hxx/article/details/10066655,原出處不詳。編程
如下內容基於VC 6.0。要實現界面多語言化,必需要先配置項目使其支持Unicode編碼,文章《VC下的Unicode編程》 對此有詳細介紹。框架
首先建立一個基於MFC的工程,在選擇語言時選擇 中文[簡體,中國]。函數
項目框架選擇對話框、單文檔和多文檔均可以,這裏就選個基於對話框的吧,而後當即修該項目屬性使其支持Unicode。工具
MFC已經爲咱們加入了一些資源,包括2個對話框、1個String Table等。爲了節省空間修改了對話框的大小。ui
如今項目中的資源狀況以下:this
而後再新建一個DLL項目,爲了方便管理能夠將其添加到當前工做空間中。編碼
當即修改此DLL項目使其支持Unicode,而後設置項目依賴性(Project->Dependencies…) ,資源DLL要在exe項目以前編譯:spa
爲了將生成的資源DLL自動拷貝到exe項目執行目錄下,還須要修改DLL項目的Post-build Step:操作系統
而後將主項目目錄下的res文件夾、resource.h、TestMultiLang.rc文件拷貝到ResENG項目目錄下,res文件夾和resource.h直接替換,將ResENG.rc刪除後再將TestMultiLang.rc重命名爲ResENG.rc。.net
切換到資源視圖就會發現這兩個項目的資源內容是同樣的了,將ResENG項目的資源更改成英文以下:
爲了讓程序在啓動的時候加載英文語言資源,須要在CTestMultiLangApp::InitInstance()函數中Dlg建立以前添加以下語句:
HINSTANCE hLanguageDll = AfxLoadLibrary(_T("ResENG")); if (hLanguageDll) AfxSetResourceHandle(hLanguageDll);
最後從新編譯TestMultiLang項目,運行就會發現對話框已是英文界面了 :)
以上程序僅爲示例,爲了能使程序自動選擇合適的語言,還須要作許多工做。好比要在程序中添加程序語言切換菜單或語言選擇下拉列表框,並將用戶喜愛保存在ini配置文件中,而後在程序啓動時自動讀取此ini文件加載相應的資源DLL;若是用戶未設置語言,則默認根據操做系統語言加載合適資源,若是不存在針對此語言的資源DLL,就使用最國際化的語言——英語。
在stdafx.h中作以下定義:
#define CHINESE 0 #define ENGLISH 1
在CTestMultiLangApp類中添加private變量 int m_Lang, 用來保存當前語言類型是CHINESE,仍是ENGLISH。
在CTestMultiLangApp類中添加public方法GetLang用於返回當前語言類型。
int CTestMultiLangApp::GetLang(void) { return m_Lang; }
根據配置加載相應資源的DLL包裝成一個函數以下:
void CTestMultiLangApp::LoadLanguage(void) { CString strDLL; HINSTANCE hLanguageDll, hLanguageNow; //保存自己的資源句柄 static HINSTANCE hOriginalHandle = ::AfxGetResourceHandle(); //讀取ini配置文件 CString strFileName = _T("Language.ini"); if (PathFileExists(strFileName)) { int lang = 0; CFile file; file.Open(strFileName, CFile::modeRead | CFile::typeBinary); file.Read(&lang, sizeof(lang)); file.Close(); m_Lang = lang; } //根據用戶喜愛來設置 if (m_Lang == ENGLISH)//英文 hLanguageDll = ::AfxLoadLibrary(_T("ResENG")); else if (m_Lang == CHINESE)//中文 hLanguageDll = hOriginalHandle; else { //用戶未指定,則根據系統選擇合適語言,默認爲英文 WORD wLangPID = PRIMARYLANGID(GetSystemDefaultLangID()); if (wLangPID == LANG_CHINESE) hLanguageDll = hOriginalHandle; else if (wLangPID == LANG_ENGLISH) hLanguageDll = ::AfxLoadLibrary(_T("ResENG")); else hLanguageDll = ::AfxLoadLibrary(_T("ResENG")); } //保存已加載的資源DLL句柄 hLanguageNow = ::AfxGetResourceHandle(); //加載新的資源DLL if(hLanguageDll) ::AfxSetResourceHandle(hLanguageDll); //釋放以前加載的資源DLL if (hLanguageNow != hOriginalHandle) FreeLibrary(hLanguageNow); }
由於在切換界面語言的過程當中須要頻繁地銷燬和建立對話框,因此咱們也把建立對話框的代碼包裝成一個函數:
void CTestMultiLangApp::OpenWindow(void) { CTestMultiLangDlg dlg; m_pMainWnd = &dlg; dlg.DoModal(); }
如今在InitInstance()函數裏簡單得調用一下這兩個函數就能夠了:
BOOL CTestMultiLangApp::InitInstance() { AfxEnableControlContainer(); #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif LoadLanguage(); if (!OpenWindow()) return FALSE; return FALSE; }
而後要實現用戶界面的語言選擇消息響應函數。該函數要將用戶的選擇保存到ini文件裏,銷燬當前窗口,而後再從新加載資源並建立新的窗口:
void CTestMultiLangDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知處理程序代碼 CTestMultiLangApp*pApp = (CTestMultiLangApp*)AfxGetApp(); int old_Lang = pApp->GetLang(); int new_Lang = 0; if(old_Lang == ENGLISH) new_Lang = CHINESE; else new_Lang = ENGLISH; CFile file; file.Open(_T("Language.ini"), CFile::modeWrite | CFile::modeCreate | CFile::typeBinary); file.Write(&new_Lang, sizeof(new_Lang)); file.Close(); //銷燬當前窗口 pApp->m_pMainWnd = NULL; this->DestroyWindow(); //建立新的窗口 pApp->LoadLanguage(); pApp->OpenWindow(); }
上面這段代碼中pApp->m_pMainWnd = NULL這一句是關鍵,它切斷了銷燬當前程序消息向上的路由,所以進程不會被銷燬,纔有了機會從新建立新的窗口。若是項目是基於單文檔/多文檔的程序的話,還要加一句pApp->m_pDocManager = NULL才能夠。
從新編譯項目,如今語言就能夠動態切換了。
若是項目不只要支持中英文這兩種語言,好比還須要支持德語,這裏介紹兩種方法來實現。
第一種方法顯而易見————新建一個資源DLL項目。理論上這是可行的,可是有個棘手的問題:若是須要支持的語言不少,那麼對程序資源的任何更改都須要同步更新到其餘全部資源項目!
第二種方法是借用工具,由一個資源DLL製做出其餘各語言版本的資源DLL。這個工具軟件會把資源DLL中的字符串、對話框、菜單項等資源提取出來並保存到一個po文件裏,以後使用poedit就能夠進行翻譯了。翻譯完成後再根據此po文件和原資源DLL生成新的資源DLL。
工具軟件截圖以下: