2016年11月6日日曜日

多言語化支援モジュール "node-m17n"

Node.jsで多言語化を支援するモジュール node-m17n を公開しました。


特徴

Node.js用の多言語化モジュールはいくつかありますが、これの特徴は「メッセージ」と「言語情報」と「地域情報」を独立に管理できることです。

作ったきっかけ

日本に住んでいると忘れがちですが、世界では同じ言語が複数の国で使われていたり、逆にひとつの国に公用語が複数あることがめずらしくありません。
むしろ日本語のような「言語=国」がほぼ成立する言語のほうがめずらしいといえるかもしれません。

ウェブサービスの多言語化というと、表示するメッセージの翻訳ばかり意識が行きがちですが、実際には
  • 数値の桁区切り記号・小数点の記号
  • 日付の表記方法
  • 時差・タイムゾーン
など、クライアントの国や地域に合わせた細かな調整がたくさん必要です。
これらの情報は言語が同じでも国によって異なりますし、さらに言えば時差は東西に広い国だと国の中でも違う場合があるので話がややこしくなります。

つまり、本当にウェブサービスを世界中の人に使ってほしければ、メッセージの翻訳の他にも必要なことはたくさんあるのです。

しかし、巷にあふれている多言語化支援ツールはメッセージの翻訳に焦点を当てたものがとても多く、国・地域まで考慮したものはあまり見当たりません。

そこでnode-m17nです。

node-m17nを使えば、クライアントの環境にあわせたメッセージの翻訳はもちろん、国や地域の固有の情報も簡単に調整できます。

使い方

まずはnpmでインストール。
$ npm install --save node-m17n
翻訳データの他に「言語情報」「地域情報」のデータが必要ですが必須ではありません。
省略した場合はnode-m17nに用意されているデータ(日本語/英語/フランス語、日本/アメリカ/イギリス/フランスのみ)を使います。

用意されているデータ以外にもいろいろ情報を詰めたいとか、ドイツ語とかも入れたい場合は自分でデータをYAML形式で作ってください。
いいのができたらプルリクください。追加しておきます。

次に以下のコードをサーバの初期化フェーズに書き、一度だけ実行します。
var path = require("path");
var m17n = require("node-m17n");

m17n.configure({
    dirLanguages: path.resolve("languages"),
    dirRegions: path.resolve("regions"),
    dirMessages: path.resolve("messages"),
    fallback: "ja-jp"
});
言語情報、地域情報、メッセージデータのディレクトリを指定し、fallbackにはクライアントの環境に合うデータが見つからなかった場合に使うフォールバック情報をIETF言語タグの"languageまたは"language-region"形式で指定します。

次に以下のコードをリクエスト処理フェーズに書き、リクエストごとに実行します。
var m = m17n({
    ietf: "<多言語化対象のIETF言語タグを直接指定>",
    acceptLanguage: "<Accept-Language>リクエストヘッダの値",
    fallback: "<このリクエスト内で使うフォールバック情報>"
});
オプションはいずれも必須ではありませんが、最低でもietfacceptLanguageのどちらかを渡さないと多言語化の意味がありません。

この2つは、以下のように使い分けます。
  • ietf…URLのパスやクエリストリング、ドメイン等で使用言語を直接指定する場合
    • http://example.com/ja/
    • http://example.com/?hl=en-US
    • http://fr.example.com/
  • acceptLanguage…URLは変えず、ブラウザの設定情報によって表示を変える場合
優先順位はietf>acceptLanguage>fallbackです。

最後に、メッセージや地域情報等が必要なところで以下のように書きます。
m.region.currency.sign; // 地域情報の通貨単位
m.lang.dir; // 言語情報の表記方向("ltr" / "rtl")
m._.message(); // メッセージデータファイルの"message"に入っている文字列
m._.messages.to.be.replaced({ // メッセージデータファイルの"messages.to.be.replaced"に入っている文字列の{aaa}を{bbb}に、{bbb}を{ccc}に、{ccc}を{aaa}に置換
    aaa: "{bbb}",
    bbb: "{ccc}",
    ccc: "{aaa}"
}));
この例からわかるとおり、多言語化情報はネストできます。また、メッセージは文字列ではなく関数なのでカッコを忘れないでください。

メッセージ中の文字列をを入力値やDBの値などで置き換えたい場合は、{xxx}と波括弧で囲い、引数に{xxx: "yyy"}のようなオブジェクト形式で渡してください。
このとき、一度置換された部分はその状態で確定されます。上記の例では{aaa}{bbb}に置換され、それがさらに{ccc}に置換され、最後に再び{aaa}に戻るわけではありません
この部分の実装は結構苦労しました。有用だと思うので、そのうち別ライブラリとして独立させるかもしれません。

諸事情で公開を急いだので、説明やサンプルコードが不足しています。これもそのうち充実させていきます。

ライセンス

MITライセンスです。自由に使ってください。

0 件のコメント:

コメントを投稿