iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 18
0
Modern Web

BeeGo系列 第 18

Multiple language

今天來介紹 Multiple language,BeeGo 主要是使用 ini 來做多國語言翻譯檔,並不是使用 gettext。

官方文件寫很長,是為了說明官方網站(BeeWeb)的作法。

說明

BeeWeb 裡建立 baseRouter (routers/router.go),同時繼承了 beego.Controller 與 i18n.Locale,於是 baseRouter 就有了 i18n.Locale 的 Tr() 函式。然後,其他像 HomeRouter 等,再去繼承 baseRouter。

在程式啟動時,則注入 i18n 函式到 template 模組裡,並且呼叫函式去載入多國語言翻譯檔。

使用

了解 BeeWeb 怎麼做以後,我們來參考 BeeWeb 作法來改寫 Controller。

先安裝 i18n 模組

go get github.com/beego/i18n

接著在 controllers 資料夾裡新增 base.go,我們要在裏面新增一個 BaseController。基本上這個檔案是從 beeweb 的 routers/router.go 來的,我移除了暫時用不到的部份。

package controllers

import (
        "strings"

        "github.com/astaxie/beego"
        "github.com/beego/i18n"
)

var langTypes []*langType // Languages are supported.

// langType represents a language type.
type langType struct {
        Lang, Name string
}

// BaseController implemented global settings for all other controllers.
type BaseController struct {
        beego.Controller
        i18n.Locale
}

// Prepare implemented Prepare method for BaseController.
func (this *BaseController) Prepare() {
        // Redirect to make URL clean.
        if this.setLangVer() {
                i := strings.Index(this.Ctx.Request.RequestURI, "?")
                this.Redirect(this.Ctx.Request.RequestURI[:i], 302)
                return
        }
}

// setLangVer sets site language version.
func (this *BaseController) setLangVer() bool {
        isNeedRedir := false
        hasCookie := false

        // 1. Check URL arguments.
        lang := this.Input().Get("lang")

        // 2. Get language information from cookies.
        if len(lang) == 0 {
                lang = this.Ctx.GetCookie("lang")
                hasCookie = true
        } else {
                isNeedRedir = true
        }

        // Check again in case someone modify by purpose.
        if !i18n.IsExist(lang) {
                lang = ""
                isNeedRedir = false
                hasCookie = false
        }

        // 3. Get language information from 'Accept-Language'.
        if len(lang) == 0 {
                al := this.Ctx.Request.Header.Get("Accept-Language")
                if len(al) > 4 {
                        al = al[:5] // Only compare first 5 letters.
                        if i18n.IsExist(al) {
                                lang = al
                        }
                }
        }

        // 4. Default language is English.
        if len(lang) == 0 {
                lang = "en-US"
                isNeedRedir = false
        }

        curLang := langType{
                Lang: lang,
        }

        // Save language information in cookies.
        if !hasCookie {
                this.Ctx.SetCookie("lang", curLang.Lang, 1<<31-1, "/")
        }

        restLangs := make([]*langType, 0, len(langTypes)-1)
        for _, v := range langTypes {
                if lang != v.Lang {
                        restLangs = append(restLangs, v)
                } else {
                        curLang.Name = v.Name
                }
        }
        // Set language properties.
        this.Lang = lang
        this.Data["Lang"] = curLang.Lang
        this.Data["CurLang"] = curLang.Name
        this.Data["RestLangs"] = restLangs

        return isNeedRedir
}

然後,在 controllers 資料夾裡新增一個 init.go ,這裡負責載入多國語系翻譯檔並且注入 i18n 函式,讓 template 也可以使用。那什麼時候會執行呢?這裡有提供 InitApp() 。等等我們會修改 main.go ,在啟動的時候去呼叫這個 InitApp()

package controllers

import (
        "strings"

        "github.com/astaxie/beego"
        "github.com/beego/i18n"
)

func initLocales() {
        // Initialized language type list.
        langs := strings.Split(beego.AppConfig.String("lang::types"), "|")
        names := strings.Split(beego.AppConfig.String("lang::names"), "|")
        langTypes = make([]*langType, 0, len(langs))
        for i, v := range langs {
                langTypes = append(langTypes, &langType{
                        Lang: v,
                        Name: names[i],
                })
        }

        for _, lang := range langs {
                beego.Trace("Loading language: " + lang)
                if err := i18n.SetMessage(lang, "conf/"+"locale_"+lang+".ini"); err != nil {
                        beego.Error("Fail to set message file: " + err.Error())
                        return
                }
        }
}

func initTemplates() {
        beego.AddFuncMap("i18n", i18n.Tr)
}

func InitApp() {
        initTemplates()
        initLocales()
}

修改 main.go

import (
  // ...略...
  "my/hello/controllers"
  // ...略...
)

// ...略...
func init() {
  // ...略...
  controllers.InitApp()
}

// ...略...

最後修改 controllers/about.go 與 views/about.tpl ,以及在 conf 裡新增多國語言翻譯檔

// controllers/about.go
// ...略...
// AboutController operations for About
type AboutController struct {
        BaseController  // 改成繼承 BaseController
}
// ...略...

func (c *AboutController) Get() {
  // ...略...
  c.Data["Message"] = c.Tr("Cat is on the piano")
  // ...略...
}

  <!-- views/about.tpl -->
  <p>
    {{ .Message }}
  </p>
  <p>
    {{ i18n .Lang "Dog is on the piano" }}
  </p>

conf/locale_en-US.ini

Cat is on the piano=Cat is on the piano
Dog is on the piano=Dog is on the piano

conf/locale_zh-TW.ini

Cat is on the piano=貓在鋼琴上
Dog is on the piano=狗在鋼琴上

在 conf/base.conf 加入 [lang] 區段設定

[lang]
types=en-US|zh-TW
names=English|繁體中文

小結

這樣修改以後,就可以使用多國語言了,基本上決定語言的順序是這樣:

  1. Query parameter → lang
  2. Cookie 裡的 lang
  3. HTTP 請求裡的 Accept-Language header
  4. 使用 en-US

完整的程式碼可以看 github


上一篇
訊息顯示
下一篇
Logging
系列文
BeeGo30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言