1. 概要

多くのソフトウェア開発者は、プロとしてのキャリアの中で、多言語システムまたはアプリケーションを開発する機会に直面しています。 これらは通常、さまざまな地域またはさまざまな言語領域のエンドユーザーを対象としています。

これらのアプリケーションを維持および拡張することは常に困難です。 通常、さまざまなローカリゼーション固有のデータを同時に操作できることが重要です。 アプリケーションデータの変更は、再コンパイルの必要がなく、可能な限り単純にする必要があります。 そのため、通常、ラベルやボタンの名前をハードコーディングすることは避けています。

幸いなことに、このクラスを提供するJavaを利用することができます。これは、上記のすべての問題を解決するのに役立ちます。

簡単に言うと、 ResourceBundle を使用すると、アプリケーションは、ロケール固有のデータを含む個別のファイルからデータを読み込むことができます。

1.1. ResourceBundles

最初に知っておくべきことは、 1つのリソースバンドル内のすべてのファイルが同じパッケージ/ディレクトリにあり、共通のベース名を持っている必要があるということです。 言語、国、またはプラットフォームをアンダースコア記号で区切って示すロケール固有のサフィックスが付いている場合があります。

言語コードがすでに存在する場合は国コードを追加し、言語と国コードが存在する場合はプラットフォームを追加することが重要です。

ファイル名の例を見てみましょう。

  • ExampleResource
  • ExampleResource_en
  • ExampleResource_en_US
  • ExampleResource_en_US_UNIX

各データバンドルのデフォルトファイルは、常にサフィックスのないファイル– ExampleResourceです。 ResourceBundle には、PropertyResourceBundleListResourceBundleの2つのサブクラスがあるため、Javaファイルだけでなくプロパティファイルにもデータを交換可能に保持できます。

各ファイルには、ロケール固有の名前と適切なファイル拡張子が必要です(例: ExampleResource_en_US.propertiesまたはExample_en.java)。

1.2. プロパティファイル– PropertyResourceBundle

プロパティファイルは、PropertyResourceBundleで表されます。大文字と小文字を区別するキーと値のペアの形式でデータを格納します。

サンプルのプロパティファイルを分析してみましょう。

# Buttons
continueButton continue
cancelButton=cancel

! Labels
helloLabel:hello

ご覧のとおり、キーと値のペアを定義する方法は3つあります。

それらはすべて同等ですが、最初のものはおそらくJavaプログラマーの間で最も人気があります。 プロパティファイルにもコメントを入れることができることを知っておく価値があります。 コメントは常にまたはで始まります。

1.3. Javaファイル– ListResourceBundle

まず、言語固有のデータを保存するには、 ListResourceBundle を拡張し、 getContents()メソッドをオーバーライドするクラスを作成する必要があります。 クラス名の規則は、プロパティファイルの場合と同じです。

Locale、ごとに、個別のJavaクラスを作成する必要があります。

サンプルクラスは次のとおりです。

public class ExampleResource_pl_PL extends ListResourceBundle {

    @Override
    protected Object[][] getContents() {
        return new Object[][] {
          {"currency", "polish zloty"},
          {"toUsdRate", new BigDecimal("3.401")},
          {"cities", new String[] { "Warsaw", "Cracow" }} 
        };
    }
}

Javaファイルには、プロパティファイルに比べて大きな利点が1つあります。それは、Strings。だけでなく必要なオブジェクトを保持できる可能性があることです。

一方、新しいロケール固有のJavaクラスを変更または導入するたびに、アプリケーションを再コンパイルする必要がありますが、プロパティファイルは追加の作業なしで拡張できます。

2. リソースバンドルを使用する

リソースバンドルを定義する方法はすでにわかっているので、使用する準備ができています。

短いコードスニペットについて考えてみましょう。

Locale locale = new Locale("pl", "PL");
ResourceBundle exampleBundle = ResourceBundle.getBundle("package.ExampleResource", locale);

assertEquals(exampleBundle.getString("currency"), "polish zloty");
assertEquals(exampleBundle.getObject("toUsdRate"), new BigDecimal("3.401")); 
assertArrayEquals(exampleBundle.getStringArray("cities"), new String[]{"Warsaw", "Cracow"});

まず、デフォルトのものを使用したくない場合を除いて、Localeを定義できます。

その後、ResourceBundleの静的ファクトリメソッドを呼び出しましょう。 バンドル名とそのパッケージ/ディレクトリおよびロケールをパラメータとして渡す必要があります。

デフォルトのロケールで問題がない場合にのみバンドル名を必要とするファクトリメソッドもあります。 オブジェクトを取得するとすぐに、それらのキーによって値を取得できます。

さらに、この例は、 getString(String key) getObject(String key)、、および getStringArray(String key)を使用して必要な値を取得できることを示しています。 。

3. 適切なバンドルリソースの選択

バンドルリソースを使用する場合は、Javaがバンドルファイルを選択する方法を知っておくことが重要です。

ポーランド語のラベルが必要なアプリケーションを使用しているとしましょう。ただし、デフォルトのJVMロケールはLocale.USです。

最初に、アプリケーションは、要求したロケールに適したクラスパス内のファイルを探します。 最も具体的な名前、つまり、プラットフォーム、国、言語を含む名前で始まります。

次に、より一般的になります。 一致するものがない場合は、今回はプラットフォームチェックなしでデフォルトのロケールにフォールバックします。

一致しない場合は、デフォルトのバンドルを読み取ろうとします。選択したファイル名の順序を見ると、すべてが明確になっているはずです。

  • Label_pl_PL_UNIX
  • Label_pl_PL
  • Label_pl
  • Label_en_US
  • Label_en
  • ラベル

それぞれの名前は.javaファイルと.propertiesファイルの両方を表しますが、前者が後者よりも優先されることに注意してください。 適切なファイルがない場合、MissingResourceExceptionがスローされます。

4. 継承

リソースバンドルの概念のもう1つの利点は、プロパティの継承です。 これは、特定性の低いファイルに含まれるキーと値のペアが、継承ツリーの上位にあるファイルによって継承されることを意味します。

3つのプロパティファイルがあると仮定しましょう。

#resource.properties
cancelButton = cancel

#resource_pl.properties
continueButton = dalej

#resource_pl_PL.properties
backButton = cofnij

Locale( “pl”、 “PL”)に対して取得されたリソースバンドルは、結果の3つのキー/値すべてを返します。 プロパティの継承が考慮される限り、デフォルトのロケールバンドルにフォールバックすることはありません。

さらに、ListResourceBundlesとPropertyResourceBundlesは同じ階層にありません。

したがって、プロパティファイルがクラスパスで見つかった場合、キーと値のペアはプロパティファイルからのみ継承されます。 同じルールがJavaファイルにも適用されます。

5. カスタマイズ

上記で学んだのは、ResourceBundleのデフォルトの実装についてだけでした。 ただし、その動作を変更する方法があります。

これを行うには、 ResourceBoundle.Control を拡張し、そのメソッドをオーバーライドします。

たとえば、値をキャッシュに保持する時間を変更したり、キャッシュを再ロードする必要がある条件を決定したりできます。

理解を深めるために、例として短いメソッドを用意しましょう。

public class ExampleControl extends ResourceBundle.Control {

    @Override
    public List<Locale> getCandidateLocales(String s, Locale locale) {
        return Arrays.asList(new Locale("pl", "PL"));
    }
}

このメソッドの目的は、クラスパス内のファイルを選択する方法を変更することです。 ご覧のとおり、 ExampleControl は、デフォルトまたは定義済みの Locale に関係なく、ポリッシュLocaleのみを返します。

6. UTF-8

JDK 8 以前のバージョンを使用するアプリケーションはまだたくさんあるので、Java 9 ListResourceBundlesより前のにはよりももう1つの利点があることを知っておく価値があります。 X185X]PropertyResourceBundles。 JavaファイルはStringオブジェクトを格納できるため、UTF-16エンコーディングでサポートされている任意の文字を保持できます。

逆に、 PropertyResourceBundle は、デフォルトで ISO 8859-1 エンコーディングを使用してファイルをロードします。これは、 UTF-8 よりも文字数が少なくなります(ポーランド語の例では問題が発生します)。 )。

UTF-8 を超える文字を保存するために、 Native-To-ASCII コンバーター– native2asciiを使用できます。 ISO 8859-1に準拠していないすべての文字を、 \uxxxx表記にエンコードすることで変換します。

コマンドの例を次に示します。

native2ascii -encoding UTF-8 utf8.properties nonUtf8.properties

そして、エンコーディングの変更の前後でプロパティがどのように見えるかを見てみましょう。

#Before
polishHello=cześć

#After
polishHello=cze\u015b\u0107

幸い、この不便さはJava9には存在しません。 JVMUTF-8エンコーディングでプロパティファイルを読み取り、非ラテン文字を使用しても問題はありません。

7. 結論

BundleResource には、多言語アプリケーションを開発するために必要なものの多くが含まれています。 ここで説明した機能により、さまざまなロケールの操作が非常に簡単になります。

また、値のハードコーディングを回避し、新しい Locale ファイルを追加するだけで、サポートされている Locales を拡張できるため、アプリケーションをスムーズに変更および保守できます。

いつものように、サンプルコードはGitHubで入手できます。