Programmer's Reference Guide
| Zend_Translate のアダプタ |
翻訳アダプタの使用法
次は、アダプタをコード内で使用する方法です。
例1 単一言語の PHP コードの例
上の例の出力は、翻訳に対応していません。 おそらく実際はあなたの母国語でコードを書くでしょう。 翻訳しなければならないのは、普通は出力内容だけではありません。 たとえばエラーメッセージやログメッセージなども対象となります。
次のステップは、既存のコードに Zend Translate を組み込むことです。 もちろん、あとからコードを変更するよりも 最初から翻訳を意識したコードを書くほうがずっと簡単です。
例2 多言語対応の PHP コードの例
では、何が起こっているのか、そしてどうやって Zend_Translate をコードに組み込むのかについて もうすこし詳しく見ていきましょう。
新しい Zend_Translate オブジェクトを作成し、もととなるアダプタを定義します。
- $translate = new Zend_Translate(
- 'adapter' => 'gettext',
- 'content' => '/path/to/translation/source-de.mo',
- 'locale' => 'de'
- )
- );
この例では、 Gettext アダプタ を使うことにしました。 source-de.mo というファイルを /path/to/translation に置いています。 この gettext ファイルにはドイツ語の翻訳が含まれています。 また、その後で別途フランス語のファイルも追加しています。
次に行うのは、翻訳対象の文字列をすべてラップすることです。 一番シンプルな手法は、このように文字列や文章を囲むことです。
中には翻訳する必要のない文字列もあるでしょう。 区切り線などは、たとえ言語が何であっても同じです。
データの値を翻訳文字列に組み込むこともできます。 この場合は埋め込みパラメータを使用します。
print() の代わりに printf() 関数を使用し、 すべてのパラメータを %1\$s のように置き換えます。 最初のパラメータが %1\$s、その次が %2\$s、 といったようになります。 これにより、実際の値を知らなくても翻訳を進めることができます。 今回の例では、日付は常に今日の日付になります。 しかし、文字列を翻訳する際には、実際の日付が何であるかを知る必要はありません。
各文字列は、メッセージ ID によって識別します。 文字列の代わりに、コード内でメッセージ ID を指定することもできます。 その場合は、このようになります。
しかし、この方法にはいくつか欠点があります。
コードを見ただけでは、そこでどんな内容が出力されるのかがわかりません。
また、文字列の一部が翻訳されていない場合にも問題が起こるでしょう。 翻訳の動作原理について考えてみましょう。 まず Zend_Translate は、指定した ID あるいは文字列に対応する翻訳が その言語に存在するかどうかを探します。 翻訳文字列が見つからない場合は、Zend_Locale で定義されているその次の言語の翻訳を探します。 つまり "de_AT" の場合は "de" のみで探します。 "de" の翻訳も見つからない場合は、 もとのメッセージをそのまま返します。 このようにして、たとえ翻訳文字列がなくても何らかの出力を得ることになっています。 Zend_Translate は、文字列の翻訳の際に エラーや例外を発生させることはありません。
翻訳ソースの構造
次に行うのは、翻訳したい言語用の翻訳ソースを作成することです。 それぞれのアダプタには個別の方法があるので、それをここで説明します。 その前に、すべてのアダプタに共通する一般的な事項について説明しておきます。
どこに翻訳ソースファイルを保存すべきなのかを知っておきましょう。 Zend_Translate では特に制限はありませんが、 以下のような構造を推奨します。
-
単一構造のソース
- /application/
- /languages/
- /languages/lang.en
- /languages/lang.de
- /library/
利点: すべての言語のソースファイルを同じディレクトリに配置できます。 関連するファイルを分割する必要がありません。
-
言語ごとに分けた構造
- /application/
- /languages/
- /languages/en/
- /languages/en/first.en
- /languages/en/second.en
- /languages/de/
- /languages/de/first.de
- /languages/de/second.de
- /library
利点: すべての言語がひとつのディレクトリにまとめられます。 各言語のチームは、ひとつのディレクトリを翻訳するだけですみます。 また、複数のファイルを透過的に使用できます。
-
アプリケーションごとに分けた構造
- /application/
- /application/languages/
- /application/languages/first.en
- /application/languages/first.de
- /application/languages/second.en
- /application/languages/second.de
- /library/
利点: すべての言語のソースファイルを同じディレクトリに配置できます。 関連するファイルを分割する必要がありません。
欠点: 同じ言語で複数のファイルを使用する場合に問題が発生します。
-
Gettext 形式の構造
- /application/
- /languages/
- /languages/de/
- /languages/de/LC_MESSAGES/
- /languages/de/LC_MESSAGES/first.mo
- /languages/de/LC_MESSAGES/second.mo
- /languages/en/
- /languages/en/LC_MESSAGES/
- /languages/en/LC_MESSAGES/first.mo
- /languages/en/LC_MESSAGES/second.mo
- /library/
利点: 以前から使っている gettext 形式のソースを、 そのままの形式で使用できます。
欠点: これまでに gettext を使ったことがない人たちにとって、 サブディレクトリの中にまたサブディレクトリという構造は不可解でしょう。
-
ファイル構造のソース
- /application/
- /application/models/
- /application/models/MyModel.php
- /application/models/MyModel.de
- /application/models/MyModel.en
- /application/controllers/
- /application/controllers/MyController.php
- /application/controllers/MyController.de
- /application/controllers/MyController.en
- /library/
利点: すべてのファイルについて、翻訳ソースを関連付けられます。
欠点: 小さな翻訳ファイルがあちこちに散らばってしまうので、翻訳が面倒です。 また、すべてのファイルに対して翻訳ソースを追加する必要があります。
Zend_Translate で最も便利なのは、単一構造か 言語ごとに分けた構造でしょう。
さあ、これでどんな構造でいくかが決まりました。 次に翻訳ソースファイルを作っていきましょう。
| Zend_Translate のアダプタ |
Add A Comment
Please do not report issues via comments; use the ZF Issue Tracker.
If you have a JIRA/Crowd account, we suggest you login first before commenting.

Comments
printf($translate->_("Today is the %1\$s") . "\n", date('d.m.Y'));
but :
printf($translate->_("Today is the %1$s") . "\n", date('d.m.Y'));
$this->translate->_($vartext);
This is possible. It will not be properly scanned by gettext, poedit, or whatever else. However, if the text in $vartext is contained in a translation source, it will be translated. Therefore in order to do this, you may need to declare a bunch of
_('text');statements in an unused "reference" file. If you are using array, CSV, or ini, that is not necessary.I've tested this with gettext sources, and it works. I've not tested with others.
This is useful when... well it should be more than obvious why. For me it was because the page was completely dynamic - the text was being read from a DB. I do not want to maintain so many tables of translations.
HTH
$this->translate->_($vartext);
I do prefer using it in other way. something like:
if ( $x==1)
$vartext = $this->translate->_("MSG1");
else
$vartext = $this->translate->_("MSG2");
print( $vartext );
This way it will be properly scanned by gettext, poedit, or whatever else.