人気のある Web アプリケーションの多くはさまざまな言語で利用可能で、ときにはユーザーカルチャにもとづいてカスタマイズされます。 symfony はこれらの機能の管理を楽にする組み込みのフレームワークを搭載しています (「A Gentle Introduction to symfony」 の「国際化とローカライゼーション」の章をご参照ください)。
フォームフレームワークはユーザーインターフェイス用の組み込みサポートを備えており国際化オブジェクトの管理を楽にする方法を提供します。
フォームの国際化
symfony のフォームはデフォルトで国際化に対応しています。翻訳ファイルを編集してラベル、ヘルパーテキストとエラーメッセージを翻訳できます。これらは XLIFF
、gettext
もしくは symfony がサポートするその他のフォーマットです。
リスト8-1は以前の章で開発した問い合わせフォームを示します。
リスト8-1 - 問い合わせフォーム
class ContactForm extends BaseForm { public function configure() { $this->setWidgets(array( 'name' => new sfWidgetFormInputText(), // デフォルトのラベルは "Name" 'email' => new sfWidgetFormInputText(), // デフォルトのラベルは "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 の国際化フレームワークの機能を利用する場合、フォームを特定のカタログにバインドできます(カタログは「A Gentle Introduction to symfony」の「国際化とローカライゼーションの章」をご参照ください) 。
リスト8-3において、ContactForm
フォームを contact_form
カタログに関連づけます。ですので、フォーム要素の翻訳は contact_form.fr.xml
ファイルで捜索されます。
リスト8-3 - 翻訳カタログのカスタマイズ
class ContactForm extends BaseForm { public function configure() { // ... $this->widgetSchema->getFormFormatter() ->setTranslationCatalogue('contact_form'); } }
note
カタログを使うことで、たとえばフォームごとに1つのファイルを使った翻訳の組織化が改善されます。
エラーメッセージの国際化
ときどき、エラーメッセージにはユーザーによって投稿された値が埋め込まれます (たとえば、
「メールアドレスの user@domain は有効ではありません。」)。
これをフォームクラスのなかでカスタマイズされたエラーメッセージを定義してユーザーが投稿した値をかんたんに利用できることを2章ですでに見ました。これらの参照は %parameter_name%
パターンにしたがいます。
リスト8-4はこの原則を問い合わせフォームの name
フィールドに適用する方法を示しています。
リスト8-4 - エラーメッセージの国際化
class ContactForm extends BaseForm { 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'); // => 「Subject」を表示します $_SESSION['culture'] = 'fr'; echo $myI18n->translateText('Subject'); // => 「Suject」を表示します
リスト8-7で示されるようにそれぞれのフォームはフォームの要素の国際化を管理する独自の callable を定義できます。
リスト8-7 - フォームのための国際化メソッドをオーバーライドする
class ContactForm extends BaseForm { 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) いくつかのウィジェットを搭載しています。ユーザーカルチャにしたがってウィジェットをローカライズするためにこれらのウィジェットを使うことができます。
日付セレクタ
日付をローカライズするために利用できるウィジェットは次のとおりです。
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'));
カントリ (国コード) セレクタ
sfWidgetFormI18nChoiceCountry
ウィジェットは国コードのリストで満たされたセレクトボックスを表示します。国コードの名前は指定された言語に翻訳されます。
$this->widgetSchema['country'] = new sfWidgetFormI18nChoiceCountry(array('culture' => 'fr'));
countries
オプションのおかげで、セレクトボックス内の国コードを制限することもできます。
$countries = array('fr', 'en', 'es', 'de', 'nl'); $this->widgetSchema['country'] = new sfWidgetFormI18nChoiceCountry(array('culture' => 'fr', 'countries' => $countries));
カルチャセレクタ
sfWidgetFormI18nChoiceLanguage
ウィジェットは言語コードの一覧で満たされたセレクトボックスを表示します。言語コードの名前は指定された言語に翻訳されます。
$this->widgetSchema['language'] = new sfWidgetFormI18nChoiceLanguage(array('culture' => 'fr'));
languages
オプションのおかげで、セレクトボックスの言語を制限することもできます:
$languages = array('fr', 'en', 'es', 'de', 'nl'); $this->widgetSchema['language'] = new sfWidgetFormI18nChoiceLanguage(array('culture' => 'fr', 'languages' => $languages)); ### タイムゾーンセレクタ
sfWidgetFormI18nChoiceTimezone
ウィジェットはタイムゾーンで満たされたセレクトボックスを表示します。
$this->widgetSchema['timezone'] = new sfWidgetFormI18nChoiceTimzione();
This work is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported License license.