はじめに
本連載では、PHP上で動作するアプリケーションフレームワーク「symfony」でアプリケーション開発を行う方法について紹介します。前回はビューの断片化や、ルーティング、キャッシュコントロールについて紹介しました。今回は国際化機能、プラグインの使用などについて紹介します。
対象読者
PHPの基本構文は一通り理解しているが、フレームワークを利用したことはないという方を対象としています。
必要な環境
symfonyはPHP5とWebサーバがインストールされている環境で利用可能です。本連載ではWebサーバとしてApache 2.2を、OSにWindows XPを、データベースとしてMySQLを用いています。以下に、本連載でアプリケーション作成/動作確認に用いている環境を示します(インストールにあたっては最新安定版の使用を推奨します)。各項目の詳細なインストール手順は、「サーバサイド技術の学び舎 - WINGS」より「サーバサイド環境構築設定手順」を参照ください。
- Windows XP SP2
- PHP 5.2
- PEAR
- Apache 2.2.3
- MySQL 5.0.24a
LinuxやFreeBSDなどUNIX系OSをお使いの方もコマンドはほぼ一緒ですので、パスなどは適宜読み替えてください。
国際化対応
symfonyにおける国際化機能について紹介します。ここでの国際化とは、アプリケーションの表示言語や通貨・日時表記などをユーザーの属するカルチャ(国や言語)に対応させることをいいます。
国と言語を別々に分ける
一口に国際化/カルチャと言っても、国と言語の二つの側面から考える必要があります。例えばベルギーではフランス語とドイツ語が話されていますし、ポルトガル本国でのポルトガル語と、ブラジルでのポルトガル語は(その歴史・文化背景により)微妙に違います。そこでsymfonyでは、国と言語を次のように表します。
<言語(小文字2文字)>_<国(大文字2文字)> 例:en_US, ja_JP
言語の違いに加え、国ごとの違いでは、例えば日時の表し方や数字の表示の仕方などに差が出てくるわけです。そこで、DateヘルパーやNumberヘルパーが登場します。
国と言語について
国名は「ISO 3166-1」に、言語名は「ISO 639-1」に準拠しています。例えば日本国は「JP」で、日本語は「ja」となります。具体的にはそれぞれ
- Wikipedia 『ISO 3166-1』
- Wikipedia 『ISO 639』
などを参照してください。
ユーザーカルチャの設定
それではここから、ユーザーカルチャ設定の方法について紹介していきます。
デフォルトの設定
アプリケーションフォルダ「config/i18n.yml」ファイルにデフォルトカルチャの設定を保存できます。
all: default_culture: ja_JP
ユーザーカルチャを把握してカルチャを設定する
ユーザーのブラウザの言語設定に従ってカルチャを設定することも有用です。リクエストの際、ユーザーのブラウザからは「Accept-Language」HTTPヘッダーが送られてきます。symfonyでは「sfRequest」オブジェクトを使用し、そのカルチャを得ることができます。
$languages = $this->getRequest()->getLanguage();
 ->getLanguage()メソッドで、ユーザー側のカルチャを配列で得ることができます。上記の例では、ブラウザ側の設定で最も優先的に使用されている言語は$languages[0]でアクセスすることができるでしょう。
アクション中での設定
 symfonyでは、sfUserクラスのセッター/ゲッターメソッドで国と言語を登録/参照します。これは例えばユーザーがブラウジング中に他国語のページを見に行った場合などアクション中でカルチャを確認/変更したい場合に便利です。例えばカルチャを日本(国も言語も日本語)にする場合、次のように->setCulture()メソッドで設定できます。
$this->getUser()->setCulture('ja_JP');
また、現在どのカルチャのセッションなのかを確認したい場合は、次のようにします。
$this->getUser()->getCulture(); (上記セッター例のように設定していれば「ja_JP」を返す)
これに従い、アクセスされたページでは該当するカルチャに合わせた表示がなされる訳です。そしてそのカルチャに対応した表示をするのが、I18NヘルパーやDate、Numberヘルパーなどです。
国際化のためのヘルパー
これらヘルパーについて一つ一つ見ていきます。先程の「setCulture」や「i18n.yml」などの全体の設定を、ここで具体的に形にしていくのがこれらのヘルパーです。
I18Nヘルパー
現在のカルチャや訳文を表示するためのヘルパーです。
| ヘルパー例 | 出力 | 内容 | 
| format_country('DE') | 'Germany' | 国のコードから国名を表示 | 
| format_language('en') | 'English' | 言語のコードから言語名を表示 | 
| __('Welcome to our website.') | '歓迎光臨 我們網頁' | XLIFFファイルに沿って翻訳文字列を表示(後述) | 
Dateヘルパー
前回も少し紹介しましたが、日付のフォーマットを整えるヘルパーです。
format_date(time())      (日付のフォーマットを行う)
    出力例 '3/25/2007'
format_datetime(time())  (日付と時刻のフォーマットを行う)
    出力例 'March 25, 2007 11:00:11 AM CEST'
上記はいずれも第2引数でフォーマットを細かく設定できますが、上記のように省略した場合は設定されているカルチャによって整えられます。
Numberヘルパー
数字、特に金額などをフォーマットするヘルパーです。
format_number(12345.67)  (金額などを表す数字のフォーマット)
    言語enでの出力 12,345.67
    言語frでの出力 12 345,67
データベース上のテキスト情報
データベース上で各カルチャに適合したデータを扱う場合、「schema.yml」の記述で、実際はカルチャの数だけ用意したテーブルを、あたかも一つのテーブルのように扱うことができます。この時、国際化されないデータを格納するテーブルと国際化データを格納する部分(i18n)のテーブルに分けます。
my_connection  (databases.ymlにあるデータベース接続名)
  my_product:  (国際化されないデータを格納するテーブル)
    _attributes: {phpName: Product, isI18N: true, i18nTable: my_product_i18n}
    id: { type: integer, required: true,
 isI18N: true, i18nTable: my_product_i18n}
    id: { type: integer, required: true, primaryKey: true, autoincrement: true }
    price: { type; float }
  my_product_i18n:  (国際化対応用テーブル)
    _attributes: {phpName: ProductI18n}
    id: { type: integer, required: true, primaryKey: true,
 primaryKey: true, autoincrement: true }
    price: { type; float }
  my_product_i18n:  (国際化対応用テーブル)
    _attributes: {phpName: ProductI18n}
    id: { type: integer, required: true, primaryKey: true, foreignTable: my_product, foreignReference: id }  (省略可)
    culture: { isCulture: true, type: varchar, size: 7,
 foreignTable: my_product, foreignReference: id }  (省略可)
    culture: { isCulture: true, type: varchar, size: 7, required: true, primaryKey: true }  (カルチャ。省略可)
    name:  { type: varchar, size: 50 }
 required: true, primaryKey: true }  (カルチャ。省略可)
    name:  { type: varchar, size: 50 }
ここで各属性の意味を補足しておきます。
| 属性 | 内容 | 
| 「_attributes:」内 | |
| phpName: | テーブルにアクセスするためのオブジェクト名 | 
| isI18N: | trueで国際化機能を持たせる | 
| i18nTable: | 国際化対応用のテーブル名 | 
| 「フィールド名:」内 | |
| type: | (原則必須)BOOLEAN/INTEGER/FLOAT/DATE/VARCHAR/TIMESTAMPなどの型 | 
| required: | trueなら必須項目(デフォルトはfalse) | 
| autoIncrement: | trueならオートインクリメント属性 | 
| primaryKey: | trueなら主キーを示す | 
| foreignTable: | 外部キーに指定、その際の参照先テーブル名 | 
| foreignRefernce: | (foreignTable:指定がある時)外部テーブルの参照先フィールド名 | 
| size: | (文字列型において)最大文字数の指定 | 
| isCulture: | trueであれば国際化対応 | 
この2つのテーブルは1対多で関連しています。上記の例では単一のidごとに、culture(カルチャ)とnameの組み合わせが複数(カルチャの数だけ)存在しています。これでモデルクラスを構築した場合、そのクラスはi18nをサポートしていて、次のようにカルチャを切り替えて利用できます。
$product = ProductPeer::retrieveByPk(1);
$product->setCulture('fr');           (フランス語に設定)
$product->setName('Nom du produit');  (フランス語名を設定)
$product->save();
$product->setCulture('en');           (英語に設定)
$product->setName('Product name');    (英語名を設定)
$product->save();
echo $product->getName();
 => 'Product name'  (英語に設定されているので英語名が出力される)
$product->setCulture('fr');  (フランス語に設定)
echo $product->getName();
 => 'Nom du produit'         (フランス語名が出力される)

 
              
               
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                          
                           
                              
                               
                              
                               
                              
                               
                              
                               
                              
                               
                      
                     
                      
                     
                      
                     
                      
                     
                      
                     
                      
                     
                      
                     
															
														 
															
														.png) 
     
     
     
     
     
													 
													 
													 
													 
													 
										
									
 isI18N: true, i18nTable: my_product_i18n}
    id: { type: integer, required: true,
 isI18N: true, i18nTable: my_product_i18n}
    id: { type: integer, required: true, 
                     
                    