2013-01-02 10 views
21

GAEには必ずしも限定されませんが、私は人々がウェブアプリケーションの翻訳やローカライズに使用しているものについて興味があります。Go for App EngineのためのI18nの戦略

私自身のアプローチ私は、ユーザーのプロファイルに記録されたロケール値に基づいて各パッケージのデータストアからエンティティを読み込むことによって、まったく素朴な問題であることを懸念しています。少なくとも、これを提供するために、いくつかの文字列の翻訳を可能にする:

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) 
} 

明らかに非常に限られている:

package foo 

... 

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

ストアを文字列IDは、ロケールに対応して、その後、ゴリラのコンテキストまたは類似のロード少なくとも、context.Get(r、foo.Messages)を介してコードを呼び出して文字列を利用できるようにします。誰かがより便利な実装で私を指すことができる、またはより良いアプローチを提案する?

編集(関連するが、完全には有用ではない):

+3

提案された編集について:私は "ローカリゼーション" [正しい方法]を綴る権利を有します(http://en.wikipedia.org/wiki/American_and_British_English_spelling_differences#-ise.2C_-ize_.28-isation.2C_-ization 29)。ねえ、少なくともタグ付けするときに私は 'z'を使いました! ;) –

+1

「より便利な実装」からどのような機能を期待していますか?ほとんどのi18nアプリケーションでは、キー値ストア(おそらくいくつかのフォーマットコード付き)はうまく動作するはずです。 –

+2

さて、私は、翻訳者が仕事をより簡単にすることができるように思っています。私が見逃していた可能性のある他の一般的なアプローチ(gettextなど)のうちに行くポートがあるかどうか不思議でした。今、私は[chrome.i18nのJSON形式](http://developer.chrome.com/extensions/i18n.html)を使って簡単なモジュールをまとめています。 –

答えて

9

Jonathan Chan参照Samuel Stauffer'sgo-gettextポイントトリックを行うms。

~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を使用することはできません。ディレクトリを考えますxgettextに、-kフラグを使ってcamelcase関数名 "GetText"を探すように指示できます。

最小限の作業例:にxgettextはGetTextはへの呼び出しを認識しませんよう、それは何も出力されないだろうせずに、

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

注-k:

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.")) 
} 

がでテンプレートを作成します。関連する文字列を編集し、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のロケールディレクトリにはテストデータが格納されており、展開のために削除できます。)

すべてうまくいけば、appnameを訪問すると「Oui」と表示されます。

+0

訂正を歓迎します。これは私にとって新しい領域です。 –

3

go-i18nはいくつかの素晴らしい機能を備えた代替パッケージです:

  • CLDR plural rulesを実装します。
  • 変数を持つ文字列にはtext/templateを使用します。
  • 翻訳ファイルは単純なJSONです。
+0

go-i18nの実装は同時使用で安全ですか?これは、OPがgoウェブサービスでそれを使用したいので、ここでは重要です。私はすべてのクエリは、ユーザーの言語のためのクッキーによって構成されているgo-i18nの新しいオブジェクトインスタンスを使用する必要があると仮定しますか? – Frankenstein

+1

@Frankenstein go-i18nの内部には同期がありません。ただし、同期は必要ありません。ウェブサーバの初期化段階で翻訳をgo-i18nにロードする必要があります。 init()中またはhttp要求の処理を開始する前のいずれかです。その後、状態は読み込まれるだけなので、同期は必要ありません。 –

-1

GNU Gettextは、i18nソリューションのデファクトスタンダードとして広く採用されています。 https://github.com/leonelquinteros/gotext

それはかなり簡単だし、直接ポイントへ:

があなたの囲碁プロジェクトから直接.poファイルを使用してパフォーマンスを向上させるため、メモリ内のすべての翻訳をロードするには、私のパッケージを使用することができます。 /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)) 
} 

を使用すると、最後の例で見ることができるように、それは内部の変数を使用することも可能です翻訳されたイオン弦。

ほとんどのソリューションは、あなたのものを含め、かなり類似していますが、一般的なフォーマットをgettextとして使用すると、いくつかの利点があります。

また、あなたのソリューションは同時使用(いくつかのゴルーチンから消費された場合)では安全ではないようです。このパッケージはあなたのためにすべてのものを扱います。パッケージの単体テストもあり、寄付も大歓迎です。

関連する問題