MFC 多语言环境的实现
2016-04-20 21:12
302 查看
关于MFC多语言环境的实现,其本质其实只是下面的几句代码
它所实现的效果如下:
当然,对于复杂的项目,这么做是很坑爹的。问题两点:
1.翻译一种语言就要写一个case,如果有1000项要改,适配三种语言,就要写3000+行来改。
2.需要给翻译人员源代码,或者想办法暴露接口给他们,分工复杂,不符合现在程序设计的分块化理念。
那么,问题就来了,怎么做才能回避掉上面的问题呢?
答案是将上面的代码改成如下的形式(下面是伪代码):
在这种形式下,上面的两个问题就解决了:
1.每增加一种需要翻译的语言,只需制作一个相应的文件与之对应,且在代码里增加对应的文件读取接口即可。
2.该语言文件可以直接交给翻译人员制作。
那么,下面我们来真正的实现它。
按照上面伪代码的做法,我们可以自己写一个类来实现,但是那样比较麻烦。因此,我们借助这篇文章的帮忙,无视掉他繁琐乏味的文字,直接去下载他的工程,找到里面即犀利又有用的dll文件夹。打开文件夹,看到里面是一个动态链接库的三个文件,这就是我们要实现的这个类。把他配起来:
1.把三个文件拷贝到我们自己的工程目录下。
2.项目->属性->配置属性->链接器->输入->附加依赖项->LanguageLib.lib
3.解决方案资源管理器项目名称上面右键->添加->现有项->wxLocale.h
好了,我们只需要引用这个类就行了。为了有更好的兼容性,我们把这个类再封装一下,代码如下:
然后我们把这个类利用起来,声明一个它的实例m_languageobj,然后改写主代码如下:
完成,编译运行,找不到语言包,囧。。。。。。
我们需要做这个工程相应的语言包。用poedit,下载(我下载的是官网最新版本1.8.7),安装,然后
1.文件->新建->中文->确定->保存(放到工程主路径下面,就是放源文件.h和.cpp的那个路径下)
2.从源代码中提取->翻译属性->源代码字符集->gb2312(其他项默认也行,填下也行)
3.源路径->添加文件->选择刚刚放了很多_(“xxx”)的那个cpp文件
4.源关键字->额外的关键字->_ (这里是为了让poedit知道文件中的_(“”)所包含的内容就是需要翻译的内容,这么写了之后程序会自动查找这些内容)
OK,点确定,就出现下面的画面
左上方的列表就是待翻译的项,直接翻译如下
文件->编译为MO,这就完成了中文mo文件的制作了,英文的也类似,就不再赘述。
完成了中英文的mo制作,我们在工程主路径下建一个Languages的文件夹,把两个mo文件放进去(这里不是固定的,但是要跟工程相应的代码配合好),就完成了。运行工程,可以看到程序实现了开头演示的中英文效果。而且是基于mo语言包实现的。
本篇文章相关工程下载路径在这里(10分 & VS2015,如果不合适就照着文章做就行了)。
上面的内容是针对MFC”Unicode字符集”的,如果你的工程是”多字节字符集”或者其他,就应该不可以直接用,需要将输入字符转成wchar_t再输入到dll相关的函数中(也就是AddCatalog和wxGetTranslation这两个函数),然后将wxGetTranslation函数输出的wchar_t字符转成相应字符集能接受的字符。这个时候为了尽可能少改已有的代码,最好是将wxLocale.h的宏定义删掉,然后自己写个函数,重新定义一个宏,形式如下:
#define CHINESE 0 #define ENGLISH 1 void CMFCMultiLanguageDemoDlg::LanguageChange(int nLanguage) { CMenu* pSubMenu; CMenu* pMenu = GetMenu(); switch (nLanguage) { case CHINESE: //菜单字符修改 pMenu->ModifyMenu(0, MF_BYPOSITION, 0, L"文件(F)"); pSubMenu = pMenu->GetSubMenu(0); pSubMenu->ModifyMenu(ID_NEWFILE, MF_BYCOMMAND, ID_NEWFILE, L"新建(N)"); pMenu->ModifyMenu(1, MF_BYPOSITION, 0, L"编辑(E)"); pSubMenu = pMenu->GetSubMenu(1); pSubMenu->ModifyMenu(ID_EDIT, MF_BYCOMMAND, ID_EDIT, L"撤销(U)"); DrawMenuBar(); //按钮字符修改 GetDlgItem(IDC_BUTTON_CHINESE)->SetWindowTextW(L"中文"); GetDlgItem(IDC_BUTTON_ENGLISH)->SetWindowTextW(L"英文"); break; case ENGLISH: //菜单字符修改 pMenu->ModifyMenu(0, MF_BYPOSITION, 0, L"File(F)"); pSubMenu = pMenu->GetSubMenu(0); pSubMenu->ModifyMenu(ID_NEWFILE, MF_BYCOMMAND, ID_NEWFILE, L"New(N)"); pSubMenu = pMenu->GetSubMenu(0); pMenu->ModifyMenu(1, MF_BYPOSITION, 0, L"Edit(E)"); pSubMenu = pMenu->GetSubMenu(1); pSubMenu->ModifyMenu(ID_EDIT, MF_BYCOMMAND, ID_EDIT, L"Undo(U)"); DrawMenuBar(); //按钮字符修改 GetDlgItem(IDC_BUTTON_CHINESE)->SetWindowTextW(L"Chinese"); GetDlgItem(IDC_BUTTON_ENGLISH)->SetWindowTextW(L"English"); break; } } void CMFCMultiLanguageDemoDlg::OnBnClickedButtonChinese() { LanguageChange(CHINESE); } void CMFCMultiLanguageDemoDlg::OnBnClickedButtonEnglish() { LanguageChange(ENGLISH); }
它所实现的效果如下:
当然,对于复杂的项目,这么做是很坑爹的。问题两点:
1.翻译一种语言就要写一个case,如果有1000项要改,适配三种语言,就要写3000+行来改。
2.需要给翻译人员源代码,或者想办法暴露接口给他们,分工复杂,不符合现在程序设计的分块化理念。
那么,问题就来了,怎么做才能回避掉上面的问题呢?
答案是将上面的代码改成如下的形式(下面是伪代码):
#define CHINESE 0 #define ENGLISH 1 void CMFCMultiLanguageDemoDlg::LanguageChange(int nLanguage) { switch (nLanguage) { case CHINESE: mylanguage.SelectLanguage=loadlanguagefile("CHINESE.mo");//读取语言包文件 break; case ENGLISH: mylanguage.SelectLanguage=loadlanguagefile("ENGLISH.mo");//读取语言包文件 break; } //根据语言包翻译控件字符,Translation函数以中文字符为输入参数,返回翻译完的字符给控件 CMenu* pSubMenu; CMenu* pMenu = GetMenu(); //菜单字符修改 pMenu->ModifyMenu(0, MF_BYPOSITION, 0, mylanguage.Translation(L"文件(F)")); pSubMenu = pMenu->GetSubMenu(0); pSubMenu->ModifyMenu(ID_NEWFILE, MF_BYCOMMAND, ID_NEWFILE, mylanguage.Translation(L"新建(N)")); pMenu->ModifyMenu(1, MF_BYPOSITION, 0, mylanguage.Translation("编辑(E)")); pSubMenu = pMenu->GetSubMenu(1); pSubMenu->ModifyMenu(ID_EDIT, MF_BYCOMMAND, ID_EDIT, mylanguage.Translation(L"撤销(U)")); DrawMenuBar(); //按钮字符修改 GetDlgItem(IDC_BUTTON_CHINESE)->SetWindowTextW(mylanguage.Translation(L"中文")); GetDlgItem(IDC_BUTTON_ENGLISH)->SetWindowTextW(mylanguage.Translation(L"英文")); } void CMFCMultiLanguageDemoDlg::OnBnClickedButtonChinese() { LanguageChange(CHINESE); } void CMFCMultiLanguageDemoDlg::OnBnClickedButtonEnglish() { LanguageChange(ENGLISH); }
在这种形式下,上面的两个问题就解决了:
1.每增加一种需要翻译的语言,只需制作一个相应的文件与之对应,且在代码里增加对应的文件读取接口即可。
2.该语言文件可以直接交给翻译人员制作。
那么,下面我们来真正的实现它。
按照上面伪代码的做法,我们可以自己写一个类来实现,但是那样比较麻烦。因此,我们借助这篇文章的帮忙,无视掉他繁琐乏味的文字,直接去下载他的工程,找到里面即犀利又有用的dll文件夹。打开文件夹,看到里面是一个动态链接库的三个文件,这就是我们要实现的这个类。把他配起来:
1.把三个文件拷贝到我们自己的工程目录下。
2.项目->属性->配置属性->链接器->输入->附加依赖项->LanguageLib.lib
3.解决方案资源管理器项目名称上面右键->添加->现有项->wxLocale.h
好了,我们只需要引用这个类就行了。为了有更好的兼容性,我们把这个类再封装一下,代码如下:
class mylanguage { public: wxLocale* m_local; void init(int nLanguage) { if (m_local != NULL) m_local->Release(); m_local = CreateObject(nLanguage); if (m_local != NULL) { //选择语言包 bool bRet = false; switch (nLanguage) { case wxLocale::wxLANGUAGE_ENGLISH: bRet = m_local->AddCatalog(_T("Languages\\en.mo")); break; case wxLocale::wxLANGUAGE_CHINESE_SIMPLIFIED: bRet = m_local->AddCatalog(_T("Languages\\zhcn.mo")); break; } if (!bRet) { AfxMessageBox(_("Language package is not find!")); } } } };
然后我们把这个类利用起来,声明一个它的实例m_languageobj,然后改写主代码如下:
void CMFCMultiLanguageDemoDlg::LanguageChange(int nLanguage) { m_languageobj.init(nLanguage); CMenu* pSubMenu; CMenu* pMenu = GetMenu(); //菜单字符修改 pMenu->ModifyMenu(0, MF_BYPOSITION, 0, _("文件(F)")); pSubMenu = pMenu->GetSubMenu(0); pSubMenu->ModifyMenu(ID_NEWFILE, MF_BYCOMMAND, ID_NEWFILE, _("新建(N)")); pMenu->ModifyMenu(1, MF_BYPOSITION, 0, _("编辑(E)")); pSubMenu = pMenu->GetSubMenu(1); pSubMenu->ModifyMenu(ID_EDIT, MF_BYCOMMAND, ID_EDIT, _("撤销(U)")); DrawMenuBar(); //按钮字符修改 GetDlgItem(IDC_BUTTON_CHINESE)->SetWindowTextW(_("中文")); GetDlgItem(IDC_BUTTON_ENGLISH)->SetWindowTextW(_("英文")); } void CMFCMultiLanguageDemoDlg::OnBnClickedButtonChinese() { LanguageChange(wxLocale::wxLANGUAGE_CHINESE_SIMPLIFIED); } void CMFCMultiLanguageDemoDlg::OnBnClickedButtonEnglish() { LanguageChange(wxLocale::wxLANGUAGE_ENGLISH); }
完成,编译运行,找不到语言包,囧。。。。。。
我们需要做这个工程相应的语言包。用poedit,下载(我下载的是官网最新版本1.8.7),安装,然后
1.文件->新建->中文->确定->保存(放到工程主路径下面,就是放源文件.h和.cpp的那个路径下)
2.从源代码中提取->翻译属性->源代码字符集->gb2312(其他项默认也行,填下也行)
3.源路径->添加文件->选择刚刚放了很多_(“xxx”)的那个cpp文件
4.源关键字->额外的关键字->_ (这里是为了让poedit知道文件中的_(“”)所包含的内容就是需要翻译的内容,这么写了之后程序会自动查找这些内容)
OK,点确定,就出现下面的画面
左上方的列表就是待翻译的项,直接翻译如下
文件->编译为MO,这就完成了中文mo文件的制作了,英文的也类似,就不再赘述。
完成了中英文的mo制作,我们在工程主路径下建一个Languages的文件夹,把两个mo文件放进去(这里不是固定的,但是要跟工程相应的代码配合好),就完成了。运行工程,可以看到程序实现了开头演示的中英文效果。而且是基于mo语言包实现的。
本篇文章相关工程下载路径在这里(10分 & VS2015,如果不合适就照着文章做就行了)。
上面的内容是针对MFC”Unicode字符集”的,如果你的工程是”多字节字符集”或者其他,就应该不可以直接用,需要将输入字符转成wchar_t再输入到dll相关的函数中(也就是AddCatalog和wxGetTranslation这两个函数),然后将wxGetTranslation函数输出的wchar_t字符转成相应字符集能接受的字符。这个时候为了尽可能少改已有的代码,最好是将wxLocale.h的宏定义删掉,然后自己写个函数,重新定义一个宏,形式如下:
#define _(s) zijishixiandehanshu(s)
相关文章推荐
- RESTful WebService入门(转)
- 学会不用for循环
- TimesTen 与Oracle 数据库 12c的结合
- QML与C++交互:在qml中使用QSqlQueryModel显示数据库数据
- 实验二 作业调度模拟程序
- vivado: found timing loop
- jquery源码学习2
- 【Leetcode】:343. Integer Break 问题 in JAVA
- 用最简单的方法实现---C++输入10个数存到数组,找出最小值并与第一个元素交换
- linux 内存管理 2016/04/20
- VC6.0如何插入条件断点
- R语言学习笔记2
- LeetCode *** 40. Combination Sum II
- 20160420javaweb之文件上传和下载
- Windows上安装Xampp后通过命令行进入MariaDB
- Gradle体验/第一篇:下装、安装、配置、体验
- 超级强大的vim配置(vimplus)
- Android M App Permissions
- Problem M
- Problem M