ローカライズの要点
内容の確認日: 2026-10-04
この分野では、アプリケーションを複数の言語・地域に対応させる (ローカライズする) ための API が問われます。ロケールの表し方、言語ごとにメッセージを切り替えるリソース・バンドル、ロケールに合わせた数値・日付の書式の 3 つが柱です。
出題項目は「Locale クラスの使用」「リソース・バンドルの使用」「メッセージ、日付および数値のフォーマットの指定」の 3 つです。リソース・バンドルの検索順と、日付のパターン文字の大文字・小文字の違いは特によく問われます。
Locale の作り方と表示名
Locale は言語と国 (地域) の組み合わせを表します。主な作り方は次のとおりです。
・定数: Locale.JAPAN (ja_JP)・Locale.US (en_US)・Locale.JAPANESE (ja) など
・コンストラクタ: new Locale("ja", "JP") (Java SE 19 以降は非推奨で、代わりに Locale.of)
・言語タグの解析: Locale.forLanguageTag("ja-JP") (区切りは -)
・Locale.Builder: new Locale.Builder().setLanguage("fr").setRegion("CA").build()
言語コードは小文字、国コードは大文字に正規化されます。Locale は不変 (イミュータブル) で、作った後に言語や国を変更するメソッドはありません。getDisplayCountry(表示に使うロケール)・getDisplayLanguage(表示に使うロケール) は、引数のロケールの言語で国名・言語名を返します。
import java.util.Locale;public class Main { public static void main(String[] args) { System.out.println(new Locale("EN", "us") + " " + Locale.forLanguageTag("ja-JP") + " " + new Locale.Builder().setLanguage("fr").setRegion("CA").build()); System.out.println(Locale.JAPAN.getDisplayCountry(Locale.ENGLISH) + " " + Locale.US.getDisplayLanguage(Locale.JAPANESE)); }}java Main en_US ja_JP fr_CA Japan 英語
リソース・バンドル
リソース・バンドルは、ロケールごとのメッセージなどをまとめたものです。ResourceBundle.getBundle(基底名, ロケール) で取得し、getString(キー) で値を取り出します。バンドルは、基底名_言語_国 という名前のプロパティ・ファイル (messages_ja.properties など) か、ListResourceBundle を継承したクラスで用意します。同じ名前のクラスとプロパティ・ファイルがあれば、クラスが優先されます。
# messages.properties (基底のバンドル)greeting=Hellofarewell=Bye# messages_fr.propertiesgreeting=BonjourgetBundle("messages", ロケール) は、次の順番でバンドルを探し、最初に見つかったものを使います。既定のロケールが ja_JP で、fr_CA を指定した場合の例です。
1. messages_fr_CA (指定したロケール)
2. messages_fr (指定したロケールの言語だけ)
3. messages_ja_JP (既定のロケール)
4. messages_ja (既定のロケールの言語だけ)
5. messages (基底のバンドル)
見つかったバンドルにキーがない場合は、親のバンドルをたどって探します。親は、名前の末尾を 1 つずつ削ったバンドルです (messages_fr_CA → messages_fr → messages)。既定のロケールのバンドルは親には含まれません。上の例で fr_CA を指定すると messages_fr が見つかるので、greeting は Bonjour、messages_fr にない farewell は親の messages から Bye になります。どこにもキーがなければ MissingResourceException です。
ListResourceBundle は、値に String 以外のオブジェクトも入れられます。その場合は getObject(キー) で取り出します。
数値の書式: NumberFormat
NumberFormat は、ロケールに合わせて数値を書式化します。getInstance (通常の数値)・getCurrencyInstance (通貨)・getPercentInstance (パーセント) に Locale を渡して作ります。
通貨の書式では、通貨ごとの小数点以下の桁数に丸められます。日本円は小数点以下の桁を持たないので整数になります。丸めは既定で HALF_EVEN (偶数への丸め) なので、1234.5 は 1234 です。parse は、文字列の先頭から数値として読める部分だけを解析し、後ろの解析できない部分は無視します (先頭から読めなければ ParseException)。
import java.text.NumberFormat;import java.util.Locale;public class Main { public static void main(String[] args) throws Exception { System.out.println(NumberFormat.getCurrencyInstance(Locale.JAPAN).format(1234.5)); System.out.println(NumberFormat.getCurrencyInstance(Locale.US).format(1234.5)); System.out.println(NumberFormat.getPercentInstance(Locale.US).format(0.256)); System.out.println(NumberFormat.getInstance(Locale.GERMANY).format(1234.5)); System.out.println(NumberFormat.getInstance(Locale.US).parse("123abc")); System.out.println(String.format(Locale.GERMANY, "%,.2f", 1234.5)); }}java Main ¥1,234 $1,234.50 26% 1.234,5 123 1.234,50
ドイツのロケールでは、桁区切りが .、小数点が , です。String.format や printf も、第 1 引数にロケールを渡すと、そのロケールの記号で数値を書式化します。
日付の書式: DateTimeFormatter
DateTimeFormatter.ofPattern(パターン) で、日付や時刻の書式を自分で指定できます。パターン文字は大文字と小文字で意味が変わるので注意が必要です。
・y・u: 年 (yy は下 2 桁、yyyy は 4 桁)
・M: 月 (M は 1 桁ならそのまま、MM は 2 桁、MMM は略称) / m: 分
・d: 日 / D: 年の中の通算日
・H: 時 (0〜23) / h: 時 (1〜12。a で午前・午後)
・E: 曜日
パターンを自分で書かずに、ロケールに合った書式を使うときは、ofLocalizedDate(FormatStyle.SHORT) などに withLocale でロケールを指定します。
import java.time.LocalDate;import java.time.format.DateTimeFormatter;import java.time.format.FormatStyle;import java.util.Locale;public class Main { public static void main(String[] args) { LocalDate date = LocalDate.of(2026, 4, 5); System.out.println(DateTimeFormatter.ofPattern("uuuu年M月d日(E)", Locale.JAPAN).format(date)); System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).withLocale(Locale.US).format(date)); System.out.println(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withLocale(Locale.JAPAN).format(date)); System.out.println(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm").format(date)); }}java Main 2026年4月5日(日) 4/5/26 2026年4月5日
実行時に例外が発生: UnsupportedTemporalTypeException
最後の行は、LocalDate (日付だけで時刻を持たない) を、時・分 (HH:mm) を含むパターンで書式化しようとしたため、実行時に UnsupportedTemporalTypeException になっています。時刻も書式化するなら LocalDateTime を使います。
メッセージの書式: MessageFormat
MessageFormat.format(パターン, 引数...) は、パターンの {0}・{1} の位置に引数を埋め込みます。同じ番号は何度でも使えます。数値は、既定のロケールの書式 (日本や米国なら 3 桁ごとの ,) で書式化されます。リソース・バンドルから取り出したメッセージのパターンに値を埋め込むのによく使います。
import java.text.MessageFormat;import java.util.Locale;public class Main { public static void main(String[] args) { Locale.setDefault(Locale.US); System.out.println(MessageFormat.format("{0} さんの得点は {1} 点 ({0})", "Sato", 1234)); }}java Main Sato さんの得点は 1,234 点 (Sato)
パターンの中で ' (シングルクォート) は特別な意味を持ち、'{0}' のように囲んだ部分は置き換えられません。' そのものを出力したいときは '' と 2 つ重ねます。
試験でよくある引っかけ
表示名の言語
Locale.JAPAN.getDisplayCountry(Locale.ENGLISH)はJapanです。引数のロケールの言語で表示されます。リソース・バンドルの検索順
指定したロケール → その言語 → 既定のロケール → その言語 → 基底の順です。既定のロケールは、指定したロケールの言語の後に探されます。
親バンドルへのフォールバック
キーがないときにたどるのは親 (名前の末尾を削ったもの) だけで、既定のロケールのバンドルは含まれません。
NumberFormatのparseparse("123abc")は例外にならず123を返します。先頭から読めない文字列はParseExceptionです。Mとm、HとhMは月、mは分です。Hは 0〜23 時、hは 1〜12 時です。LocalDateと時刻のパターンLocalDateをHH:mmを含むパターンで書式化するとUnsupportedTemporalTypeExceptionです。
問題で確認する
この分野の問題を、解説つきで読めます (登録不要)。
出典・参考
- Oracle University 日本「Java SE 17 Programmer II (1Z0-826-JPN) 試験」
- Java SE 17 API ドキュメント「ResourceBundle」 (検索順)
- Java SE 17 API ドキュメント「DateTimeFormatter」 (パターン文字)
- Java SE 17 API ドキュメント「MessageFormat」
コード例は、試験の対象バージョンで実際にコンパイル・実行して結果を確認しています。