> For the complete documentation index, see [llms.txt](https://willh.gitbook.io/build-web-application-with-golang-zhtw/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://willh.gitbook.io/build-web-application-with-golang-zhtw/10.0/10.1.md).

# 設定預設地區

## 什麼是 Locale

Locale 是一組描述世界上某一特定區域文字格式和語言習慣的設定的集合。locale 名通常由三個部分組成：第一部分，是一個強制性的，表示語言的縮寫，例如"en"表示英文或"zh"表示中文。第二部分，跟在一個下劃線之後，是一個可選的國家說明符，用於區分講同一種語言的不同國家，例如"en\_US"表示美國英語，而"en\_UK"表示英國英語。最後一部分，跟在一個句點之後，是可選的字符集說明符，例如"zh\_CN.gb2312"表示中國使用 gb2312 字符集。

GO 語言預設採用"UTF-8"編碼集，所以我們實現 i18n 時不考慮第三部分，接下來我們都採用 locale 描述的前面兩部分來作為 i18n 標準的 locale 名。

> 在 Linux 和 Solaris 系統中可以透過 `locale -a` 命令列舉所有支援的地區名，讀者可以看到這些地區名的命名規範。對於 BSD 等系統，沒有 locale 命令，但是地區資訊儲存在/usr/share/locale 中。

## 設定 Locale

有了上面對 locale 的定義，那麼我們就需要根據使用者的資訊(存取資訊、個人資訊、存取域名等)來設定與之相關的 locale，我們可以透過如下幾種方式來設定使用者的 locale。

### 透過域名設定 Locale

設定 Locale 的辦法之一是在應用執行的時候採用域名分級的方式，例如，我們採用 [www.asta.com](http://www.asta.com) 當做我們的英文站(預設站)，而把域名 [www.asta.cn](http://www.asta.cn) 當做中文站。這樣透過在應用裡面設定域名和相應的 locale 的對應關係，就可以設定好地區。這樣處理有幾點好處：

* 透過 URL 就可以很明顯的識別
* 使用者可以透過域名很直觀的知道將存取那種語言的站點
* 在 Go 程式中實現非常的簡單方便，透過一個 map 就可以實現
* 有利於搜尋引擎抓取，能夠提高站點的 SEO

我們可以透過下面的程式碼來實現域名的對應 locale：

```go
if r.Host == "www.asta.com" {
    i18n.SetLocale("en")
} else if r.Host == "www.asta.cn" {
    i18n.SetLocale("zh-CN")
} else if r.Host == "www.asta.tw" {
    i18n.SetLocale("zh-TW")
}
```

當然除了整域名設定地區之外，我們還可以透過子域名來設定地區，例如"en.asta.com"表示英文站點，"cn.asta.com"表示中文站點。實現程式碼如下所示：

```go
prefix := strings.Split(r.Host,".")

if prefix[0] == "en" {
    i18n.SetLocale("en")
} else if prefix[0] == "cn" {
    i18n.SetLocale("zh-CN")
} else if prefix[0] == "tw" {
    i18n.SetLocale("zh-TW")
}
```

透過域名設定 Locale 有如上所示的優點，但是我們一般開發 Web 應用的時候不會採用這種方式，因為首先域名成本比較高，開發一個 Locale 就需要一個域名，而且往往統一名稱的域名不一定能申請的到，其次我們不願意為每個站點去本地化一個配置，而更多的是採用 url 後面帶參數的方式，請看下面的介紹。

### 從域名參數設定 Locale

目前最常用的設定 Locale 的方式是在 URL 裡面帶上參數，例如 [www.asta.com/hello?locale=zh](http://www.asta.com/hello?locale=zh) 或者 [www.asta.com/zh/hello](http://www.asta.com/zh/hello) 。這樣我們就可以設定地區：`i18n.SetLocale(params["locale"])`。

這種設定方式幾乎擁有前面講的透過域名設定 Locale 的所有優點，它採用 RESTful 的方式，以使得我們不需要增加額外的方法來處理。但是這種方式需要在每一個的 link 裡面增加相應的參數 locale，這也許有點複雜而且有時候甚至相當的繁瑣。不過我們可以寫一個通用的函式 url，讓所有的 link 地址都透過這個函式來產生，然後在這個函式裡面增加`locale=params["locale"]`參數來緩解一下。

也許我們希望 URL 地址看上去更加的 RESTful 一點，例如：[www.asta.com/en/books](http://www.asta.com/en/books) (英文站點)和 [www.asta.com/zh/books](http://www.asta.com/zh/books) (中文站點)，這種方式的 URL 更加有利於 SEO，而且對於使用者也比較友好，能夠透過 URL 直觀的知道存取的站點。那麼這樣的 URL 地址可以透過 router 來取得 locale(參考 REST 小節裡面介紹的 router 外掛實現)：

```go
mux.Get("/:locale/books", listbook)
```

### 從客戶端設定地區

在一些特殊的情況下，我們需要根據客戶端的資訊而不是透過 URL 來設定 Locale，這些資訊可能來自於客戶端設定的喜好語言(瀏覽器中設定)，使用者的 IP 地址，使用者在註冊的時候填寫的所在地資訊等。這種方式比較適合 Web 為基礎的應用。

* Accept-Language

客戶端請求的時候在 HTTP 頭資訊裡面有`Accept-Language`，一般的客戶端都會設定該資訊，下面是 Go 語言實現的一個簡單的根據`Accept-Language`實現設定地區的程式碼：

```go
AL := r.Header.Get("Accept-Language")
if AL == "en" {
    i18n.SetLocale("en")
} else if AL == "zh-CN" {
    i18n.SetLocale("zh-CN")
} else if AL == "zh-TW" {
    i18n.SetLocale("zh-TW")
}
```

當然在實際應用中，可能需要更加嚴格的判斷來進行設定地區

* IP 地址

  另一種根據客戶端來設定地區就是使用者存取的 IP，我們根據相應的 IP 函式庫，對應存取的 IP 到地區，目前全球比較常用的就是 GeoIP Lite Country 這個函式庫。這種設定地區的機制非常簡單，我們只需要根據 IP 資料庫查詢使用者的 IP 然後回傳國家地區，根據回傳的結果設定對應的地區。
* 使用者 profile

```
當然你也可以讓使用者根據你提供的下拉選單或者別的什麼方式的設定相應的 locale，然後我們將使用者輸入的資訊，儲存到與它帳號相關的 profile 中，當用戶再次登陸的時候把這個設定複寫到 locale 設定中，這樣就可以保證該使用者每次存取都是基於自己先前設定的 locale 來獲得頁面。
```

## 總結

透過上面的介紹可知，設定 Locale 可以有很多種方式，我們應該根據需求的不同來選擇不同的設定 Locale 的方法，以讓使用者能以它最熟悉的方式，獲得我們提供的服務，提高應用的使用者友好性。

## links

* [目錄](https://github.com/doggy8088/build-web-application-with-golang-zhtw/tree/80abfb9f0c5f9f703922f4114d78f2e3c26a4dfb/preface.md)
* 上一節: [國際化和本地化](/build-web-application-with-golang-zhtw/10.0.md)
* 下一節: [本地化資源](/build-web-application-with-golang-zhtw/10.0/10.2.md)
