1 国際化の概要

国際化とは、技術的な変更をせずにアプリケーションをさまざまな言語および地域に適合させるための、アプリケーションの設計プロセスのことです。国際化(internationalization)という語は、最初の「i」と最後の「n」の間に18文字あるため、i18nと略されることがあります。

国際化されたプログラムには、次の特徴があります。

  • ローカリゼーション・データを追加することにより、同じ実行可能ファイルを世界中で実行できる。
  • ステータス・メッセージやGUIコンポーネントのラベルなどの、テキスト要素がプログラム内でハードコード化されていない。その代わり、ソース・コードの外側に保存され、動的に取り出される。
  • 新しい言語をサポートするために再コンパイルをする必要がない。
  • 日付や通貨などの文化に依存するデータが、エンド・ユーザーの地域と言語に一致した形式で表示される。
  • 短期間でローカライズできる。

インターネットでは、世界中どこでも使えるソフトウェアが必要になります。つまり、ユーザーの国や言語を意識しないで開発でき、様々な国や地域に合わせてローカライズできるソフトウェアです。Javaプラットフォームでは、グローバル・アプリケーションを開発するための豊富なAPI群が提供されています。このような国際化のためのAPIは、Unicode標準に基づいており、テキスト、数値、日付、通貨、およびユーザー定義のオブジェクトを任意の国の慣習に合わせる機能を備えています。

このガイドでは、Java Platform, Standard Editionの国際化に関するAPIと機能の概要を説明します。コーディング例と詳しいステップの説明については、Javaチュートリアルの国際化の学習に関する項を参照してください。

テキストの表現

Javaプログラミング言語はUnicode文字セットをベースにしており、いくつかのライブラリではUnicode標準が実装されています。Unicodeは、国際文字セット標準で、世界の主要な書記法すべてに加えて、基本的な学術記号をサポートしています。Unicode仕様では最初、各文字を16ビット固定長の実体として定義していましたが、その後、16ビットより長い表現を必要とする文字も取り扱えるようにUnicode標準が変更されました。有効なコード・ポイントの範囲は現在、U+0000 - U+10FFFFです。UTF-16標準により定義されるエンコーディングでは、すべてのUnicodeコード・ポイントを、1つまたは2つの16ビット単位を使用して表現できます。

Javaプログラミング言語の基本データ型charは、符号なしの16ビット整数なので、U+0000 - U+FFFFの範囲のUnicodeコード・ポイントや、UTF-16のコード単位を表現できます。Javaプラットフォームで文字シーケンスを表現する各種の型およびクラスは、UTF-16のシーケンスです。そのような型およびクラスとしては、char[]java.lang.CharSequenceの実装(たとえばStringクラス)、java.text.CharacterIteratorの実装などがあります。ほとんどのJavaソース・コードは、7ビット文字エンコーディングのASCIIまたは8ビット文字エンコーディングのISO-8859-1で記述されますが、処理の前にUTF-16に変換されます。

Characterクラスは、charプリミティブ型のオブジェクト・ラッパーとしての役割を果たします。Characterクラスには、isLowerCase()isDigit()など、文字のプロパティを判別するためのstaticメソッドも含まれています。これらのメソッドは、char (U+0000 - U+FFFFの範囲のUnicodeコード・ポイントを表現できる)またはint (すべてのUnicodeコード・ポイントを表現できる)のいずれかを受け付けるようにオーバーロードされています。

ロケールの識別とローカリゼーション

ロケール・オブジェクトは、言語と地域の特定の組合せを指定する識別子です。ローカライゼーションは、ロケール固有のコンポーネントを追加し、テキストを翻訳することで、特定地域または言語にソフトウェアを適応させるプロセスです。

ロケール

Javaプラットフォームでは、ロケールは、言語と地域の特定の組み合わせに対する単なる識別子です。ロケール固有の属性の集合ではありません。ロケール固有の情報は、ロケールの影響を受けるクラスがそれぞれ独自に保持しています。このような設計のため、ロケール固有のリソースを保持する方法に関し、ユーザー・オブジェクトとシステム・オブジェクトで違いはありません。どちらも、標準のローカリゼーション・メカニズムを使います。

Javaプログラムには、単一のグローバル・ロケールは割り当てられていません。ロケールに依存するすべての操作には、引数として明示的にロケールを渡すことができます。これにより、多言語プログラムが非常に簡単になります。グローバル・ロケールが強制的に使われることはありませんが、ロケールを明示的に管理する必要のないプログラムでは、デフォルトのロケールを利用できます。デフォルト・ロケールを使うと、全体的な表示形式を一度の選択で変えることができます。

Javaのロケールは、別のオブジェクトから出される、ある動作に対する要求として機能します。たとえば、カレンダ・オブジェクトにフランス語系カナダ用ロケールを渡すと、ケベック州の慣習に従って正しく動作するようカレンダに要求したことになります。ロケールを受け取ったオブジェクトは、適切な処理を行わなければなりません。オブジェクトが特定のロケールに対してローカライズされていない場合、オブジェクトは、ローカライズされているロケールでよく似たものを探します。たとえば、カレンダ・オブジェクトがフランス語系カナダのロケール用にローカライズされていなくても、一般的なフランス語についてローカライズされている場合は、かわりにフランス語のローカライズ版を使用します。

Localeクラス

Localeオブジェクトは、地理的、政治的、または文化的に特定の地域を表します。タスクを実行するためにロケールを必要とする操作のことを、ロケール依存操作と呼びます。ロケール依存操作は、Localeオブジェクトを使用して、ユーザーに合うように情報を加工します。たとえば、数値の表示はロケールに依存する操作です。数値の書式は、ユーザーに固有の国、地域、文化などの慣習や決まりに従って設定する必要があります。

サポートされるロケール

Javaプラットフォームでは、クラスごとに独自のローカライズ版が保持されるので、サポートされるロケールの集合は1種類だけでなくてもかまいません。ただし、Javaプラットフォームのクラスとしては、一貫性のあるローカリゼーションをサポートしています。Javaプラットフォームの他の実装では、異なるロケールをサポートする場合があります。JDKでサポートされているロケールは、リリースごとにまとめられています。Oracleの技術リソース・ページの検索フィールドを使用し、「サポートされるロケール」を検索して、サポートされているものを確認します。

ローカライズされたリソース

すべてのロケール依存クラスは、サポートするロケール用にカスタマイズされたリソースにアクセスできなければなりません。ローカリゼーションの処理を容易にするには、ロケールごとにリソースをグループ化し、プログラムのロケールに依存しない部分から切り離すことが有用です。

ResourceBundleクラス

ResourceBundleクラスは、リソースのコンテナを表す抽象基底クラスです。プログラムでは、特定のロケールのためのリソースを含むResourceBundleのサブクラスを作成します。使用するコードを変更しなくても、ResourceBundleのインスタンスに新しいリソースを追加したり、ResourceBundleの新しいインスタンスをシステムに追加したりできます。リソースをクラスとしてパッケージ化することで、Javaのクラス・ローディング・メカニズムを利用してリソースを探すことができます。

リソース・バンドルには、ロケール固有のオブジェクトが含まれます。Stringオブジェクトなど、ロケール固有のリソースが必要な場合は、現在のユーザーのロケールに適したリソース・バンドルからリソースをロードします。このようにして、リソースのバンドルに含まれているロケール固有の情報のすべて、または少なくとも大部分を切り離し、ユーザーのロケールとの依存関係が弱いコードを作成できます。

そのため、次のような特徴を備えたJavaコードを作成できます

  • 異なる言語への地域対応、または翻訳が容易
  • 複数のロケールを同時に処理可能
  • 将来サポートするロケールを追加する際の修正が容易
ResourceBundle.Controlクラス

ResourceBundle.ControlはResourceBundleのネストされたクラスです。このクラスで、ResourceBundle.getBundleファクトリ・メソッドから呼び出されるメソッドを定義すれば、リソース・バンドル・ロード処理の動作を変更できます。たとえば、XMLなどのアプリケーション固有のリソース・バンドル形式は、メソッドをオーバーライドすることでサポート可能になります。

ResourceBundle.Controlは名前のあるモジュールでサポートされていません。Controlを使用した既存のコードは動作しますが、名前のあるモジュール内の新規コードの場合、basenameProviderを実装し、ここからリソース・バンドルをロードします。名前のあるリソース・バンドルに関する項を参照してください。

ListResourceBundleクラス

ListResourceBundleは、ロケール用のリソースを便利かつ使いやすいリストで管理する、ResourceBundleの抽象サブクラスです。

PropertyResourceBundleクラス

PropertyResourceBundleは、プロパティ・ファイルからの一連のstatic文字列を使用してロケール用のリソースを管理する、ResourceBundleの具象サブクラスです。

日付と時間の処理

日時パッケージのjava.timeでは、日付と時間に関する包括的なモデルを提供します。java.timeは国際標準化機構(ISO)のカレンダ・システムに基づいていますが、一般的に使用されるグローバル・カレンダもサポートしています。

Javaチュートリアル(Java SE 8以前)日時パッケージに関するレッスンを参照してください。

テキスト処理

テキスト処理には、通貨、日付、時間およびテキスト・メッセージなどのロケールに依存する情報の書式指定が含まれています。これにはロケールに依存する方法でのテキストの操作も含まれており、検索やソートなどの文字列操作がロケールに関係なく適切に実行されることを意味しています。

書式指定

データを出力するときの書式指定には、多くの文化的な慣習が適用されます。数値、日付、時間、およびメッセージのすべてについて、書式を指定してからでないと表示できない場合があります。Javaプラットフォームでは、柔軟性のある書式指定クラス群が提供されており、ロケールの標準的な書式および独自に定義された書式の両方を扱うことができます。これらの書式指定クラスを使うと、書式を設定された文字列の構文を解析して、構成するオブジェクトに戻すこともできます。

Formatクラス

Formatクラスは、日付、時間、メッセージ、数値など、ロケールに依存する情報に書式を指定する機能のための、抽象基底クラスです。主要なサブクラスとして、DateFormatNumberFormatおよびMessageFormatの3つが提供されています。これら3つのクラスでは、それぞれ独自のサブクラスが提供されています。

DateFormatクラス

日付と時間は内部的にはロケールに依存しない方法で格納されますが、ロケールを反映した形式で表示できるよう書式を指定する必要があります。たとえば、次は同じ日付に対する異なる書式の例です。

  • November 3, 1997 (英語)
  • 3 novembre 1997 (フランス語)

DateFormatクラスは、ロケールに依存しない方法で日付と時間の値の書式指定と構文解析を行うための、抽象基底クラスです。特定のロケールに対する時間の標準書式を取得するためのstaticファクトリ・メソッドがいくつか用意されています。

DateFormatオブジェクトは、CalendarオブジェクトとTimeZoneオブジェクトを使用して、時間の値を解釈します。デフォルトでは、特定のロケールに対するDateFormatオブジェクトは、そのロケールに対する適切なCalendarオブジェクトとシステムのデフォルトのTimeZoneオブジェクトを使用します。これらの設定は、必要に応じてオーバーライドできます。

SimpleDateFormatクラス

SimpleDateFormatクラスは具象クラスで、ロケールに依存した方法で日付と時間の書式指定と構文解析を行います。このクラスを使うと、書式指定(ミリ秒をテキストに)、構文解析(テキストをミリ秒に)、および正規化を行うことができます。

DateFormatSymbolsクラス

DateFormatSymbolsクラスは、月の名前、曜日の名前、時間、タイムゾーンのデータなど、日付と時間の書式指定に関するローカライズ可能なデータをカプセル化するために使用します。DateFormatクラスとSimpleDateFormatクラスはどちらも、DateFormatSymbolsクラスを使用してこの情報をカプセル化します。

通常、プログラムでDateFormatSymbolsクラスを直接使用することはありません。実際には、DateFormatクラスのファクトリ・メソッドで、書式指定の機能を実装します。

NumberFormatクラス

NumberFormatクラスは、数値データの書式指定と構文解析のための抽象基底クラスです。異なる種類のロケール固有の数値書式を取得するため、staticファクトリ・メソッドがいくつか用意されています。

NumberFormatクラスは、任意のロケールで数値の書式指定と構文解析を行うときに役に立ちます。このクラスを使うコードは、小数点、桁区切り、使われている特定の10進数字、または数値の書式が10進数かどうかなどに対するロケールの規則から、完全に独立しています。通常の10進数、通貨、パーセントなどで数値を表示することもできます。

  • 1,234.5 (米国形式での10進数)
  • $1,234.50 (米国形式での米国通貨)
  • 1.234,50€(ドイツ形式での欧州通貨)
  • 123.450% (ドイツ形式でのパーセント)
DecimalFormatクラス

数値は、内部的にはロケールに依存しない方法で格納されていますが、ロケールを反映した形式で表示できるよう書式を指定する必要があります。たとえば、「#,###.00」というパターンを使うと、同じ数値でも次のように異なる書式になる場合があります。

  • 1.234,56 (ドイツ語)
  • 1,234.56 (英語)

DecimalFormatクラスは、NumberFormatクラスの具象サブクラスで、10進数値の書式指定を行うことができます。通常、このクラスのインスタンスを直接生成することはありませんが、提供されているファクトリ・メソッドは使います。

DecimalFormatクラスには、数値の書式指定の方法を指定するパターン文字列を受け取る機能があります。パターンでは、数値の精度、先頭の0を表示するかどうか、使用する通貨記号などの属性を指定します。プログラムで独自の書式を作る必要がある場合は、パターン文字列を変更できます。

DecimalFormatSymbolsクラス

DecimalFormatSymbolsクラスは、数値の書式を指定するときにDecimalFormatが必要とする記号群(小数点、グループ化区切り文字など)を表します。DecimalFormatクラスは、それ自体のために、ロケール・データからDecimalFormatSymbolsクラスのインスタンスを生成します。これらの記号のいずれかを変更する必要がある場合は、DecimalFormatオブジェクトからDecimalFormatSymbolsオブジェクトを取得して修正できます。

ChoiceFormatクラス

ChoiceFormatクラスは、NumberFormatクラスの具象サブクラスです。ChoiceFormatクラスを使用すると、ある範囲の数値に書式を指定できます。このクラスは、通常、MessageFormatオブジェクトの中で複数形を処理するときに使用されます。

MessageFormatクラス

プログラムでは、一連の文字列、数値、およびほかのデータからメッセージを作らなければならない場合がよくあります。たとえば、ディスク・ドライブにあるファイルの数を表示するメッセージのテキストは、状況によって次のように変わります。

  • The disk C contains 100 files.
  • The disk D contains 1 file.
  • The disk F contains 0 files.

一連の文字列と数値から組み立てるメッセージがハードコードされている場合は、ほかの言語に翻訳できません。たとえば、次の例で、パラメータの「3」と「G」の位置が違うことに注意してください。

  • The disk G contains 3 files. (英語)
  • Il y a 3 fichiers sur le disque G. (フランス語)

MessageFormatクラスを使用すると、言語に依存しない方法で、文字や数字を連結したメッセージを作成できます。MessageFormatオブジェクトは、複数のオブジェクトを受け取り、書式を設定して、パターンの適切な位置に書式を設定した文字列を挿入します。

ParsePositionクラス

ParsePositionクラスは、Formatクラスとそのサブクラスによって使用され、構文解析中の現在位置を記録します。FormatクラスのparseObject()メソッドでは、引数としてParsePositionオブジェクトが必要です。

FieldPositionクラス

FieldPositionクラスは、Formatクラスとそのサブクラスによって使用され、書式指定された出力のフィールドを識別します。Formatクラスのformat()メソッドの1つでは、引数としてFieldPositionオブジェクトが必要です。

ロケールに依存する文字列の操作

プログラムでは、文字列の操作が頻繁に必要になります。文字列に対する共通の操作として、検索とソートがあります。文字列の照合やテキストのさまざまな境界の検出など、ある種の処理は、正確に行おうとすると非常に難しく、複数の言語を考慮する必要がある場合はさらに困難になります。Javaプラットフォームでは、このような共通の文字列操作の多くをロケールに依存した方法で処理するためのクラス群が提供されています。

Collatorクラス

Collatorクラスでは、ロケールに依存した文字列の比較が行われます。自然言語テキストのための検索ルーチンおよびアルファベット順ソート・ルーチンを作るには、このクラスを使います。Collatorは、抽象基底クラスです。サブクラスでは、具体的な照合方法が実装されます。RuleBasedCollatorサブクラスは広範囲の言語に適用可能です。さらに特殊な必要性がある場合には、ほかのサブクラスを作成できます。

RuleBasedCollatorクラス

RuleBasedCollatorクラスは、Collatorクラスの具象サブクラスで、データ駆動の簡単な表照合機能を提供します。RuleBasedCollatorクラスを利用し、目的にあわせてカスタマイズした表ベースの照合機能を作成できます。たとえば、大文字、アクセント、およびUnicode複合文字を無視(または意識)する照合機能を作ることができます。

CollationElementIteratorクラス

CollationElementIteratorクラスは、多国語文字列の各文字を処理するときのイテレータとして使用されます。イテレータは、位置付けされた文字の順序の優先順位を返すために使われます。文字の順序の優先順位つまりキーは、特定のCollatorオブジェクトの中で文字を照合する方法を定義するものです。CollationElementIteratorクラスは、RuleBasedCollatorクラスのcompare()メソッドで使用されます。

CollationKeyクラス

CollationKeyオブジェクトは、特定のCollatorオブジェクトの規則が適用された文字列を表します。2つのCollationKeyオブジェクトを比較すると、それらが表す文字列の相対的な順序が返されます。CollationKeyオブジェクトを使用して文字列を比較する方が、一般に、Collator.compare()メソッドを使用するより高速です。したがって、文字列の一覧をソートするときのように、文字列を比較する回数が多い場合は、CollationKeyオブジェクトを使用する方が効率的です。

BreakIteratorクラス

BreakIteratorクラスは、テキスト文字列の中から次のような種類の境界の位置を見つけるためのメソッドを間接的に実装します。

  • 潜在的な行分割
  • 文字

行、文、語、および文字を区切る場所の規則は、言語の種類により異なります。BreakIteratorクラスはロケールに依存するので、テキストを操作するプログラムで使うことができます。たとえば、文字の強調表示、語の切り取り、次の文へのカーソルの移動、行末での折り返しなどが可能なワープロ・プログラムを考えます。このワープロ・プログラムは、分割イテレータを使ってテキストの論理的な境界を決定し、ロケールを意識した方法でテキストを操作できるようにします。

StringCharacterIteratorクラス

StringCharacterIteratorクラスは、Unicode文字の文字列に対して双方向の反復処理を行う機能を提供します。このクラスは、カーソルを使ってある範囲のテキストの中を移動し、個別の文字または文字のインデックス値を返すことができます。StringCharacterIteratorクラスは、CharacterIteratorインタフェースの文字イテレータ機能を実装しています。

CharacterIteratorインタフェース

CharacterIteratorインタフェースは、Unicode文字に対する双方向の反復処理のためのプロトコルを定義しています。ある範囲のテキストの中を移動し、個別のUnicode文字またはそのインデックス値を返すクラスの場合、このインタフェースを実装する必要があります。CharacterIteratorは、文字検索を行うときに役に立ちます。

Normalizerクラス

Normalizerクラスは、Unicodeテキストを等価な合成形式または分解形式に変換するメソッドを提供します。このクラスは、Unicode標準によって定義されたUnicode Normalization Formをサポートします。

ロケールに依存するサービスのSPI

java.textおよびjava.utilパッケージ内のクラスが提供する、ロケールに依存するサービスは、ロケールに依存するサービスのSPIを実装すれば、Javaランタイムがまだサポートしていないロケールにも拡張できます。

拡張機能メカニズムはサポートされておらず、java.text.spijava.util.spiおよびjava.awt.im.spiパッケージの国際化関数のSPI実装はアプリケーションのクラスパスからロードされます。

java.utilパッケージに含まれるCurrencyLocaleおよびTimeZoneの各クラスのローカライズされた記号や名前のほか、java.textパッケージに含まれる次のクラスの実装は、SPIとともにプラグインできます。

文字エンコーディングの変換

Javaプラットフォームは、ネイティブの文字エンコーディングとしてUnicodeを使っていますが、Javaプログラムの多くでは、まだ、ほかのエンコーディングのテキスト・データを扱う必要があります。そのため、Javaでは、多くの標準的な文字エンコーディングとUnicodeの間の変換を行うクラス群が提供されています。Unicode以外のテキスト・データを扱う必要があるJavaプログラムでは、データをいったんUnicodeに変換し、Unicodeとしてデータを処理してから、その結果を変換して外部の文字エンコーディングに戻します。InputStreamReaderクラスとOutputStreamWriterクラスでは、他の文字エンコーディングとUnicodeの間の変換を行うメソッドが提供されています。

サポートされるエンコーディング

InputStreamReaderOutputStreamWriter、Stringの各クラスでは、Unicodeと「サポートされるエンコーディング」の一覧に示されている文字エンコーディングの間での変換が可能です。

ストリーム入出力

Javaプラットフォームでは、文字データ処理機能を向上させるため、java.ioパッケージに機能が追加されています。つまり、ReaderクラスとWriterクラスの追加、およびPrintStreamクラスに対する拡張です。

ReaderクラスとWriterクラス

ReaderクラスとWriterクラスの階層は、文字ストリームで入出力操作を行う機能を提供します。これらの階層は、InputStreamクラスとOutputStreamクラスの階層と並列になっていますが、バイトのストリームではなく、文字のストリームを処理します。文字ストリームを使うと、特定の文字エンコーディングに依存しないプログラムを簡単に記述でき、したがって、国際化も簡単になります。ReaderクラスとWriterクラスには、Unicodeと他の文字エンコーディングの間の変換を行う機能もあります。

PrintStreamクラス

PrintStreamクラスは、システムのデフォルトの文字エンコーディングと行末記号を使用して出力を生成します。この変更により、System.out.println()などのメソッドは、ASCII以外のデータをより適切に処理できます。

charsetパッケージ

java.nio.charsetパッケージは、文字エンコーディング変換のための土台を提供します。アプリケーションでは、このパッケージに含まれるクラスを使用して、組込みの文字変換プログラムの動作を微調整できます。また、java.nio.charset.spiパッケージを使用すると、組込みの文字変換プログラムでサポートされていない文字エンコーディング用のカスタム変換プログラムを作成することもできます。

インプット・メソッド

インプット・メソッドは、ユーザーがテキストを単にキーボード上でタイプする以外の方法でテキストを入力できるソフトウェア・コンポーネントです。数千種類もの文字を使う日本語、中国語、韓国語を、キーボードのそれよりはるかに少ないキーで入力する場合に、共通してこのインプット・メソッドを使用します。Javaプラットフォームでは、この3言語以外のインプット・メソッドもサポートされており、手書きや音声認識などの異なる入力メカニズムにも使用できます。

また、Javaプラットフォームでは、WindowsやLinuxなどのホスト・オペレーティング・システムから提供されるネイティブ・インプット・メソッドを使うことができるほか、Javaプログラミング言語で記述されたインプット・メソッドを実装して使うこともできます。

インプット・メソッドという用語は、Javaプログラミング言語のクラス・メソッドを指しているのではありません。

Swingでのインプット・メソッドのサポート

Swingテキスト・コンポーネントは、インプット・メソッドを使用したテキスト入力のための統合ユーザー・インタフェースを提供します。ロケールに応じて、オンザスポットまたはビロウザスポット入力方式が使用されます。ほとんどのロケールで使用されているオンザスポット(インライン)入力方式の場合、インプット・メソッドはテキストを入力している間テキストをテキスト・コンポーネントに直接挿入します。中国語圏のロケールで使用されているビロウザスポット入力方式の場合は、独立した変換ウィンドウが使用されます。このウィンドウは、確定したテキストの挿入位置の近くに自動的に配置されます。

Swingテキスト・コンポーネントを使用するアプリケーションでは、テキスト・コンポーネントとインプット・メソッド間のやり取りを調整する必要はありません。ただし、ドキュメントを保存または印刷する場合など、すべてのテキストの確定が必要な場合は、InputContext.endCompositionを呼び出す必要があります。

Input Method Framework

Input Method Frameworkは、テキスト編集時に、テキスト編集コンポーネントとインプット・メソッドの間の共同作業を可能にします。このフレームワークを使用するのは、テキスト編集コンポーネントまたはインプット・メソッドを開発するプログラマです。その他のアプリケーション開発者は、通常はほとんど使用しません。たとえば、ドキュメントを保存または印刷する場合など、すべてのテキストの確定が必要な場合は、InputContext.endCompositionを呼び出す必要があります。