|
|
次は、アダプタをコード内で使用する方法です。
Example #1 単一言語の PHP コードの例
print "Example\n";
print "=======\n";
print "Here is line one\n";
print "Today is the " . date("d.m.Y") . "\n";
print "\n";
print "Fix language here is line two\n";
上の例の出力は、翻訳に対応していません。 おそらく実際はあなたの母国語でコードを書くでしょう。 翻訳しなければならないのは、普通は出力内容だけではありません。 たとえばエラーメッセージやログメッセージなども対象となります。
次のステップは、既存のコードに Zend Translate をインクルードすることです。 もちろん、あとからコードを変更するよりも 最初から Zend_Translate を使ったコードを書くほうがずっと簡単です。
Example #2 多言語対応の PHP コードの例
$translate = new Zend_Translate('gettext', '/my/path/source-de.mo', 'de');
$translate->addTranslation('//my/path/fr-source.mo', 'fr');
print $translate->_("Example")."\n";
print "=======\n";
print $translate->_("Here is line one")."\n";
printf($translate->_("Today is the %1\$s") . "\n", date("d.m.Y"));
print "\n";
$translate->setLocale('fr');
print $translate->_("Fix language here is line two") . "\n";
では、何が起こっているのか、そしてどうやって Zend_Translate をコードに組み込むのかについて もうすこし詳しく見ていきましょう。
新しい Translation オブジェクトを作成し、もととなるアダプタを定義します。
$translate = new Zend_Translate('gettext', '/my/path/source-de.mo', 'de');
この例では、
Gettext アダプタ
を使うことにしました。
source-de.mo というファイルを
/my/path に置いています。
この gettext ファイルにはドイツ語の翻訳が含まれています。
また、その後で別途フランス語のファイルも追加しています。
次に行うのは、翻訳対象の文字列をすべてラップすることです。 一番シンプルな手法は、このように文字列や文章を囲むことです。
print $translate->_("Example")."\n";
print "=======\n";
print $translate->_("Here is line one")."\n";
中には翻訳する必要のない文字列もあるでしょう。
区切り線などは、たとえ言語が何であっても同じです。
データの値を翻訳文字列に組み込むこともできます。 この場合は埋め込みパラメータを使用します。
printf($translate->_("Today is the %1\$s") . "\n", date("d.m.Y"));
print() の代わりに printf() 関数を使用し、
すべてのパラメータを %1\$s のように置き換えます。
最初のパラメータが %1\$s、その次が %2\$s、
といったようになります。
これにより、実際の値を知らなくても翻訳を進めることができます。
今回の例では、日付は常に今日の日付になります。
しかし、文字列を翻訳する際には、実際の日付が何であるかを知る必要はありません。
各文字列は、メッセージ ID によって識別します。 文字列の代わりに、コード内でメッセージ ID を指定することもできます。 その場合は、このようになります。
print $translate->_(1)."\n"; print "=======\n"; print $translate->_(2)."\n";しかし、この方法にはいくつか欠点があります。
コードを見ただけでは、そこでどんな内容が出力されるのかがわかりません。
また、文字列の一部が翻訳されていない場合にも問題が起こるでしょう。 翻訳の動作原理について考えてみましょう。 まず Zend_Translate は、指定した ID あるいは文字列に対応する翻訳が その言語に存在するかどうかを探します。 翻訳文字列が見つからない場合は、Zend_Locale で定義されているその次の言語の翻訳を探します。 つまり "de_AT" の場合は "de" のみで探します。 "de" の翻訳も見つからない場合は、 もとのメッセージをそのまま返します。 このようにして、たとえ翻訳文字列がなくても何らかの出力を得ることになっています。 Zend_Translate は、文字列の翻訳の際に エラーや例外を発生させることはありません。
次に行うのは、翻訳したい言語用の翻訳ソースを作成することです。 それぞれのアダプタには個別の方法があるので、それをここで説明します。 その前に、すべてのアダプタに共通する一般的な事項について説明しておきます。
どこに翻訳ソースファイルを保存すべきなのかを知っておきましょう。 Zend_Translate では特に制限はありませんが、 以下のような構造を推奨します。
単一構造のソース
/application /languages lang.en lang.de /library
利点: すべての言語のソースファイルを同じディレクトリに配置できます。 関連するファイルを分割する必要がありません。
言語ごとに分けた構造
/application
/languages
/en
lang.en
other.en
/de
lang.de
other.de
/library
利点: すべての言語がひとつのディレクトリにまとめられます。 各言語のチームは、ひとつのディレクトリを翻訳するだけですみます。 また、複数のファイルを透過的に使用できます。
アプリケーションごとに分けた構造
/application
/languages
lang.en
lang.de
other.en
other.de
利点: すべての言語のソースファイルを同じディレクトリに配置できます。 関連するファイルを分割する必要がありません。
欠点: 同じ言語で複数のファイルを使用する場合に問題が発生します。
Gettext 形式の構造
/languages
/de
/LC_MESSAGES
lang.mo
other.mo
/en
/LC_MESSAGES
lang.mo
other.mo
利点: 以前から使っている gettext 形式のソースを、 そのままの形式で使用できます。
欠点: これまでに gettext を使ったことがない人たちにとって、 サブディレクトリの中にまたサブディレクトリという構造は不可解でしょう。
ファイル構造のソース
/application
/models
mymodel.php
mymodel.de
mymodel.en
/views
/controllers
mycontroller.de
/document_root
/images
/styles
.htaccess
index.php
index.de
/library
/Zend
利点: すべてのファイルについて、翻訳ソースを関連付けられます。
欠点: 小さな翻訳ファイルがあちこちに散らばってしまうので、翻訳が面倒です。 また、すべてのファイルに対して翻訳ソースを追加する必要があります。
Zend_Translate で最も便利なのは、単一構造か 言語ごとに分けた構造でしょう。
さあ、これでどんな構造でいくかが決まりました。 次に翻訳ソースファイルを作っていきましょう。
Array ソースファイルは、単なる配列です。 しかし、専用のツールはないので自分でそれを定義しなければなりません。 とは言え、この配列は非常にシンプルです。 コードが期待通りに動作しているかを確認するのにも最も手っ取り早いでしょう。 翻訳作業を始めるにあたっては、一般的に最適なアダプタであるといえます。
$english = array('message1' => 'message1',
'message2' => 'message2',
'message3' => 'message3');
$german = array('message1' => 'Nachricht1',
'message2' => 'Nachricht2',
'message3' => 'Nachricht3');
$translate = new Zend_Translate('array', $english, 'en');
$translate->addTranslation($deutsch, 'de');
リリース 1.5 以降では、配列を外部のファイルに含めることもサポートしています。
ファイル名を指定すると、Zend_Translate
が自動的にそれをインクルードして配列を探します。
詳細は、次の例を参照ください。
// myarray.php
return array(
'message1' => 'Nachricht1',
'message2' => 'Nachricht2',
'message3' => 'Nachricht3');
// コントローラ
$translate = new Zend_Translate('array', 'path/to/myarray.php', 'de');
Note:
配列を返さないファイルはインクルードできません。 また、このファイル内での出力はすべて無視されます。
Gettext ソースファイルは、GNU の gettext ライブラリで作成します。 あなたのコードをパースして gettext ソースファイルを作成してくれるツールが、 フリーで公開されています。このファイルは、 *.mo のような名前のバイナリファイルとなります。 ファイルを作成するためのフリーソフトウェアのひとつに » poEdit があります。これは、ファイルの作成だけでなく翻訳作業自体もサポートしています。
// mo ファイルを作成し、翻訳を済ませているものとします
$translate = new Zend_Translate('gettext', 'path/to/english.mo', 'en');
$translate->addTranslation('path/to/german.mo', 'de');
ご覧の通り、アダプタの使用法はまったく同じです。 違っているのはたったの一点だけ。 'array' が 'gettext' になっているということです。 その他の部分は、どのアダプタを使用してもまったく同じになります。 gettext アダプタを使用する際には、 gettext の標準的なディレクトリ構造や bindtextdomain、 textdomain にこだわる必要はありません。 単にパスとファイル名をアダプタに渡せばいいのです。
Note:
ソースのエンコーディングには常に UTF-8 を使用しなければなりません。そうしないと、 複数のソースエンコーディングを使用することで問題が発生します。 たとえば、あるソースファイルは ISO-8815-11 でエンコードされており、 他のファイルは CP815 でエンコードされているとしましょう。 ソースファイルのエンコーディングはひとつしか指定できないので、 どちらか一方は正しく表示されなくなります。
UTF-8 は可搬性の高いフォーマットで、全言語をサポートしています。 すべての言語で UTF-8 を使用することで、 エンコーディングの非互換性による問題をなくすことができます。
gettext エディタの多くは、
空の翻訳文字列という形式で追加情報を記録します。
そのため、gettext アダプタは空の文字列の翻訳を行いません。
これらの情報は翻訳テーブルからは削除され、かわりに
getAdapterInfo() メソッドで取得できるようになります。
このメソッドは、追加された gettext
ファイルすべてから取得した情報を配列で返します。
ファイル名を配列のキーとして使用します。
// アダプタの情報を取得する方法
$translate = new Zend_Translate('gettext', 'path/to/english.mo', 'en');
print_r $translate->getAdapterInfo();
TMX ソースファイルは、新しい業界標準です。 XML ファイルを使用しているので、どんなエディタでも読み込め、 かつ人間にも読める形式であるという利点があります。 TMX ファイルはテキストエディタで作成することもできますし、 ツールを用いて作成することもできます。しかし、 現在使用できる TMX ソースファイル作成ツールの多くは フリーソフトウェアではありません。
Example #3 TMX ファイルの例
Nachricht1 message1 message2 Nachricht2
$translate = new Zend_Translate('tmx', 'path/to/mytranslation.tmx', 'en');
// TMX では、複数の言語をひとつの TMX ファイルに含めることができます
TMX ファイルには、同一ファイルに複数の言語を含めることができます。
含まれている言語はすべて自動的に追加されるので、
addLanguage() をコールする必要はありません。
ソース中の特定の言語のみを翻訳対象としたい場合は、オプション
defined_language を true
に設定します。このオプションを指定した場合は、
対象としたい言語を addLanguage()
で明示的に指定します。このオプションのデフォルト設定は、
全言語を対象とするようになっています。
CSV ソースファイルは、サイズが小さく可読性があります。 顧客が自分で翻訳をしたいということなら、 おそらく CSV アダプタを使用することになるでしょう。
Example #4 CSV ファイルの例
# csv ファイルの例 message1;Nachricht1 message2;Nachricht2
$translate = new Zend_Translate('csv', 'path/to/mytranslation.csv', 'de');
$translate->addTranslation('path/to/other.csv', 'fr');
CSV アダプタで使用できるオプションは、
'delimiter' と 'limit' そして
'enclosure' の 3 つです。
CSV 文字列の標準の区切り文字は ';' 記号です
[1]
。
しかし、必ずこれでなければならないというわけではありません。
オプション 'delimiter' を使用すると、
別の区切り文字を使用することができます。
CSV ファイルのデフォルトの行長制限は '0' です。
この場合は、CSV ファイルの行末を自動的に検出します。
'limit' オプションに何らかの値を設定すると
CSV ファイルの読み込みが高速になりますが、
その長さを超えた部分は切り捨てられます。
CSV ファイルの値を囲む文字のデフォルトは '"' です。
別の文字を使用する場合は 'enclosure' オプションを設定します。
Example #5 CSV ファイルの例 その 2
# csv ファイルの例 # 元メッセージは 'message,1' "message,1",Nachricht1 # 翻訳は 'Nachricht,2' message2,"Nachricht,2" # 元メッセージは 'message3,' "message3,",Nachricht3
$translate = new Zend_Translate('csv',
'path/to/mytranslation.csv',
'de',
array('delimiter' => ','));
$translate->addTranslation('path/to/other.csv', 'fr');
INI ソースファイルは可読性がありますが、 翻訳以外のデータを含めるとサイズはそれほど小さくなりません。 直接顧客に変更させるようなデータの場合にも INI アダプタが使えるでしょう。
Example #6 INI ファイルの例
[Test] ;TestPage Comment Message_1="Nachricht 1 (de)" Message_2="Nachricht 2 (de)" Message_3="Nachricht :3 (de)"
$translate = new Zend_Translate('ini', 'path/to/mytranslation.ini', 'de');
$translate->addTranslation('path/to/other.ini', 'it');
INI にはいくつかの制約があります。 INI ファイルの値に非英数字が含まれる場合は、値をダブルクォート (") で囲まなければなりません。また、ini ファイルのキーとしては使えない予約語があります。 予約語には null, yes, no, true, そして false があります。 値に null, no および false を指定するとそれは "" と同じ扱いとなり、yes と true を指定するとそれは "1" と同じ扱いとなります。 {}|&~
