ロケールをパラメーターとして使用するAPI(Javaを使用)を作成しています。私たちはクライアントが「en-US」または「en_US」を指定できるようにしたいのです。どちらもすべての言語で広く使用されているようです。
私はこれらのリンクを通過しました
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」の両方の形式からロケールを解析する方法はありますか?ここで推奨されるアプローチは何ですか?
パラメータを受け取ったら、ロケール文字列で"_"
をすべて"-"
に置き換え、ロジックが"-"
のみを期待するようにします。
理解せずに置き換えるのではなく、下線付きとハイフン付きの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は区切り文字としてハイフン( '-')のみを使用します。これはより寛大です)。