locale 国际化配置(springboot)
1. 创建文件
1.1 创建 bundle
这里是在 resources目录下新建的i18n目录中创建。
1.2 添加文件名及语言
添加文件名:messages(建议,也可以任意),并添加中文(zh_CN),英文(en_US)两种语言。
1.3 文本编写
添加完成,打开任意一个文件,切换编写模式,进行对应的文本编写。这里我们需要的文件已经创建完毕。
2. springboot自带配置类解析
springboot 有很多自动装配类:XXXAutoConfiguration,国际化配置->MessageSourceAutoConfiguration
@Configuration(proxyBeanMethods = false)
/**
* AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME = "messageSource"
* SearchStrategy.CURRENT:只搜索当前上下文。
* 这里注解表示:如果当前上下文环境中不存在 messageSource 类,就加载本配置文件中的 MessageSource。
*/
@ConditionalOnMissingBean(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
/**
* 满足 当前配置文件中的ResourceBundleCondition的匹配规则才会加载当前配置文件,详情请看下面具体解释
*/
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
private static final Resource[] NO_RESOURCES = {
};
/**
* 属性配置:basename: i18n/messages(文件位置)
* use-code-as-default-message: true(是否使用消息代码作为默认消息,而不是抛出“NoSuchMessageException”。仅在开发过程中推荐false)
* always-use-message-format: false(是否总是应用MessageFormat规则,甚至解析没有参数的消息,当前属性可以看出,我们的国际化文件可以写一些可以被解析的字符串,比如:帐号允许长度范围%s-%s)
* encoding: UTF-8 (默认就是UTF-8)
* cache-duration: PT-1S(国际化文件中的内容可以被缓存起来,如果不填写将永久被缓存,可以根据情况设置具体的过期时间,格式为:Duration,具体可以百度如何配置,获取查看源码【实际为正则表达式】)
*/
@Bean
@ConfigurationProperties(prefix = "spring.messages")
public MessageSourceProperties messageSourceProperties() {
return new MessageSourceProperties();
}
/**
* 这里使用 ResourceBundleMessageSource 作为获取具体值得管理类,如果需要获取外部文件或者更多功能
* 可以使用 ReloadableResourceBundleMessageSource,但这需要重写 MessageSource,和 类注解@ConditionalOnMissingBean 交相呼应。
*/
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(properties.getBasename())) {
messageSource.setBasenames(StringUtils
.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
}
if (properties.getEncoding() != null) {
messageSource.setDefaultEncoding(properties.getEncoding().name());
}
messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
Duration cacheDuration = properties.getCacheDuration();
if (cacheDuration != null) {
messageSource.setCacheMillis(cacheDuration.toMillis());
}
messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
return messageSource;
}
/**
* 这里规则为:获取环境变量spring.messages.basename(默认为messages),也就是创建国际化文件的位置
* 去查看是否存在,如果不存在,则没有匹配成功,配置类不加载(不具有国际化功能),反之加载配置文件。
*/
protected static class ResourceBundleCondition extends SpringBootCondition {
private static ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap<>();
@Override
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");
ConditionOutcome outcome = cache.get(basename);
if (outcome == null) {
outcome = getMatchOutcomeForBasename(context, basename);
cache.put(basename, outcome);
}
return outcome;
}
private ConditionOutcome getMatchOutcomeForBasename(ConditionContext context, String basename) {
ConditionMessage.Builder message = ConditionMessage.forCondition("ResourceBundle");
for (String name : StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(basename))) {
for (Resource resource : getResources(context.getClassLoader(), name)) {
if (resource.exists()) {
return ConditionOutcome.match(message.found("bundle").items(resource));
}
}
}
return ConditionOutcome.noMatch(message.didNotFind("bundle with basename " + basename).atAll());
}
private Resource[] getResources(ClassLoader classLoader, String name) {
String target = name.replace('.', '/');
try {
return new PathMatchingResourcePatternResolver(classLoader)
.getResources("classpath*:" + target + ".properties");
}
catch (Exception ex) {
return NO_RESOURCES;
}
}
}
}
3. 获取值
配置类加载好了,那么接下来如何获取值呢?
spring 提供了两种总方式: