さて、今度はLocale::MaketextとLocale::Maketext::Lexicon。
Locale::Maketextは基本操作は以下のようなイメージ。get_handle() というメソッドでローカリゼーション用のオブジェクトを引っ張り出し、それに対してmaketext() を呼び出して変換を行う。
use MyApp::I18N;
my $handle = MyApp::I18N->get_handle('ja');
print $handle->maketext("Hello, World!"), "\n";
get_handle() になにげに言語IDが渡されているのもポイント。引数無しでget_handle() を呼び出すと、前出のI18N::LangTag::Detectのコードとかが自動的に呼ばれる。もしこの辺りを自分でコントロールする必要がないと感じるのであれば、引数無しでもよいかもしれない。
話は戻って、MyApp::I18Nを設定するのに、Locale::Maketextを継承した国際化用のモジュールを作る必要がある。
package MyApp::I18N;
use strict;
use base qw(Locale::Maketext);
1;
国際化ルール自体は、上記MyApp::I18N名前空間以下に置かれる。Locale::Maketextは基本的に.poファイルや.moファイルには対応しないので、直接ハッシュに指定する形になる。
package MyApp::I18N::ja;
use strict;
use base qw(MyApp::I18N);
our %Lexicon = (
"Hello, World!" => "みなさん、こんにちは!"
);
1;
この名前空間が前もって固定されている、というところに「後付で(プラグイン等から)国際化ルールを追加できない」という制限が出てくる。もちろん、%Lexiconハッシュに直接ぶっこめばいいんだけれども・・・それ用のコード書くのは微妙じゃないか?というわけでなんとなく自分はこのアプローチはよくない気がする。
Locale::Maketext::LexiconはLocale::Maketextから継承とかなんもしないくせに、Locale::Maketextを拡張している。意図はいいんだけど、APIデザインとかに全くセンスを感じられないモジュール。こちらは上記Locale::Maketextを使うときと同じくMyApp::I18Nの設定はするのだけれども、この際に.poファイルや.moファイルの扱いができるようになる。要はLocale::Maketext::Lexiconはそれらのファイルの中味を解析して、%MyApp::I18N::xxx::Lexiconにぶちこんでくれるわけです。
package MyApp::I18N;
use strict;
use base qw(Locale::Maketext);
use Locale::Maketext::Lexicon {
'*' => [ 'Gettext' => '/path/to/localization/*.po' ],
# ファイル名じゃなくてパス中にen/jaとかがはいるなら、以下のようにする:
# '*' => [ 'Gettext' => '/path/to/localization/*/data.po' ],
_decode => 1
};
1;
上記の場合全ての言語(「*」という表記)の国際化データは、gettext形式(.poファイル)で/path/to/localization/ディレクトリ以下の、それぞれの言語IDの名前の付いたファイルに格納されている、と表記してある。Locale::Maketext::Lexiconの場合はあとは.poファイルを作るだけ。
ちなみにAPIは最悪なのですが、Locale::Maketext::Lexiconは後からPerl形式以外の国際化データを使えるというのと、それらを後から追加できるというのが最大のメリット。
eval "package MyApp::I18N;
Locale::Maketext::Lexicon->import( {
ja => [ Gettext => '/path/to/another/localization/ja.po' ]
_decode => 1
});
"
とかすると、新しい日本語データを追加することができる。何回も言うけどAPIは最悪。パッケージ名を指定しなくちゃいけないとか、本当にアホだけど、しないとできない。
あとカバーしてないのは_AUTOとかかな。以下次号。
コメント