Java Gold対策：ローカライズ

# はじめに

本稿は、Java Goldの学習のまとめとして以下項目についてまとめる。
（同じくJava Goldを学習中やローカライズについて知りたい方の参考になればと。）

* ロケール
* リソースバンドル


## ロケールとは

`java.util.Locale`

言語や国ごとに異なるものの表記規則を示す。
＃ 例：単位・記号・日付・通貨など

アプリケーションを使用した国毎に、表示を変えたい場合などにロケールを利用する。
（アプリを使用する国によって文字を日本語・英語と分けたり等）

インスタンス生成方法は主に以下3種類ある。

* new
* Localクラスの定数
* getDefault()メソッド


### ■ 主なコンストラクタ・メソッド

| コンストラクタ | 内容 |
|:-:|:-:|
| Local(String language, String country)  | 引数の言語/国コードからオブジェクトを生成  |

```java
// newによるインスタンス生成
// ja・en：言語名コード ｜ JP・US：国名コード
Locale localeJp = new Locale("ja","JP");  // 日本のロケール
Locale localeUs = new Locale("en","US");  // アメリカのロケール

// Localeクラスの定数によるインスタンス生成
Locale localeJp = Locale.JAPAN;
Locale localeUs = Locale.US;

// getDefault()メソッドによるインスタンス生成
// 日本で実行すると日本のLocaleインスタンスが生成される
Locale localeJp = Locale.getDefault();
```

| メソッド | 内容 |
|:-:|:-:|
| static getDefault() | デフォルトロケールの現在の値を取得 |
| final String getDisplayCountry() | ロケールの国名を返却 |
| final String getDisplayLanguage() | ロケールの言語名を返却 |
| String getCountry() | ロケールの国名コードを返却 |
| String getLanguage() | ロケールの言語名コードを返却 |

```java
// ja_JP が格納される（OSが日本の場合）
Locale locale = Locale.getDefault();

// 日本 が格納される
String country = locale.getDisplayCountry();

// 日本語 が格納される
String language = locale.getDisplayLanguage();

// JP が格納される
String country_code = locale.getCountry();

// ja が格納される
String language_code = locale.getLanguage();

// 備考：他のインスタンス生成方法
Locale locale = new Locale.Builder().setLanguage("ja")
                                    .setScript("Jpan")
                                    .setRegion("JP")
                                    .build();
// setScript()：引数はISO 15924 alpha-4スクリプトコード（Javadoc参照）
// build()：Locale.Builderのメソッドで、Localオブジェクトを生成
```


## リソースバンドル

`java.util.ResourceBundle`

言語や国ごとに異なる表記規則をロケールに応じて対応させる。
これによりロケールに応じて日本表記や英語表記を切り替えることが出来る。

主に使用するメソッドは以下の通り。

| メソッド | 内容 |
|:-:|:-:|
| boolean containsKey(String key) | 引数で指定されたキーがリソースにある場合はtrueを返却 |
| final Object getObject | 引数で指定されたキーに紐づくオブジェトを返却 |
| final String getString(String key) | 引数で指定されたキーに紐づく文字列を返却 |
| final String[] getStringArray(String key) | 引数で指定されたキーに紐づく文字列の配列を返却 |
| Set<String> keySet() | バンドルに含まれるすべてのキーを返却 |



また、サブクラスとして以下がある。

| サブクラス | 内容 |
|:-:|:-:|
| ListResourceBundle | ロケール用のリソースを便利かつ使いやすいリストで管理 |
| PropertyResourceBuilder | プロパティファイルからの一連のstatic文字列を使用してロケール用のリソースを管理 |


### ■ ListResourceBundleを使用する場合

こちらを使用する場合の定義ルールは以下の通り。

>* 定義方法
    * ListResourceBundleを継承したpublicクラスを作成する
    * getContents()メソッドをオーバーライドして配列でリソースのリストを作成する
    * リソースは、キーと値を要素とする配列として作成

※ [引用](https://www.amazon.co.jp/%E3%82%AA%E3%83%A9%E3%82%AF%E3%83%AB%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E6%95%99%E7%A7%91%E6%9B%B8-Java%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E-Gold-SE-8-ebook/dp/B01J1LPKJY/ref=sr_1_2?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=gold+java&qid=1593530267&sr=8-2)

**▼ 実装例**


```java:Resource.java
public class Resource extends ListResourceBundle {

	public Object[][] getContents() {
		Object[][] contents = {
				{"apple", "リンゴ"},
				{"orange", "オレンジ"}
		};
		return contents;
	}
}
```

```java:Resource_en_US.java
public class Resource_en extends ListResourceBundle {

	protected Object[][] getContents() {
		Object[][] contents = {
				{"apple", "apple"},
				{"orange", "orange"}
		};
		return contents;
	}
}
```

基底名_言語コード_国コード.javaとすることでロケール
のオブジェクトに対応した言語のファイルが参照される。

デフォルトのロケールインスタンスの場合は基底名のリソースが参照される。
また、ロケールのインスタンスに言語コードのみ指定した場合は、基底名の後に言語コードのみで良い。

```java:Main.java

// 出力結果は以下の通り
// リンゴ:オレンジ
// apple:orange

class Main {
	public static void main(String[] args) {

		Locale localeJa = Locale.JAPAN;
		Locale localeUs = Locale.US;

		// 第二引数の指定がない場合デフォルトロケートを指定する
		List<Locale> locales =
				new ArrayList<Locale>(Arrays.asList(localeJa, localeUs));

		for(Locale locale : locales) {
			// パッケージ名.ファイル名を指定
			ResourceBundle rb =
				ResourceBundle.getBundle("resource.Resource", locale);

			// String以外を取得する場合はgetObjectメソッドを使用してキャストする
			System.out.println(rb.getString("apple") + ":" + rb.getString("orange"));
		}
	}
}
```


### ■ PropertyResourceBuilderを使用する場合

こちらを使用する場合の定義ルールは以下の通り。

* プロパティファイル名は、基底名_言語コード_国コード.properties
* リソースのキーと値はプロパティファイル内にキー = 値の形の形で記載

**▼ 実装例**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239591/252ce0bd-4059-553a-1462-bbf5a96f6353.png)


```properties:Source.properties
apple=J_apple
orange=J_orange
```

```properties:Source_en_US.properties
apple=U_apple
orange=U_orange
```

```java:Main.java

// 出力結果
// J_appleJ_orange
// U_appleU_orange

class Main {
	public static void main(String[] args) throws MalformedURLException {

        File dicDir = Paths.get(".\\resource").toFile();

        URLClassLoader urlLoader;
        urlLoader = new URLClassLoader(new URL[]{dicDir.toURI().toURL()});

		Locale localeJp = Locale.JAPAN;
		Locale localeUs = Locale.US;

		List<Locale> locales =
				new ArrayList<Locale>(Arrays.asList(localeJp, localeUs));

		for (Locale locale : locales) {
			// ファイル名のみ指定
			ResourceBundle rb =
					ResourceBundle.getBundle("Source" ,locale ,urlLoader);

			System.out.println(rb.getString("apple") + rb.getString("orange"));

		}
	}
}
```



# 参考文献

* https://docs.oracle.com/javase/jp/7/api/java/util/Locale.html
* https://docs.oracle.com/javase/jp/8/docs/api/java/util/ResourceBundle.html