Java 自定义 Spring Boot starter:如何向 MessageSource 贡献 i18n 消息?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28750292/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Custom Spring Boot starter: how do you contribute i18n messages to the MessageSource?
提问by Les Hazlewood
I'm writing a custom Spring Boot starter that other developers will drop into their applications, and this starter contains out-of-the-box controllers and UI screens.
我正在编写一个自定义 Spring Boot 启动器,其他开发人员会将其放入他们的应用程序中,这个启动器包含开箱即用的控制器和 UI 屏幕。
These UI screens are internationalized and the i18n keys/values are in a package file: com/foo/wherever/i18n.properties
.
这些 UI 屏幕是国际化的,i18n 键/值位于包文件中:com/foo/wherever/i18n.properties
.
I want to ensure that when my starter is loaded at startup, that these i18n.properties are available in the application's MessageSource
automatically so that my UI pages work (rendered via normal Spring Controller + ViewResolver + View implementations) without the app developer having to specify this file themselves.
我想确保在启动时加载我的 starter 时,这些 i18n.properties 在应用程序中MessageSource
自动可用,以便我的 UI 页面工作(通过普通的 Spring Controller + ViewResolver + View 实现呈现)而无需应用程序开发人员指定文件自己。
In other words, they should be able to add my starter to their runtime classpath and everything 'just works' without the need to configure anything.
换句话说,他们应该能够将我的 starter 添加到他们的运行时类路径中,并且一切“正常工作”而无需进行任何配置。
Now, I have discovered that the app developer can create their own src/main/resources/messages.properties
file andmanually configure the additional messages file in application.properties
:
现在,我发现应用程序开发人员可以创建自己的src/main/resources/messages.properties
文件并手动配置附加消息文件application.properties
:
spring.messages.basename = messages, com.foo.wherever.i18n
And this will work.
这将起作用。
However, this requires both of the following:
但是,这需要以下两项:
- They must manually configure the
spring.messages.basename
property - it's not automatic. and - They must have their own
messages.properties
file in their application classpath. If amessages.properties
file does not exist,spring.messages.basename
doesn't even work. Even if they don't care about i18n, this is still required - not desirable.
- 他们必须手动配置
spring.messages.basename
属性 - 这不是自动的。和 - 他们
messages.properties
的应用程序类路径中必须有自己的文件。如果messages.properties
文件不存在,spring.messages.basename
甚至不起作用。即使他们不关心 i18n,这仍然是必需的 - 不可取。
I suppose I couldmove my i18n.properties file to a classpath:/messages.properties file in the starter .jar, but that doesn't seem like a good solution: if the app dev has their own messages.properties file only one of them would be read, resulting in missing message values.
我想我可以将 i18n.properties 文件移动到 starter .jar 中的 classpath:/messages.properties 文件,但这似乎不是一个好的解决方案:如果应用程序开发人员有自己的 messages.properties 文件,则只有其中一个它们将被读取,导致丢失消息值。
It seems as if Spring Boot MessageSourceAutoConfigurationshould have a concept of a CompositeMessageSource
that iterates over one or more MessageSource
instances that are available (and Order
ed) in the Spring ApplicationContext and thatis used by the DispatcherServlet. This would allow any starter to contribute to the available messages just by declaring a MessageSource
in their auto config
看起来好像春天启动MessageSourceAutoConfiguration应该有一个概念CompositeMessageSource
是在一个或多个迭代MessageSource
实例可用(并且Order
在Spring的ApplicationContext ED)和该所使用的DispatcherServlet的。这将允许任何启动器仅通过MessageSource
在其自动配置中声明 a 来为可用消息做出贡献
Is it possible to do what I ask? What is the most 'hands off' solution for the app developer?
可以按我的要求做吗?对于应用程序开发人员来说,最“放手”的解决方案是什么?
采纳答案by sodik
Maybe it is long shot but you can try to use BeanFactoryPostProcessor.
也许它是远射,但您可以尝试使用BeanFactoryPostProcessor。
Idea is following:
思路如下:
Take "messageSource" bean out of the application context. Note that it might but does not have to be a spring boot's one if e.g. developer wants to use its own implementation and don't use spring boot autoconfiguration.
Replace it with your own implementation that tries to resolve "your keys" and the rest delegate to original message source. Or vice versa if you want to make possible to override your translations by developer (there can be problems if original message source does not throw exception for unknown keys).
从应用程序上下文中取出“messageSource”bean。请注意,如果例如开发人员想要使用自己的实现而不使用 spring boot 自动配置,它可能但不一定是 spring boot 的。
将其替换为您自己的尝试解决“您的密钥”的实现,其余部分委托给原始消息源。反之亦然,如果您想让开发人员覆盖您的翻译(如果原始消息源不为未知键抛出异常,则可能会出现问题)。
But there might be a better way to do that.
但可能有更好的方法来做到这一点。
回答by anataliocs
I set this up in the following way. I'm only currently supporting en_US but it is setup to handle any number of languages using internationalization(i18n).
我按照以下方式进行设置。我目前只支持 en_US,但它设置为使用国际化(i18n)处理任意数量的语言。
View the Code here
在此处查看代码
View the code gist here: Code on github gist
在此处查看代码要点:github gist 上的代码
Add Message Source and Default locale Beans
添加消息源和默认语言环境 Bean
Add these beans to your Application.java to set your default locale and configure the location of your message props
将这些 bean 添加到您的 Application.java 以设置您的默认语言环境并配置您的消息道具的位置
Create Message Service
创建消息服务
Service will get the default locale from the session and then get the message text from your props
服务将从会话中获取默认语言环境,然后从你的道具中获取消息文本
Use the Message service in Controller
使用 Controller 中的 Message 服务
Inject the message svc and then pass in the id to get the value from the props file
注入消息svc,然后传入id从props文件中获取值
Add message.properties file in the locale
在语言环境中添加 message.properties 文件
Goto /resources:
转到/资源:
- create the locale folder
- create a file called messages_en_US.properties
- 创建语言环境文件夹
- 创建一个名为 messages_en_US.properties 的文件
Read more
阅读更多
You can view a more complete article on this subject here: Spring Boot Internationalization i18n using Message Properties
您可以在此处查看有关此主题的更完整的文章: Spring Boot Internationalization i18n using Message Properties
Look at the Code
看代码
View the code gist here: Code on github gist
在此处查看代码要点:github gist 上的代码
回答by Thomas K?sene
I realize this is an old and answered question by now, but I encountered the same problem the other day, and wrote a blog post about how I've decided to solve it. I thought I should share it here since I got some inspiration for my solution from this thread.
我现在意识到这是一个古老的问题,但前几天我遇到了同样的问题,并写了一篇关于我决定如何解决它的博客文章。我想我应该在这里分享它,因为我从这个线程中获得了一些解决方案的灵感。
In short, it takes sodik's idea of intercepting the creation of the MessageSource
bean, but instead of using a BeanFactoryPostProcessor
I'm using a BeanPostProcessor
, and rather than replacing the original MessageSource
in the application context, I just add my own as its parent:
简而言之,它采用了 sodik 拦截MessageSource
bean创建的想法,但是BeanFactoryPostProcessor
我没有使用 a我正在使用 a 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;
}
};
}
You can read the full blog post where I explain some caveats about my solution: http://www.thomaskasene.com/2016/08/20/custom-spring-boot-starter-messagesource/
您可以阅读完整的博客文章,其中我解释了有关我的解决方案的一些注意事项:http: //www.thomaskasene.com/2016/08/20/custom-spring-boot-starter-messagesource/
Update
更新
After some tinkering I realized that using a BeanFactoryPostProcessor
was wrong as it will cause the original MessageSource
bean to be created prematurely and ignore application properties (most importantly, spring.messages.basename
). That means the application won't be able to configure these properties. See the excerpt from the BeanFactoryPostProcessordocumentation below.
经过一些修补后,我意识到使用 aBeanFactoryPostProcessor
是错误的,因为它会导致MessageSource
过早创建原始bean 并忽略应用程序属性(最重要的是,spring.messages.basename
)。这意味着应用程序将无法配置这些属性。请参阅下面BeanFactoryPostProcessor文档的摘录。
A BeanFactoryPostProcessor may interact with and modify bean definitions, but never bean instances. Doing so may cause premature bean instantiation, violating the container and causing unintended side-effects. If bean instance interaction is required, consider implementing BeanPostProcessor instead.
BeanFactoryPostProcessor 可以与 bean 定义交互并修改 bean 定义,但绝不能与 bean 实例交互。这样做可能会导致 bean 过早实例化、违反容器并导致意外的副作用。如果需要 bean 实例交互,请考虑实现 BeanPostProcessor。
I've updated the example above to use BeanPostProcessor
instead, which alters the bean instance rather than the bean definition.
我已经更新了上面的例子来使用BeanPostProcessor
,它改变了 bean 实例而不是 bean 定义。