Java | Java 標準ライブラリ:ResourceBundle

Java Java
スポンサーリンク

ResourceBundle を一言でいうと

java.util.ResourceBundle は、
「画面メッセージや文言を、言語ごと・国ごとに切り替えるための仕組み」です。

アプリのソースコードに日本語や英語の文字列をべた書きする代わりに、
テキストは外部ファイル(.properties など)に出しておき、
ユーザーの言語(ロケール)に応じて、
「どのファイルから文字列を取るか」を自動で切り替えてくれます。

国際化(i18n)の基本パーツが ResourceBundle です。


基本イメージ:キーとメッセージを言語ごとのファイルに分ける

1つのキーに対して、言語別のメッセージを用意する

まず頭に置いてほしいイメージは、
「キー(識別子)は共通で、メッセージだけ言語ごとに変える」というものです。

例えば「挨拶」を表すキーを greeting とします。
日本語なら「こんにちは」、英語なら「Hello」にしたい。

このとき、メッセージを次のようなファイルに分けます。

Messages.properties(デフォルト、例えば英語)

greeting=Hello
farewell=Good bye

Messages_ja.properties(日本語)

greeting=こんにちは
farewell=さようなら

ここで重要なのは、
「キー名(greeting, farewell)は全ファイルで共通」
「値だけ言語ごとに変える」
という設計にすることです。

ResourceBundle.getBundle で「適切なファイル」を選んでくれる

コード側では、
キー文字列("greeting" など)だけを知っていれば OK です。

実際のメッセージ文字列は、ResourceBundle に聞きに行きます。

import java.util.Locale;
import java.util.ResourceBundle;

public class ResourceBundleBasic {
    public static void main(String[] args) {
        Locale locale = Locale.getDefault();  // 今のロケール(例:ja_JP)
        ResourceBundle bundle = ResourceBundle.getBundle("Messages", locale);

        String greeting = bundle.getString("greeting");
        String farewell = bundle.getString("farewell");

        System.out.println(greeting);
        System.out.println(farewell);
    }
}
Java

ここで getBundle("Messages", locale) とすると、
Messages_ja.propertiesMessages.properties など、
ロケールに合ったファイルを自動的に探してくれます。


ファイル名とロケールの関係をちゃんと理解する

ベース名 + 言語コード + 国コード

ResourceBundle.getBundle("Messages", locale) の第1引数 "Messages" は、
「ベース名」と呼ばれます。

Messages をベース名とすると、
Java は次のようなファイル名候補を順に探します(簡略化して説明します)。

ロケールが ja_JP の場合:

  1. Messages_ja_JP.properties
  2. Messages_ja.properties
  3. Messages.properties

最初に見つかったものが使われます。

例えば、
Messages_ja_JP.properties が無くて Messages_ja.properties はある、という場合、
ja_JP でも Messages_ja.properties が使われます。

これが「フォールバック」の仕組みです。

デフォルトロケールと明示的ロケール

何も考えずに ResourceBundle.getBundle("Messages") と書くと、
Locale.getDefault() が暗黙に使われます。

日本の環境(ja_JP)なら自動的に日本語用のファイルを探しに行きます。

テストやサンプルで、特定の言語を強制したい場合は、
次のように明示的にロケールを指定します。

ResourceBundle bundleJa = ResourceBundle.getBundle("Messages", Locale.JAPAN);
ResourceBundle bundleEn = ResourceBundle.getBundle("Messages", Locale.US);
Java

Locale.JAPAN はだいたい "ja_JP"
Locale.US"en_US" に対応します。


実用例:簡単な多言語対応メッセージ

プロパティファイルを用意する

次の3つのファイルを、クラスパス上に置きます(普通は src/main/resources など)。

Messages.properties(デフォルト・英語)

title=Sample Application
greeting=Hello, {0}!

Messages_ja.properties(日本語)

title=サンプルアプリケーション
greeting={0} さん、こんにちは!

ここでは {0} が「差し込み用のプレースホルダ」です。
後で MessageFormat を使って埋め込みます。

ResourceBundle と MessageFormat を組み合わせて使う

import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;

public class I18nExample {
    public static void main(String[] args) {
        Locale locale = Locale.JAPAN; // ここを Locale.US に変えると英語になる
        ResourceBundle bundle = ResourceBundle.getBundle("Messages", locale);

        String title = bundle.getString("title");
        String greetingTemplate = bundle.getString("greeting");

        String greeting = MessageFormat.format(greetingTemplate, "山田");

        System.out.println(title);
        System.out.println(greeting);
    }
}
Java

日本ロケールなら、日本語ファイルから文字列を取得します。

title → 「サンプルアプリケーション」
greetingTemplate → 「{0} さん、こんにちは!」
MessageFormat.format{0} の部分に 山田 をはめ込み、
「山田 さん、こんにちは!」になります。

ロケールを Locale.US に変えると、

title → 「Sample Application」
greetingTemplate → 「Hello, {0}!」
→ 「Hello, Yamada!」のような形になります。

ここで重要なのは、
Java コード側は「キー」と「ロケール」しか知らない
という点です。

文言そのもの(日本語/英語)は、.properties ファイル側に切り離されています。


ResourceBundle と Properties の違い・関係

どちらも「キーと値」だが、目的が違う

PropertiesResourceBundle も、
「キーと値(文字列)」を扱う入れ物です。

ただし、役割が異なります。

Properties
設定情報や、単一言語のキー・値を扱うための汎用的なクラス。
ファイルの読み書き(load/store)に向いている。

ResourceBundle
主に「ロケールごとに別れたメッセージ」を扱うための抽象クラス。
getBundle がロケールに応じて適切な .properties を選んでくれる。

実際、ResourceBundle は内部で .properties ファイルを読み込むとき、
ほぼ Properties に似た仕組みを使っています。

「多言語メッセージなら ResourceBundle、設定なら Properties」くらいの感覚でOK

アプリの「文言」や「メッセージ」に対しては ResourceBundle
ポート番号やフラグなど単純な設定値には Properties

まずはこのくらいのざっくりした使い分けで十分です。


もう少しだけ踏み込む:クラスベースの ResourceBundle

プロパティファイルではなくクラスで定義する方法

ResourceBundle は、.properties ファイルだけでなく、
専用のクラスとして定義することもできます。

例えば、Messages_ja というクラスをこう書きます。

import java.util.ListResourceBundle;

public class Messages_ja extends ListResourceBundle {
    @Override
    protected Object[][] getContents() {
        return new Object[][]{
            {"title", "サンプルアプリケーション"},
            {"greeting", "{0} さん、こんにちは!"}
        };
    }
}
Java

ListResourceBundle を継承して、
Object[][] でキーと値のペアを列挙します。

同様に Messages_en なども定義できます。

このやり方のメリットは、

値を計算で作れる
Java のコードで条件分岐やロジックを使える

といった柔軟さにあります。

ただし、単純な文字列の多言語化であれば、
.properties ファイルだけで十分なことが多いです。

初心者のうちは「.properties ベースで使う」と覚えておけば問題ありません。


ResourceBundle を使うときに意識したいポイント

「キーを先に決める」習慣

最初から日本語や英語の文言をコードに書き込むのではなく、
まず「キー」を決めてしまう発想を持つと、
後からの多言語対応が非常に楽になります。

例えば、

"ログインに失敗しました" とベタ書きする代わりに、
"error.login.failed" というキーを決めておき、

Java コードでは bundle.getString("error.login.failed") を使う。

文言そのものは、Messages_ja.properties / Messages_en.properties に書く。
こうしておくと、言語追加や文言修正のたびに Java コードを触らなくて済みます。

メッセージ中のパラメータは MessageFormat で扱う

メッセージ中の可変部分(ユーザー名、数値、日付など)は、
{0}, {1} といったプレースホルダにしておき、
MessageFormat.format で埋めるのが定石です。

言語によって語順が変わる場合も、
プレースホルダと引数の順だけ変えれば、
同じ Java コードで対応できます。


まとめ:ResourceBundle を自分の中でこう位置づける

ResourceBundle を初心者向けにまとめると、こうです。

ロケール(言語・国)に応じて、対応する .properties ファイルやクラスからメッセージ文字列を取り出してくれる仕組み

特に意識してほしいのは、

  • ベース名(Messages)とロケールから、適切な Messages_xx[_YY].properties が自動で選ばれる
  • キーは共通、値だけを言語ごとに変えるのが基本設計
  • getBundle でバンドルを取得し、getString でメッセージを取り出す
  • プレースホルダを使う場合は MessageFormat と組み合わせる
  • 「文言は外部ファイルに出す」「コードはキーだけを知る」という分離を徹底すると、多言語対応が楽になる

タイトルとURLをコピーしました