Catalyst::Plugin::I18Nで国際化 with Template-Toolkit(Catalyst::View::TT)
前回のCatalyst+Template-Toolkit(Catalyst::View::TT)で国際化 - ヒルズで働く@robarioの技ログはCatalyst::Plugin::I18Nでできるよとのコメントをいただきましたので、それでやることにしました。
Catalyst::Plugin::I18Nで国際化
lib/MyApp/L10Nではなく lib/MyApp/I18N を用意します。
lib/MyApp/I18N/en.pm
package MyApp::I18N::en; use base qw(MyApp::I18N); our %Lexicon = ( '_AUTO' => 1, );
Template-Toolkitで使う
これをテンプレートで利用するには
[% c.localize('Hello') %]
のように書くらしいです。そのまんま過ぎます。さすがに長ったらしいので、MACROを定義する方法がPODに書いてあります。
[% MACRO l(text, args) BLOCK; c.localize(text, args); END; %] [% l('Hello') %]
ただ[% l('Hello') %]でも十分長ったらしいので、やはりここは_('Hello')のように書きたいですよね。
xgettext
ところで話は変わって、Catalyst::Plugin::I18NはGNU gettextのpoやmoを直接扱うことができます。
Locale-Maketext-Lexicon-1.00 - Use other catalog formats in Maketext - metacpan.orgというディストリビューションにxgettext.plというツールが付いてきます。これは翻訳対象文字列を抽出してpoファイルを生成してくれるツールです。
抽出対象文字列はLocale::Maketext::Extract - Extract translatable strings from source - metacpan.orgに書かれている、以下の全てです。
Perl関数呼び出し形式
- translate(...)
- maketext(...)
- gettext(...)
- loc(...)
- x(...)
- _(...)
- __(...)
HTML::Mason風
- <&|/l&>...&>
- <&|/loc&>...&>
(ここドキュメントが間違ってますのでご注意)
Template Toolkit風
- [% |l %]...[% END %]
- [% |loc %]...[% END %]
Text::Template風
- STARTxxx ... ENDxxx
一般Template
{{...}}
これらは全てが抽出の対象となるため、例えばTemplate-Toolkit用のテンプレート内で<&|/l&>...&>と書いても抽出されます。で、_(...)か{{...}}が一番簡単っぽいのでそれらを対象とすることします。
テンプレートroot/defaultを
<html><body> <p>{{Hello}}<p> <p>_('World')<p> </html></body>
としておきます。
% xgettext.pl -o ja.po root/default
とすると、ja.poの中身は
# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: root/default:2 msgid "Hello" msgstr "" #: root/default:3 msgid "World" msgstr ""
となります。msgstrのところに「こんにちわ」「世界」を書き込み、CHARSETをutf-8に変更し、「#, fuzzy」行を削除します。
poの編集に関しては他のサイトを参照してください。
Template-Toolkitで簡単に使う
出来上がったpoファイルを lib/MyApp/I18N/ja.po として置いておきます。(msgfmtでja.moに変換しても構いません)
テンプレートへの記述を[% c.localize(...) %]という関数呼び出しから{{...}},_(...)という記述に変えたので、このままでは翻訳されません。ですので、ビューにlocalizeを呼び出すコードを追加します。
package MyApp::View::TT; use base qw(Catalyst::View::TT); sub process { my ( $self, $c ) = @_; $self->SUPER::process($c); my $output = $c->res->body; $output =~ s/{{(.+?)}}/$c->localize($1)/egmsx; $output =~ s/_\((["'])(.+?)\1\)/$c->localize($2)/egmsx; $c->res->body($output); return; } 1;
これでroot/defaultを表示させると
<html><body> <p>こんにちわ<p> <p>世界<p> </html></body>
という出力が得られます。
ところで、今回はlanguageの指定をしていません。これはCatalyst::Plugin::I18Nが$c->request->header('Accept-Language')を見て勝手に設定してくれているからです。実際の判定はI18N::LangTags::Detectが行なっています。