21

必ずしも GAE に固有のものではないと思いますが、人々が Web アプリケーションを翻訳またはローカライズするために何を使用しているかについて興味があります。

ユーザーのプロファイルに記録されたロケール値に基づいて各パッケージのデータストアからエンティティをロードすることで、問題を解決するだけです。少なくともこれにより、いくつかの文字列の翻訳を提供できます。

package foo

...

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

ロケールに対応する文字列 ID で保存してから、Gorilla コンテキストなどにロードします。

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) を介して呼び出しコードから文字列を利用できるようにします。誰かがより有用な実装を教えてくれますか、またはより良いアプローチを提案できますか?

編集(関連しますが、完全に役立つわけではありません):

4

3 に答える 3

9

ジョナサン・チャンは、サミュエル・スタウファーの ゴーゲットテキストを指摘します。与えられたディレクトリ:

~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

Goにはアンダースコアの特殊な特性があるため、ソースの準備では_( "文字列を変換する")の短縮形を使用できません。-kフラグを使用して、キャメルケース関数名「GetText」を検索するようにxgettextに指示できます。

最小限の作業例:

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 <wombat@example.com>, 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 <rich@example.com>\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」と表示されます。

于 2013-01-12T23:11:16.513 に答える
4

go-i18nは、いくつかの優れた機能を備えた代替パッケージです。

于 2014-01-30T06:37:30.410 に答える
1

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

Go プロジェクトから直接 .po ファイルを使用し、すべての翻訳をメモリにロードしてパフォーマンスを向上させるには、私のパッケージを使用できます: https://github.com/leonelquinteros/gotext

それはかなり単純で、要点に直接的です。

そのため、default.po ファイル (GNU gettext: https://www.gnu.org/software/gettext/manual/html_node/PO-Files.htmlの後にフォーマットされた) がある/path/to/locales/es_ES/default.po場合、このパッケージを使用してそれをロードし、使用を開始できます。すぐに翻訳:

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 オブジェクトを使用して 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 として使用すると、いくつかの追加の利点が得られます。

また、ソリューションは同時使用に対して安全ではないようです(複数のゴルーチンから消費される場合)。このパッケージは、それらすべてを処理します。パッケージの単体テストもあり、貢献は大歓迎です。

于 2016-06-19T22:49:41.757 に答える