此随笔中主要内容来自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。
工具软件截图以下: