本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

PHP V5.3 では Unicode に関して何が新しいのか

Unicode と国際化サポート

Jirka Kosek, Author, Consultant
Photo of Jirka Kosek
Jirka Kosek は、フリーランスの XML コンサルタントであると同時に、プラハの University of Economics で教職に就いています。これまで 10 年以上、XML のコンサルタントとトレーニングを行ってきました。OASIS (DocBook TC、RELAX NG TC)、W3C (XSL WG、ITS WG)、ISO/IEC JTC1/SC34 (DSDL、Topic Maps) をはじめ、複数の標準化団体のメンバーとしても活躍しています。Jirka は Web 技術に関する本や記事を何本か執筆しています。彼は時間があるときには、DocBook XSL スタイルシートのオープンソース・プロジェクトにコードを提供しています。彼の最近の業績と構想については、彼のブログを参照してください。

概要: PHP はよく使用される言語ですが、まだ相変わらず Unicode を適切にサポートしていません。しかし最近リリースされたV5.3 には、有名な ICU ライブラリーをベースに作成された国際化ライブラリーが追加されています。この新しいライブラリーを使用すると、さまざまなロケールに対して数字や日付の比較、ソート、フォーマット設定を適切に行うことができます。この新しいライブラリーを使用してアプリケーションを適切に国際化する方法、そして Unicode に関する一般的な問題を克服する方法を学びましょう。

日付:  2009年 12月 15日
レベル:  中級 この記事の原文:  英語
アクティビティー: 3777 ビュー
お気軽にご意見・ご感想をお寄せください: 


Web は全世界を対象とするアプリケーションやサービスを開発するための理想的なプラットフォームですが、本当に全世界で使われるアプリケーションを作成するためには、さまざまな言語体系や表記体系でデータの処理や表示ができるようにアプリケーションを加工する必要があります。

よく使われる頭字語

  • HTML: HyperText Markup Language
  • HTTP: HyperText Transfer Protocol
  • IETF: Internet Engineering Task Force
  • UI: User interface
  • XML: Extensible Markup Language

他の言語用にアプリケーションを加工するための段階はいくつかあり、第 1 段階は、いわゆる国際化です (国際化 (internationalization) は i18n と省略されることがよくあります)。国際化の目的は、ユーザーの国の言葉や表記方式をアプリケーションで使えるようにすることであり、例えばデータの入力や表示に特別な文字を使えるようにすることや、数字や日付を適切なフォーマットで表示すること、言語特有の規則に従ってリストをソートすることなどが含まれます。

より高度な手法として、ローカライズもあります (ローカライズ (localization) は l10n と省略されることがよくあります)。ローカライズでは、文化的、言語学的、そして地域的な特有の習慣に合わせてアプリケーションを加工します。このプロセスには、その地域で使われている言語への翻訳や、日付、数字、通貨のフォーマットをその地域に合った適切なフォーマットへ変換すること、そしてソート・ルールの変更などが含まれます。

この記事では PHP V5.3 の新機能について説明します。これらの新機能によって、国際化されたアプリケーションを PHP で容易に作成できるようになります。この記事では、ローカライズに関する一般的な問題、特に翻訳については取り上げません。翻訳に関しては、GNU の gettext のような PHP ライブラリーを追加することで処理すると最適です (「参考文献」を参照)。

PHP での Unicode のサポート

適切に国際化されたアプリケーションであるためには、さまざまな表記体系で記述されたデータを処理できる必要があります。西ヨーロッパで使用される英語およびその他の言語はラテン文字体系に基づいており、ラテン文字のみを使用しますが、場合によるとアクセント記号 (発音区別符号) が追加されている場合があります。東に移動していくと、中東にはキリル文字、ヘブライ文字、アラビア文字などの文字体系があり、続いてインド語系の文字が何種類かあり、さらに東へ行くと中国語や日本語、その他十数種類の東洋の文字体系があります。一般的に使用される文字体系の大部分は Unicode による文字セットに含まれています (詳細は「参考文献」を参照)。

しかし Unicode 文字は抽象的なものにすぎません。メモリーやディスクに保存する場合、あるいはネットワークを介して送信する場合には、コンピューター・システムは Unicode 文字をエンコードする必要があります。Unicode にはいくつかのエンコード方式が使われますが、なかでも最もよく使われる方式は UTF-8 と UTF-16 の 2 つです。Java™ 技術や Microsoft® .NET Framework などの最近の開発環境は Unicode を使用しており、また Unicode 文字やストリングのためのデータ型を持っています。そのため開発者は、Unicode 文字を使用したテキストを扱うことをまったく意識する必要がありません。ライブラリー関数が、すべての入力と出力 (UI、HTML フォーム、データベース、XML) を適切に処理し、必要に応じて Unicode ストリングを表示するために使用する内部エンコーディングへと変換してくれるのです。

残念ながら、PHP 言語には未だに適切な Unicode のサポートがありません。PHP の開発者の中心となる人達は、PHP に Unicode サポートを追加することを 2001年以来考えていますが、PHP V5.3 にさえ Unicode のサポートは含まれていません。しかし次のメジャー・リリースである PHP V6 では Unicode のサポートが計画されています。


PHP で Unicode がサポートされていない問題を克服する

PHP で Unicode がサポートされていないことは残念ですが、たとえ PHP を使用する場合であっても、適切に国際化されたアプリケーションを作成する方法がいくつかあります。それらの方法で最初に解決しなければならない問題は、Unicode データを適切に表示できるようにすることです。PHP は、いわゆるバイナリー・ストリングを使います。つまり PHP ではストリングは Unicode 文字の連続ではなく、バイトの連続です。したがって、Unicode に対応する方法としては、ストリングを保存する際に内部ではすべて UTF-8 エンコーディングで保存するようにしておき、スクリプトとの受け渡しのときに適切にエンコード、デコードするという方法を取ることができます。

理論的には UTF-8 以外のエンコーディングを使うこともできますが、他の方式を使うよりも UTF-8 を使用した方が無難です。多くの PHP ライブラリーでは、ストリングが UTF-8 でエンコードされていることを初めから想定しており、XML を扱う関数や、新たに追加された intl ライブラリーなども、すべて同様です。UTF-8 でエンコードされたストリングを容易に処理するためには、文字は UTF-8 でエンコードするようにし、スクリプトの出力も UTF-8 でエンコードして送信するようにしておくのが最適です。

それでも、すべてを UTF-8 にしたからといって、あらゆる問題が解決されるわけではありません。アクセント記号付きラテン文字やラテン語以外の文字を UTF-8 でエンコードすると、1 文字が 2 バイト、3 バイト、または 4 バイトものサイズとなり、ストリング長の計算やサブストリングの処理を行う PHP のストリング関数が混乱してしまいます。この問題を示したものがリスト 1 です。


リスト 1. PHP で Unicode が適切にサポートされていないことによる問題

<?php

Header("Content-type: text/plain;charset=utf-8");
 
$text["en"] = "The Hitchhiker's Guide to the Galaxy";
$text["es"] = "Guía del autoestopista galáctico";
$text["cs"] = "Stopařův průvodce po Galaxii";
$text["ru"] = "Путеводитель хитч-хайкера по Галактике";
$text["ja"] = "銀河ヒッチハイク・ガイド";

foreach($text as $lang => $t)
{
 echo $lang, ": ", $t, " (", strlen($t), " vs. ", mb_strlen($t, "utf-8"), ")\n";
}
?>

このリストから出力される結果を示したものが図 1 です。


図 1. UTF-8 でエンコードされたテキストに対して単純な PHP ストリング関数を実行すると返される不適切な結果
単純な PHP ストリング関数の出力を表示する画像

これを見るとわかるように、さまざまな表記体系でストリング長が誤って計算されています。ラテン語の文字から成るテキストの場合にのみ、正しい結果が返されています。この問題は、mbstring ライブラリー (「参考文献」を参照) の関数を使用することで解決することができます。つまり、UTF-8 でエンコードされたストリングの正しい長さを取得するためには、単純な strlen(string) ではなく mb_strlen(string, "utf-8") を使う必要があります。

エディターを構成する

リスト 1 のコードは UTF-8 でエンコードされています。そのため、UTF-8 エンコーディングを使用するようにエディターを適切に構成してからファイルをロードする必要があります。同様に、出力エンコーディングが UTF-8 になるように、適切な HTTP ヘッダーを使ってエンコーディングを設定する必要があります。そうしないとブラウザーには適切な出力が表示されません。

スクリプトが UTF-8 でデータを処理するようになると、intl ライブラリーを使ってより多くの国際化機能を追加できるようになります。

intl ライブラリーをインストールする

intl ライブラリーは、有名な ICU (International Components for Unicode) ライブラリー (「参考文献」を参照) に対する PHP のラッパーです。多くのアプリケーションは ICU を使用して Unicode とローカライズのサポートを実装しています。

V5.3 から、PHP には intl ライブラリーが標準で含まれるようになっています。PHP V5.3 またはそれ以降を持っている人は、このライブラリーが使えるはずです。古いバージョンの PHP の場合も、PECL 拡張機能を使うことで intl ライブラリーを使うことができます。


ロケールを扱う

ローカライズを制御するための、言語、地域、表記体系、その他のパラメーターの組み合わせは、ロケールとして知られています。ロケールは通常、IETF の BCP (Best Current Practices) 47 で定義される言語タグ (詳細は「参考文献」を参照) によって識別されます。例えば、英語は単純な en タグによって識別されます。同じ言語でも異なる地域で歴史的に発展してきた言語の間には、今日では大きな違いが生じています。こうした状況に対応するために、言語の ID の後に国の ID を追加します。例えば、pt_PT はポルトガルで使われているポルトガル語を指し、pt_BR はブラジルで使われているポルトガル語を表します。BCP 47 ではさらに詳細な制御を定義していますが、この記事では簡単にするために、ロケール ID の詳細については説明しないことにします。

intl のすべての関数とメソッドはロケールを認識し、言語タグをロケール ID として受け付けます。また、intl ライブラリーには関数型とオブジェクト指向の 2 つのインターフェースが用意されており、PHP のコーディング・スタイルに応じて適切なインターフェースを選択することができます。例えば、あるロケールの言語の名前を、選択された言語で返す関数やメソッドがあります。関数型の表記を使用した場合、以下のように記述することで、そのコードを呼び出すことができます。

// return name of language used for "en" locale in French (fr)
echo locale_get_display_language("en", "fr"); // Anglais

オブジェクト指向の方法が望ましい場合は、上記に対応する以下の静的メソッドを使用することができます。

// return name of language used for "en" locale in French (fr)
echo Locale::getDisplayLanguage("en", "fr"); // Anglais

intl ライブラリーの Locale クラスには便利なユーティリティー・メソッドが定義されています。そのいくつかの例をリスト 2 に挙げます。


リスト 2. Locale クラスのメソッドを使用する

<?php
Header("Content-type: text/plain; charset=utf-8");
 
// display name of Portuguese as used in Brazil in different languages
echo Locale::getDisplayName("pt_BR", "en"), "\n";
echo Locale::getDisplayName("pt_BR", "de"), "\n";
echo Locale::getDisplayName("pt_BR", "ru"), "\n";
echo Locale::getDisplayName("pt_BR", "ja"), "\n";
 
// return preferred locale set in user's browser
echo "Preferred locale from browser: ", 
     Locale::acceptFromHttp($_SERVER['HTTP_ACCEPT_LANGUAGE']);
?>

このスクリプトによって、指定したロケール (pt_BR) の言語名 (ポルトガル語) と国名 (ブラジル) がいくつかの異なる言語で出力されます。また、acceptFromHttp() メソッドによって、ユーザーが設定した推奨ロケールを読み取ることができます。このリストから出力される結果を示したものが図 2 です。


図 2. リスト 2 のコードによる出力
Locale クラスの出力を示す画像


数字のフォーマットを設定する

ちょっと考えると、数字のフォーマットの設定は容易なことのように思えますが、ありとあらゆるこまごました詳細 (さまざまな言語での異なる小数点区切りや桁区切りなど) を設定しなければならない場合には、intl を使用するとすべての処理を行ってくれるので便利です。数字や通貨のフォーマット設定以外にも、intl はさらに高度な処理もすることができ (例えば数字を文字で適切に表現する、など)、しかもそれが英語に対してだけではなく、サポートされる多くのロケールでも可能なのです。

フォーマット設定機能は、NumberFormatter クラスの関数として (numfmt_ 接頭辞で始まります)、あるいはメソッドとして利用することができます。この記事の例ではオブジェクト指向のスタイルを使用しますが、関数型の方法でも同じ結果を得ることができます。

フォーマット設定を行う前に、NumberFormatter の新しいインスタンスを作成する必要があります。そして、コンストラクター・メソッドの引数として、フォーマッターのロケール ID とスタイルを指定する必要があります。スタイルを指定するためには、いくつかの定義ずみ定数を使います (NumberFormatter::DECIMAL (小数点形式)、NumberFormatter::CURRENCY (通貨形式)、NumberFormatter::SCIENTIFIC (科学形式)、NumberFormatter::SPELLOUT (数字を文字として綴る) など)。以下に一例を示します。

$fmt = new NumberFormatter("en", NumberFormatter::SPELLOUT);

新たに作成されたフォーマッターでは、いくつかのメソッドを呼び出すことができます。最も便利なメソッドはおそらく、数字のフォーマット設定のための format() と、金額のフォーマット設定のための formatCurrency() でしょう。formatCurrency() メソッドは 2 番目の引数として通貨コードを受け付けます。この 2 つのメソッドの使い方をリスト 3 に示します。


リスト 3. FormatNumber クラスのメソッドの使い方

<?php
Header("Content-type: text/plain; charset=utf-8");
 
// Locale-aware number formatting
$fmt = new NumberFormatter("en", NumberFormatter::DECIMAL);
echo $fmt->format(19841984.123456), "\n";
 
// Spelling out numbers in English
$fmt = new NumberFormatter("en", NumberFormatter::SPELLOUT);
echo $fmt->format(1984), "\n";
 
// Spelling out numbers in Russian
$fmt = new NumberFormatter("ru", NumberFormatter::SPELLOUT);
echo $fmt->format(1984), "\n";
 
// Formatting Euro and Czech crowns in German
$fmt = new NumberFormatter("de", NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(123456.789, "EUR"), "\n";
echo $fmt->formatCurrency(123456.789, "CZK"), "\n";
 
// Formatting Euro and Czech crowns in Czech
$fmt = new NumberFormatter("cs", NumberFormatter::CURRENCY);
echo $fmt->formatCurrency(123456.789, "EUR"), "\n";
echo $fmt->formatCurrency(123456.789, "CZK"), "\n";

?>

図 3 に示す出力を見るとわかるように、十進数が適切に桁区切りされ、また小数点で区切られて表示されています。英語とロシア語を理解する読者であれば、数字が適切な綴りで表現されていることも確認できるはずです。そして最後に、EUR などの一部の通貨コードが自動的に と表され、それ以外はローカライズされた形式で表現されていることがわかります (例えばチェコのクラウン通貨 (CZK) はチェコ語で と表記されています)。


図 3. リスト 3 のスクリプトの出力
FormatNumber クラスの出力を示す画像


データの比較および並び替え

多くのアプリケーションでは、データをソートしてから表示する必要があります。しかし、英語以外の言語での文字の並び替えルールは複雑な場合があります。アクセント記号付き文字は通常、特別な方法で処理されます。例えば、一部の言語ではソートをする際に、特定の形式で連続している 2 つの文字は 1 つの文字として扱います (チェコ語や伝統的なスペイン語での ch など)。幸いなことに、intl ライブラリーには Collator クラス (そして collator_ で始まる名前を持つシャドウ関数) があり、このクラスを使うことで、選択されたロケールに従ってストリングの比較やソートを行うことができます。

比較やソートを行うには、新しい Collator クラスを作成し、そのクラスにロケールを指定する必要があります (例えば $coll = new Collator("en_US"); など)。

これにより、この作成されたオブジェクトのさまざまなメソッドを呼び出せるようになります。例えば、compare() メソッドは 2 つのストリングを比較します。sort() メソッドと asort() メソッドは、これらのメソッドに対応する PHP の配列関数と同様の方法で配列または連想配列をソートします。リスト 4 のコードは、これとは異なる方法で Collator に使用されるロケールを基に、チェコ語の単語の配列をソートする方法を示しています。


リスト 4. 異なるロケールでの並び替え

<?php

Header("Content-type: text/plain; charset=utf-8");
 
// words to sort
$words = array("čočka", "čekanka", "cena", "chalupa",
               "ťululum", "dálnopis", "tyfus", "traktor");
 
// sort using built-in PHP sort function
sort($words);
echo "Words sorted using built-in sort function:\n";
var_export($words);

// sort according to English rules
$coll = new Collator("en_US");
$coll->sort($words);
echo "\n\nWords sorted according to English rules:\n";
var_export($words);

// sort according to Czech rules
$coll = new Collator("cs");
$coll->sort($words);
echo "\n\nWords sorted according to Czech rules:\n";
var_export($words);

?>

PHP に組み込みの sort() 関数を使って単語群をソートすると、アクセント記号付き文字で始まる単語は並びの最後に来ます。これは PHP がストリングをバイナリー値として比較し、アクセント記号付き文字を特別な方法では扱わないからです。しかし同じ単語群のソートを、英語用に作成された Collator を使って行うと、まるでアクセント記号付き文字が無視されたかのようにソートされます。これは英語のテキストの中に英語以外の単語がいくつか混在している場合には望ましい動作です。そしてリスト 4 の最後では、チェコ語の Collator が使われています。見るとわかるように、今度は奇妙なルールが適用されています。つまり、一部のアクセント記号付き文字 (例えば ť など) はアクセント記号が付いていない文字と同様に扱われ、一部の文字 (例えば c や č など) は別々の文字として扱われ、そして ch は特殊文字として扱われています。図 4 はリスト 4 のコードの実行結果を示しています。


図 4. リスト 4 のスクリプトの出力
リスト 4 のスクリプトの出力を示す画像


高度な話題

Unicode と国際化は大きなトピックですが、少なくとももう 1 つ、重要なことを知っておかなければなりません。Unicode では歴史的な理由から、一部の文字に対して 2 つの表記方法が許されています。例えば á は、Unicode のコード・ポイント U+00E1 を持つ合成された文字の á として表記することも、あるいは a という文字 (U+0061) と ´ という強勢記号 (U+0301) という別々の文字に分解し、それらを組み合わせた文字として表記することもできます。比較やソートを行う場合には、この 2 つの表記方法を同じものとして扱う必要があります。

この状況を解決するために、intl ライブラリーには Normalizer クラスが用意されています。このクラスは normalize() メソッドを提供しており、このメソッドを使うことで、正規化された合成形式または分解形式にストリングを変換することができます。アプリケーションでは比較を行う前に、一貫した方法ですべてのストリングをいずれかの形式に変換する必要があります。

echo Normalizer::normalize("a´, Normalizer::FORM_C); // á 
echo Normalizer::normalize("á", Normalizer::FORM_D);      // a´


まとめ

この短い記事では、intl ライブラリーが提供している最も重要かつ有用な機能を紹介しました。このライブラリーは PHP V5.3 の標準的な部分となっています。このライブラリーには他にも、ローカライズ形式で保存された日付のフォーマット設定や値の解析など、この記事では説明しきれなかったさまざまな機能が豊富にあります。詳細については PHP のサイトで PHP のマニュアルを参照してください。



ダウンロード

内容ファイル名サイズダウンロード形式
Source code for this articleos-php-5.3unicode-source.zip4KBHTTP

ダウンロード形式について


参考文献

学ぶために

製品や技術を入手するために

  • PHP の翻訳ライブラリー、GNU gettext について調べてください。

  • 国際化ライブラリー、mbstring をダウンロードし、このライブラリーについて学んでください。

  • ICU ライブラリーをダウンロードし、このライブラリーについて学んでください。

  • 皆さんの次期オープンソース開発プロジェクトを IBM ソフトウェアの試用版を使って革新してください。ダウンロード、あるいは DVD で入手することができます。

  • IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox のオンライン試用版で、DB2®、Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。

議論するために

著者について

Photo of Jirka Kosek

Jirka Kosek は、フリーランスの XML コンサルタントであると同時に、プラハの University of Economics で教職に就いています。これまで 10 年以上、XML のコンサルタントとトレーニングを行ってきました。OASIS (DocBook TC、RELAX NG TC)、W3C (XSL WG、ITS WG)、ISO/IEC JTC1/SC34 (DSDL、Topic Maps) をはじめ、複数の標準化団体のメンバーとしても活躍しています。Jirka は Web 技術に関する本や記事を何本か執筆しています。彼は時間があるときには、DocBook XSL スタイルシートのオープンソース・プロジェクトにコードを提供しています。彼の最近の業績と構想については、彼のブログを参照してください。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=464025
ArticleTitle=PHP V5.3 では Unicode に関して何が新しいのか
publish-date=12152009
author1-email=jirka@kosek.cz
author1-email-cc=

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。