zoukankan      html  css  js  c++  java
  • MFC多国语言——资源DLL

    此随笔中主要内容来自http://blog.csdn.net/china_hxx/article/details/10066655,原出处不详。

        以下内容基于VC 6.0。要实现界面多语言化,必须要先配置项目使其支持Unicode编码,文章《VC下的Unicode编程》 对此有详细介绍。

        首先创建一个基于MFC的工程,在选择语言时选择 中文[简体,中国]。

        项目框架选择对话框、单文档和多文档都可以,这里就选个基于对话框的吧,然后立即修该项目属性使其支持Unicode。

        MFC已经为我们加入了一些资源,包括2个对话框、1个String Table等。为了节省空间修改了对话框的大小。

        现在项目中的资源情况如下:

        然后再新建一个DLL项目,为了方便管理可以将其添加到当前工作空间中。

        立即修改此DLL项目使其支持Unicode,然后设置项目依赖性(Project->Dependencies…) ,资源DLL要在exe项目之前编译:

        为了将生成的资源DLL自动拷贝到exe项目执行目录下,还需要修改DLL项目的Post-build Step:

        然后将主项目目录下的res文件夹、resource.h、TestMultiLang.rc文件拷贝到ResENG项目目录下,res文件夹和resource.h直接替换,将ResENG.rc删除后再将TestMultiLang.rc重命名为ResENG.rc。

        切换到资源视图就会发现这两个项目的资源内容是一样的了,将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。
        工具软件截图如下:

  • 相关阅读:
    基于OpenSSL自建CA和颁发SSL证书
    SSL与TLS的区别以及介绍
    Ubuntu中Nginx的安装与配置
    Openssl源代码整理学习---含P7/P10/P12说明
    动态加载js文件
    常用方法
    对reducers 理解
    小复习(3)
    如何使移动web页面禁止横屏?
    九个Console命令,让 JS 调试更简单
  • 原文地址:https://www.cnblogs.com/xiaoyusmile/p/3924931.html
Copyright © 2011-2022 走看看