翻訳者から:これは、 ペルソナプロジェクトに関係する、Mozilla IdentityチームによるNode.jsシリーズの 11番目の記事です。
文字列を使用する
そのため、最初にi18n-abideモジュールをアプリケーションに接続し、gettext呼び出しで行をラップしました。 その後、翻訳チームがこれらの行を翻訳し、各言語の翻訳を準備しました。
それでは、Node.jsアプリケーションをローカライズされた文字列で動作させましょう。 poファイル形式の翻訳は、次の形式のファイルシステムにあります。
locale en LC_MESSAGES messages.po de LC_MESSAGES messages.po es LC_MESSAGES messages.po
アプリケーションの実行中に、これらのファイルから翻訳された行を抽出する必要があります。 これを行うには2つの方法があります。
- i18n-abideモジュールの同じgettext関数を使用するサーバー側。
- i18n-abideの一部でもあるgettext.jsスクリプトを使用して、クライアント側で。
これらのメソッドは両方とも、文字列がJSON形式であることが必要です。 サーバー側で翻訳する場合、それらはアプリケーションの起動時にロードされ、クライアントはHTTPリクエストを使用してロードします(または、ビルドプロセス中に縮小されたJavaScriptファイルに含めることができます)。
私たちの翻訳システムはGNU Gettextと互換性があるため、3番目の方法
-node-gettextモジュールもあります。 サーバー側の翻訳に非常に効果的です。
さらに、これはi18n-abideを使用する最も一般的な方法であるため、最初の方法を検討します。
compile-json
poファイルから文字列を抽出してJSON形式に変換するにはどうすればよいですか? この目的のためのスクリプトは、compile-jsonと呼ばれます。
翻訳ファイルがプロジェクトのルートのロケールフォルダーにあり、JSONファイルがstatic / i18nにあるとします。
$ mkdir -p static/i18n $ ./node_modules/.bin/compile-json locale static/i18n
次のファイル構造を取得します。
static i18n en messages.json messages.js de messages.json messages.js es messages.json messages.js
compile-jsonはすべてのpoファイルを調べ、それぞれに対してpo2json.jsスクリプトを呼び出します。これにより、対応する.jsonファイルと.jsファイルが生成されます。
スペイン語の翻訳を例に取ります。
彼は次のようになります。
"messages": { "": { "Project-Id-Version": " PACKAGE VERSION\nReport-Msgid-Bugs-To: \nPOT-Creation-Date: 2012-06-24 09:50+0200\nPO-Revision-Date: 2013-04-24 16:42-0700\nLast-Translator: Austin King <ozten@nutria.localdomain>\nLanguage-Team: German\nLanguage: de\nMIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8\nContent-Transfer-Encoding: 8bit\nPlural-Forms: nplurals=2; plural=(n != 1);\n" }, "Mozilla Persona": [ null, "Mozilla Personidada" ] } }
このファイルは、サーバー側、Node.jsアプリケーション、およびクライアント側の両方で使用でき、ajaxリクエストでプルします。
静的ディレクトリはインターネットからアクセスできるように開いているため、スペイン語の翻訳を取得するには、ファイル/i18n/es/messages.jsonを要求する必要があります。
静的ディレクトリは、エクスプレスフレームワークの一般的な合意であり、他のものを使用できます。 Node.jsとNginxなどのWebサーバーの両方を使用して翻訳ファイルを送信できます。
Poファイル自体も可能ですが、本番環境にアップロードする必要はありません。
構成
i18n-abideは、使用可能な言語と翻訳ファイルの場所を知るために設定する必要があります。 このような構成の例は、最初の部分に記載されています。
app.use(i18n.abide({ supported_languages: ['en-US', 'de', 'es', 'zh-TW'], default_lang: 'en-US', translation_directory: 'static/i18n' }));
- ここのsupported_languagesは、英語、ドイツ語、スペイン語、および繁体字中国語への翻訳があることをアプリケーションに示します。
- translation_directoryは、翻訳付きのjsonファイルがstatic / i18nディレクトリにあることを示しています。
translation_directoryパラメーターは、サーバー側のgettextにのみ必要であることに注意してください。
i18n-abideは、supported_languagesにリストされている言語から最も適切なものを選択しようとします。
モーターを始動します
したがって、構成が設定され、少なくとも1つのロケールで翻訳の準備ができたら、開始できます。 ブラウザで、優先言語を実行中のアプリケーションでチェックインしたい言語に変更します。

アプリケーションのいずれかのページに移動します。 翻訳に表示する必要があります。 たとえば、ペルソナのギリシャ語版は次のとおりです。

ぐちゃぐちゃ
翻訳の準備が整う前に多言語アプリケーションをテストするために、David Bowieのクリップ「
Labyrinth 」に触発された特別なモジュールを作成しました。
それを使用するには、supported_languagesおよびdebug_langパラメーターのit-CHなど、翻訳の準備がまだ整っていないロケールを追加します。
app.use(i18n.abide({ supported_languages: ['en-US', 'de', 'es', 'zh-TW', 'it-CH'], debug_lang: 'it-CH', ...
現在、ブラウザをスイス語イタリア語に切り替えると、i18n-abideはこの言語にgobbledygookを使用します。

これは、ヘブライ語など、右から左へのスペルの言語もサイトデザインでサポートされるようにするための便利な方法です。

もっと深く
国際化とローカリゼーションの表面に触れました。 Node.jsで多言語アプリケーションを開発すると、多くの興味深いニュアンスと予期しないトラップに遭遇します。 ここにそれらのいくつかがあります。
文字列補間
I18n-abideには、クライアント側とサーバー側の両方で使用できるフォーマット機能があります。 書式設定された文字列を受け取り、実行時にパラメータ値を置き換えます。 次の2つのバージョンで使用できます。
- %s-フォーマットは、フォーマットされた文字列と順番に置換されるパラメーターの配列で呼び出されます。
- %(name)s-パラメーターは、フィールド名が文字列内のパラメーター名と一致する必要があるオブジェクトとして転送されます。
formatは、HTMLマークアップを使用してpoファイルを詰まらせるのに使用できます。 3つの例を挙げます。
<%= gettext('<p>Buy <a href="/buy?prod=blue&type=ticket">Blue Tickets</a> Now!</p>') %> <p><%= format(gettext('Buy <a href="%s">Blue Tickets</a> Now!'), ['/buy?prod=blue&type=ticket']) %></p> <p><%= format(gettext('Buy <a href="%(url)s">Blue Tickets</a> Now!'), {url: '/buy?prod=blue&type=ticket'}) %></p>
poファイルでは、それぞれの行は次のようになります。
msgid "<p>Buy <a href=\"/buy?prod=blue&type=ticket\">Blue Tickets</a> Now!</p>" msgid "Buy <a href="%s">Blue Tickets</a> Now!" msgid "Buy <a href="%(url)s">Blue Tickets</a> Now!"
最初の例では、文字列にタグが含まれています
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "
. ! - , . URL.
format , , HTML, , .
, . , URL. - .
- , :
<p><%= format(gettext('Welcome back, %(user_name)s'), {user_name: user.name}) %></p>
, .
. CSS, .
CSS. . , .
. , 100%- , , .
, . .
, .
: " Node.js " " Node " " , " " . 1 — , , " " , " " . 2 — etagify " " - node-convict " " . 3 — " " Node.js. 1 " " Node.js. 2: " " Node.js. 3: " " Awsbox - PaaS- Node.js Amazon "