本章將討論 Solaris 作業系統中所包含的一些國際化功能。本章包含以下主題。
EUC 是擴充式 UNIX 編碼 (Extended UNIX® Code) 的縮寫。Solaris 作業系統支援非 EUC 的編碼方式,例如日本的 PC-Kanji (慣用名稱是 Shift_JIS)、台灣的 Big5以及中華人民共和國的 GBK。由於大部分的電腦銷售需要非 EUC 字碼集支援,目前 Solaris 環境提供了一個可同時啟用 EUC 和非 EUC 字碼集支援的穩固架構。此支援稱為字碼集獨立性 (CSI)。
CSI 的目的是從 Solaris 作業系統程式庫與指令中,移除對特定字碼集或編碼方式的依賴性。CSI 架構可以使 Solaris 作業系統支援任何 UNIX 檔案系統安全編碼。CSI 支援一些新的字碼集,例如 UTF-8、PC-Kanji 以及 Big5。
透過字碼集獨立性,應用程式與平台軟體開發人員能夠將其程式碼保持獨立於任何編碼方式,例如 UTF-8。CSI 也提供在不需修改原始程式碼的情況下採用任何新編碼方式的能力。此架構方法不同於 JavaTM 國際化,因為應用程式不必受限於使用 UTF-16。
許多現有國際化的應用程式 (例如 Motif) 自動從基礎系統繼承 CSI 支援。這些應用程式在不需修改的情況下即可在新的語言環境中使用。
CSI 自始即獨立於任何字碼集。然而,下列關於檔案程式碼編碼方式 (字碼集) 的假設,仍然可適用於目前 Solaris 系統:
本節內容將列出目前 Solaris 環境中已啟用 CSI 的指令。每個指令的線上說明手冊中所包含的屬性區段,會指出該指令是否為已啟用 CSI 的指令。
所有的指令都位在 /usr/bin 目錄中,除非另有說明。
所有在 libc (/usr/lib/libc.so) 中的函式,幾乎都是已啟用 CSI 的函式。然而,下列在 libc 中的函式並非已啟用 CSI 的函式,而是依賴於 EUC 的函式:
csetcol()
csetlen()
csetno()
euccol()
euclen()
eucscol()
getwidth()
wcsetno()
在目前 Solaris 環境中,libgen /usr/ccs/lib/libgen.a 以及 libcurses /usr/ccs/lib/libcurses.a 皆已國際化,但沒有啟用 CSI。
語言環境資料庫的格式與結構是私有的,並將在未來發行版本中有所變動。當您在開發國際化應用程式時,可以使用 libc 中的國際化 API。這些 API 的說明位於libc 的國際化 API,而非連結到語言環境資料庫。
當您在 Solaris 環境中作業時,請使用已包含於目前 Solaris 發行版本中的語言環境資料庫。請不要使用上一個 Solaris 版本的語言環境。
程序碼格式,也就是 Solaris 作業系統中的寬字元程式碼格式,是私有的並將在未來發行版本中有所變動。因此,在開發國際化應用程式時,請不要假設程序碼格式是相同的。相反地,請使用 libc 中的國際化 API,這個部分將於libc 的國際化 API說明。
所有 Unicode 語言環境的程序碼皆使用 UTF 32 表示法。如需 UTF 32 的詳細資訊,請參閱「Unicode 標準附錄 #19:UTF 32」以及「Unicode 標準附錄 #27:Unicode 3.1」(摘自「Unicode 學術學會」或 http://www.unicode.org/)。
多位元組字元是無法使用單一位元組來儲存的字元,例如中文、日文或韓文字元。這些字元需要 2、 3 或 4 個位元組的儲存空間。ISO/IEC 9899:1990 子條款 3.13 中記載了更精確的定義。
ANSI C 的一號修正案 (即 ISO/IEC 9899:1990) 中, 增加了新的國際化功能,並統稱為多位元組支援環境 (MSE)。一號修正案針對多位元組字碼集與較佳的寬字元處理支援,定義了附加的國際化 API 並隨附說明。
程式設計模型使得這些多位元組字元可以邏輯單位讀取,並如寬字元般儲存在內部。程式可以將這些寬字元視為邏輯實體來處理。最後,可以經由適當轉譯,將這些寬字元以邏輯單位寫出。
這個程序類似讀取、處理單一位元組字元,並再次寫出的方法。MSE 使程式可以使用與單一位元組字元所用相同之程式設計模型,來處理多位元組字元。
您可以使用動態連結或靜態連結,將應用程式連結至系統程式庫,例如 libc。任何需要系統程式庫中國際化功能的應用程式,都必須是動態連結。如果應用程式已經靜態連結,那麼想要使用 setlocale 功能將語言環境設定為任何其他不是 C 和 POSIX 的作業將會失敗。靜態連結的應用程式只能在 C 和 POSIX 語言環境中作業。
依預設值,連結程式會嘗試動態連結至應用程式。如果連結程式與編譯程式的指令行選項包含 -Bstatic 或 -dn 規格,那麼您的應用程式可能已靜態連結。您可以檢查現有的應用程式是否為使用 /usr/bin/ldd 指令完成動態連結。
例如,下列指令的回應表示 /sbin/sh 指令並不是一個動態連結的程式:
% /usr/bin/ldd /sbin/sh ldd: /sbin/sh: file is not a dynamic executable or shared object |
下列指令的回應表示 /usr/bin/ls 指令已動態連結至兩個程式庫,libc.so.1 和 libdl.so.1。
% /usr/bin/ldd /usr/bin/ls libc.so.1 => /usr/lib/libc.so.1 libdl.so.1 => /usr/lib/libdl.so.1 |
libw 和 libintl 已經移至 libc,並且不再放置於 libw 和 libintl。
共用物件會確保現有應用程式的運行時間相容性,並伴隨歸檔的使用提供建立應用程式編譯環境的相容性。然而,您不再需要針對 libw 或 libintl 來建立應用程式。
下列清單將顯示 libw 中的 stub 進入點:
下列清單將顯示 libintl 中的 stub 根進入點:
字元分類和轉換巨集定義在 /usr/include/ctype.h 之中。目前 Solaris 環境提供一組 ctype 巨集,此巨集支援由 XPG4 定義的字元分類和轉換語義。若要使所有 XPG4 和 XPG4.2 應用程式自動地存取新巨集,必須符合下列其中一項條件:
已定義 _XPG4_CHAR_CLASS。
已定義 _XOPEN_SOURCE 和 _XOPEN_VERSION=4。
已定義 _XOPEN_SOURCE 和 _XOPEN_SOURCE_EXTENDED=1。
由於 _XOPEN_SOURCE、_XOPEN_VERSION 和 _XOPEN_SOURCE_EXTENDED 引進除了新的 ctype 巨集以外的 XPG4 相關功能,因此非 XPG4 或 XPG4.2 應用程式就應該使用 __XPG4_CHAR_CLASS__。
同時存在相對應的 ctype 函式。目前 Solaris 環境函式也支援 XPG4 語義。
目前 Solaris 環境提供兩組 API:
多位元組 (檔案程式碼)
寬字元 (程序碼)
寬字元程式碼為固定寬度的邏輯實體單位。因此使用多位元組字元時,並不需要維護適當字元界限的記錄。
當程式讀取來自於檔案的輸入時,您可以使用像是 fscanf 和 fwscanf 的輸入函式或是在輸入之後使用像是 mbtowc 和 mbsrtowcs 的轉換函式,自動將檔案中的多位元組資料轉換為寬字元程序碼。若要將輸出資料從寬字元格式轉換為多位元組字元格式,請使用像是fwprintf 和 fprintf 的輸出函式或在輸出之前套用像是 wctomb 和 wcsrtombs 的轉換函式。
本章其餘表格將說明包含在目前 Solaris 系統中的國際化 API。
下列表格將說明 libc 中的訊息傳送函式 API。
表 2–1 libc 中的訊息函式
程式庫常式 |
描述 |
---|---|
bindtextdomain() |
將路徑連結至訊息網域 |
catclose() |
關閉訊息目錄 |
catgets() |
讀取程式訊息 |
catopen() |
開啟訊息目錄 |
dcgettext() |
從訊息目錄中取得指定網域與種類的訊息 |
dgettext() |
從訊息目錄中取得指定網域的訊息 |
gettext() |
從訊息資料庫取回文字串 |
textdomain() |
設定與查詢目前的網域 |
下列表格將說明 libc 中的字碼轉換函式 API。
表 2–2 libc 中的字碼轉換
程式庫常式 |
描述 |
---|---|
iconv() |
轉換字碼 |
iconv_close() |
取消配置轉換描述元 |
iconv_open() |
配置轉換描述元 |
下列表格將說明 libc 中的常規表示式 API。
表 2–3 libc 中的常規表示式
程式庫常式 |
描述 |
---|---|
fnmatch() |
符合的檔案或路徑名稱 |
regcomp() |
編譯常規表示式 |
regerror() |
提供錯誤代碼與錯誤訊息的對映 |
regexec() |
執行常規表示式匹配 |
regfree() |
釋放 regcomp() 所配置的記憶體 |
下列表格將說明 libc 中的寬字元函式 API。
表 2–4 libc 中的寬字元類別
程式庫常式 |
描述 |
---|---|
wctrans() |
定義字元對映 |
wctype() |
定義字元類別 |
下列表格將列出 libc 中的修改和查詢語言環境。
表 2–5 libc 中的修改和查詢語言環境
程式庫常式 |
描述 |
---|---|
setlocale() |
修改以及查詢程式的語言環境 |
表 2–6 libc 中的查詢語言環境資料
程式庫常式 |
描述 |
---|---|
localeconv() |
取得目前語言環境的貨幣與數值格式資訊 |
nl_langinfo() |
取得目前語言環境的語言與文化資訊 |
下列表格將說明 libc 中的字元分類函式 API。
表 2–7 libc 中的字元分類和轉譯
程式庫常式 |
描述 |
---|---|
isalnum() |
字元為字母或數字? |
isalpha() |
字元是否為字母? |
isascii() |
字元是否為 ASCII 字元? |
iscntrl() |
字元是否為控制字元? |
isdigit() |
字元是否為數字? |
isenglish() |
寬字元是否在補充字碼集的英文字母表中? |
isgraph() |
字元是否為可視字元? |
isideogram() |
寬字元是否為表意文字? |
islower() |
字元是否為小寫? |
isnumber() |
寬字元是否為補充字碼集中的數字? |
isphonogram() |
寬字元是否為音標符號? |
isprint() |
字元是否可以列印? |
ispunct() |
字元是否為標點符號? |
isspace() |
字元是否為空白? |
isspecial() |
特殊寬字元是否源自補充字碼集? |
isupper() |
字元是否為大寫? |
iswalnum() |
寬字元是字母字元或數字? |
iswalpha() |
寬字元是否為字母? |
iswascii() |
寬字元是否為 ASCII 字元? |
iswcntrl() |
寬字元是否為控制字元? |
iswdigit() |
寬字元是否為數字? |
iswgraph() |
寬字元是否為可視字元? |
iswlower() |
寬字元是否為小寫? |
iswprint() |
寬字元是否為可列印的字元? |
iswpunct() |
寬字元是否為標點符號? |
iswspace() |
寬字元是否為空格? |
iswupper() |
寬字元是否為大寫? |
iswxdigit() |
寬字元是否為十六進位數字? |
isxdigit() |
字元是否為十六進位數字? |
tolower() |
將大寫字元轉換為小寫。 |
toupper() |
將小寫字元轉換為大寫。 |
towctrans() |
寬字元對映。 |
towlower() |
將大寫寬字元轉換為小寫。 |
towupper() |
將小寫寬字元轉換為大寫。 |
下列表格將說明 libc 中的字元比較函式 API。
表 2–8 libc 中的字元比較
程式庫常式 |
描述 |
---|---|
strcoll() |
排序字串 |
strxfrm() |
變換字串以進行比較 |
wcscoll() |
排序寬字元字串 |
wcsxfrm() |
變換寬字元字串以進行比較 |
下列表格將說明 libc 中的貨幣處理函式 API。
表 2–9 libc 中的貨幣格式
程式庫常式 |
描述 |
---|---|
localeconv() |
取得目前語言環境的貨幣格式資訊 |
strfmon() |
將貨幣值轉換為字串表示式 |
下列表格將說明 libc 中的日期與時間格式。
表 2–10 libc 中的日期與時間格式
程式庫常式 |
描述 |
---|---|
getdate() |
轉換使用者格式日期與時間。 |
strftime() |
將日期與時間轉換為字串表示式。%u 轉換函式遵循系統介面和標頭第 2 版第 4 次修訂中的 X/Open CAE 規格。此函式以十進位數字 [1,7] 來表示工作日,1 代表星期一。 |
strptime() |
日期與時間轉換。 |
下列表格將說明 libc 中的多位元組處理函式 API。
表 2–11 libc 中的多位元組處理
程式庫常式 |
描述 |
---|---|
btowc() |
單一位元組至寬字元的轉換 |
mblen() |
取得字元中的位元組數目 |
mbrlen() |
取得字元中的位元組數目 (可重新開始計數) |
mbrtowc() |
將字元轉換為寬字元程式碼 (可重新開始計數) |
mbsinit() |
決定轉換物件的狀態 |
mbsrtowcs() |
將字串轉換為寬字元字串 (可重新開始計數) |
mbstowcs() |
將字串轉換為寬字元字串 |
mbtowc() |
將字元轉換為寬字元程式碼。 |
下列表格將說明 libc 中的寬字元與字串處理。
表 2–12 libc 中的寬字元和字串處理
程式庫常式 |
描述 |
---|---|
wcrtomb() |
將寬字元程式碼轉換為字元 (可重新開始計數) |
wcscat() |
串接寬字元字串 |
wcschr() |
尋找寬字元字串中的字元 |
wcscmp() |
比較寬字元字串 |
wcscpy() |
複製寬字元字串 |
wcscspn() |
傳回未出現在另一個寬字元字串的字串長度 |
wcslen() |
取得寬字元字串的長度 |
wcsncat() |
將寬字元字串串接至長度 n |
wcsncmp() |
比較寬字元字串至長度 n |
wcsncpy() |
將寬字元字串複製為長度 n |
wcspbrk() |
傳回出現在另一個寬字元字串的字元後的字串 |
wcsrchr() |
從右邊開始尋找寬字元字串中的字元 |
wcsrtombs() |
將寬字元字串轉換為字串 (可重新開始計數) |
wcsspn() |
傳回出現在另一個寬字元字串的字串長度 |
wcstod() |
將寬字元字串轉換為雙精度 |
wcstok() |
在寬字元字串之間移動記號 |
wcstol() |
將寬字元字串轉換為長整數 |
wcstombs() |
將寬字元字串轉換為多位元組字串 |
wcstoul() |
將寬字元字串轉換為無符號長整數 |
wscwcs() |
尋找寬字元字串中的字串 |
wcswidth() |
決定寬字元字串的欄數位置 |
wctob() |
寬字元至單一位元組的轉換 |
wctomb() |
將寬字元轉換為多位元組字元 |
wcwidth() |
決定寬字元的欄數位置 |
wscol() |
傳回寬字元字串的顯示寬度 |
wsdup() |
複製寬字元字串 |
下列表格將說明 libc 中的格式化寬字元輸入與輸出。
表 2–13 libc 中的格式化寬字元輸入與輸出
程式庫常式 |
描述 |
---|---|
fwprintf() |
列印格式化寬字元輸出 |
fwscanf() |
轉換格式化寬字元輸入 |
swprintf() |
列印格式化寬字元輸出 |
swscanf() |
轉換格式化寬字元輸入 |
vfwprintf() |
stdarg 引數清單的寬字元格式化輸出 |
vswprintf() |
stdarg 引數清單的寬字元格式化輸出 |
wprintf() |
列印格式化寬字元輸出 |
wscanf() |
轉換格式化寬字元輸入 |
wsprintf() |
根據格式產生寬字元字串 |
wsscanf() |
格式化輸入轉換 |
這個表格將說明 libc 中的寬字串函式 API。
表 2–14 libc 中的寬字串
程式庫常式 |
描述 |
---|---|
wcsstr() |
尋找寬字元子字串 |
wmemchr() |
在記憶體中尋找寬字元 |
wmemcmp() |
比較記憶體中的寬字元 |
wmemcpy() |
複製記憶體中的寬字元 |
wmemmove() |
使用重疊區域複製記憶體中的寬字元 |
wmemset() |
設定記憶體中的寬字元 |
wscasecmp() |
比較寬字元字串,忽略大小寫的差異 |
wsncasecmp() |
程序碼字串作業 |
下列表格將說明 libc 中的寬字元輸入與輸出。
表 2–15 libc 中的寬字元輸入與輸出
程式庫常式 |
描述 |
---|---|
fgetwc() |
從串流中取得多位元組字元,並轉換為寬字元 |
fgetws() |
從串流中取得多位元組字串,並轉換為寬字元 |
fputwc() |
將寬字元轉換為多位元組字元,並放入串流中 |
fputws() |
將寬字元轉換為多位元組字串,並放入串流中 |
fwide() |
設定串流方向 |
getwchar() |
從 stdin 中取得多位元組字元,並轉換為寬字元 |
getws() |
從 stdin 中取得多位元組字串,並轉換為寬字元 |
putwchar() |
將寬字元轉換為多位元組字元,並放入stdin 串流中 |
putws() |
將寬字元轉換為多位元組字串,並放入 stdin 串流中 |
ungetwc() |
將寬字元後推至輸入串流中 |
新的 genmsg 公用程式可以與 catgets() 函式家族配合使用,以建立國際化來源訊息目錄。這個公用程式會檢查 catgets 中函式呼叫的來源程式檔案,並從尋獲的資訊建立來源訊息目錄。例如:
% cat example.c ... /* NOTE: %s is a file name */ printf(catgets(catd, 5, 1, "%s cannot be opened.")); /* NOTE: "Read" is a past participle, not a present tense verb */ printf(catgets(catd, 5, 1, "Read")); ... % genmsg -c NOTE example.c The following file(s) have been created. new msg file = "example.c.msg" % cat example.c.msg $quote " $set 5 1 "%s cannot be opened" /* NOTE: %s is a file name */ 2 "Read" /* NOTE: "Read" is a past participle, not a present tense verb */
在上述的範例中,genmsg 會在來源檔案上執行 example.c,並產生了名為 example.c.msg 的來源訊息目錄。-c 選項 (包含引數 NOTE) 會使得 genmsg 在目錄中包含註釋。若是來源程式中的註釋包含指定的字串,則下一個從 catgets 呼叫中所擷取的字串之後的訊息目錄便會出現註釋。
您可以使用 genmsg,自動為訊息集合中的訊息計數。
若要產生格式化的訊息目錄檔,請使用 gencat(1) 公用程式。
關於可攜式訊息檔案 (.po 檔案) 的訊息擷取公用程式以及如何從 .po 檔案產生訊息物件檔案 (.mo 檔案) 的資訊。
您可以使用 geniconvtbl 公用程式,建立使用者自行定義的字碼集轉換器。
這個公用程式使用像是 iconv(1) 和 iconv(3C) 的標準系統公用程式和介面,來啟用使用者自行定義和使用者可自訂的字碼集轉換。這個功能加強了應用程式處理不相容資料類型 (特別是從專用及傳統應用程式所產生的資料) 的功能。也支援對現存 Solaris 字碼集轉換的修改。
此公用程式的範例輸入來源檔位於 /usr/lib/iconv/geniconvtbl/srcs/ 目錄中。
一旦使用者自行定義字碼轉換已準備好並正確放置之後,使用者可以使用 32 位元和 64 位元 Solaris 作業系統上 iconv(1) 公用程式和 iconv(3C) 函式的字碼轉換。
國際化網域名稱 (IDN) 使得主機和網域名稱可以使用非英文原生語言名稱。若要使用非英文的主機和網域名稱,請在將這些名稱傳送到解析程式常式 (RFC 3490 中指定的) 之前,先轉換為 ASCII 相容編碼 (ACE) 的編碼名稱。對於不支援 IDN 的系統管理應用程式,系統管理員也需要在檔案系統和應用程式中使用 ACE 名稱。
請參閱 RFC 3490 應用程式中的國際化網域名稱 (IDNA)。
libidnkit(3EXT) 中用於國際化網域名稱的 API,在 UTF-8 或應用程式語言環境的字碼集與 ACE 之間,提供方便的轉換。如果使用了 idn_decodename2(3EXT),您也可以指定任意字碼集名稱做為輸入引數的字碼集。
來源字碼 |
目的字碼 |
---|---|
ACE ACE-ALLOW-UNASSIGNED |
UTF-8 UTF-8 |
UTF-8 UTF-8 |
ACE ACE-ALLOW-UNASSIGNED |
ACE 和 ACE-ALLOW-UNASSIGNED iconv 字碼轉換名稱具有下列含義:
ACE。
在 iconv 字碼轉換中,ACE 是一個用來參閱到 ASCII 相容編碼 (定義於 RFC 3490) 的 fromcode 或 tocode 名稱。此轉換使用 STD3 ASCII 規則。不允許使用未指定的字元。ACE 通常用於儲存或是給定機器的主機或網域名稱。
ACE-ALLOW-UNASSIGNED。
ACE-ALLOW-UNASSIGNED 執行與 ACE 相同的作業,並且 ACE-ALLOW-UNASSIGNED 允許使用未指定的字元。ACE-ALLOW-UNASSIGNED 通常用於查詢目的。
下列是從 ACE 轉換為 UTF-8 的範例,輸入來源是 hostnames.txt 檔案。輸出為標準輸出。
system% iconv -f ACE -t UTF-8 hostnames.txt
專屬的 IDN 轉換公用程式 idnconv(1) 提供 IDN 轉換及許多選項。這些選項可以控制轉換細節。
如需關於 IDN、轉換常式和 iconv 字碼轉換的資訊,請參閱「libidnkit(3LIB) 線上說明手冊」、「idn_decodename(3EXT) 線上說明手冊」、「idn_decodename2(3EXT) 線上說明手冊」、「idn_encodename(3EXT) 線上說明手冊」以及「iconv_en_US.UTF-8(5) 線上說明手冊」。