Elixir Advent Calendar 2014 20日目。前日は @ma2ge さんの [excoveralls で Elixir プロジェクトのカバレッジレポートを取る] (http://qiita.com/ma2ge/items/8bca27709380f8320d9e) でした。
はじめに
elixir自体はUTF-8を採用しているため、いわゆる国際化(i18n)されています。しかしながら、多言語化(m17n)はされておらず、基本は英語(en)のみです。iexにはドキュメントが豊富に揃っているのにもったいないと思い、地域化(l10n)してみました。今回は、その宣伝(すみません)をかねて、elixirリファレンスの日本語版を組み込む方法です。
準備
l10n_elixir というパッケージをcloneします。
air13:erl k-1$ git clone https://github.com/k1complete/l10n_elixir.git
Cloning into 'l10n_elixir'...
remote: Counting objects: 813, done.
remote: Total 813 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (813/813), 1.12 MiB | 229.00 KiB/s, done.
Resolving deltas: 100% (321/321), done.
Checking connectivity... done.
air13:erl k-1$
その後、ビルドすると、依存パッケージをダウンロードしながらビルドされます。
air13:l10n_elixir k-1$ mix deps.get
* Getting exgettext (https://github.com/k1complete/exgettext.git)
Cloning into '/Users/k-1/work/erl/l10n_elixir/deps/exgettext'...
remote: Counting objects: 403, done.
remote: Total 403 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (403/403), 202.85 KiB | 149.00 KiB/s, done.
Resolving deltas: 100% (200/200), done.
Checking connectivity... done.
* Getting l10n_iex (https://github.com/k1complete/l10n_iex.git)
Cloning into '/Users/k-1/work/erl/l10n_elixir/deps/l10n_iex'...
remote: Counting objects: 108, done.
remote: Total 108 (delta 0), reused 0 (delta 0)
(略)
==> l10n_elixir
Compiled lib/l10n_elixir.ex
Generated l10n_elixir.app
msgfmt for l10n_elixir
priv/po/ja.po /Users/k-1/work/erl/l10n_elixir/_build/dev/lib/l10n_elixir/priv/lang/ja/l10n_elixir.exmo
air13:l10n_elixir k-1$
つかってみる
ビルドできたので、ためしに使ってみます。試しで使うためには、先ほどビルドしたディレクトリでiex -S mixとすることで、現在のプロジェクト(つまりl10n_elixir)を読み込むことができますので、それを利用します。
air13:l10n_elixir k-1$ iex -S mix
Erlang/OTP 17 [erts-6.3] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Interactive Elixir (1.1.0-dev) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> h Enum.into/2
def into(collection, list)
Inserts the given enumerable into a collectable.
Examples
┃ iex> Enum.into([1, 2], [0])
┃ [0, 1, 2]
┃
┃ iex> Enum.into([a: 1, b: 2], %{})
┃ %{a: 1, b: 2}
iex(2)>
英語のままですが、これは、ヘルパを有効にしていないためです。以下のコマンドでヘルパを有効にした後、同じことをしてみましょう。
iex(2)> import Exgettext.Helper
nil
iex(3)> h Enum.into/2
def into(collection, list)
collectableに与えられたenumerableを挿入します。
例
┃ iex> Enum.into([1, 2], [0])
┃ [0, 1, 2]
┃
┃ iex> Enum.into([a: 1, b: 2], %{})
┃ %{a: 1, b: 2}
iex(4)>
なお、環境変数LANGが"ja"的になっていることが条件です。あるいは、Exgettext.setlocale/1で明示的に"ja"を指定します。
翻訳のアレが何ですが、もし、気に入ったら、_build/dev/lib配下の4つのアプリ
- [l10n_iex] (https://github.com/k1complete/l10n_iex)
- [l10n_ex_unit] (https://github.com/k1complete/10n_ex_unit)
- [l10n_elixir] (https://github.com/k1complete/10n_elixir)
- [exgettext] (https://github.com/k1complete/exgettext)
をiexが認識する場所におく事でいつでも使うことができます。
翻訳自体は拙作なので、githubを個別にチェックして突っ込んでもらえると幸いです。また、リリースタイミングでタグを打っていますが、ドキュメントのブレが大きいと翻訳されないものが出てきます。
なお、ex_docにパッチをいれて、日本語リファレンスのwebページを作成していますので、読めれば良いという人はこちらをご覧くださいませ(内容は同等です)。
仕組みについて
この仕組みは、国際化支援ライブラリGNU gettextを内部で利用していて、翻訳ファイルは.poファイルそのものです。
全体の流れは、以下のようになっています。
- ビルド時にソースファイル中から翻訳ターゲット文字列を抜き出し、potファイル(翻訳テンプレート)を作成するマクロを作り、Sigil_T/2でマークアップする。さらに、@docや@moduledocもスキャンしておく。
- .potファイルから.poファイルを作成したり、マージするタスクをmixタスクとして作成。
- .poファイルをdetsファイルにコンパイルするコンパイラをmixタスクとして作成。
- Sigil_T/2は、現在のロケールに従い、翻訳ファイルdetsを参照して置き換えるという内容になっているので、実行すると、翻訳された文字列が出力される。
これらをどうやって作ったかについては、
- [exgettext] (https://github.com/k1complete/exgettext/)
- [elixir地域化の話] (http://d.hatena.ne.jp/k-1/20140714/p1)
- [elixir地域化の話2] (http://d.hatena.ne.jp/k-1/20141005/p1)
を参照してください。
以上、iexでの日本語版ヘルプを使う方法でした。
明日は @ryuone さんです。