MFC多國語言——資源DLL

此隨筆中主要內容來自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。
    工具軟件截圖以下:

相關文章
相關標籤/搜索