C++ 實現多語言程序開發研究與Xtreme ToolkitPro的使用(三)

       在上一篇”C++ 實現多語言程序開發研究與Xtreme ToolkitPro的使用(二)”在MultiLanguageDemo程序中添加語言資源的定義,這裏繼續開始介紹如何使用在程序中動態添加語言資源DLL文件。

       回到Xtreme ToolkitPro源碼中兩個關於多語言的例子:ScribbleMultiLang(Xtreme ToolkitPro v15.2.1\Samples\CommandBars\ScribbleMultiLang\)和MultiLanguage(Xtreme ToolkitPro v15.2.1\Samples\ToolkitPro\MultiLanguage)。可以在MultiLanguage中看到一個管理語言資源的類CLanguageManger,類中有幾個比較關鍵的函數:

BOOL CLanguageManger::InitLanguageDlls()
{
	TCHAR szBuff[_MAX_PATH];
	::GetModuleFileName(NULL, szBuff, _countof(szBuff));

	TCHAR *p = _tcsrchr(szBuff, _T('\\'));
	if (p != NULL) {
		*p = _T('\0');
	}

	CString strDllPath;

	if (!DIRECTORYEXISTS_S(CString(szBuff) + _T("\\Translations")) && 
		DIRECTORYEXISTS_S(CString(szBuff) + _T("\\..\\..\\Utils\\Translations")))
	{
		strDllPath.Format(_T("%s\\..\\..\\Utils\\Translations\\*.dll"), szBuff);
	}
	else
	{
		strDllPath.Format(_T("%s\\Translations\\*.dll"), szBuff);
	}

	return InitLanguageDlls(strDllPath);
}

       這個函數是查找Translations目錄(路徑可以根據實際情況做修改)下所有的語言資源DLL並加載後其語言ID並保存:

WORD CLanguageManger::GetLangID(HMODULE hResDll) const
{
	typedef WORD (CALLBACK* PGETLANGID)();

	if (hResDll != NULL)
	{

		PGETLANGID pfnGetLangID = (PGETLANGID)::GetProcAddress(
				hResDll, "GetLangID");

		if (pfnGetLangID)
			return (*pfnGetLangID)();
		
		WORD wLanguage = 0;
		DWORD Zero;
		UINT cbTranslate;
		TCHAR pszPath[MAX_PATH];
		
		struct LANGANDCODEPAGE 
		{
			WORD wLanguage;
			WORD wCodePage;
		} *lpTranslate;
		
		GetModuleFileName(hResDll, pszPath, MAX_PATH);
		DWORD dwDataLen = ::GetFileVersionInfoSize(pszPath, &Zero);
		
		if (dwDataLen == 0)
		{
			EnumResourceTypes(hResDll, &CLanguageManger::EnumResTypeProc, (LONG_PTR)&wLanguage);
			return wLanguage;
		}
		
		LPVOID pData = new BYTE[dwDataLen];
		
		if (::GetFileVersionInfo((TCHAR*)pszPath, NULL, dwDataLen, pData))			
		{
			::VerQueryValue(pData, _T("\\VarFileInfo\\Translation"), (LPVOID*)&lpTranslate, &cbTranslate);
			
			if (cbTranslate >= 4)
			{
				wLanguage = lpTranslate->wLanguage;
			}
		}
		
		delete [] pData;
		
		return wLanguage;
	}
	return 0;
}
       這樣,就很方便地在CMainFrame中操作語言資源了,加入的主要操作函數是:

	void OnInitCommandsPopup(CXTPPopupBar* pCommandBar);
	void ResetCommandBars(); // 重置命令欄

	// 語言更新函數
	afx_msg BOOL OnLangaugeFile(UINT nID);
	afx_msg void OnUpdateLangaugeFile(CCmdUI* pCmdUI);
        在CMainFrame::OnCreate函數中添加工具條:
	// 2017-08-25
	// Create  Language ToolBar
	CXTPToolBar* pLangBar = (CXTPToolBar*)
		pCommandBars->Add(_T("Language"), xtpBarTop);
	if (!pLangBar || !pLangBar->LoadToolBar(IDR_LANGBAR))
	{
		TRACE0("Failed to create toolbar\n");
		return -1;
	}
         然後初始化之前選擇的語言:

	// Load previously selected language.
	OnLangaugeFile(m_langManager.GetCmdID(m_langManager.GetLangID()));
        更新操作:

// 重置命令欄
void CMainFrame::ResetCommandBars()
{
	m_bInRecalcLayout = TRUE;

	CXTPCommandBars* pCommandBars = GetCommandBars();
	for (int i = 0; i < pCommandBars->GetCount(); i++)
	{
		CXTPToolBar* pToolBar = pCommandBars->GetAt(i);
		if (pToolBar->IsBuiltIn())
		{
			if (pToolBar->GetType() != xtpBarTypeMenuBar)
			{
				pToolBar->LoadToolBar(pToolBar->GetBarID(), FALSE);
			}
			else
			{
				CMenu menu;
				menu.LoadMenu(IDR_MultiLanguageDeTYPE);

				pToolBar->LoadMenu(&menu);
				pToolBar->GetControls()->CreateOriginalControls();
				((CXTPMenuBar*)pToolBar)->RefreshMenu();
			}
		}
		// 隱藏未加載的語言
		if (pToolBar->GetBarID() == IDR_LANGBAR)
		{
			CXTPControls* pCommandList = pToolBar->GetControls();
			for (int iIndex = pCommandList->GetCount()-1; iIndex >= 0; --iIndex)
			{
				CXTPControl* pButton = pCommandList->GetAt(iIndex);
				if (pButton)
				{
					WORD wLangID = m_langManager.GetLangID(pButton->GetID());
					pButton->SetCaption(m_langManager.GetDescription(wLangID));

					LANGUAGE_DLL langDll;
					if (!m_langManager.GetDllInfo(wLangID, langDll))
						pCommandList->Remove(iIndex);
				}
			}
		}
	}

	m_bInRecalcLayout = FALSE;
	RecalcLayout();
	AfxGetApp()->OnIdle(0);

	RedrawWindow(NULL, NULL,
		RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ALLCHILDREN);
}

// 語言更新函數
BOOL CMainFrame::OnLangaugeFile(UINT nID)
{
	LANGUAGE_DLL langDll;
	if (m_langManager.GetDllInfo(m_langManager.GetLangID(nID), langDll))
	{
		if (m_langManager.LoadLanguageDll(langDll.strDllPath))
		{
			::SetThreadLocale(MAKELCID(m_langManager.GetLangID(nID), SORT_DEFAULT)); 

			BOOL bRTLLayout = ((::GetWindowLong(m_hWnd, GWL_EXSTYLE)
				& WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL);

			if (bRTLLayout != m_langManager.IsRTL())
			{
				m_langManager.SetRTLLayout(this, m_langManager.IsRTL());

				XTPImageManager()->DrawReverted(m_langManager.IsRTL());
			}

			ResetCommandBars();
			return TRUE;
		}
	}
	return FALSE;
}

       其他的函數比較簡單,參考下Xtreme ToolkitPro中的例子很容易實現。最終,完成的MultiLanguageDemo如下:



        提供完整的工程下載:MultiLanguageDemo



發佈了160 篇原創文章 · 獲贊 95 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章