人気のあるWebアプリケーションの多くはさまざまな言語で利用可能で、時にユーザーのcultureに基づいてカスタマイズされます。symfonyはこれらの機能の管理を楽にする組み込みのフレームワークを搭載しています(symfony bookの"国際化と ローカライズ"の章を参照)。
フォームフレームワークはユーザーのインターフェイス用の組み込みサポートを備えており国際化オブジェクトの管理を楽にする方法を提供します。
フォームの国際化
symfonyのフォームはデフォルトで国際化が可能です。翻訳ファイルを編集することでラベル、ヘルパーテキスト、とエラーメッセージを翻訳できます。これらはXLIFF
、gettext
、もしくはsymfonyがサポートするその他のフォーマットです。
リスト8-1は以前の章で開発したコンタクトフォームを示します。
リスト8-1 - コンタクトフォーム
class ContactForm extends sfForm { public function configure() { $this->setWidgets(array( 'name' => new sfWidgetFormInput(), // デフォルトのラベルは"Name" 'email' => new sfWidgetFormInput(), // デフォルトのラベルは"Email" 'body' => new sfWidgetFormTextarea(), // デフォルトのラベルは"Body" )); // emailのウィジェットのラベルを変更する $this->widgetSchema->setLabel('email', 'Email address'); } }
リスト8-2で示されるようにラベルのフランス語訳をXLIFF
で定義します。
リスト8-2 - XLIFF翻訳ファイル
// apps/frontend/i18n/messages.fr.xml <?xml version="1.0" ?> <xliff version="1.0"> <file original="global" source-language="en" datatype="plaintext"> <body> <trans-unit> <source>Name</source> <target>Nom</target> </trans-unit> <trans-unit> <source>Email address</source> <target>Adresse email</target> </trans-unit> <trans-unit> <source>Body</source> <target>Message</target> </trans-unit> </body> </file> </xliff>
翻訳のために使うカタログを指定する
symfonyの国際化フレームワークの機能を利用する場合 (/book/1_1/13-I18n-and-L10n#Managing%20Dictionaries
)、フォームを特定のカタログにバインドできます。リスト8-3において、ContactForm
フォームをcontact_form
カタログに関連づけします。ですので、フォーム要素の翻訳はcontact_form.fr.xml
ファイルで捜索されます。
リスト8-3 - 翻訳カタログのカスタマイズ
class ContactForm extends sfForm { public function configure() { // ... $this->widgetSchema->getFormFormatter()->setTranslationCatalogue('contact_form'); } }
note
カタログを利用することで例えばフォームごとに1つのファイルを使用する翻訳の編成がよりベターになります。
エラーメッセージの国際化
時々、エラーメッセージにはユーザーによって投稿された値が埋め込まれます(例えば、"Eメールアドレスのuser@domainは有効ではありません。")。これをフォームクラスの中でカスタマイズされたエラーメッセージを定義してユーザーが投稿した値を簡単に利用できることを2章ですでに見ました。これらの参照は%parameter_name%
のパターンに従います。
リスト8-4はこの原則をコンタクトフォームのname
フィールドに適用する方法を示しています。
リスト8-4 - エラーメッセージの国際化
class ContactForm extends sfForm { public function configure() { // ... $this->validatorSchema['name'] = new sfValidatorEmail( array('min_length' => 2, 'max_length' => 45), array('min_length' => 'Name "%value%" must be at least %min_length% characters.', 'max_length' => 'Name "%value%" must not exceed %max_length% characters.', ), ); } }
リスト8-5で示されるようにXLIFFファイルを編集することでこれらのエラーメッセージを翻訳できます。
リスト8-5 - エラーメッセージ用のXLIFF翻訳ファイル
<trans-unit> <source>Name "%value%" must be at least %min_length% characters</source> <target>Le nom "%value%" doit comporter un minimum de %min_length% caractères</target> </trans-unit> <trans-unit> <source>Name "%value%" must not exceed %max_length% characters</source> <target>Le nom "%value%" ne peut comporter plus de %max_length% caractères</target> </trans-unit>
翻訳オブジェクトのカスタマイズ
symfonyの国際化フレームワーク無しでsymfonyのフォームフレームワークを使いたい場合、翻訳オブジェクトを提供する必要があります。
翻訳オブジェクトはPHPの単なるcallableです。これは次の3つのものの1つです:
my_function
のような関数の名前を表す文字列array($anObject, 'oneOfItsMethodsName')
のような、クラスのインスタンスとメソッドの1つの名前への参照を伴う配列sfCallable
インスタンス。このカプセルは一貫した方法でPHPのcallableをカプセル化します。
note
PHPのcallableは関数もしくはメソッドのインスタンスへの参照です。これはis_callable()
関数に渡されるときにtrue
を返すPHP変数でもあります。
リスト8-6で示されるクラスによって提供される独自の国際化メカニズムをすでに持つプロジェクトをマイグレートしなければならない場合を考えてみましょう。
リスト8-6 - カスタムの国際化クラス
class myI18n { static protected $default_culture = 'en'; static protected $messages = array('fr' => array( 'Name' => 'Nom', 'Email' => 'Courrier électronique', 'Subject' => 'Sujet', 'Body' => 'Message', )); static public function translateText($text) { $culture = isset($_SESSION['culture']) ? $_SESSION['culture'] : self::$default_culture; if (array_key_exists($culture, self::$messages) && array_key_exists($text, self::$messages[$culture])) { return self::$messages[$_SESSION['culture']][$text]; } return $text; } } // クラスの使い方 $myI18n = new myI18n(); $_SESSION['culture'] = 'en'; echo $myI18n->translateText('Subject'); // => display "Subject" $_SESSION['culture'] = 'fr'; echo $myI18n->translateText('Subject'); // => display "Sujet"
リスト8-7で示されるようにそれぞれのフォームはフォームの要素の国際化を管理する独自のcallableを定義できます。
リスト8-7 - フォームのための国際化メソッドをオーバーライドする
class ContactForm extends sfForm { public function configure() { // ... $this->widgetSchema->getFormFormatter()->setTranslationCallable(array(new myI18n(), 'translateText')); } }
パラメータとして受容できる翻訳のcallable
翻訳のcallableは3つの引数を取ります:
翻訳するテキスト;
オリジナルのテキストの範囲で置き換える引数の連想配列。よくあるのはこの章で以前見たように動的な引数を置き換えるため;
テキストを翻訳するときに使うカタログの名前。
下記のコードは翻訳のcallableを呼び出すためにsfFormWidgetSchemaFormatter::translate()
メソッドによって使われる呼び出しです:
return call_user_func(self::$translationCallable, $subject, $parameters, $catalogue);
self::$translationCallable
は翻訳のcallableへの参照です。ですので、以前のコードは下記のものと同等です:
$myI18n->translateText($subject, $parameters, $catalogue);
下記のコードはこれらの追加の引数をサポートするMyI18n
クラスのアップデートされたバージョンです:
class myI18n { static protected $default_culture = 'en'; static protected $messages = array('fr' => array( 'messages' => array( 'Name' => 'Nom', 'Email' => 'Courrier électronique', 'Subject' => 'Sujet', 'Body' => 'Message', ), )); static public function translateText($text, $arguments = array(), $catalogue = 'messages') { $culture = isset($_SESSION['culture']) ? $_SESSION['culture'] : self::$default_culture; if (array_key_exists($culture, self::$messages) && array_key_exists($messages, self::$messages[$culture] && array_key_exists($text, self::$messages[$culture][$messages])) { $text = self::$messages[$_SESSION['culture']][$messages][$text]; $text = strtr($text, $arguments); } return $text; } }
Propelのオブジェクトの国際化
フォームフレームワークは国際化されたPropelオブジェクト用の組み込みサポート機能を持ちます。これが動作する方法を説明するために国際化されたモデルの例を見てみましょう:
propel: article: id: author: varchar(255) created_at: article_i18n: title: varchar(255) content: longvarchar
次のコマンドでPropelのクラスと関連するフォームクラスを生成できます:
$ php symfony build:model $ php symfony build:forms
これらのコマンドはsymfonyのプロジェクトディレクトリの中で次のようなファイルを生成します:
lib/ form/ ArticleForm.class.php ArticleI18nForm.class.php BaseFormPropel.class.php model/ Article.php ArticlePeer.php ArticleI18n.php ArticleI18nPeer.php
リスト8-8は同じフォームでフランス語と英語の記事を編集できるようにするためにArticleForm
を設定する方法を示しています。
リスト8-8 - 国際化されたPropelオブジェクト用の国際化フォーム
class ArticleForm extends BaseArticleForm { public function configure() { $this->embedI18n(array('en', 'fr')); } }
リスト8-9で示されるように次のコードをconfigure()
メソッドに追加することでフォームの言語ラベルをカスタマイズすることもできます。
リスト8-9 - 言語のラベルのカスタマイズ
$this->widgetSchema->setLabel('en', 'English'); $this->widgetSchema->setLabel('fr', 'French');
図8-1 - 国際化されたPropelのフォーム
これでお終いです。フォームオブジェクトのsave()
メソッドを呼び出すとき、関連するPropelオブジェクトと国際化オブジェクトは自動的に保存されます。
ローカライズされたウィジェット
symfonyのフォームフレームワークは国際化を"認識する"(aware)いくつかのウィジェットを搭載しています。ユーザーのcultureに従ってウィジェットをローカライズするためにこれらを使うことができます。
日付セレクタ
日付をローカライズするために利用できるウィジェットは下記の通りです:
sfWidgetFormI18nDate
ウィジェットは日付用の入力を表示します(日にち、月、年):$this->widgetSchema['published_on'] = new sfWidgetFormI18nDate(array('culture' => 'fr'));
3つの異なる値を受け取る
month_format
オプションのおかげで、月の表示フォーマットも定義できます:- 月の名前を表示するための
name
(デフォルト) - 月の短縮名を表示するための
short_name
- 月の番号を表示するための
number
(1から12)
- 月の名前を表示するための
sfWidgetFormI18nTime
ウィジェットは時間用の入力を表示します(時、分、と秒):$this->widgetSchema['published_on'] = new sfWidgetFormI18nTime(array('culture' => 'fr'));
sfWidgetFormI18nDateTime
ウィジェットは日付と時間用の入力を表示します:$this->widgetSchema['published_on'] = new sfWidgetFormI18nDateTime(array('culture' => 'fr'));
国セレクタ
sfWidgetFormI18nSelectCountry
ウィジェットは国のリストで満たされた選択ボックスを表示します。国の名前は指定された言語に翻訳されます:
$this->widgetSchema['country'] = new sfWidgetFormI18nSelectCountry(array('culture' => 'fr'));
countries
オプションのおかげで、選択ボックス内の国を制限することもできます:
$countries = array('fr', 'en', 'es', 'de', 'nl'); $this->widgetSchema['country'] = new sfWidgetFormI18nSelectCountry(array('culture' => 'fr', 'countries' => $countries));
cultureセレクタ
sfWidgetFormI18nSelectLanguage
ウィジェットは言語の一覧で満たされた選択ボックスを表示します。言語の名前は指定された言語に翻訳されます:
$this->widgetSchema['language'] = new sfWidgetFormI18nSelectLanguage(array('culture' => 'fr'));
languages
オプションのおかげで、選択ボックスの言語を制限することもできます:
$languages = array('fr', 'en', 'es', 'de', 'nl'); $this->widgetSchema['language'] = new sfWidgetFormI18nSelectLanguage(array('culture' => 'fr', 'languages' => $languages));
This work is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License license.