Locale

**地區設定**（locale），也稱作「在地化策略集」、「本地環境」，是表達程式使用者地區方面的軟體設定。不同系統、平台、與軟體有不同的地區設定處理方式和不同的設定範圍，但是一般地區設定最少也會包括語言和地區。作業系統的地區設定通常比較複雜。地區設定的內容包括：資料格式、貨幣金額格式、小數點符號、千分位符號、度量衡單位、通貨符號、日期寫法、日曆類型、文字排序、姓名格式、位址等等。

地區設定的主要目標是讓使用者選擇最適合他自己的設定。比如用以上的 Windows 作比喻：在控制面板的區域和語言選擇中，使用者可以選擇自己的字元集排序方法；當瀏覽檔案時，系統會使用「使用者選擇的排序」來排列檔案。

## 實際落實

電腦中一套定義使用者的語言、國家和用於定義使用者希望在其使用者介面上看到的各種可以改變的選擇的參數集合。通常一個地區設定識別碼至少包括一個語言識別碼和一個區域識別碼。

在 UNIX 和 Windows 中，地區設定的控制是不同的。在 UNIX 下，通常通過環境變數來控制地區設定。這些環境變數包括：LC\_ALL, LC\_CTYPE, LC\_TIME, 等等。你可以通過改變這些環境變數來控制你的程式或者命令所表現出來的地區設定，前提是這些程式或者命令必須是已經被國際化的和在地化的。在 Windows 下，你可以通過改變控制面板上的「語言 / 區域」中的區域的值來設定 Windows 的當前使用者的地區設定。

### Ubuntu 作業系統

在 Ubuntu 作業系統中，使用 man locale-gen 或 man locale 可獲得關於 locale 實現的細節。實際上是由 glibc 庫實現的。

locale 相關（環境）變數生效的優先順序：

1. LANGUAGE 指定個人對語言環境值的主次偏好，例如 zh\_CN:en\_US:en
2. LC\_ALL 這不是一個環境變數，是一個可被 C 語言庫函式 setlocale 設定的宏，其值可覆蓋所有其他的 locale 設定。因此預設時此值為空
3. LC\_xxx 可設定 locale 各方面（category）的值，可以覆蓋 LANG 的值。
4. LANG 指定預設使用的 locale 值

可以把上述環境變數設在 /etc/profile 或 /etc/environment 等系統初始檔案中。值得注意的是，若 LANG 或 LC\_ALL 被設定為 "C"，那麼 LANGUAGE 的值將被忽視。 

除 C 和 POSIX 這兩個 locale 名稱外，locale 的名稱並未標準化。Linux 平台與 Windows 系統的 locale 名稱有很大不同。Linux 名稱的命名規則為：

```
 language[_territory[.codeset]][@modifier]
```

其中 language 是 ISO 639-1 標準中定義的雙字母的語言代碼，territory 是 ISO 3166-1 標準中定義的雙字母的國家和地區代碼，codeset 是字元集的名稱 (如 UTF-8 等)，而 modifier 則是某些 locale 變體的修正符。

bash 中的使用範例：

```
$ LC_TIME=en_US.UTF-8 date
Fri Oct 31 19:51:16 CST 2014
$ LC_TIME=fi_FI.UTF-8 date
pe 31.10.2014 19.52.00 +0800
$ LC_TIME=zh_CN.UTF-8 date
2014年 10月 31日 星期五 19:53:07 CST
```

相關系統檔案：

* 在檔案 /usr/share/i18n/SUPPORTED 中，列出了當前系統支援的所有 locale 與字元集的名字。
* 在目錄 /var/lib/locales/supported.d/ 下，列出了當前系統已經生成的所有 locale 的名字。
* 在檔案 /var/lib/locales/supported.d/local 中，列出了所有想要生成或已經生成的 locale 的名字
* 在目錄 /usr/lib/locale/<locale\_name>/LC\_\*，用 locale-gen 編譯出的 locale 檔案
* 在檔案 /usr/lib/locale/locale-archive 中，包含了很多本地已經生成的 locale 的具體內容，因此這個檔案往往很大。使用命令 localedef 管理這一檔案。使用 locale-gen 命令編譯出來的 locale 內容預設寫入該檔案中。
* 在檔案 /etc/default/locale 中，可以手動組態 locale 環境變數，LC\_CTYPE 之類
* 在目錄 /usr/share/i18n/charmaps 下，預設的 charmap 存放路徑
* 在目錄 /usr/share/i18n/locales 下，預設的 locale source file 存放路徑

相關系統命令：

* locale 列出當前採用的各項本地策略，這些由 LC\_\* 環境變數定義
* locale charmap 列出系統當前使用的字元集
* locale -a 列出系統中已經安裝的所有 locale
* locale -m 列出系統中已經安裝的所有 charmap
* locale-gen --purge 將 /usr/lib/locale/ 裡面的 locale 支援檔案刪掉
* 編輯檔案 /var/lib/locales/supported.d/local，增加需要的 locale 與字元集名字，如：

```
en_US.UTF-8 UTF-8
cs_CZ.UTF-8 UTF-8
cs_CZ.iso88592 iso88592
zh_CN.UTF-8 UTF-8
zh_CN.GBK GBK
zh_CN.GB2312 GB2312
zh_CN.GB18030 GB18030
```

儲存並關閉此檔案。執行 sudo dpkg-reconfigure --force locales，則重新生成字元集。

* 或者使用命令 sudo locale-gen en\_US.UTF-8，生成制定的 locale en\_US.UTF-8，並把這個 locale 名字加入檔案 /var/lib/locales/supported.d/local 中
* 或者使用命令 sudo locale-gen，生成所有列在檔案 /var/lib/locales/supported.d/local 中的 locale
* 或者

```
cd /usr/share/locales
sudo ./install-language-pack zh_CN
```

也可以安裝 zh\_CN 的相關語言套件。

* 或者使用命令 localedef -f UTF-8 -i zh\_CN zh\_CN.UTF8，從字元對映檔案 UTF-8，locale 原始檔 zh\_CN，編譯出 locale 稱為 zh\_CN.UTF8，存放入檔案 /usr/lib/locale/locale-archive 中
* 使用命令 localedef --list-archive，列出檔案 /usr/lib/locale/locale-archive 中所有可用的 locale 的名字
* sudo apt-get install language-selector language-env language-pack-zh-hans language-pack-zh-hant 安裝中文語言套件
* sudo nano /etc/default/locale 修改該檔案內容。

### Windows 作業系統

Windows SDK 規定，「語言」是與溝通有關的一組屬性的集合，包括所有允許的字元、通貨符號、日期時間格式等等。每個「語言」有一個語言名字與語言識別碼。語言往往還需要指出國家 / 地區，如「英語（美國）」使用的語言名字是「en-US」。

每個地區設定（locale）是一個「語言」及一個排序規則。Windows XP 支援超過 150 個地區設定（locale）；Windows Vista 支援超過 200 個地區設定（locale）;Windows 7 支援至少 365 個地區設定（locale）。每個地區設定（locale）有**地區設定名字 (Locale Name)** 與**地區設定識別碼 (Locale ID ,LCID)**。例如："de-DE\_phoneb" 是德國德語使用德式電話薄排序規則（該排序規則與拉丁字母序稍有不同）。「區域識別碼」(Locale ID ,LCID) 為 32 位元的值**，在程式設計中經常用到。LCID 構成為：**

```
+-------------+---------+-------------------------+-------------------------+
|   Reserved  | Sort ID |     SubLanguage ID      |   Primary Language ID   |
+-------------+---------+-------------------------+-------------------------+
31         20 19     16 15                    10  9                         0   bit
```

LCID 的低 10 位是主語言（primary language）的 ID；高 6 位指定次語言（sublanguage）。LCID 的低 16 位元稱為語言識別碼（language identifier），資料類型名為 LANGID。例如，中文作為主語言，編號是 0x04。作為次語言的台灣中文的編號是 0x01；簡體中文的編號是 0x02，香港中文是 0x03，新加坡中文是 0x04，澳門中文是 0x05。因此，「中國大陸簡體中文」的區域識別碼等於次語言的標識 0x02 左移 10 位，再加上主語言的標識 0x04，即 (0x02<<10)+0x04=2052，所以簡體中文的 LCID 是 2052。類似的，可以算出繁體中文的 LCID 是 1028。美國英語的 LCID 是 1033。使用 Windows 預定義宏，MAKELANGID (LANG\_CHINESE, SUBLANG\_CHINESE\_SIMPLIFIED) 的結果也是 2052。所有的語言 - 國家地區列表見：MSDN:Language Identifier Constants and Strings（頁面存檔備份，存於網際網路檔案館）

**排序識別碼**（Sort Order Identifier）占 4 位元，用於表示排序的方法。如簡體中文有 SORT\_CHINESE\_PRC（筆劃序）、SORT\_CHINESE\_PRCP（拼音序）。例如，使用筆劃序的簡體中文的 locale 名字為 "zh-CN\_stroke"。所有排序規則列表見：Sort Order Identifiers（頁面存檔備份，存於網際網路檔案館）。

**地區設定名字 (Locale Name)** 的命名格式為：

```
locale ::
    primaryLanguage[-Script][-SubLanguage[_sortorder]]
   | "locale-name"
   | "language[_countryORregion[.CodePage]]"
   | ".CodePage"
   | "C"
   | ""
   | NULL
```

可理解為：

* primaryLanguage 是 ISO 639-1 或 ISO 639-2/T 中定義的語言縮寫的小寫形式；
* Script 是 ISO 15924 定義的書寫系統的首字母大寫的 4 字母表示。例如，拉丁字母拼寫的烏茲別克語為「uz-Latn-UZ」。
* SubLanguage 是 ISO 3166-1 中定義的國家 / 地區二位字母代碼的大寫形式；例如：zh-CN\_stroke 的值為 MAKELCID (MAKELANGID (LANG\_CHINESE, SUBLANG\_CHINESE\_SIMPLIFIED), SORT\_CHINESE\_PRC)，即 133124。
* locale-name 形式是簡短的標準化字串，見表的 Language tag 欄目（頁面存檔備份，存於網際網路檔案館）。a short, IETF-standardized string; for example, en-US for English (United States) or bs-Cyrl-BA for Bosnian (Cyrillic, Bosnia and Herzegovina). These forms are preferred. For a list of supported locale names by Windows operating system version, see the Language tag column of the table in Appendix A: Product Behavior in [MS-LCID]: Windows Language Code Identifier (LCID) Reference. This resource lists the supported language, script, and region parts of the locale names. For information about the supported locale names that have non-default sort orders, see the Locale name column in Sort Order Identifiers. Under Windows 10 or later, locale names that correspond to valid BCP-47 language tags are allowed. For example, jp-US is a valid BCP-47 tag, but it is effectively only US for locale functionality.
* 同一個地區設定（locale），可以有多種字元集編碼表示。例如，Windows 作業系統的簡體中文的預設編碼字元集（即頁碼）是 GBK，即「936 (ANSI/OEM - Simplified Chinese GBK)」。而 Linux 作業系統統一使用 UTF8 字元集，所以 Linux 簡體中文的預設編碼字元集是 UTF8。所有頁碼列表見：Code Page Identifiers（頁面存檔備份，存於網際網路檔案館）。如果需要指出使用的頁碼，在上述字串最後用「.」區隔，後跟 Windows 頁碼數字或者「ACP」、「OCP」。例如："French\_Canada.1252"。指定頁碼只適用於 LC\_ALL 或 LC\_CTYPE。
* 可以對當前預設的 locale 只指明頁碼，形如 ".code\_page"。使用使用者預設語言與國家地區設定，即來自 GetUserDefaultLocaleName () 的結果。不建議採用此種方式，因為可能會產生不一致結果。

對於 C 標準庫函式 setlocale ()，指定參數 locale 的基本格式為：

```
Locale Name | language[_country_region[.code_page]] 
```

上述 language 與 country\_region 一般不用縮寫，詳細列表見 National Language Support (NLS) API Reference（頁面存檔備份，存於網際網路檔案館）。例如，對與中文簡體，使用字串 "chinese"、"chinese-simplified"、"chinese\_CHN"、"chs"，都能得到 "Chinese (Simplified)\_People's Republic of China.936" 效果。

作業系統有一個當前地區設定。使用者可以在控制面板的地區設定中改變它。每個地區設定有許多相關的資訊，編程時可以用 Locale information types 取得這些值的資訊。作業系統賦予每個執行緒一個地區設定，初始值為 LOCALE\_SYSTEM\_DEFAULT

相關系統 API 函式：

* GetUserDefaultLCID 取得當前使用者的預設 LCID。對於簡體中文作業系統返回值為 2052
* GetUserDefaultLocaleName 取得當前使用者的預設 locale 的名字。對於簡體中文作業系統該名字為 zh-CN
* GetSystemDefaultLCID 取得系統的預設 LCID。對於簡體中文作業系統返回值為 2052
* GetSystemDefaultLocaleName 取得系統預設 locale 的名字
* GetThreadLocale () 取得當前執行緒的 LCID
* SetThreadLocale 設定當前執行緒的 LCID。
* IsValidLocaleName 判斷一個字串是否為當前作業系統支援的 locale 的名字
* LocaleNameToLCID 從 locale 的名字取得它的 LCID
* GetLocaleInfoEx 取得指定 locale 的各方面的資訊
* EnumSystemLocalesEx 列舉當前作業系統支援的所有的 locale 的名字
* EnumCalendarInfoExEx 列舉指定 locale 的日曆資料。例如 zh-TW 有兩個日曆型，分別為「格里曆（本地）」與「格里曆（英文）」。
* EnumDateInfoExEx 列舉指定 locale 的各種 calendar 的日期格式。
* GetCalendarInfoEx 查詢指定 locale 指定日曆型的指定方面的資料。
* GetDateFormatEx 把時間資料轉換為指定格式的日期字串。
* GetTimeFormatEx 把時間資料轉換為指定格式的時間字串。
* GetDurationFormatEx 把一段持續時間的資料轉換為指定格式的字串。
* EnumSystemLanguageGroups 同一語言組可能共享鍵盤配置、輸入法、TT 字型、頁碼翻譯表等等。
* GetSystemDefaultLangID 系統預設的非 Unicode 語言
* GetKeyboardLayout 當前行程的輸入法
* GetSystemDefaultUILanguage 選單、對話方塊、Windows 訊息、INF 檔案、幫助檔案等的預設語言
* GetSystemPreferredUILanguages 作業系統使用的選單、對話方塊、Windows 訊息、INF 檔案、幫助檔案等的語言
* GetUserDefaultUILanguage 使用者使用的選單、對話方塊、Windows 訊息、幫助檔案等的語言
* GetUserPreferredUILanguages 使用者使用的選單、對話方塊、Windows 訊息、幫助檔案等的語言集合
* GetThreadPreferredUILanguages 當前執行緒使用的 UI 語言集合

#### 列表

## 參見

* 國際化與在地化
* iconv
* gettext

## 外部連結

* 微軟 MSDN 中的區域識別碼列表（英文） http://msdn.microsoft.com/en-us/library/0h88fahh.aspx（頁面存檔備份，存於網際網路檔案館）
* https://web.archive.org/web/20110925084131/http://www.chinaue.com/tool/vbs/html/vsmsclcid.htm

## 參考文獻