私は他の開発者が自分のアプリケーションにドロップするカスタムのSpring Bootスターターを書いています。このスターターには、すぐに使えるコントローラーとUI画面が含まれています。
これらのUI画面は国際化されており、i18nキー/値はパッケージファイルcom/foo/wherever/i18n.properties
にあります。
スターターが起動時に読み込まれるときに、これらのi18n.propertiesがアプリケーションのMessageSource
で自動的に使用できるようにして、UIページが機能するようにします(通常のSpring Controller + ViewResolver + View実装を介してレンダリングされます)アプリ開発者がこのファイルを自分で指定する必要はありません。
言い換えると、彼らは私のスターターをランタイムクラスパスに追加でき、何も設定しなくてもすべてが「機能する」だけです。
今、私はアプリ開発者が独自のsrc/main/resources/messages.properties
ファイルを作成し、手動でapplication.properties
に追加のメッセージファイルを設定できることを発見しました:
spring.messages.basename = messages, com.foo.wherever.i18n
そして、これはうまくいきます。
ただし、これには次の両方が必要です。
spring.messages.basename
プロパティを手動で設定する必要があります-自動ではありません。そしてmessages.properties
ファイルが必要です。 messages.properties
ファイルが存在しない場合、spring.messages.basename
も機能しません。彼らが国際化について気にしない場合でも、これは依然として必要です-望ましくありません。私はできましたi18n.propertiesファイルをスターター.jarのclasspath:/messages.propertiesファイルに移動すると思いますが、それは適切な解決策:アプリ開発者が独自のmessages.propertiesファイルを持っている場合、そのうちの1つだけが読み取られ、メッセージ値が失われます。
Spring Boot MessageSourceAutoConfiguration は、利用可能な1つ以上のCompositeMessageSource
インスタンス(およびMessageSource
edを反復処理するOrder
の概念を持つ必要があるようです)Spring ApplicationContext内で、thatがDispatcherServletによって使用されます。これにより、スターターは、自動構成でMessageSource
を宣言するだけで、使用可能なメッセージに貢献できます。
私が求めることを行うことは可能ですか?アプリ開発者にとって最も手助けになるソリューションは何ですか?
多分それは長いショットですが、あなたは BeanFactoryPostProcessor を使用してみることができます。
アイデアは次のとおりです:
「messageSource」Beanをアプリケーションコンテキストから取り出します。スプリングブーツの場合もありますが、そうである必要はありません。開発者は独自の実装を使用し、スプリングブート自動構成を使用しないことを望んでいます。
「キー」を解決しようとする独自の実装に置き換え、残りを元のメッセージソースに委任します。または、開発者による翻訳のオーバーライドを可能にしたい場合はその逆です(元のメッセージソースが不明なキーに対して例外をスローしない場合、問題が発生する可能性があります)。
しかし、そのためのより良い方法があるかもしれません。
以下のように設定しました。現在en_USのみをサポートしていますが、国際化(i18n)を使用して任意の数の言語を処理するように設定されています。
ここでコードGistを表示: github Gist上のコード
これらのBeanをApplication.Javaに追加して、デフォルトのロケールを設定し、メッセージプロップの場所を構成します。
サービスはセッションからデフォルトのロケールを取得し、小道具からメッセージテキストを取得します
メッセージsvcを挿入し、IDを渡して、propsファイルから値を取得します
/リソースに移動:
このテーマに関するより完全な記事は、こちらで確認できます。 Spring Boot Internationalization i18n using Message Properties
ここでコードGistを表示: github Gist上のコード
これは古くて回答済みの質問であることに気づきましたが、先日同じ問題に遭遇し、それを解決することに決めた方法についてブログに投稿しました。このスレッドから自分の解決策にインスピレーションを得たので、ここで共有する必要があると思いました。
要するに、MessageSource
Beanの作成をインターセプトするというsodikのアイデアが必要ですが、BeanFactoryPostProcessor
を使用する代わりに、BeanPostProcessor
を使用して、元のMessageSource
アプリケーションコンテキストでは、自分自身をその親として追加するだけです。
@Bean
BeanPostProcessor messageSourceCustomExtender() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof HierarchicalMessageSource && beanName.equals("messageSource")) {
ResourceBundleMessageSource parent = new ResourceBundleMessageSource();
parent.setBasename("custom");
((HierarchicalMessageSource) bean).setParentMessageSource(parent);
}
return bean;
}
};
}
私のソリューションに関するいくつかの警告を説明するブログの全文を読むことができます: http://www.thomaskasene.com/2016/08/20/custom-spring-boot-starter-messagesource/
いじくり回した後、BeanFactoryPostProcessor
を使用すると、元のMessageSource
Beanが途中で作成され、アプリケーションプロパティ(最も重要なのはspring.messages.basename
)。つまり、アプリケーションはこれらのプロパティを構成できません。以下の BeanFactoryPostProcessor ドキュメントからの抜粋を参照してください。
BeanFactoryPostProcessorは、Bean定義と対話してBean定義を変更できますが、Beanインスタンスは変更できません。これを行うと、Beanのインスタンスが早まってしまい、コンテナに違反して、意図しない副作用が発生する可能性があります。 Beanインスタンスの相互作用が必要な場合は、代わりにBeanPostProcessorの実装を検討してください。
上記の例を更新して、代わりにBeanPostProcessor
を使用します。これにより、Bean定義ではなくBeanインスタンスが変更されます。