web-dev-qa-db-ja.com

en = USとen-USの両方をJava

ロケールをパラメーターとして使用するAPI(Javaを使用)を作成しています。私たちはクライアントが「en-US」または「en_US」を指定できるようにしたいのです。どちらもすべての言語で広く使用されているようです。

私はこれらのリンクを通過しました

  1. Javaの文字列表現からロケールを取得する方法
  2. en_USまたはen-US、どちらを使用するか
  3. Javaロケールのドキュメント

Javaのドキュメント(上記のソース3)には、「整形式のバリアント値の形式はSUBTAG(( '_' | '-')SUBTAG)*です。SUBTAG= [0-9] [0-9a-zA-Z] { 3} | [0-9a-zA-Z] {5,8}。(注:BCP 47は区切り文字としてハイフン( '-')のみを使用します。これはより寛大です)。

これが「_」と「-」の両方であることを理解した方法はサポートされていますが、それらのコードは「-」のみをサポートしています。以下のサンプルユニットテストが失敗するが、「en-US」を使用するとパスする。

@Test
public void testLocale() {
    Locale locale = Locale.forLanguageTag("en_US");
    assertThat(locale.getLanguage(), equalTo("en"));
}

文字列「en_US」と「en-US」の両方の形式からロケールを解析する方法はありますか?ここで推奨されるアプローチは何ですか?

5
srini

パラメータを受け取ったら、ロケール文字列で"_"をすべて"-"に置き換え、ロジックが"-"のみを期待するようにします。

2

理解せずに置き換えるのではなく、下線付きとハイフン付きの2つのフォームがあるように見える理由と、なぜ気にする必要があるのか​​を説明したいと思います。

tl; drこれは、単一の文字の置き換えとして単純ではありません。


1。仕様

ここにいくつかの仕様があります:

  • [〜#〜] icu [〜#〜] :The[〜#〜] i [〜#〜]国際[〜#〜] c [〜#〜]の要素[〜#〜] u [〜#〜 ]nicodeには、ロケール(言語、国、スクリプト、バリアントなど)をエンコード/表現する方法に関するセクションがあり、このプロジェクトは主にCなどのネイティブ言語で使用されます。 POSIXシステムのロケールと混在。

  • nicode CLDR :おもしろいことに 言語タグとの同等性 の単純なページを提供します。この表現では、ハイフンを優先しながら、ハイフンとアンダースコアの両方を使用できます。これもICUとは異なります。

  • (BCP 47 / RFC 4646)⇒ RFC 5646 は、特にContent-LanguageおよびAccept-Language(言語範囲)でHTTPヘッダー( RFC 3282 )で使用される言語タグに関するものです。

そのため、Webの標準は、一部のヘッダーで言語タグを使用することです。つまり、

  • サーバーアプリケーションが標準のHTTPヘッダーに依存している場合は、言語タグ(より具体的にはAccept-Languageの言語範囲)を処理する必要があります。

  • サーバーアプリケーションがCompany-MyApp-Other-Languageのようなカスタムヘッダーを使用している場合、問題はありません。このエコシステムに対してカスタムです。

  • クライアントアプリケーションが標準のHTTPヘッダーを使用しているが、形式が正しくない場合、実際にサーバーアプリはそれらを処理する必要があります。


2。いくつかの実装の詳細

PHPの良い点は Locale がICU形式と言語タグを処理することです。

ただし、Javaの場合、 Locale クラスはかなり古く(1997年頃のJDK 1.1以降))、ストーリーはもう少し複雑です。 (toString)を上記の標準のいずれかに解析またはフォーマットするには、区切り文字としてアンダースコアを使用しましたが、ICUに準拠していません。2011年頃のJDK 1.7ではforLanguageTag/toLanguageTagは、BCP 47/RFC 4646標準をサポートするために追加されました;彼の古いメソッドは、下位互換性のためにレガシー動作を維持しました。現在(2018年3月)ICU/CLDRロケール形式は、JDKのロケールではサポートされていません。

実際、単純なアプローチでは、ほとんどの状況(99.999%)でアンダースコアをハイフンに置き換えます。文字列に拡張子のみが含まれている場合、まれに表示されることがあります。

ただし、これはすべてのICU表現で機能しません。特に@currency=...のようなICUキーワードがある場合、これらは単一の文字置換では変換できません。

  • sr_Latn_RS_REVISED@currency=USD
  • en_IE@currency=IEP

また、これはJava JavaロケールのtoStringを使用するクライアントでは機能しません。これにより、問題が発生する可能性が高くなります。スクリプトがロケールにとって重要な部分である国、たとえばセルビア:

  • Locale.forLanguageTag("sr-Latn-RS").toString()sr_RS_#Latn、このレガシーtoStringは有効な言語タグとして解釈できません。実際、パーサーはスクリプトを完全に閉じます。

したがって、標準ヘッダーで考えられるすべての悪い動作を処理するのは難しいので、ブラウザが尊重する言語タグRFCを尊重するように強制するのが最善でしょう。それが不可能な場合は、この誤動作の原因となっているアプリケーションと、使用されている形式を特定するのが最善です。これにより、可能なすべての形式を処理することが回避されます。


3。ポストスクリプト

さらに、質問で引用されているjavadoc部分は、ロケールのバリアント部分にのみ適用され、言語や国には適用されません

整形式のバリアント値の形式はSUBTAG(( '_' | '-')SUBTAG)*です。SUBTAG= [0-9] [0-9a-zA-Z] {3} | [0-9a-zA-Z] {5,8}。 (注:BCP 47は区切り文字としてハイフン( '-')のみを使用します。これはより寛大です)。

13
Brice