ResourceBundleへのガイド

1概要

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

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

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

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

1.1. リソースバンドル

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

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

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

  • ExampleResource

  • ExampleResource ja__

  • ExampleResource en US

  • ExampleResource en US UNIX__

各データバンドルのデフォルトファイルは、サフィックスのない ExampleResource です。 ResourceBundle には2つのサブクラスがあります。

  • PropertyResourceBundle ListResourceBundle ** では、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ファイルは、 Strings. だけでなく、プロパティファイルよりも1つ大きな利点があります。

一方、新しいロケール固有の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 ja JP

  • Label ja__

  • ラベル

各名前は .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 は、 PropertyResourceBundles よりももう1つの利点があることを知っておく価値があります。 JavaファイルはStringオブジェクトを格納できるため、 UTF-16__エンコーディングでサポートされている任意の文字を保持できます。

反対に、 PropertyResourceBundle はデフォルトで ISO 8859-1 エンコーディングを使ってファイルをロードします。

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

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

7. 結論

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

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

いつものように、サンプルコードはhttps://github.com/eugenp/tutorials/tree/master/core-java/src/main/java/com/baeldung/resourcebundle[GitHubで入手]で入手できます。