目录
- 2.8、国际化配置
- 2.8.1、配置文件
- 2.8.2、管理国际化
- 2.8.3、在HTML获取
2.8、国际化配置
2.8.1、配置文件
国际化为 Internationalization 简称 I18n ,国际化的配置需要在resource包内创建 i18n包,
- resource包内创建i18n包,在内部创建国际化资源文件(文件格式为:基本名_ 语言代码 _国家或地区代码),idea会自动识别,进行合并
- message.properties:默认的设置
- message_en_US.properties :英语时生效
- message_zh_CN.properties:中文时生效
- 创建完成后idea自动识别成如下情况
- 下载一个插件 Resource Bundle Editor
下载完此插件后,左下角会出现2个按钮
- 点击 Resource Bundle 切换到可视化操作
- 可视化页面添加完毕后,会在配置文件中以 键=值的形式自动生成
- 在配置文件中设定国际化文件的位置
spring:
messages:
basename: i18n/message
2.8.2、管理国际化
ResourceBundleMessageSource
类用于管理国际化资源文件,Spring Boot 通过 MessageSourceAutoConfiguration 对 ResourceBundleMessageSource 提供了默认配置。
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(name = AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
private static final Resource[] NO_RESOURCES = {};
// Spring Boot 将 ResourceBundleMessageSource 以组件的形式添加到容器中,进而实现对国际化资源文件的管理。,(yml文件中配置的国际化文件的位置)
@Bean
@ConfigurationProperties(prefix = "spring.messages")
public MessageSourceProperties messageSourceProperties() {
return new MessageSourceProperties();
}
//Spring Boot 从容器中获取 MessageSourceProperties 组件,并从中读取国际化资源文件的 basename(文件基本名)、encoding(编码)等信息,将它们封装到 ResourceBundleMessageSource 中;
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
//资源包属性
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
//读取国际化资源文件的 基本名,并封装到 ResourceBundleMessageSource 中
if (StringUtils.hasText(properties.getBasename())) {
messageSource.setBasenames(StringUtils
.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
}
//读取国际化资源文件的 编码,封装到 ResourceBundleMessageSource 中
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;
}
//资源束条件
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;
}
//获取 Basename 的匹配结果
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;
}
}
}
}
- Spring Boot 创建MessageSourceProperties保存基本信息,并作为组件配置到容器中
- MessageSourceProperties 的属性与配置文件中以“spring.messages”开头的配置进行了绑定;
所以当我们自己编写了国际化配置文件时, 需要在springboot的默认配置文件中指定spring.messages.basename
的值用于解析国际化配置文件, 如果值不包含包限定, 那么将直接从classpath类路径下进行解析 - Spring Boot 从容器中获取 MessageSourceProperties 组件,并从中读取国际化资源文件的 basename(文件基本名)、encoding(编码)等信息,将它们封装到 ResourceBundleMessageSource 中;
- Spring Boot 将 ResourceBundleMessageSource 以组件的形式添加到容器中,进而实现对国际化资源文件的管理。
public class MessageSourceProperties {
/**逗号分隔的基本名称列表(本质上是完全限定的类路径位置)*/
private String basename = "messages";
/**消息包编码。*/
private Charset encoding = StandardCharsets.UTF_8;
/**加载的资源包文件缓存持续时间 */
@DurationUnit(ChronoUnit.SECONDS)
private Duration cacheDuration;
/**如果没有找到特定语言环境的文件,是否回退到系统语言环境*/
private boolean fallbackToSystemLocale = true;
/**是否始终应用 MessageFormat 规则,甚至解析没有参数的消息。*/
private boolean alwaysUseMessageFormat = false;
/**是否使用消息代码作为默认消息而不是抛出“NoSuchMessageException”*/
private boolean useCodeAsDefaultMessage = false;
.....get、set等方法..........
}
2.8.3、在HTML获取
- 配置LocaleResolver(用于切换国际化的不同配置,WebMvcAutoConfiguration中的localeResolver为国际化解析器)。
@Configuration
public class MyMessageConfig implements LocaleResolver {
//使用自定义LocaleResolver生效
@Bean
public LocaleResolver localeResolver(){
return new MyMessageConfig();
}
//用于解析路径中的配置的(l='zh_CN')
@Override
public Locale resolveLocale(HttpServletRequest request) {
String l = request.getParameter("l");
Locale locale = Locale.getDefault();
if (!StringUtils.isEmpty(l)){
String[] s = l.split("_");
locale = new Locale(s[0],s[1]);
}
return locale;
}
@Override
public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
}
}
- HTML中获取国际化:
在标签里面用:th:text="#{xxx.xxx}"
在标签外面用:[[#{xxx.xxx}]]
- 切换中英文按钮
<a class="btn btn-sm" th:href="@{/跳转到此页面的路径(l='zh_CN')}">中文</a>|
<a class="btn btn-sm" th:href="@{/跳转到此页面的路径(l='en_US')}">English</a>