ElixirとI18N

ElixirのI18N対応について。すぐ出てくるライブラリは下の2つあたり。

chrismccord/linguist
https://github.com/chrismccord/linguist

elixir-lang/gettext
https://github.com/elixir-lang/gettext

前者はProgramming Phoenixという来年1月発売予定の本の執筆者が作ってるライブラリで、
Rubyのi18nに近い使い方ができそうです。辞書ファイルはyamlで定義するやつ。

後者は古き良きgettext(cf. Wikipedia)といった感じです。こちらは.poファイルという形式の辞書ファイルを利用します。
今回はあるライブラリへの提案をするという背景もあり、gettextを試してみました。
Phoenix製Webアプリの開発だったら前者を試すかも。

導入

mixを利用している前提です。mix.exsにgettextを追加します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
defp deps do
[
{:gettext, "~> 0.7"}
]
end

# アプリケーション起動前に:getetxtが立ち上がるようにする。必須
def application do
[
applications: [:gettext, :logger]
]
end

# オプション: 指定しておくと`.po`ファイルが更新されるたびにコンパイルされます。
def project do
[
compilers: [:gettext] ++ Mix.compilers
]
end

モジュールの定義

1
2
3
defmodule YourLibraryName.Gettext do
use Gettext, otp_app: :your_library_name
end

辞書ファイルの定義

例えば日本語(ja_JP)に対応する辞書ファイル(.po)の初期パスは
priv/gettext/ja_JP/LC_MESSAGES/default.poとなります。

.poファイルは以下のような感じに記述します。

1
msgid "Hello, gettext"
msgstr "こんにちは、ゲットテクスト"

msgid "Hello, %{name}"
msgstr "こんにちは、%{name}"

利用方法

これを利用するには、ソースコード内で

1
2
3
4
import YourLibraryName.Gettext

def hello_gettext, do: gettext "Hello, gettext"
def hello(name), do: gettext "Hello, %{name}", name: name

のようにgettextを呼び出します。
他にも、単数/複数への対応といった英語圏ぽい機能もありますので、気になる方は以下をどうぞ。

Gettext – gettext v0.7.0

ロケールについて

デフォルトのロケールはconfig/config.exsあたりに記述するのが良さそうです。

1
config :your_library_name, YourLibraryName.Gettext, default_locale: "ja_JP"

また、コード中でロケールを変更することもできます。

1
2
3
4
5
# 取得
locale = Gettext.get_locale(YourLibraryName.Gettext)

# 設定
old_locale = Gettext.put_locale(YourLibraryName.Gettext, "en")

おまけ1: 既存のコードから辞書ファイルの雛形を作る

例えば既にあるライブラリに対してI18N対応を行う場合などを考えてみます。

まずは既存コードのリテラル文字列などをすべてgettext関数経由で呼ぶように変更します。

1
2
3
4
5
# "Hello, Elixir"
gettext "Hello, Elixir"

# "Hello, #{name}"
gettext "Hello, %{name}", name: name

次に、mixに追加されたタスクを実行します。

1
$ mix gettext.extract

これでpriv/gettext/default.potというテンプレートファイルが生成されます。

おまけ2: 気になる速度について

Gettextは可能な処理はランタイム時ではなくコンパイル時に行うように作られているそうです。
Elixirのコンパイル時間についてGettext開発者がElixirConf 2015で話した内容が閲覧できますので
興味のある方は聴いてみてください。

まとめ

駆け足ですが、ざっくりとElixirでのI18N対応方法について見ていきました。
ちょっとしたライブラリならgettextの仕組みで十分対応できそうですね。

実際に、これを利用してelixircnx/comeoninというライブラリをI18N化しました。
comeoninはパスワードのダイジェストを生成するためのライブラリで、簡易的なバリデーションのような仕組みを備えています。
例えばパスワード強度が足りない時に、I18N化されたメッセージが得られるという感じです。

元々英語だったのですが、日本語辞書を皮切りに、フランス語やドイツ語が追加されているようです。興味がある方は使ってみてください。

あと、Phoenix本、いい感じです。comeoninもこの本で知りました。β版ですが既に販売していますよ。

The Pragmatic Bookshelf | Programming Phoenix