Java ローカライズ

Java 11 Gold 取得に向けた学習記録

# ローカライズとは
localize

アプリケーションを異なる国、地域に対応させるプロセスを**ローカライズ**、または **i18n** と言う。

i18n は、internationalization の **i** と **n** の間の文字数が **18** 文字であることに由来する用語。

ローカライズの対象には以下のものが含まれる。

- 言語
- 日付の表示形式
- 時刻の表示形式
- 暦の表示形式
- 通貨の表示形式



# `Locale`
locale = （物語の）舞台、現場、場所

ソフトウェアにおける言語、国、地域などの設定のことを**ロケール**（locale）と呼ぶ。（最初 local だと思っていた。。。locale ≠ local）

ロケールは単に「国」のことではない。例えば英語とフランス語が公用語とされているカナダのような国においては、「カナダ」がロケールに相当するのではなく、「カナダで英語を使用する地域」と「カナダでフランス語を使用する地域」がロケールに相当する。

Javaでは`java.util.Locale`クラスがロケールを表現する。

https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Locale.html

ロケールは主に以下の要素で構成される。これらは`Locale`クラスのフィールドでもあり、コンストラクタの引数で指定することができる。

| フィールド名 | 説明 | 例 |
|:-|:-|:-|
| `language` | 言語 | `en`、`ja`、`de`（ドイツ語）、`zh`（中国語）、`fr`（フランス語） |
| `script` | 文字体系 | `Latn`（ラテン文字）、`Cyrl`（キリル文字）、`Hans`（簡体字）、`Hant`（繁体字） |
| `contry` / `region` | 国、地域<br>`contry` と `region` は同じものを参照している | `US`、`JP`、`DE`（ドイツ）、`FR`（フランス） |
| `variant` | ロケールのバリエーション<br>（ロケール以外のバリエーションに使用されることもある）<br>優先順に `_` で繋いで複数指定することができる | `WIN`（Windows）、`MAC`（Mac）、`POSIX` |

`de`はドイツ語で「ドイツの」「ドイツ語」を意味する deutsch が語源。

`zh`は中国語で「中文」を意味する Zhōngwén が語源。「漢語」は Hànyǔ。

**POSIX** とは、IEEE が管理する Portable Operation System Interface と言う規格を指す。異なるOS間での互換性を確保するための仕様を定義したもの。

異なるOSにシステムを移植できるように、ファイル操作、プロセス・スレッド管理、入出力操作など標準的な機能を提供するためのAPIなどがPOSIXによって定義されている。

`Locale` クラスの `variant` として `POSIX` を指定する場合、そのロケール設定がPOSIXに準拠していることを表す。

## `Locale`の取得

`Locale`オブジェクトの取得方法はいくつかある。

### `Locale.getDefault()`

Javaプログラムが実行されている環境のロケールのデフォルト値を取得することができる。

```java:Locale.getDefault()
import java.util.Locale;

Locale defaultLocale = Locale.getDefault();
```

### コンストラクタ

コンストラクタを利用すると、各引数を細かく指定して`Locale`オグジェクトを作成することができる。

> `Locale(String language)`
`Locale(String language, String country)`
`Locale(String language, String country, String variant)`

```java:コンストラクタ
import java.util.Locale;

Locale locale = new Locale("en", "US", "POSIX");
```

コンストラクタでは引数が正しいかどうかの確認が行われない。

### ロケール定数

[コンストラクタ](#コンストラクタ)を利用した方法では、引数の誤りに気が付かないことがある。そこで事前に定義された定数を利用することで、誤りを防ぐことができる。

| `Locale.` | `language` | `country` |
|:-|:-:|:-:|
| `CANADA` | `en` | `CA` |
| `CANADA_FRENCH` | `fr` | `CA` |
| `JAPAN` | `ja` | `JP` |
| `JAPANESE` | - | `JP` |
| `UK` | `en` | `GB` |
| `US` | `en` | `US` |

```java:ロケール定数
import java.util.Locale;

Locale locale = Locale.JAPAN;
```

### `Locale.Builder`

Builderパターンを利用する方法。

https://qiita.com/AsahinaKei/items/021978099a59944c76b8


```java:Locale.Builder
import java.util.Locale;

Locale locale = new Locale.Builder()
        .setLanguage("fr")
        .setRegion("CA")
        .setVariant("POSIX")
        .setScript("Latn")
        .build();
```

### `Locale.forLanguageTag`（ファクトリメソッド）

`Locale`にで定義されたファクトリメソッドを使用して、`Locale`オブジェクトを取得することもできる。

https://qiita.com/AsahinaKei/items/3a1f17b728769bab95b7

> Locale.forLanguageTag(String languageTag)

`languageTag` 文字列は、ISO や IETF によって策定された仕様で、通常 [`language`](#locale)、[`script`](#locale)、[`country`](#locale) または [`region`](#locale)、[`variant`](#locale) で構成される。IETF によって作成された BCP 47（Best Current Practice 47）という文書で詳細な仕様が策定されている。


https://www.w3.org/TR/ltli/

https://appmakers.dev/bcp-47-language-codes-list/

https://ja.wikipedia.org/wiki/IETF%E8%A8%80%E8%AA%9E%E3%82%BF%E3%82%B0

```java:Locale.forLanguageTag（ファクトリメソッド）
import java.util.Locale;

Locale locale = Locale.forLanguageTag("ja-JP");
```

### `HttpServletRequest`

Webアプリでは`javax.servlet.http.HttpServletRequest`インターフェースの`getLocale()`メソッドを使用することでロケールを取得することができる。

```java
import java.util.Locale;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Locale locale = request.getLocale();
    }
}
```

# 参考
- [徹底攻略Java SE 11 Gold問題集[1Z0-816]対応](https://amzn.asia/d/0eV9L1Wp)