1. 程式人生 > >怎樣在程式中利用C++支援多國語言(一種解決方案)

怎樣在程式中利用C++支援多國語言(一種解決方案)

  emule是利用動態載入資源DLL來實現多語言切換的,每一個資源DLL中包含了一份對應某一語言的字串表。在原始碼的srchybrid/lang 路徑上可以發現一個lang解決方案,其中包含了差不多40個專案,每個專案編譯出來都是一個單獨的DLL。這些DLL在程式安裝時拷貝到指定的目錄中。每個DLL裡面都是一個大的string table。emule為每一個用到的字串(大約為1400多個)都指定了一個固定ID,在不同的DLL中這個ID對應了這個字串的不同語言的翻譯版本。這樣每當需要這個字串時就通過ID去獲取,在當時程式載入的某一特定語言的DLL,就可以取到相應語言的字串。

  英文版本的string table編譯在主EXE檔案中,這樣當某一語言不支援,或DLL檔案載入失敗時還可以使用英語版本。

  下面我們就看看具體的實現。

  主要實現程式碼在I18n.cpp檔案中。入口函式是 void CPreferences::SetLanguage() ,這個函式在在 void CPreferences::LoadPreferences() 函式中被呼叫,即載入了程式的各種選項後。當程式第一次執行時,在選項檔案(即 preferences.ini)中沒有內容,SetLanguage函式會根據系統的本地語言設定來載入對應的語言DLL資源,所以我們第一次安裝後就是中文,無需設定。這一點我們後面會說到。

  另外在 BOOL CPPgGeneral::OnApply() 中也呼叫了該函式,即使用者在“選項”視窗中改變了語言選擇後。

  在 void CPreferences::SetLanguage() 函式中,首先呼叫了 static void InitLanguages(const CString& rstrLangDir, bool bReInit = false) 函式。這個函式主要是通過遍歷“語言”目錄(即我們前面說地的,專門用於存放各種語言版本DLL的目錄),來初始化靜態“語言表” (_aLanguages),這是個靜態陣列,其中的每一項對應一種支援的語言。凡能找到相應DLL檔案的,就在表中標記該語言為支援。

  然後呼叫 static bool LoadLangLib(const CString& rstrLangDir, LANGID lid) 來載入相應的語言DLL。這個函式比較簡單,通過查“語言表”(_aLanguages),如果要載入的語言是支援的,就載入相應的DLL檔案,並將DLL模組控制代碼存到_hLangDLL中,這也是一個靜態變數。我們可以看到如果是英語,是不需要載入的,直接用EXE模組中的資源字串表。

  如果呼叫LoadLangLib檔案載入指定的語言失敗,程式會嘗試判斷本地系統的語言集,並載入對應的語言,如果載入也失敗就使用英語。

  語言檔案載入成功後,程式會嘗試從中載入一個字串,如果失敗,說明可能DLL檔案損壞,則再重設語言為英語。英語字串是內建在EXE檔案中的,所以是最可靠的。

  至此,載入成功,控制代碼儲存在_hLangDLL靜態變數中。

  最後在需要字串的地方程式通過 CString GetResString(UINT uStringID, WORD wLanguageID) 或 CString GetResString(UINT uStringID) 函式載入相應的字串。這個函式的功能很簡單,就是從_hLangDLL指定的模組中載入字串資源。如果_hLangDLL為 NULL就是從當前模組載入,我們前面已經看到了,如果使用英語這個變數的值就是NULL。

  在emule的原始碼中,幾乎每個對話方塊都實現了一個Localize(void)函式,這個函式就是通過呼叫GetResString來設定對話方塊上所有控制元件的文字。在  BOOL CPPgGeneral::OnApply() 函式中我們可以看到,在呼叫CPreferences::SetLanguage函式切換了語言後,會依次呼叫對話方塊和視窗的Localize(void)函式,重新設定UI的文字內容。

  最後注意一點,如果你想讓應用支援多語言,在設計對話方塊時要把對話方塊的Language屬性設為“非特定語言”。在“資源”檢視中選中相應的對話方塊節點,再切換到“屬性”檢視就可以看到這個選項了。如果不設定會出現亂碼。

相關推薦

怎樣在程式利用C++支援語言解決方案

  emule是利用動態載入資源DLL來實現多語言切換的,每一個資源DLL中包含了一份對應某一語言的字串表。在原始碼的srchybrid/lang 路徑上可以發現一個lang解決方案,其中包含了差不多40個專案,每個專案編譯出來都是一個單獨的DLL。這些DLL在程式安裝時拷貝到指定的目錄中。每個DLL裡面都

【轉】Mybatis傳個參數解決方案

三種 方案 var nbsp myba rom name bsp 什麽 轉自: http://www.2cto.com/database/201409/338155.html 據我目前接觸到的傳多個參數的方案有三種。 第一種方案: DAO層的函數方法 Public

修改陣列的變數,無法立馬觸發檢視更新解決方案

第一:使用$set. 直接給student賦值操作,雖然可以新增屬性,但是不會觸發檢視更新 mounted () { this.student.age = 24}原因是:受 ES5 的限制,Vue.js 不能檢測到物件屬性的新增或刪除。因為 Vue.js 在初始化例項時將屬性轉為 getter/sette

Mybatis傳個參數解決方案 mapper.xml的sql語句修改!

修改 and 接收 select sql 函數 resultmap rom var 第一種 Public User selectUser(String name,String area); 對應的Mapper.xml <select id="selectUs

VS使用QT,語言翻譯問題

VS版本:VS2010 Qt版本:Qt5.5.1 例 子:英譯漢以下介紹是我站在巨人們的肩膀上,並結合自己在工作中所遇到的問題作出的總結。在VS中使用Qt程式設計,VS是不支援中文格式的,所以遇到了語言翻譯的問題。例如,一個按鈕的名字你是在UI介面上使用中文命名的,現在你要通過程式碼將該按鈕的名字用另一個名字

Qt實現語言即介面翻譯可實時進行切換

新建一個Qt Widgets Application的工程, 然後在UI介面上放置QLabel以及一個按鈕 最終要實現點選按鈕,實現QLabel上的文字進行中英切換 大致步驟: 1.由介面的UI資訊

unity利用C#產生隨機不相同的組數

using UnityEngine; using System.Collections; using System.Collections.Generic; public class game : M

一個".java"原始檔是否可以包括個類不是內部類?有什麼限制?

可以有多個類,但只能有一個public的類,可以是package或者abstract或者final的類,並且public的類名必須與檔名一致。 package Example; public cla

【一道面試題】一個".java"原始檔是否可以包括個類不是內部類?有什麼限制?

這個面試題的答案在網上一搜一大把 但都是兩句話就結束了,我們來仔細看一下具體是什麼情況! 首先 肯定的一點是一個.java的原始檔中是可以包含多個類的,但是public類只能有一個,並且類名要和檔名相同,如果有兩個public類 就會報出以下的錯誤 這

記錄開發Nodejs c++ addon的一些經驗、技術棧

c++編寫 fstream href ren http lan www. 記錄 ref Nodejs c++ addon 是用c++去編寫Nodejs的插件 技術棧: 1、node-gyp   一個用於把c++文件編譯成node可執行文件的庫 2、v8   google

華為ENSPAR啟動失敗錯誤程式碼40,42,43,及啟動後一直#的問題的解決方案

系統是64位win10安裝ensp510時不斷40.42.43的錯且在不報錯時開啟ar時一直輸出#  查閱網上各種方法 一 一嘗試後發現, 我的問題是虛擬機器不是最新版本,且虛擬機器中沒有配置網絡卡,檢視是否有網絡卡配置,在virtualbox中點選左上角的管理,選擇全域性設定,然後在

[JAVA IDEA]在使用maven專案,無法讀取resources資料夾的配置檔案的解決方案

1、在通過配置檔案來連線資料庫時,在resouces檔案中放入了db.properties配置檔案,但無法正常讀取到  讀取配置檔案資訊的程式碼: InputStream input=JdbcUtil.class.getClassLoader().getResourceAsStream("db.prope

eclipse執行tomcat提示埠被佔的4解決方案

今天碰到一個問題,在eclipse中執行一個程式,eclipse裡面的tomcat一啟動就報錯說端口占用,eclipse完全不能聯網,maven不能下載依賴包,不能建立maven專案,不能安裝外掛,然後我查看了本機的端口占用情況也沒有看到我要用的埠被別的應用佔用,最後…….折騰了好久,終於弄好了,分享如下:錯

c++ 行內函數看就懂

1.行內函數 在C++中我們通常定義以下函式來求兩個整數的最大值: int max(int a, int b) { return a > b ? a : b; } 為這麼一個小的操作定義一個函式的好處有: ① 閱讀和理解函式 max 的

利用AbstractRoutingDataSource實現動態資料來源切換 、Spring+Hibernate

package com.hoo.framework.spring.interceptor; import java.lang.reflect.Proxy; import org.aopalliance.intercept.MethodInterceptor; import org.aopalli

Android MVVM DataBinding在Fragment onCreateView()getAdapter()顯示空指標的問題的解決方法

Android MVVM框架和Data Binding庫已經出來很長一段時間了,但是自己最近才開始在專案中使用,很是”慚愧”。因為自己習慣了Android原來的那種所有邏輯都放在Fragment或Activity中處理的方式,所以在接觸Data Binding的

“XXX.exe 的 0xXXXXXXXX處未處理的異常: 0xC0000005: 讀取位置 0xXXXXXXXX 時發生訪問衝突”的解決方案

CxxxDlg *pDlg = (CxxxDlg*)AfxGetMainWnd(); 定時器回撥函式中pDlg呼叫類成員變數和成員函式時出現以上錯誤。經觀察pDlg為空指標,確實意想不到。 解決方法: 設定全域性變數CxxxDlg* g_pDlg = NULL;並且在O

Butterknife.OnClick防止按鍵過快的點選的的解決方案

按鍵的防抖就是判斷一下兩次點選的時間差,但是如果在Butterknife.OnClick中寫,每次都要寫一堆程式碼 其實我們希望的最理想的解決方案是: @OnClick({R.id.record, R.id.combine}) public void o

"/bin 不在PATH 環境變數,故無法找到該命令"的解決方法

今天我在UNUNTU系統上配置CUDA,新增PATH,source ~/.bashrc 後卻出現了下面的問題:  命令 'ls' 可在 '/bin/ls' 處找到  由於/bin 不在PATH 環境變

android監控網路狀態變化防止次廣播的解決辦法

從網上查閱了好多資料,整合成這篇,感謝csdn。測試了一下,能夠在獲得多次廣播狀態下顯示一次網路斷開的toast,不多說,上程式碼: 網路連線檢測類: import android.content.Context; import android.net.Connectivi