在嵌入式系統(tǒng)開發(fā)中,某些產(chǎn)品可能會(huì)需要跨區(qū)域銷售,因此,通常會(huì)有多語言的需求。對(duì)于這一類多語言需求的解決,在嵌入式產(chǎn)品中有其特殊的地方。以下,給出一種可能的解決方案。
該方案的核心思想是為所有文本建立索引,通過索引可以得到特定語言的文字編碼,隨后通過該編碼獲得字庫資源,并進(jìn)行輸出。在這過程中,唯一需要注意的是對(duì)于特殊的某些語言,如阿拉伯語等的處理。(阿拉伯語字符在連寫時(shí),其形狀會(huì)發(fā)生變化。)
1. 字庫的建立:
文本最終都將輸出給用戶,因此,必須為文本內(nèi)容指定字庫。本方案中采用UNICODE編碼字庫。字庫文件采用二進(jìn)制存儲(chǔ),按UNICODE編碼順序排列存儲(chǔ)點(diǎn)陣數(shù)據(jù),點(diǎn)陣大小為24*24。
2. 文本資源文件:
文本資源文件描述了特定語言的文本內(nèi)容,以及相關(guān)的字符編碼。例如對(duì)于Chinese.cfg文件來說,就保留了一個(gè)索引為1的文本,該文本內(nèi)容為“確認(rèn)”;相應(yīng)對(duì)于English.cfg文件來說,必然會(huì)同樣有一個(gè)索引為1的文本,該文本內(nèi)容為“Confirm”。通過對(duì)所有的文本建立索引并生成文本資源文件,就為最終的解決掃清了障礙。
文本資源文件采用二進(jìn)制存儲(chǔ)。文件頭部16個(gè)字節(jié)為描述性信息,之后是文本映射表,緊跟映射表之后為文本的實(shí)際Unicode編碼。
3. 對(duì)文本資源文件進(jìn)行描述的數(shù)據(jù)結(jié)構(gòu)
typedef struct _txtres_fileheader {
LONG lFileType; //文件類型,0x2E434647='.CFG'
LONG lVersionNum; //適用版本,0x56313032='V102'
LONG lMapOffset; //偏移量,文件頭到文本映射區(qū)的偏移量
LONG lDataOffset; //偏移量,文件頭到文本數(shù)據(jù)區(qū)的偏移量
} APPTEXT_FILEHEADER;
4. 文本映射表結(jié)構(gòu)
typedef struct _txtres_txtmap {
WORD wTextIndes; //當(dāng)前文本的索引值
WORD wTextSize; //當(dāng)前文本的Unicode編碼所占用的字節(jié)數(shù)
LONG lUnicodeOffset; //從文件頭到當(dāng)前文本Unicode編碼存儲(chǔ)位置的偏移量
} TXTRES_TXTMAP;
5. 特殊語言(阿拉伯語等)的解決
特殊語言在連寫時(shí)可能發(fā)生變化,因此采用固定字庫可能無法解決該問題。針對(duì)這種狀況可以直接新增一個(gè)自定義字庫。以阿拉伯語為例,該字庫的處理過程如下:
a. 首先將阿拉伯的文本內(nèi)容按預(yù)定格式(例如24*24)在windows系統(tǒng)上顯示輸出,并將內(nèi)容保存為圖片格式。此時(shí)圖片中便為連寫內(nèi)容。
b. 隨后,對(duì)圖片進(jìn)行分割。如按照24*24進(jìn)行分割便可得到特定的24*24大小的字庫內(nèi)容。
c. 最后,將原先的UNICODE編碼轉(zhuǎn)為按照之前生成的字庫來編碼。
d. 之后在程序代碼中就可利用自定義字庫與自定義編碼來顯示阿拉伯語。
最后附上部分示例代碼。
//定義文本配置文件路徑
#define TXT_FILE_ENGLISH "config/English.cfg"
#define TXT_FILE_CHINASIM "config/ChinaSim.cfg"
#define TXT_FILE_CHINATRA "config/ChinaTra.cfg"
#define TXT_FILE_KOREAN "config/Korean.cfg"
#define TXT_FILE_JAPANESE "config/Japanese.cfg"
#define TXT_FILE_SPANISH "config/Spanish.cfg"
#define TXT_FILE_RUSSIAN "config/Russian.cfg"
#define TXT_FILE_THAI "config/Thai.cfg"
#define TXT_FILE_GERMAN "config/German.cfg"
#define TXT_FILE_FRANCE "config/France.cfg"
#define TXT_FILE_ITALY "config/Italy.cfg"
#define TXT_FILE_ARABIA "config/Arabia.cfg"
#define TXT_FILE_PORTUGAL "config/Portugal.cfg"
#define TXT_FILE_HINDI "config/Hindi.cfg"
#define TXT_FILE_TURKISH "config/Turkish.cfg"
#define TXT_FILE_VIETNAM "config/Vietnam.cfg"
#define TXT_FILE_SWIDISH "config/Swedish.cfg"
#define TXT_FILE_POLISH "config/Polish.cfg"
//根據(jù)文本索引及文本語言,讀取相應(yīng)的文本配置文件,以得到該文本,成功返回有效指針
GUISTRING * GetTextResource(LONG lIndex, LONG lLanguage)
{
GUISTRING * pTxt;
APPTEXT_FILEHEADER fh;
APPTEXT_MAPPING map;
STRING strFile;
WORD * pBuf;
int fd, iOff;
//確定要讀取的配置文件
switch (lLanguage)
{
case TXT_LANG_ENGLISH:
strFile = TXT_FILE_ENGLISH;
break;
case TXT_LANG_CHINASIM:
strFile = TXT_FILE_CHINASIM;
break;
case TXT_LANG_CHINATRA:
strFile = TXT_FILE_CHINATRA;
break;
case TXT_LANG_KOREAN:
strFile = TXT_FILE_KOREAN;
break;
case TXT_LANG_JAPANESE:
strFile = TXT_FILE_JAPANESE;
break;
case TXT_LANG_SPANISH:
strFile = TXT_FILE_SPANISH;
break;
case TXT_LANG_RUSSIAN:
strFile = TXT_FILE_RUSSIAN;
break;
case TXT_LANG_THAI:
strFile = TXT_FILE_THAI;
break;
case TXT_LANG_GERMAN:
strFile = TXT_FILE_GERMAN;
break;
case TXT_LANG_FRANCE:
strFile = TXT_FILE_FRANCE;
break;
case TXT_LANG_ITALY:
strFile = TXT_FILE_ITALY;
break;
case TXT_LANG_ARABIA:
strFile = TXT_FILE_ARABIA;
break;
case TXT_LANG_PORTUGAL:
strFile = TXT_FILE_PORTUGAL;
break;
case TXT_LANG_HINDI:
strFile = TXT_FILE_HINDI;
break;
case TXT_LANG_TURKISH:
strFile = TXT_FILE_TURKISH;
break;
case TXT_LANG_VIETNAM:
strFile = TXT_FILE_VIETNAM;
break;
case TXT_LANG_SWIDISH:
strFile = TXT_FILE_SWIDISH;
break;
case TXT_LANG_POLISH:
strFile = TXT_FILE_POLISH;
break;
default:
return NULL;
}
//打開配置文件并檢查其格式
if ((fd = open(strFile, O_RDONLY)) == -1)
{
return NULL;
}
if (read(fd, &fh, 16) != 16)
{
close(fd);
return NULL;
}
if (fh.lFileType != 0x4746432E || fh.lVersionNum != 0x32303156)
{
close(fd);
return NULL;
}
//在文本映射區(qū)內(nèi)查找匹配的文本索引
for (iOff = fh.lMapOffset; iOff < fh.lDataOffset; iOff += 8)
{
if (read(fd, &map, 8) != 8)
{
close(fd);
return NULL;
}
if (map.wTextIndex == lIndex)
{
break;
}
}
if (iOff >= fh.lDataOffset)
{
close(fd);
return NULL;
}
//根據(jù)找到的文本映射來讀取文本內(nèi)容
if (!(pBuf = GuiMemAlloc(map.wTextSize + 2)))
{
close(fd);
return NULL;
}
lseek(fd, fh.lDataOffset + map.lTextOffset, SEEK_SET);
if (read(fd, pBuf, map.wTextSize) != map.wTextSize)
{
GuiMemFree(pBuf);
close(fd);
return NULL;
}
pBuf[map.wTextSize >> 1] = 0;
//建立字符串對(duì)象
pTxt = CreateStringDirect(pBuf);
GuiMemFree(pBuf);
close(fd);
return pTxt;
}
//定義與字符串相關(guān)的數(shù)據(jù)結(jié)構(gòu)
#ifndef GUI_STRING_STRUCT
typedef struct _string
{
WORD wWidth; //字符串寬度,字符串輸出時(shí)的總點(diǎn)陣寬度
WORD wLength; //字符串長(zhǎng)度,不包括'\0'
WORD * pContent; //字符串內(nèi)容,以'\0'結(jié)尾
} GUISTRING;
//結(jié)束與字符串相關(guān)的數(shù)據(jù)結(jié)構(gòu)的定義
#define GUI_STRING_STRUCT
#endif
/***
* 功能:
根據(jù)指定的信息直接建立字符串,函數(shù)返回字符串指針
* 參數(shù):
1.WORD * pContent: 字符串內(nèi)容
* 返回:
成功返回字符串指針
失敗返回NULL
* 備注:
***/
GUISTRING * CreateStringDirect(WORD * pContent)
{
GUISTRING * pStr;
//嘗試為字符串分配內(nèi)存
if (!(pStr = GuiMemAlloc(sizeof(GUISTRING))))
{
PRINT_INF(CreateStringDirect Err0!);
return NULL;
}
//字符串內(nèi)容為空,建立一個(gè)空字符串對(duì)象
if (!pContent)
{
pStr->wWidth = 0;
pStr->wLength = 0;
pStr->pContent = NULL;
return pStr;
}
//統(tǒng)計(jì)字符串長(zhǎng)度
pStr->wLength = 0;
pStr->pContent = pContent;
while (*pStr->pContent++)
{
pStr->wLength++;
}
//嘗試為字符串內(nèi)容分配內(nèi)存
if (!(pStr->pContent = GuiMemAlloc((pStr->wLength + 1) << 1)))
{
GuiMemFree(pStr);
PRINT_INF(CreateStringDirect Err1!);
return NULL;
}
//寫入字符串內(nèi)容
memcpy(pStr->pContent, pContent, (pStr->wLength + 1) << 1);
//計(jì)算字符串寬度
if (_StringObjectFill(pStr))
{
GuiMemFree(pStr->pContent);
GuiMemFree(pStr);
PRINT_INF(CreateStringDirect Err2!);
return NULL;
}
return pStr;
}
“本文由華清遠(yuǎn)見http://www.embedu.org/index.htm提供”