Java 8での国際化と地域化
1.概要
-
国際化とは、言語、地域、文化、政治に固有のさまざまなデータをサポートするためのアプリケーションを作成するプロセスです。
-
、
** をさらに読むために、国際化のための非常にポピュラーな略語(おそらく実際の名前よりもポピュラー)があることを知っておくべきです –
i18n
は ‘i’と ‘n’の間の18文字のためです。
今日の企業向けプログラムでは、世界のさまざまな場所または複数の文化的地域の人々にサービスを提供することが重要です。異なる文化や言語の地域では、言語固有の説明だけでなく、通貨、数字の表現、さらには異なる日付と時刻の構成も決定されません。
たとえば、国固有の数字に注目しましょう。彼らは様々な小数点と千の区切り記号があります。
-
102,300.45(アメリカ合衆国)
-
102 300,45(ポーランド)
-
102.300、45(ドイツ)
さまざまな日付形式もあります。
-
2018年1月1日、月曜日、3:20:34 PM CET(アメリカ合衆国)
-
1月1日2018 15時間20 CET(フランス)。
-
2018年1月1日星期1時03时20分34秒CET(中国)
さらに、国によって通貨記号が異なります。
-
£1,200.60(イギリス)
-
€1.200,60(イタリア)
-
1 200,60€(フランス)
-
1,200.60米ドル(アメリカ合衆国)
知っておくべき重要な事実は、たとえ国が同じ通貨と通貨記号を持っていたとしても – フランスとイタリアのように – 彼らの通貨記号の位置は異なるかもしれないということです。
2.ローカライゼーション
-
Java内には、
Locale
クラスと呼ばれる素晴らしい機能があります。
これにより、文化的なロケールをすばやく区別し、コンテンツを適切にフォーマットすることができます。国際化プロセスの中で不可欠です。国際化と同じように、ローカライゼーションもその略語 –
l10n
.
を持っています
Locale
を使用する主な理由は、必要なロケール固有のフォーマットすべてに再コンパイルなしでアクセスできることです。アプリケーションは複数のロケールを同時に処理できるため、新しい言語をサポートするのは簡単です。
ロケールは通常、アンダースコアで区切られた言語、国、およびバリアントの略語で表されます。
-
de(ドイツ語)
-
it__CH(イタリア語、スイス)
-
en
US
UNIX(米国、UNIXプラットフォーム)
2.1. フィールド
-
Locale
は言語コード、国別コード、および派生形で構成されていることをすでに学びました。設定可能なフィールドがさらに2つあります。
スクリプトと拡張機能** 。
フィールドのリストを見て、ルールが何であるかを見てみましょう。
-
言語
は
ISO 639 alpha-2またはalpha-3
コード、あるいは登録済みです。
言語サブタグ。
-
地域
(Country)は
ISO 3166 alpha-2
country codeまたは__UNです。
数値3__市外局番。
-
Variant
は、大文字と小文字を区別する値、または
Locale
のバリエーション。
-
スクリプト
は有効な
ISO 15924 alpha-4
コードでなければなりません。 -
Extensions
は単一の文字キーと
String
値
IANA Language Subtag Registry
には、
language
、
region
、
variant
、および
script
に指定できる値が含まれています。
可能な
extension
値のリストはありませんが、値は整形式のhttps://docs.oracle.com/javase/tutorial/i18n/locale/extensions.html[
BCP-47
]サブタグである必要があります。キーと値は常に小文字に変換されます。
2.2.
Locale.Builder
Locale
オブジェクトを作成する方法はいくつかあります。 1つの可能な方法は
Locale.Builder
を利用します。
Locale.Builder
には、オブジェクトを構築して同時にそれらの値を検証するために使用できる5つの設定メソッドがあります。
Locale locale = new Locale.Builder()
.setLanguage("fr")
.setRegion("CA")
.setVariant("POSIX")
.setScript("Latn")
.build();
上記の
Locale
の
String
表現は
fr
CA
POSIX
#Latn__です。
setterメソッドでは
BCP-47
に準拠している必要がありますが、** 「variant」の設定はバリアント値に対する公式の制限がないため、少しトリッキーになるかもしれません。
そうでない場合は、
IllformedLocaleException
がスローされます。
検証に合格しない値を使用する必要がある場合は、値を検証しないため、
Locale
コンストラクタを使用できます。
2.3. コンストラクタ
Locale
には3つのコンストラクタがあります。
-
新しいロケール(String language)
-
新しいロケール(String language、String country)
-
新しいロケール(String language、String country、String variant)
3パラメータのコンストラクタ
Locale locale = new Locale("pl", "PL", "UNIX");
有効な
variant
は、5から8文字の英数字または単一の数値の後に3文字の英数字の
String
でなければなりません。これらの要件を満たしていないため、コンストラクタを介してのみ
variant
フィールドに「UNIX」を適用できます。
ただし、
Locale
オブジェクトを作成するためにコンストラクタを使用することには1つの欠点があります。拡張子やスクリプトフィールドを設定することはできません。
2.4. 定数
これはおそらく
Locales
を取得するための最も簡単で制限された方法です。
Locale
クラスには、最も普及している国または言語を表すいくつかの静的定数があります。
Locale japan = Locale.JAPAN;
Locale japanese = Locale.JAPANESE;
2.5. 言語タグ
Locale
を作成するもう1つの方法は、静的ファクトリメソッド
forLanguageTag(String languageTag)
を呼び出すことです。このメソッドは
IETF BCP 47
規格を満たす
String
を必要とします。
これが私達がどのように英国
Locale
を作成できるかです:
Locale uk = Locale.forLanguageTag("en-UK");
2.6. 利用可能なロケール
Locale
オブジェクトを複数組み合わせて作成することはできますが、使用できない可能性があります。
注意すべき重要な注意点は、プラットフォーム上の
Locales
は、Java Runtime内にインストールされているものに依存していることです。
フォーマットに
Locales
を使用しているので、さまざまなフォーマッタがランタイムにインストールされている利用可能な
Locales
のさらに小さいセットを持つことができます。
利用可能なロケールの配列を取得する方法を確認しましょう。
Locale[]numberFormatLocales = NumberFormat.getAvailableLocales();
Locale[]dateFormatLocales = DateFormat.getAvailableLocales();
Locale[]locales = Locale.getAvailableLocales();
その後、
Locale
が利用可能な__Localesの中にあるかどうかを確認できます。
利用可能なロケールのセットは、Javaプラットフォームのさまざまな実装と機能のさまざまな分野で異なることを覚えておいてください。
サポートされているロケールの完全なリストはhttp://www.oracle.com/technetwork/java/javase/documentation/java9locales-3559485.html[OracleのJava SE Development Kit Webページ]にあります。]
2.7. デフォルトロケール
ローカライズ作業中は、
JVM
インスタンスのデフォルトの
Locale
が何であるかを知る必要があるかもしれません。幸いなことに、それを行う簡単な方法があります。
Locale defaultLocale = Locale.getDefault();
また、同様のセッターメソッドを呼び出して、デフォルトの
Locale
を指定することもできます。
Locale.setDefault(Locale.CANADA__FRENCH);
JVM
インスタンスに依存しない
JUnit
テストを作成したい場合は特に重要です。
3.数字と通貨
このセクションでは、ロケール固有のさまざまな規則に準拠する必要がある数字および通貨のフォーマッタについて説明します。
プリミティブな数値型(
int
、
double
)と同等のオブジェクト(
Integer
、
Double
)をフォーマットするには、
NumberFormat
クラスとその静的ファクトリメソッドを使用する必要があります。
2つの方法は私たちにとって興味深いものです。
-
NumberFormat.getInstance(ロケールロケール)
-
NumberFormat.getCurrencyInstance(ロケールのロケール)
サンプルコードを見てみましょう。
Locale usLocale = Locale.US;
double number = 102300.456d;
NumberFormat usNumberFormat = NumberFormat.getInstance(usLocale);
assertEquals(usNumberFormat.format(number), "102,300.456");
ご覧のとおり、
Locale
を作成し、それを使用して
NumberFormat
インスタンスを取得してサンプル番号をフォーマットするのと同じくらい簡単です。 ** 出力にはロケール固有の10進数と千の区切り記号が含まれています。
これは別の例です。
Locale usLocale = Locale.US;
BigDecimal number = new BigDecimal(102__300.456d);
NumberFormat usNumberFormat = NumberFormat.getCurrencyInstance(usLocale);
assertEquals(usNumberFormat.format(number), "$102,300.46");
通貨の書式設定には、数値の書式設定と同じ手順が含まれます。
唯一の違いは、フォーマッタが通貨記号と小数点以下の桁数を2桁に追加することです。
4.日時
それでは、数字のフォーマットよりも複雑な日付と時刻のフォーマットについて学びます。
まず第一に、我々はそれが完全に新しい
Date/Time
APIを含むので、日付と時刻のフォーマットがJava 8で著しく変化したことを知るべきです。
そのため、さまざまなフォーマッタクラスを見ていきます。
4.1.
DateTimeFormatter
-
Java 8が導入されて以来、日付と時刻をローカライズするためのメインクラスは
DateTimeFormatter
クラスです** 。これは
TemporalAccessor
インターフェースを実装するクラス(例えば、
LocalDateTime
、
LocalDate、LocalTime
、または
__ZonedDateTime)で動作します。
DateTimeFormatterを作成するには、少なくともパターンを指定し、次に
Localeを指定する必要があります。
__コード例を見てみましょう:
Locale.setDefault(Locale.US);
LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 1, 10, 15, 50, 500);
String pattern = "dd-MMMM-yyyy HH:mm:ss.SSS";
DateTimeFormatter defaultTimeFormatter = DateTimeFormatter.ofPattern(pattern);
DateTimeFormatter deTimeFormatter = DateTimeFormatter.ofPattern(pattern, Locale.GERMANY);
assertEquals(
"01-January-2018 10:15:50.000",
defaultTimeFormatter.format(localDateTime));
assertEquals(
"01-Januar-2018 10:15:50.000",
deTimeFormatter.format(localDateTime));
DateTimeFormatter
を取得した後は、
format()
メソッドを呼び出すだけでよいことがわかります。
より良い理解のために、我々は可能なパターン文字に精通しているべきです。
たとえば、手紙を見てみましょう。
Symbol Meaning Presentation Examples
------ ------- ------------ -------
y year-of-era year 2004; 04
M/L month-of-year number/text 7; 07; Jul; July; J
d day-of-month number 10
H hour-of-day (0-23) number 0
m minute-of-hour number 30
s second-of-minute number 55
S fraction-of-second fraction 978
説明付きの可能なパターン文字はすべてhttps://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html[
DateTimeFormatter
]のJavaドキュメントにあります。最終的な値がシンボルの数に依存することを知るために** 。この例では、月の名前を完全に表示する「MMMM」がありますが、「M」の文字を1つ付けると、先頭に0を付けずに月の番号が表示されます。
DateTimeFormatter
を完成させるために、
LocalizedDateTime
のフォーマット方法を見てみましょう。
LocalDateTime localDateTime = LocalDateTime.of(2018, 1, 1, 10, 15, 50, 500);
ZoneId losAngelesTimeZone = TimeZone.getTimeZone("America/Los__Angeles").toZoneId();
DateTimeFormatter localizedTimeFormatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.FULL);
String formattedLocalizedTime = localizedTimeFormatter.format(
ZonedDateTime.of(localDateTime, losAngelesTimeZone));
assertEquals("Monday, January 1, 2018 10:15:50 AM PST", formattedLocalizedTime);
LocalizedDateTime
をフォーマットするために、
ofLocalizedDateTime(FormatStyle dateTimeStyle)
メソッドを使用し、定義済みの
FormatStyle.
を提供することができます。
Java 8 Date/Time APIの詳細については、既存の記事リンク:/java-8-date-time-intro[here]を参照してください。
** 4.2.
DateFormat
と
SimpleDateFormatter
**
Dates
と
Calendars
を利用するプロジェクトで作業することは依然として一般的なので、
DateFormat
と
SimpleDateFormat
クラスを使用して日付と時刻をフォーマットする機能を簡単に紹介します。
最初の能力を分析しましょう。
GregorianCalendar gregorianCalendar = new GregorianCalendar(2018, 1, 1, 10, 15, 20);
Date date = gregorianCalendar.getTime();
DateFormat ffInstance = DateFormat.getDateTimeInstance(
DateFormat.FULL, DateFormat.FULL, Locale.ITALY);
DateFormat smInstance = DateFormat.getDateTimeInstance(
DateFormat.SHORT, DateFormat.MEDIUM, Locale.ITALY);
assertEquals("giovedì 1 febbraio 2018 10.15.20 CET", ffInstance.format(date));
assertEquals("01/02/18 10.15.20", smInstance.format(date));
DateFormat
は
Dates
と連携して機能し、3つの便利なメソッドがあります。
-
getDateTimeInstance
-
getDateInstance
-
getTimeInstance
それらはすべて、パラメーターとして
DateFormat
の事前定義値を取ります。各メソッドはオーバーロードされているので、
Locale
を渡すことも可能です。
DateTimeFormatter
のようにカスタムパターンを使用したい場合は、
SimpleDateFormat
を使用できます。短いコードスニペットを見てみましょう。
GregorianCalendar gregorianCalendar = new GregorianCalendar(
2018, 1, 1, 10, 15, 20);
Date date = gregorianCalendar.getTime();
Locale.setDefault(new Locale("pl", "PL"));
SimpleDateFormat fullMonthDateFormat = new SimpleDateFormat(
"dd-MMMM-yyyy HH:mm:ss:SSS");
SimpleDateFormat shortMonthsimpleDateFormat = new SimpleDateFormat(
"dd-MM-yyyy HH:mm:ss:SSS");
assertEquals(
"01-lutego-2018 10:15:20:000", fullMonthDateFormat.format(date));
assertEquals(
"01-02-2018 10:15:20:000" , shortMonthsimpleDateFormat.format(date));
5.カスタマイズ
いくつかの良い設計上の決定のために、私たちはロケール特有のフォーマットパターンに縛られていません、そして私たちは出力に完全に満足するようにほとんどすべての詳細を設定することができます。
-
数字のフォーマットをカスタマイズするために、
DecimalFormat
と
DecimalFormatSymbols
を使うことができます。
簡単な例を考えてみましょう。
Locale.setDefault(Locale.FRANCE);
BigDecimal number = new BigDecimal(102__300.456d);
DecimalFormat zeroDecimalFormat = new DecimalFormat("000000000.0000");
DecimalFormat dollarDecimalFormat = new DecimalFormat("$###,###.##");
assertEquals(zeroDecimalFormat.format(number), "000102300,4560");
assertEquals(dollarDecimalFormat.format(number), "$102 300,46");
DecimalFormat
ドキュメント
には、考えられるすべてのパターン文字が表示されます。
ここで知る必要があるのは、「000000000.000」が先行または後続のゼロを決定し、「、」が千単位の区切り文字で、「。」が10進数の1であることだけです。
通貨記号を追加することもできます。
DateFormatSymbol
クラスを使用しても同じ結果が得られることを以下で確認できます。
Locale.setDefault(Locale.FRANCE);
BigDecimal number = new BigDecimal(102__300.456d);
DecimalFormatSymbols decimalFormatSymbols = DecimalFormatSymbols.getInstance();
decimalFormatSymbols.setGroupingSeparator('^');
decimalFormatSymbols.setDecimalSeparator('@');
DecimalFormat separatorsDecimalFormat = new DecimalFormat("$###,###.##");
separatorsDecimalFormat.setGroupingSize(4);
separatorsDecimalFormat.setCurrency(Currency.getInstance(Locale.JAPAN));
separatorsDecimalFormat.setDecimalFormatSymbols(decimalFormatSymbols);
assertEquals(separatorsDecimalFormat.format(number), "$10^[email protected]");
ご覧のとおり、
DecimalFormatSymbols
クラスを使用すると、想像できる数値形式を指定できます。
-
SimpleDataFormatをカスタマイズするには、
DateFormatSymbols__ ** を使用できます。
曜日名の変更がどれほど簡単かを見てみましょう。
Date date = new GregorianCalendar(2018, 1, 1, 10, 15, 20).getTime();
Locale.setDefault(new Locale("pl", "PL"));
DateFormatSymbols dateFormatSymbols = new DateFormatSymbols();
dateFormatSymbols.setWeekdays(new String[]{"A", "B", "C", "D", "E", "F", "G", "H"});
SimpleDateFormat newDaysDateFormat = new SimpleDateFormat(
"EEEE-MMMM-yyyy HH:mm:ss:SSS", dateFormatSymbols);
assertEquals("F-lutego-2018 10:15:20:000", newDaysDateFormat.format(date));
6.リソースバンドル
最後に、
JVM
における国際化の重要な部分は
Resource Bundle
メカニズムです。
ResourceBundle
の目的は、別々のファイルに外部化できるローカライズされたメッセージ/説明をアプリケーションに提供することです。リソースバンドルの使い方と設定については、以前の記事 –
リソースバンドルのガイド
で説明しています。
7.まとめ
__Localと
それらを利用するフォーマッターは国際化されたアプリケーションを作成するのを助けるツールです。これらのツールを使用すると、複数のビルドやJavaが
Locale__をサポートしているかどうかを気にせずに、ユーザーの言語や文化の設定に動的に適応できるアプリケーションを作成できます。
ユーザーがどこにいても、どの言語でも話すことができる世界では、これらの変更を適用することができるということは、世界中のより多くのユーザーが私たちのアプリケーションをより直感的に理解できることを意味します。
Spring Bootアプリケーションを扱うときには、
Spring Boot Internationalization
という便利な記事もあります。
このチュートリアルのソースコードは、完全な例とともに、https://github.com/eugenp/tutorials/tree/master/core-java-8/src/test/java/com/baeldung/internationalization[over onにあります。 GitHub]。