2

私はSpring Webアプリケーションをやっています。

ko (韓国語)、ru (ロシア語)、en (英語) などのいくつかのロケールをサポートする必要があります。

RequestContextUtils.getLocale(request) や LocaleChangeInterceptor などの方法を使用して、ブラウザーからロケールをキャッチできます。

ただし、ブラウザーのロケールが Web アプリでサポートされているものではない可能性があります。クローゼットまたはデフォルトのロケールに解決する必要があります。

基本的に、ブラウザのロケールと、ko、ru、en などのいくつかのロケール値を指定して、解決されたロケールを取得する方法を知る必要があります。

私の理解では、Spring には、ブラウザーのロケールを指定して適切なリソース バンドルを見つけることができるため、そのようなロケール解決コードがあります。ロケール解決のためにSpringのコードを再利用したいと思っていますが、その方法がわかりません。この質問は、ブラウザのロケールの検索や適切なメッセージの表示とは関係がないことに注意してください。

編集

Spring のコードをトレースしたところ、Spring は正確なロケールまたは最も近いロケールを見つけるために JDK に依存しているようです。私はこれを見つけたばかりで、これが私が探しているものだと思います:

リソースバンドルの検索順序 https://sites.google.com/site/openjdklocale/design-notes/resource-bundle-lookup-order

適切なリソース バンドルを見つける必要がないことに注意してください。問題のロケールといくつかの既知のロケールを指定して、既存の JDK コードが返すロケールを取得する必要があるだけです。そこで、既存の JDK のルックアップ コードを再利用したいと考えています。何か案が?

私はJDK7を使用しています。


助けてくれてありがとう!

よろしく。

4

2 に答える 2

5

簡潔な答え

公式ドキュメント( 17.8章ロケールの使用 )を確認しましたか? 構成する必要がありLocaleResolver、場合によっては を作成するLocaleChangeInterceptor(または独自に作成する) 必要があります。

Spring の仕組みに関する詳細な説明

クライアントのロケールを解決することは、正しいリソース バンドルを取得することとは異なるタスクであることに注意してください。

  • Spring は、現在のロケールLocaleResolver取得または設定するために使用します。異なる戦略のためのいくつかの実装がありますLocaleResolver:
    • FixedLocaleResolver- 常にロケールを定義済みの値に解決します (別のロケールを設定することはできません)
    • SessionLocaleResolver- 特別なキーの下のセッションで、ロケールを値ストアに保存して解決します
    • AcceptHeaderLocaleResolver- これは実際にブラウザーからロケールを取得しようとするリゾルバーです (別のロケールを設定することはできません)。
    • CookieLocaleResolver- ブラウザのクックに保存されている値にロケールを保存して解決します

LocaleResolver入力するために使用されLocaleContextHolderます(ところで、それはロケールを取得する必要があるクラスです)。

ユーザー要求パラメーターに基づいLocaleChangeInterceptorて選択したロケールを設定できる2 番目のメカニズムがあります。LocaleResolver

現在、このインフラストラクチャは、リソース バンドル (messages.properties、messages_en.properties、...) およびメッセージを解決するために使用されるメカニズムとは無関係です。次の例は、その理由を示しています。

シナリオ例

  • リソース バンドルが次のようになっているとします。
    • messages.properties-ruメッセージ付き (デフォルトのメッセージ)
    • messages_ko.properties-koメッセージ付き
  • SessionLocaleResolverデフォルトのロケールで構成したと仮定しましょうru
  • そして、あなたが設定したと仮定しましょうLocaleChangeInterceptor

シナリオ I - 最初のリクエスト:

  1. ユーザーがアプリケーションに最初のリクエストを行う
  2. リクエストがSpringに到達するとすぐに、リクエストのロケールを取得するためDispatcherServletにクエリを実行しますLocaleResolver
  3. セッションにロケールが設定されていないため、ロケールはru(デフォルト)に解決されます。
  4. ...ハンドラのもの...
  5. 今、あなたはウェブページをレンダリングしていて、<spring:message>タグを使いたいと思っています...
  6. MessageSourceこのタグは、事前構成された( ResourceBundleMessageSource) とリクエスト ロケール(リゾルバーによって解決されたもの) を使用して、翻訳コードを解決しようとします。
  7. messages_ru.propertiesメッセージソースは存在しない翻訳コードを読み込もうとするため、より一般的なファイルに移動しますmessages.properties(「誤って」デフォルト言語が含まれています - ru)
  8. ユーザーは自分のページをロシア語で取得します

シナリオ II - ユーザーがリンクをクリックして、言語を次のように変更しますko

  1. 2 番目のリクエストは、クエリ パラメータを使用して行われますlocale=ko
  2. DispatcherServletリクエストのロケールを解決しますru(これは、ロケール リゾルバーが返すものです)
  3. リクエストがハンドラーに渡される前に、LocaleChangeInterceptorハンドラー インターセプターを通過します。
  4. LocaleChangeInterceptorlocaleでクエリ パラメータを検出し、setLocaleメソッドを呼び出しますLocaleResolver。これにより、リクエスト ロケールが変更され、今後のリクエストのためにセッションに新しいロケールが保存されます。
  5. ...ハンドラのもの...
  6. ...ものを見る...
  7. 今はロケール<spring:message>で呼び出しMessageSourceています。ko
  8. メッセージ ソースがロードを試みmessages_ko.properties、成功します。
  9. ユーザーは自分のページを韓国語で取得します

シナリオ III - ユーザーが無効なロケールに変更しようとしています:

  1. ユーザーはクエリ パラメータでリクエストを行いますlocale=en
  2. ...ディスパッチャーのもの...(ロケールはkoセッションから解決されます)
  3. ハンドラーインターセプターはロケールをに変更しますen(これはセッションにも保存されます)
  4. ...ハンドラのもの...
  5. ...ものを見る...
  6. 今はロケール<spring:message>で呼び出しMessageSourceています。en
  7. messages_en.propertiesメッセージ ソースは、存在しないものをロードしようとするため、より一般的なファイルに移動し、messages.propertiesメッセージはru、要求ロケールが に設定されていてもに変換されenます。
  8. ユーザーは自分のページをロシア語で取得します

概要

最後の例は、おそらく気になるところです。ユーザーが選択したロケールがサポートされているかどうかがチェックされていません。ユーザーがサポートされていないロケールに切り替えることを許可したくない場合は、一部をサブクラス化するかLocaleResolver、独自のLocaleChangeInterceptor.

于 2013-06-02T09:13:25.027 に答える
1

完全な再利用

JDK ロジックを再利用するには、既知の各ロケール (test_fr_CA.properties、test_fr.properties、test_en_US.properties、test_en.properties、test.properties など) のクラスパス内にプロパティ ファイルを作成できます。一致させたい場合は、ルート ロケール (test.properties) を忘れないでください。次に、問題のロケールのリソース バンドルを作成し、それを調べて実際に使用されているロケールを確認します。

ResourceBundle rb = ResourceBundle.getBundle("test", Locale.FRENCH);
System.out.println("Locale used is:"+rb.getLocale().toString());

ファイルは動的に作成でき、テスト後にクリーンアップできます。

高レベルのコード複製、低レベルの再利用

java.util.ResourceBundle.getBundleImpl(...)の高レベル コードを複製できます。これは基本的に、問題のロケールでjava.util.ResourceBundle.Control.getCandidateLocales(...)を再利用して、ロケールの候補リストで (equal toString() 表現のような独自のマッチング ロジックを使用して) 一致を探します。一致するものがない場合は、 java.util.ResourceBundle.Control.getFallbackLocale(...)を再利用して、問題のロケールの次のフォールバック ロケールを取得します。フォールバック ロケールごとに、候補リスト内のロケールと一致させようとし、フォールバック ロケールがなくなるまでループでフォールバックを繰り返します。ルート ロケールは各候補リストの最後の候補になりますが、すべてのフォールバック ロケールを使い果たした場合を除き、スキップする必要があることに注意してください。

この方法では、ファイルを作成する必要はありません。getCandidateLocales(...) および get FallbackLocale(...) 呼び出しで存在しない baseName を使用し、各候補ロケールを既知のロケールのリストと比較して一致を探します。

これの簡単な例は、次のようになります。

    ResourceBundle.Control rbControl = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_PROPERTIES);
    Locale localeInQuestion = Locale.CHINA;
    List<Locale> knownLocales = Arrays.asList(new Locale[] {Locale.CANADA_FRENCH, Locale.FRENCH, Locale.US, Locale.UK, Locale.ENGLISH, Locale.ROOT});
    String nonExistentBaseName = "bogus";

    Locale matchingLocale = null;
    Boolean reachedRootLocaleMatch = false;

    outerloop:
    for (Locale targetLocale = localeInQuestion;
            targetLocale != null;
            targetLocale = rbControl.getFallbackLocale(nonExistentBaseName, targetLocale)) {
        List<Locale> candidateLocales = rbControl.getCandidateLocales(nonExistentBaseName, targetLocale);
        for (Iterator iterator = candidateLocales.iterator(); iterator.hasNext();) {
            Locale currentCandidateLocale = (Locale) iterator.next();
            if (knownLocales.contains(currentCandidateLocale)) {
                if (currentCandidateLocale.equals(Locale.ROOT)) {
                    reachedRootLocaleMatch = true;
                }
                else {
                    matchingLocale = currentCandidateLocale;
                    break outerloop;
                }
            }
        }
    }

    if (matchingLocale == null && reachedRootLocaleMatch) {
        matchingLocale = Locale.ROOT;
    }

    if (matchingLocale != null) {
        System.out.println("The matching locale is: "+matchingLocale.toString());
    }
    else {
        System.out.println("There was no matching locale");
    }
于 2013-06-26T18:26:21.727 に答える