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.properties や Messages.properties など、
ロケールに合ったファイルを自動的に探してくれます。
ファイル名とロケールの関係をちゃんと理解する
ベース名 + 言語コード + 国コード
ResourceBundle.getBundle("Messages", locale) の第1引数 "Messages" は、
「ベース名」と呼ばれます。
Messages をベース名とすると、
Java は次のようなファイル名候補を順に探します(簡略化して説明します)。
ロケールが ja_JP の場合:
Messages_ja_JP.propertiesMessages_ja.propertiesMessages.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);
JavaLocale.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 の違い・関係
どちらも「キーと値」だが、目的が違う
Properties も ResourceBundle も、
「キーと値(文字列)」を扱う入れ物です。
ただし、役割が異なります。
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} さん、こんにちは!"}
};
}
}
JavaListResourceBundle を継承して、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と組み合わせる - 「文言は外部ファイルに出す」「コードはキーだけを知る」という分離を徹底すると、多言語対応が楽になる
