2013-01-02 22 views
21

不一定專用於GAE我想,但我很好奇人們正在使用什麼來翻譯或本地化他們的Web應用程序。I18n與App Engine合作的策略

我自己的方法恐怕是無望的天真,真的只是一個手動的問題,通過根據用戶配置文件中記錄的語言環境值從數據存儲爲每個包加載一個實體。至少,這使得一些字符串翻譯到提供:

package foo 

... 

type Messages struct { 
    Locale string 
    ErrorDatastore string 
    LoginSuccessful string 
    ... 
} 

存儲與對應於語言環境的字符串ID,然後加載到大猩猩的上下文或類似:

const Messages ContextKey = iota 

... 

k := datastore.NewKey(c, "Messages", "en_US", 0, nil) 
m := new(Messages) 
if err := datastore.Get(c, k, m); err != nil { 
    ... 
} else { 
    context.Set(r, Messages, m) 
} 

這顯然是令人難以置信的有限,但至少可以通過context.Get(r,foo.Messages)從調用代碼中獲得字符串。任何人都可以將我指向更有用的實現,或者提出更好的方法嗎?

編輯(相關,但不是完全有用):

+3

關於建議編輯:我保留拼寫「本地化」的權利[正確方法](http://en.wikipedia.org/wiki/American_and_British_English_spelling_differences#-ise.2C_-ize_.28-isation.2C_-ization 0.29)。嘿,至少我在標記時使用了'z'! ;) –

+1

你期望從「更有用的實現」中得到什麼樣的功能?對於大多數國際化的應用程序,鍵值存儲(可能有一些格式代碼)應該可以正常工作。 –

+2

好吧,我想這是讓翻譯人員更容易完成工作的原因。我很好奇,如果有其他流行的方法(gettext等)的端口,我可能錯過了。現在,我使用[chrome.i18n的JSON格式](http://developer.chrome.com/extensions/i18n.html)將一個簡單的模塊拼湊在一起,如果沒有更完整的內容,我會將其作爲答案發布。 –

回答

9

Jonathan Chan指出Samuel Stauffer'sgo-gettext內見毫秒做的伎倆。給出的目錄:

~appname/ 
|~app/ 
| `-app.go 
|+github.com/ 
`-app.yaml 

開始(假設* nix中):

$ cd appname 
$ git clone git://github.com/samuel/go-gettext.git github.com/samuel/go-gettext 

源製劑不能使用_( 「要翻譯的字符串」)縮寫形式,due to underscore's special characteristics in Go。您可以使用-k標誌來告訴xgettext查找camelcase函數名稱「GetText」。

最小工作例如:

package app 

import (
    "fmt" 
    "log" 
    "net/http" 

    "github.com/samuel/go-gettext" 
) 

func init() { 
    http.HandleFunc("/", home) 
} 

func home(w http.ResponseWriter, r *http.Request) { 
    d, err := gettext.NewDomain("appname", "locale") 
    if err != nil { 
     log.Fatal("Failed at NewDomain.") 
    } 

    cat := d.GetCatalog("fr_FR") 
    if cat == gettext.NullCatalog { 
     log.Fatal("Failed at GetCatalog.") 
    } 

    fmt.Fprintf(w, cat.GetText("Yes.")) 
} 

創建模板:

$ xgettext -d appname -kGetText -s -o appname.pot app/app.go 

注意-k,沒有它,我將不再作爲輸出了xgettext不會承認的getText調用。在appname.pot中編輯相關字符串,電子郵件等。假設我們正在爲本地化法語:

$ mkdir -p locale/fr_FR/LC_MESSAGES 
$ msginit -l fr_FR -o french.po -i appname.pot 

編輯french.po:

# Appname l10n 
# Copyright (C) 2013 Wombat Inc 
# This file is distributed under the same license as the appname package. 
# Wombat <[email protected]>, 2013. 
# 
msgid "" 
msgstr "" 
"Project-Id-Version: appname v0.1\n" 
"Report-Msgid-Bugs-To: \n" 
"POT-Creation-Date: 2013-01-13 11:03+1300\n" 
"PO-Revision-Date: 2013-01-13 11:10+1300\n" 
"Last-Translator: Rich <[email protected]>\n" 
"Language-Team: French\n" 
"Language: fr\n" 
"MIME-Version: 1.0\n" 
"Content-Type: text/plain; charset=UTF-8\n" 
"Content-Transfer-Encoding: 8bit\n" 
"Plural-Forms: nplurals=2; plural=(n > 1);\n" 

#: app/app.go:15 
msgid "Yes." 
msgstr "Oui." 

生成二進制(即就會得到部署與應用程序的文件):

$ msgfmt -c -v -o locale/fr_FR/LC_MESSAGES/appname.mo french.po 

最終目錄結構:

~appname/ 
|~app/ 
| `-app.go 
|~github.com/ 
| `~samuel/ 
| `~go-gettext/ 
|  +locale/ 
|  |-catalog.go 
|  |-domain.go 
|  `-mo.go 
|~locale/ 
| `~fr_FR/ 
| `LC_MESSAGES/ 
| `-appname.mo 
`-app.yaml 

(go-gettext下的locale目錄保存測試數據,可以刪除部署。)

如果一切順利,訪問appname應顯示「Oui」。

+0

更正歡迎,這是我的新領域。 –

3

go-i18n是備選封裝一些很好的功能:

+0

go-i18n是否安全並行使用?這在這裏很重要,因爲OP希望在Go Web服務中使用它。我假設每個查詢都需要使用由Cookie配置的用於用戶語言的go-i18n的新對象實例? – Frankenstein

+1

@Frankenstein go-i18n裏面沒有同步;但是,同步不應該是必需的。您應該在網絡服務器的初始化階段將翻譯加載到go-i18n;在init()期間或在開始提供http請求之前。之後,狀態只被讀取,所以不需要同步。 –

-1

GNU Gettext被廣泛採用爲i18n解決方案的事實標準。

要直接從您的圍棋項目中使用.po文件並加載所有的翻譯記憶中有更好的表現,你可以使用我的包:https://github.com/leonelquinteros/gotext

這是相當簡單的,直接的一點。位於/path/to/locales/es_ES/default.po,你可以使用這個包加載和啓動消費的翻譯馬上:

所以,對於一個default.po文件(https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html GNU gettext的格式化後):

import "github.com/leonelquinteros/gotext" 

func main() { 
    // Configure package 
    gotext.SetLibrary("/path/to/locales") 
    gotext.SetLanguage("es_ES") 

    // Translate text from default domain 
    println(gotext.Get("Translate this text")) 
} 

如果你喜歡有在一個多字符串定義的翻譯「中心」的使用,您可以分析一個PO格式化字符串與蒲對象:

import "github.com/leonelquinteros/gotext" 

func main() { 
    // Set PO content 
    str := ` 
msgid "One apple" 
msgstr "Una manzana" 

msgid "One orange" 
msgstr "Una naranja" 

msgid "My name is %s" 
msgstr "Mi nombre es %s" 
` 

    // Create Po object 
    po := new(Po) 
    po.Parse(str) 

    // Get a translated string 
    println(po.Get("One orange")) 

    // Get a translated string using variables inside the translation 
    name := "Tom" 
    println(po.Get("My name is %s", name)) 
} 

正如你可以在最後一個例子看,它也可以使用裏面的變量translat離子串。

雖然大多數解決方案都非常相似,包括你自己,但使用通用格式作爲gettext可以帶來一些額外的好處。

此外,您的解決方案似乎不是安全的併發使用(當從幾個goroutines消耗)。這個軟件包可以處理所有的功能。還有單元測試的包裝和貢獻是值得歡迎的。