国際的なアプリケーションを開発したことがあるのであれば、テキストの翻訳、ローカルスタンダードとローカライズされた内容のあらゆる面を処理することが悪夢であることはご存じでしょう。幸いにして、symfonyは国際化のすべての面をネイティブに自動化します。
国際化(internationalization)は長い単語なので、開発者はしばしばi18nと表記します(単語の文字数を数えてみればなぜなのかわかります)。ローカライゼーション(localization - 現地化)はl10nと短縮されます。これらは多言語のWebアプリケーションの2つの異なる面をカバーします。
国際化されたアプリケーションはさまざまな言語もしくはフォーマットで同じ内容のいくつかのバージョンを含みます。たとえば、Webメールのインターフェイスはインターフェイスを変更するだけでいくつもの言語で同じサービスを提供できます; インターフェイスだけ変わります。
ローカライズされたアプリケーションはブラウザーから得られた国の情報にしたがって相異なる情報を含みます。ポータルニュースを考えてみましょう。アメリカからブラウザーで見たとき、アメリカについての最新のヘッドラインを表示します。しかし、フランスからブラウザーで見たとき、ヘッドラインはフランスのニュースに関するものです。ローカライズされたアプリケーションは翻訳内容を提供するだけでなく、1つのローカライズされたバージョンから別のバージョンまで異なった内容を提供します。
全体で、国際化とローカライゼーションを扱うことはアプリケーションがつぎの内容を担当することを意味します:
この章ではsymfonyはこれらの要素と国際化とローカライズされたアプリケーションを開発するためにsymfonyを使う方法をカバーします。
symfonyにおけるすべての組み込みの国際化機能はcultureと呼ばれるユーザーセッションのパラメーターに基づいています。cultureはユーザーの国と言語の組み合わせで、テキストとcultureに依存する情報を表示する方法を決定します。これはユーザーセッションのなかでシリアライズされるので、cultureはページのあいだで持続します。
デフォルトでは、新しいユーザーのcultureはdefault_culture
です。リスト13-1で示されるように、この設定をsettings.yml
設定ファイルのなかで変更できます。
リスト13-1 - cultureのデフォルトを設定する(frontend/config/settings.yml
)
all:
.settings:
default_culture: fr_FR
NOTE 開発期間において、
settings.yml
ファイルのなかのcultureを変更してもブラウザーの現在のcultureが変更されないことに驚くかもしれません。セッションが前のページからすでにcultureを持っているからです。新しいデフォルトのcultureを持つアプリケーションを見たい場合、ドメインCookieをクリアする、もしくはブラウザーを再起動する必要があります。
言語と国の両方をcultureに保存しておくことが必要です。なぜなら、フランス、ベルギー、もしくはカナダからの異なったフランス語の翻訳、スペイン、もしくはメキシコからの異なるスペイン語の内容が存在するかもしれないからです。言語はISOの639-1標準規格にしたがって小文字の2文字表記されます(たとえばenは英語)。国はISOの3166-1標準規格にしたがって大文字の2文字で表記されます(たとえばGBはイギリス) 。
ユーザーのcultureはブラウジングセッションの間に変更できます。たとえば、ユーザーがアプリケーションを英語バージョンからフランス語バージョンに切り替えることを決心したとき、ユーザーがアプリケーションにログインしたとき、ユーザーのオプションに保存されている言語が使われます。sfUser
クラスがユーザーのcultureのためにゲッターメソッドとセッターメソッドを提供する理由はそういうわけです。リスト13-2はアクションでこれらのメソッドを使う方法を示しています。
リスト13-2 - アクションのなかでcultureを設定して読みとる
[php]
// cultureのセッター
$this->getUser()->setCulture('en_US');
// cultureのゲッター
$culture = $this->getUser()->getCulture();
=> en_US
SIDEBAR URLのなかのculture
symfonyのローカライゼーションと国際化機能を使うとき、ページは単独のURLに対して異なるバージョンを持つ傾向にあります。これはすべてユーザーセッション次第です。このことによってページが検索エンジンにキャッシュされる、もしくはインデックスに登録されることを防ぎます。
1つの解決方法はcultureがすべてのURLに表示されるようにすることで、翻訳されたページは外部の世界に対して異なるURLとして見なされます。これを行うには、
:sf_culture
トークンをアプリケーションのrouting.yml
のすべてのルールに追加します:page: url: /:sf_culture/:page requirements: { sf_culture: (?:fr|en|de) } params: ... article: url: /:sf_culture/:year/:month/:day/:slug requirements: { sf_culture: (?:fr|en|de) } params: ...
すべての
link_to()
内でsf_culture
リクエストパラメーターを手動で設定することを避けるために、自動的にsymfonyはユーザーのcultureをデフォルトのルーティングパラメーターに追加します。これは内部でも機能します。sf_culture
パラメーターがURLのなかで見つかる場合、自動的にユーザーのcultureを変更するからです。
多くのアプリケーションにおいて、ユーザーのcultureはブラウザーのオプションに基づいた最初のリクエストで定義されます。ユーザーはブラウザーで認められた言語のリストを定義することが可能で、HTTPのAccept-Language
ヘッダーにおいて、各リクエストによってこのデータはサーバーに送信されます。sfWebRequest
オブジェクトを通してこれをsymfony内部で読みとることができます。たとえば、アクションのなかでユーザーの選択言語のリストを取得するには、つぎのコードを記入します:
[php]
$languages = $request->getLanguages();
HTTPのヘッダーは文字列ですが、symfonyは自動的にこれを解析して配列に変換します。前の例ではユーザーの選択言語は$languages[0]
でアクセスできます。
サイトのホームページもしくはすべてのページに対するフィルターのなかでこれはユーザーのcultureをユーザーが選択したブラウザーの言語に自動的に設定するさいに便利です。しかしおそらくあなたのWebサイトは限定された言語の一式しかサポートしないので、getPreferredCulture()
メソッドを使うほうがベターです。これはユーザーが選択した言語とサポートされる言語を比較することでベストな言語を返します:
[php]
$language = $request->getPreferredCulture(array('en', 'fr')); // Webサイトは英語もしくはフランス語で利用できる
マッチするものが存在する場合、メソッドは最初にサポートされる言語を返します (先の例ではen
)。
CAUTION HTTPの
Accept-Language
ヘッダーはあまり信用できる情報ではありません。ユーザーがブラウザーでそれを修正する方法をほとんど知らないからです。多くの場合、選択されたブラウザー言語はインターフェイスの言語で、ブラウザーはすべての言語で利用可能ではありません。ブラウザーが選択した言語にしたがってcultureを自動的に設定することを決める場合、かならず代わりの言語を選択する方法をユーザーに提供してください。
Webアプリケーションの内部は文化の特殊性について考慮していません。たとえば、データベースはデータ、量などを保存する国際標準規格を使います。しかし、データがユーザーから送信されるもしくは読みとられる場合、変換を行う必要があります。ユーザーはタイムスタンプを理解しませんし、Frenchの代わりに母国語のFrançaisと表記することを望みます。ユーザーのcultureに基づいて、自動的に変換を行うための助けが必要です。
いったんcultureが定義されると、これに依存するヘルパーは自動的に適切な出力を持ちます。リスト13-3で示されるように、たとえば、format_number()
ヘルパーは自動的にユーザーが慣れ親しんでいる書式で数字を表示します。
リスト13-3 ユーザーのcultureに合わせて数字を表示する
[php]
<?php use_helper('Number') ?>
<?php $sf_user->setCulture('en_US') ?>
<?php echo format_number(12000.10) ?>
=> '12,000.10'
<?php $sf_user->setCulture('fr_FR') ?>
<?php echo format_number(12000.10) ?>
=> '12 000,10'
明示的にcultureをヘルパーに渡す必要はありません。ヘルパーは現在のセッションオブジェクトのなかでこれら自身でcultureを探します。リスト13-4は出力に対してユーザーのcultureを考慮しているヘルパーの一覧です。
リスト13-4 - cultureに依存するヘルパー
[php]
<?php use_helper('Date') ?>
<?php echo format_date(time()) ?>
=> '9/14/06'
<?php echo format_datetime(time()) ?>
=> 'September 14, 2006 6:11:07 PM CEST'
<?php use_helper('Number') ?>
<?php echo format_number(12000.10) ?>
=> '12,000.10'
<?php echo format_currency(1350, 'USD') ?>
=> '$1,350.00'
<?php use_helper('I18N') ?>
<?php echo format_country('US') ?>
=> 'United States'
<?php format_language('en') ?>
=> 'English'
<?php use_helper('Form') ?>
<?php echo input_date_tag('birth_date', mktime(0, 0, 0, 9, 14, 2006)) ?>
=> input type="text" name="birth_date" id="birth_date" value="9/14/06" size="11" />
<?php echo select_country_tag('country', 'US') ?>
=> <select name="country" id="country"><option value="AF">アフガニスタン</option>
...
<option value="GB">イギリス</option>
<option value="US" selected="selected">アメリカ合衆国</option>
<option value="UM">合衆国領有小離島</option>
<option value="UY">ウルグアイ</option>
...
</select>
日付ヘルパーはcultureから独立した表示を強制する追加のフォーマットパラメーターを受けとることができますが、アプリケーションが国際化されている場合は使うべきではありません。
データをユーザーのcultureに表示することが必要な場合、データを読みとることに関しては、可能なかぎり、すでに国際化されたデータを入力するようにアプリケーションのユーザーを後押しすべきです。このアプローチによって変化するフォーマットと不確定な地域によってデータを変換する方法を理解しなくてもすみます。たとえば、入力ボックスにコンマで区切られた通貨の値を入力しようとする人はいないでしょう。
実際のデータを隠す(select_country_tag()
など)、もしくは複雑なデータの異なるコンポーネントをいくつかのシンプルな入力に分離することで、ユーザーの入力フォーマットをまとめることができます。
日付に関しては、しかしながら、これは利用できないことがよくあります。ユーザーは自身の文化上の書式で日付を入力することに慣れており、このようなデータは内部(と国際化)書式に変換できるようにする必要があります。これがsfI18N
クラスを適用する事例です。リスト13-5はこのクラスの使いかたを示しています。
リスト13-5 - アクションでローカライズされた書式からデータを取得する
[php]
$date= $request->getParameter('birth_date');
$user_culture = $this->getUser()->getCulture();
// タイムスタンプを取得する
$timestamp = $this->getContext()->getI18N()->getTimestampForCulture($date, $user_culture);
// 構造化データを取得する
list($d, $m, $y) = $this->getContext()->getI18N()->getDateForCulture($date, $user_culture);
ローカライズされたアプリケーションはユーザーのcultureにしたがって異なる内容を提供します。たとえば、オンラインショップは製品を同じ価格で世界中に提供できますが、国ごとにカスタマイズされた説明が付属します。このことは、データベースは異なるバージョンのデータの任意の部分を保存できなければならず、そのためには、特定の方法でスキーマを設計しローカライズされたモデルオブジェクトを操作するたびにcultureを使う必要があります。
ローカライズされたいくつかのデータを含むそれぞれのテーブルに対して、テーブルを2つの部分に分割すべきです; 1つのテーブルは国際化カラムを持たず、一方のテーブルは国際化カラムだけを持ちます。2つのテーブルは一対多のリレーションによってリンクされます。モデルを変更しないことを求められたときに、このセットアップによってより多くの言語を追加できるようになります。たとえばProduct
テーブルを使うことを考えてみましょう。
最初に、リスト13-6で示されているように、テーブルをschema.yml
ファイルのなかに作ります。
リスト13-6 - 国際化データのためのスキーマのサンプル(config/schema.yml
)
my_connection:
my_product:
_attributes: { phpName: Product, 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, foreignTable: my_product, foreignReference: id }
culture: { isCulture: true, type: varchar, size: 7, required: true, primaryKey: true }
name: { type: varchar, size: 50 }
最初のテーブル内のisI18N
属性とi18nTable
属性と、2番目のテーブル内の特別なculture
カラムに注目してください。これらすべてはsymfony固有のPropelの強化機能です。
symfonyの自動化によってこれを書くことがはるかに速くなります。国際化したデータを含むテーブルがサフィックスとして_i18n
を持つメインのテーブルと同じ名前を持ち、それらが両方のテーブルでid
という名前のカラムに関連している場合、メインテーブルに対するi18n属性と同様に、_i18n
テーブルにおいてid
カラムとculture
カラムを省略できます; symfonyはこれらを推察します。このことはsymfonyはリスト13-7にあるスキーマをリスト13-6のスキーマと同じものとみなすということを意味します。
リスト13-7 - 省略形式の、国際化データのスキーマのサンプル(config/schema.yml
)
my_connection:
my_product:
_attributes: { phpName: Product }
id:
price: float
my_product_i18n:
_attributes: { phpName: ProductI18n }
name: varchar(50)
いったん対応するオブジェクトモデルがビルドされると(schema.yml
をそれぞれ修正した後にpropel:build-model
タスクを呼び出すことをお忘れなく)、リスト13-8で示されるように、あたかも1つのテーブルしか存在しないかのように、国際化のサポートをするProduct
クラスを使うことができます。
リスト13-8 - 国際化オブジェクトを処理する
[php]
$product = ProductPeer::retrieveByPk(1);
$product->setName('Nom du produit'); // デフォルトでは、cultureは現在のユーザーのculture
$product->save();
echo $product->getName();
=> 'Nom du produit'
$product->setName('Product name', 'en'); // 'en' culture用の値に変更する
$product->save();
echo $product->getName('en');
=> 'Product name'
ピアオブジェクトを持つクエリに関しては、リスト13-10で示されるように、通常のdoSelect
の代わりに、doSelectWithI18n
メソッドを使うことで現在のcultureのための翻訳内容を持つオブジェクトへの結果を制限できます。加えて、このメソッドは同時に通常のオブジェクトに関して関連する国際化オブジェクトを作成します。結果として全内容を取得するクエリの数を減らすことになります(パフォーマンスにおけるこのメソッドのプラスの影響に関する詳細な情報は18章を参照)。
リスト13-10 - 国際化されたCriteria
でオブジェクトを取得する
[php]
$c = new Criteria();
$c->add(ProductPeer::PRICE, 100, Criteria::LESS_THAN);
$products = ProductPeer::doSelectWithI18n($c, $culture);
// $culture引数はオプション
// cultureが与えられていない場合現在のユーザーのcultureが使われる
ですので、基本的には、国際化オブジェクトを直接処理する必要は決してありませんが、代わりに通常のオブジェクトを持つクエリを行うたびにcultureをモデルに渡します(もしくは推測させます)。
ユーザーのインターフェイスは国際化アプリケーションに適用させる必要があります。テンプレートは、同じプレゼンテーションによってですが、いくつかの言語でラベル、メッセージ、とナビゲーションを表示できます。symfonyは、デフォルトの言語でテンプレートを開発し、その上でテンプレート内部で使われるフレーズのための翻訳文を辞書ファイルで提供することを推奨します。そういうわけで、翻訳内容を修正、追加、もしくは削除するたびにテンプレートを変更する必要はありません。
テンプレートはデフォルトでは翻訳されません。このことは、リスト13-11で示されるように、ほかのすべてに先だってsettings.yml
ファイルでテンプレート翻訳機能を有効にする必要があることを意味します。
リスト13-11 - インターフェイス翻訳を有効にする(frontend/config/settings.yml
)
all:
.settings:
i18n: on
英語がデフォルトの言語で、英語とフランス語のサイトを作りたい場合を例に挙げてみましょう。サイトを翻訳することを考えるまえに、おそらくはリスト13-12の例で示されるようなテンプレートを書くでしょう。
リスト13-12 - 単独の言語テンプレート
[php]
Welcome to our website. Today's date is <?php echo format_date(date()) ?>
テンプレートの語句を翻訳するsymfonyのために、これらの語句は翻訳される文章として認識されなければなりません。これが__()
ヘルパー(2つのアンダースコア)、国際化ヘルパーグループのメンバーの目的です。ですので、すべてのテンプレートは翻訳するためにこのような関数呼び出し内部で語句を閉じている必要があります。リスト13-12は、たとえば、リスト13-13のように修正できます(この章の後のほうの"複雑な翻訳ニーズを扱う"のセクションでご覧頂けます。そこではこの例の翻訳ヘルパーを呼び出す方法より優れた方法があります) 。
リスト13-13 - 多言語の準備ができているテンプレート
[php]
<?php use_helper('I18N') ?>
<?php echo __('Welcome to our website.') ?>
<?php echo __("Today's date is ") ?>
<?php echo format_date(date()) ?>
TIP アプリケーションがすべてのページに対して国際化ヘルパーグループを使う場合、それぞれのテンプレートに対して
use_helper('I18N')
を繰り返すことを避けるために、ヘルパーをsettings.yml
ファイルのstandard_helpers
設定に含めることはおそらくよいアイディアです。
__()
関数が呼び出されるたびに、symfonyは現在のユーザーのcultureの辞書で引数の翻訳を探します。対応する語句が見つかったら、翻訳が送り戻され、レスポンスに表示されます。ですのでユーザーのインターフェイスの翻訳は辞書ファイルに依存します。
辞書ファイルはmessages.[language code].xml
にしたがって名づけられたXLIFF(XML Localization Interchange File Format)で書かれており、アプリケーションのi18n/
ディレクトリに保存されます。
XLIFFはXMLに基づいた標準フォーマットです。よく知られているように、Webサイトにおいてテキストを参照し翻訳するためにサードパーティの翻訳ツールを利用できます。翻訳会社はこのようなファイルの扱いかたや、新しいXLIFFフォーマットの翻訳文を追加することでサイト全体を翻訳する方法を知っています。
TIP XLIFF標準規格に加え、symfonyは辞書のためにいくつかのほかの翻訳用のバックエンドツールも提供します: gettext、MySQL、SQLite、とCreoleです。これらのバックエンドツールを設定することに関する詳細な情報はAPIドキュメントを参照してください。
リスト13-14はリスト13-13をフランス語に翻訳するために必要なmessages.fr.xml
ファイルのなかでXLIFF構文の例を示しています。
リスト13-14 - XLIFF辞書(frontend/i18n/messages.fr.xml
)
[xml]
<?xml version="1.0" ?>
<xliff version="1.0">
<file orginal="global" source-language="en_US" datatype="plaintext">
<body>
<trans-unit id="1">
<source>Welcome to our website.</source>
<target>Bienvenue sur notre site web.</target>
</trans-unit>
<trans-unit id="2">
<source>Today's date is </source>
<target>La date d'aujourd'hui est </target>
</trans-unit>
</body>
</file>
</xliff>
source-language
属性はつねにあなたのcultureのすべてのISOコードを含まなければなりません。それぞれの翻訳は一意的なid
属性を持つtrans-unit
タグで書きます。
デフォルトのユーザーのcultureによって(en_US
に設定します)、語句は翻訳されず、__()
の生の引数呼び出しが表示されます。リスト13-13の結果はリスト13-12に似ています。しかしながら、cultureがfr_FR
もしくはfr_BE
に変更された場合、リスト13-15のようなmessages.fr.xml
ファイルからの翻訳が代わりに表示されます。
リスト13-15 - 翻訳されたテンプレート
[php]
Bienvenue sur notre site web. La date d'aujourd'hui est
<?php echo format_date(date()) ?>
追加翻訳が必要な場合、同じディレクトリに新しいmessages.XX.xml
翻訳ファイルを追加するだけです。
TIP 辞書ファイルを探し、それらを解析し、任意の文字列に対して正しい翻訳を見つけることはある程度の時間がかかるので、symfonyはプロセスを加速するために内部キャッシュを利用します。デフォルトでは、このキャッシュはファイルシステムを使います。(たとえば、いくつかのサーバー間のキャッシュを共有するために)
factories.yml
(19章を参照)でi18Nキャッシュが動作する方法を設定できます。
messages.XX.xml
ファイルが長すぎて読みにくくなった場合、つねに翻訳をテーマによって名づけられたいくつかの辞書ファイルに分割することができます。たとえば、messages.fr.xml
ファイルをアプリケーションのi18n/
ディレクトリのなかでつぎの3つのファイルに分割できます:
navigation.fr.xml
terms_of_service.fr.xml
search.fr.xml
翻訳がデフォルトのmessages.XX.xml
ファイルですぐに見つからないのであれば、3番目の引数を使う__()
ヘルパーを呼び出すたびにどの辞書を使うのか宣言しなければならないことに注意してください。たとえば、navigation.fr.xml
の辞書で翻訳された文字列を出力するには、つぎのように書きます:
[php]
<?php echo __('Welcome to our website', null, 'navigation') ?>
翻訳辞書を編成する別の方法はモジュールによって分割することです。アプリケーション全体に対して単独のmessages.XX.xml
ファイルを書く代わりに、modules/[module_name]/i18n/
ディレクトリごとに1つのモジュールを書けます。このことによってアプリケーションからモジュールをより独立したものにします。プラグイン(17章を参照)といったものを再利用したい場合に必要です。
symfony 1.1の新しい機能
国際化用の辞書を手動で更新するとよくエラーになりやすいので、symfonyはこのプロセスを自動化するタスクを提供します。 i18n-extract
タスクは翻訳されるすべての文字列を抽出するためにsymfonyのアプリケーションを解析します。このタスクはアプリケーションとcultureを引数としてとります:
> php symfony i18n:extract frontend en
デフォルトでは、タスクは辞書を修正しないので、これは新旧の国際化された文字列の数を出力します。新しい文字列を辞書に追加するには、--auto-save
オプションを渡すことができます:
> php symfony i18n:extract --auto-save frontend en
--auto-delete
オプションを渡すことで自動的に古い文字列を削除することもできます:
> php symfony i18n:extract --auto-save --auto-delete frontend en
NOTE 現在のタスクは既知の制限をいくつか持ちます。これはデフォルトの
messages
辞書と、バックエンドに基づいたファイル(XLIFF
とgettext
)に基づいたファイルに対してのみ動作します。このタスクはマインのapps/frontend/i18n/messages.XX.xml
ファイルの文字列の保存と削除のみ行います。
つぎの項目は翻訳が必要かもしれないそのほかの要素です:
画像、テキストのドキュメント、もしくはほかのタイプのアセットもユーザーのcultureにしたがって変わることがあります。最良の例は実際は画像であるタイポグラフィを持つテキストの一部です。これらのために、ユーザーのculture
の名前を取ったサブディレクトリを作ることができます:
[php] getCulture().'/myText.gif') ?>
バリデーションファイルからのエラーメッセージは__()
によって自動的に出力されるので、これらを翻訳する辞書に追加する必要があります。
default
モジュールを作成し、__()
をテンプレートのなかで使うべきです。これらのページをカスタマイズする方法は19章を参照してください。翻訳は__()
の引数が完全な文である場合のみ意味をなします。しかしながら、単語と混ざったフォーマットもしくは変数を持つ場合、文をいくつかのチャンク(塊)に分割したくなることがありますが、ヘルパーを無意味な文に呼び出す結果になります。幸いにして、__()
ヘルパーはトークン(字句)に基づいた置き換え機能を提供します。この機能は翻訳者がより扱いやすい意味にある辞書を持つための助けになります。HTMLのフォーマッティングと同様に、ヘルパー呼び出しで同じようにトークンをそのままにできます。リスト13-16は例を示しています。
リスト13-16 - コードを含むセンテンスを翻訳する
[php]
// 基本例
Welcome to all the <b>new</b> users.<br />
There are <?php echo count_logged() ?> persons logged.
// テキストの翻訳機能を有効にするためのわるい方法
<?php echo __('Welcome to all the') ?>
<b><?php echo __('new') ?></b>
<?php echo __('users') ?>.<br />
<?php echo __('There are') ?>
<?php echo count_logged() ?>
<?php echo __('persons logged') ?>
// テキストの翻訳機能を有効にするためのよい方法
<?php echo __('Welcome to all the <b>new</b> users') ?> <br />
<?php echo __('There are %1% persons logged', array('%1%' => count_logged())) ?>
この例では、トークンは%1%
ですが、決して何でもよいわけではありません。 なぜなら翻訳ヘルパーによって使われる置き換え関数がstrtr()
だからです。
翻訳に関する共通問題の1つは複数形の使いかたです。結果の数に応じて、テキストは変わりますが、言語に従った同じ方法では変わりません。たとえば、リスト13-16の最後のセンテンスはcount_logged()
が0
もしくは1
を返す場合には正しくはありません。この関数の戻り値をテストし、使うセンテンスがどれなのかを選択できますが、これはたくさんのコードが必要になることを意味します。加えて、異なる言語は異なる文法のルールを持ち、複数形の語形変化のルールはとても複雑になる場合があります。この問題は非常にありふれたものなので、symfonyは、format_number_choice()
と呼ばれる、この問題を処理するヘルパーを提供します。リスト13-17はこのヘルパーを使う方法を示しています。
リスト13-17 - パラメーターの値に依存するセンテンスを翻訳する
[php]
<?php echo format_number_choice(
'[0]Nobody is logged|[1]There is 1 person logged|(1,+Inf]There are %1% persons logged', array('%1%' => count_logged()), count_logged()) ?>
最初の引数はテキストの複数の選択肢です。2番目の引数は(__()
ヘルパーに関する)置き換えパターンのオプションです。3番目の引数はどのテキストが取られるのかを決めるテスト上の数字です。
つぎのような構文を使うことで、メッセージ/文字列の選択は許可される値の配列の後に続くパイプ(|
)文字によって分離されます:
[1,2]
: 1と2も含めて、1と2の間の値を許可する(1,2)
: 1と2を除いて、1と2の間の値を許可する{1,2,3,4}
: 集合で定義された値のみ許可する[-Inf,0)
: 負の無限大よりも大きいもしくは厳密に0未満の値を許可する{n: n % 10 > 1 && n % 10 < 5} pliki
: 2、3、4、 22、23、24のような数字をマッチする(ポーランド語やロシア語のような言語に対して便利です) 開発バージョンの新しい機能角かっこと丸かっこの区切り子の空ではない組み合わせが許容されます。
翻訳機能を適切に機能させるにはメッセージをXLIFFファイルに明示的に表示しなければなりません。リスト13-18は例を示しています。
リスト13-18 - format_number_choice()
引数に対するXLIFFの辞書
...
<trans-unit id="3">
<source>[0]Nobody is logged|[1]There is 1 person logged|(1,+Inf]There are %1% persons logged</source>
<target>[0]Personne n'est connecté|[1]Une personne est connectée|(1,+Inf]Il y a %1% personnes en ligne</target>
</trans-unit>
...
SIDEBAR 文字集合のための少しの説明
テンプレートで国際化された内容を処理することはしばし文字集合の問題につながります。ローカライズされた文字コードを使う場合、ユーザーがcultureを変更するたびに文字コードも変更することが必要になります。加えて、任意の文字コードで書かれたテンプレートはほかの文字コードの文字を正確に表示しません。
複数のcultureを扱うと同時に、すべてのテンプレートがUTF-8で保存され、レイアウトがこの文字コードで内容を宣言しなければならない訳はそういうわけです。つねにUTF-8で扱えば、不愉快な不意打ちに合わなくてすみますし、やっかいな問題を悩まずにすみます。
symfonyのアプリケーションは
settings.yml
ファイルのなかの文字コードに関する1つのなか心的な設定に依存します。このパラメーターを変更することはすべてのレスポンスのContent-Type
ヘッダーを変更することになります。all: .settings: charset: utf-8
ページに表示されるテキストのすべてがテンプレートによってもたらされたものではありません。アプリケーションのほかの部分: アクション、フィルター、モデルクラスなどで、__()
ヘルパーをしばし呼び出す必要があるのはそういうわけです。リスト13-19はContext Singletonを通してI18N
オブジェクトの現在のインスタンスを読みとることでアクションでヘルパーを呼び出す方法を示しています。
リスト13-19 - アクションで__()
を呼び出す
[php]
$this->getContext()->getI18N()->__($text, $args, 'messages');
ユーザーのcultureの扱いかたを理解しているのであればWebアプリケーションで国際化とローカライズする作業は苦痛をともなわずに行うことができます。ヘルパーはフォーマットされたデータを正しく出力する方法を自動的に考慮し、データベースから読みとられたローカライズされた内容はあたかもシンプルなテーブルの一部として見なされます。インターフェイスの翻訳に関しては、__()
ヘルパーとXLIFFの辞書によって最小限の労力で最大限の結果が保証されます。