MojoMojoを使ってみて国際化についてちょっと研究してみた。CPANにはLocale::Maketext, Locale::Maketext::Lexicon, Locale::Maketext::Simple等々色々あって正直よくわからんかったのだが、今回調べてみてようやく把握した。

まず先に行っておくけど、Locale::Maketext::* 系のモジュールのコードは正直クレイジーなので、暇じゃなきゃあんまりソースコードを漁るのはお勧めしない。

国際化の大まかな流れは、文字列IDがあって、それに対応する言語の「翻訳」が存在する、という感じ。Catalystを使っているなら、Catalyst::Plugin::I18Nを使用して、MyApp::I18N名前空間以下に.poや.moファイルなどをおくのが主流。

問題はHTML::FormFuなど、他の国際化されたコンポーネントを入れ込む時や、プラッガブルな形で国際化ファイルを追加する時。一部はLocale::Maketextを使っていたり、一部はLocale::Maketext::Lexiconを使っていたり・・・Catalyst::Plugin::I18NはLocale::Maketext::Simpleを使っている。

まずそれぞれのおおまかな違い。Locale::Maketextが基本中の基本。これの大まかな動作としては、国際化用の名前空間を指定して、それ以下に言語毎の.pmを置く。例えば国際化用の名前空間がMyApp::I18Nだとしたら、日本語用の文字列ID → 翻訳文字列はMyApp::I18N::jaに入れる。このMyApp::I18N::ja内の%Lexiconというハッシュにこのルールをハッシュとして定義する。ちなみにこのモジュールを使う場合にはMyApp::I18Nのようなモジュールを作るわけだが、このモジュール、Locale::Maketextから継承する必要がある・・・っぽい。

これに対しLocale::Maketext::Lexiconは この%Lexiconのファクトリーと捉えるといいと思う。APIが非常にいけてないが(import()を使って定義を行うというひどいAPI)、この方式を使うと%Lexiconハッシュがtie()された物になり、後から追加するのが容易になる。Locale::Maketext は生のハッシュを使っているのでこのハッシュを自前で操作する必要があるが、Locale::Maketext::Lexiconを使えばその辺りのマージを自動的に行ってくれる。モジュールの継承はLocale::Maketextと一緒だが、こちらはハッシュを定義するのではなく、gettext形式の.poファイル、maketext形式の.moファイルなどを使える。

Locale::Maketext::SimpleはLocale::Maketext::Leixconの定義を簡単にしただけ。それ以上ではない。ただし、動的に翻訳ルールの追加はこのモジュールを通してはできないようにわざわざされている。

ざっくりとはこんな感じ。で、迷うのがあちこちに「Class」引数で名前空間を指定するとかそういう事が書いてある割に、Locale::Maketext::LexiconをLocale::Maketext::Simpleは.poファイルや.moファイルを使用する場合はそれらのファイルが存在するディレクトリを明示的に指定する必要がるということ。これ、ドキュメントにはなかなか書いてない(パスも指定できるよ!とは書いてあるけど、それが必須とは特に書いてない)。ちなみに Perlが認識できる auto/MyApp/I18N/*.po 等のパスにあればその必要はないけど、普通の人はautoにファイルなんていれないから、パスを指定するのがよいと思う。

というわけで以上がすごい悩んで二日ほどwarn()宣言をあちこちに入れながらわかった大筋。実際に投入する際にはもう少々BKが必要なのだが、そこまで書くとすげぇ長いのでまた今度。