动态语言切换是很多国际化产品的需求,SOUI之前的版本支持静态多语言翻译,通过在程序启动时设置好语言翻译模块,在程序中打开的UI都会自动调用该翻译模块进行文字翻译,但是不支持运行进语言切换。
最近几个网友都提到这个需求,还是决定在SOUI实现一套动态多语言切换机制。
先看看运行效果:
多语言切换首先需要在语言翻译模块管理对象,SOUI中使用一个扩展接口ITranslatorMgr处理。
下面是新版本的语言翻译接口:
namespace SOUI{ /** * @struct ITranslator * @brief 语言翻译接口 * * Describe */ struct ITranslator : public IObjRef { /** * Load * @brief 从资源中加载语言翻译数据 * @param LPVOID pData -- 资源指针,具体含义由接口的实现来解释 * @param UINT uType -- 资源类型,具体含义由接口的实现来解释 * @return BOOL true-加载成功, false-加载失败 * * Describe */ virtual BOOL Load(LPVOID pData,UINT uType)=0; /** * name * @brief 获取翻译资源的name * @return SOUI::SStringW 翻译资源的name * * Describe */ virtual SStringW name()=0; /** * guid * @brief 获取翻译资源的ID * @return GUID 翻译资源的ID * * Describe */ virtual GUID guid()=0; /** * tr * @brief 执行翻译的接口 * @param const SStringW & strSrc -- 原字符串 * @param const SStringW & strCtx -- 翻译上下文 * @param SStringW & strRet -- 翻译后的字符串 * @return BOOL true-翻译成功,false-翻译失败 * * Describe */ virtual BOOL tr(const SStringW & strSrc,const SStringW & strCtx,SStringW & strRet)=0; };/** * @struct ITranslatorMgr * @brief 语言翻译接口管理器 * * Describe */ struct ITranslatorMgr : public IObjRef { /** * SetLanguage * @brief 设置翻译模块当前接受的语言 * @param [in] const SStringW & strLang -- 翻译语言 * * Describe 自动清除语言和目标语言不同的模块 */ virtual void SetLanguage(const SStringW & strLang) = 0; /** * GetLanguage * @brief 获取翻译模块当前接受的语言 * @return SStringW -- 翻译语言 * * Describe */ virtual SStringW GetLanguage() const = 0; /** * CreateTranslator * @brief 创建一个语言翻译对象 * @param [out] ITranslator * * ppTranslator -- 接收语言翻译对象的指针 * @return BOOL true-成功,false-失败 * * Describe */ virtual BOOL CreateTranslator(ITranslator ** ppTranslator)=0; /** * InstallTranslator * @brief 向管理器中安装一个语言翻译对象 * @param ITranslator * ppTranslator -- 语言翻译对象 * @return BOOL true-成功,false-失败 * * Describe */ virtual BOOL InstallTranslator(ITranslator * ppTranslator) =0; /** * UninstallTranslator * @brief 从管理器中卸载一个语言翻译对象 * @param REFGUID id -- 语言翻译对象的ID * @return BOOL true-成功,false-失败 * * Describe */ virtual BOOL UninstallTranslator(REFGUID id) =0; /** * tr * @brief 翻译字符串 * @param const SStringW & strSrc -- 原字符串 * @param const SStringW & strCtx -- 翻译上下文 * @return SOUI::SStringW 翻译后的字符串 * * Describe 调用ITranslator的tr接口执行具体翻译过程 */ virtual SStringW tr(const SStringW & strSrc,const SStringW & strCtx)=0; };}
用户切换UI语言后,使用SDispatchMessage方法向所有SWindow发送UM_SETLANGUAGE消息。
SWindow收到该消息后对窗口中需要做语言翻译的对象重新翻译语言后更新显示。
要在SOUI中使用多语言切换,首先需要在winmain里设置翻译模块:1 int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int /*nCmdShow*/) 2 {
3 HRESULT hRes = OleInitialize(NULL); 4 SASSERT(SUCCEEDED(hRes)); 5 6 int nRet = 0; 7 8 SComMgr *pComMgr = new SComMgr; 9 10 //将程序的运行路径修改到项目所在目录所在的目录11 TCHAR szCurrentDir[MAX_PATH] = { 0 };12 GetModuleFileName(NULL, szCurrentDir, sizeof(szCurrentDir));13 LPTSTR lpInsertPos = _tcsrchr(szCurrentDir, _T('\\'));14 _tcscpy(lpInsertPos + 1, _T("..\\SouiWizard1"));15 SetCurrentDirectory(szCurrentDir);16 {17 BOOL bLoaded=FALSE;18 CAutoRefPtr<:iimgdecoderfactory> pImgDecoderFactory;19 CAutoRefPtr<:irenderfactory> pRenderFactory;20 CAutoRefPtr trans; //多语言翻译模块,由translator.dll提供21 22 bLoaded = pComMgr->CreateRender_GDI((IObjRef**)&pRenderFactory);23 SASSERT_FMT(bLoaded,_T("load interface [render] failed!"));24 bLoaded=pComMgr->CreateImgDecoder((IObjRef**)&pImgDecoderFactory);25 SASSERT_FMT(bLoaded,_T("load interface [%s] failed!"),_T("imgdecoder"));26 bLoaded = pComMgr->CreateTranslator((IObjRef**)&trans);27 SASSERT_FMT(bLoaded, _T("load interface [%s] failed!"), _T("translator"));28 29 pRenderFactory->SetImgDecoderFactory(pImgDecoderFactory);30 SApplication *theApp = new SApplication(pRenderFactory, hInstance);31 //从DLL加载系统资源32 HMODULE hModSysResource = LoadLibrary(SYS_NAMED_RESOURCE);33 if (hModSysResource)34 {35 CAutoRefPtr sysResProvider;36 CreateResProvider(RES_PE, (IObjRef**)&sysResProvider);37 sysResProvider->Init((WPARAM)hModSysResource, 0);38 theApp->LoadSystemNamedResource(sysResProvider);39 FreeLibrary(hModSysResource);40 }else41 {42 SASSERT(0);43 }44 45 CAutoRefPtr pResProvider;46 #if (RES_TYPE == 0)47 CreateResProvider(RES_FILE, (IObjRef**)&pResProvider);48 if (!pResProvider->Init((LPARAM)_T("uires"), 0))49 {50 SASSERT(0);51 return 1;52 }53 #else 54 CreateResProvider(RES_PE, (IObjRef**)&pResProvider);55 pResProvider->Init((WPARAM)hInstance, 0);56 #endif57 58 theApp->InitXmlNamedID(namedXmlID,ARRAYSIZE(namedXmlID),TRUE);59 theApp->AddResProvider(pResProvider);60 61 if (trans)62 {//加载中文语言翻译包63 theApp->SetTranslator(trans);64 pugi::xml_document xmlLang;65 if (theApp->LoadXmlDocment(xmlLang, _T("cn"), _T("lang")))66 {67 CAutoRefPtr langCN;68 trans->CreateTranslator(&langCN);69 langCN->Load(&xmlLang.child(L"language"), 1);//1=LD_XML70 trans->InstallTranslator(langCN);71 }72 }73 // BLOCK: Run application74 {75 CMainDlg dlgMain;76 dlgMain.Create(GetActiveWindow());77 dlgMain.SendMessage(WM_INITDIALOG);78 dlgMain.CenterWindow(dlgMain.m_hWnd);79 dlgMain.ShowWindow(SW_SHOWNORMAL);80 nRet = theApp->Run(dlgMain.m_hWnd);81 }82 83 delete theApp;84 }85 86 delete pComMgr;87 88 OleUninitialize();89 return nRet;90 }
参见上面红色代码。
需要切换语言时,如下加载新的翻译模块即可:
void CMainDlg::OnLanguage(int nID){ ITranslatorMgr *pTransMgr = SApplication::getSingletonPtr()->GetTranslator(); bool bCnLang = nID == R.id.lang_cn; pugi::xml_document xmlLang; if (SApplication::getSingletonPtr()->LoadXmlDocment(xmlLang, bCnLang?_T("cn"):_T("en"), _T("lang"))) { CAutoRefPtr lang; pTransMgr->CreateTranslator(&lang); lang->Load(&xmlLang.child(L"language"), 1);//1=LD_XML pTransMgr->SetLanguage(lang->name()); pTransMgr->InstallTranslator(lang); SDispatchMessage(UM_SETLANGUAGE,0,0); //soui2.6 新增加的方法。 }}
注:该功能只在SOUI 2.6+版本支持。