1)、編寫國際化配置文件;
2)、使用ResourceBundleMessageSource管理國際化資源文件
3)、在頁面使用fmt:message取出國際化內容
步驟:
1)、編寫國際化配置文件,抽取頁面需要顯示的國際化消息
國際化文件是peroperties文件
自動識別國際化視圖
通過國際化視圖創建國際化配置文件
同時對比編輯多個配置文件
配置國際化文件路徑:
spring.messages.basename=static.i18n.login
@Configuration @ConditionalOnMissingBean( value = {MessageSource.class}, search = SearchStrategy.CURRENT ) @AutoConfigureOrder(-2147483648) @Conditional({MessageSourceAutoConfiguration.ResourceBundleCondition.class}) @EnableConfigurationProperties public class MessageSourceAutoConfiguration { private static final Resource[] NO_RESOURCES = new Resource[0]; public MessageSourceAutoConfiguration() { } @Bean @ConfigurationProperties( prefix = "spring.messages" ) public MessageSourceProperties messageSourceProperties() { return new MessageSourceProperties(); } @Bean public MessageSource messageSource(MessageSourceProperties properties) { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); if (StringUtils.hasText(properties.getBasename())) {
//設置國際化文件的基礎名稱(去掉語言_國家代{zh_CN})的):即默認是message.properties,上圖中我們起的名稱是login.properties 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; } protected static class ResourceBundleCondition extends SpringBootCondition { private static ConcurrentReferenceHashMap<String, ConditionOutcome> cache = new ConcurrentReferenceHashMap(); protected ResourceBundleCondition() { } public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
//自定義的話就用此屬性:spring.messages.basename來指定,默認叫message.propertie
//我們上圖的需要指定為:spring.messages.basename=login String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages"); ConditionOutcome outcome = (ConditionOutcome)cache.get(basename); if (outcome == null) { outcome = this.getMatchOutcomeForBasename(context, basename); cache.put(basename, outcome); } return outcome; } private ConditionOutcome getMatchOutcomeForBasename(ConditionContext context, String basename) { Builder message = ConditionMessage.forCondition("ResourceBundle", new Object[0]); String[] var4 = StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(basename)); int var5 = var4.length; for(int var6 = 0; var6 < var5; ++var6) { String name = var4[var6]; Resource[] var8 = this.getResources(context.getClassLoader(), name);//類路徑 int var9 = var8.length; for(int var10 = 0; var10 < var9; ++var10) { Resource resource = var8[var10]; if (resource.exists()) { return ConditionOutcome.match(message.found("bundle").items(new Object[]{resource})); } } } return ConditionOutcome.noMatch(message.didNotFind("bundle with basename " + basename).atAll()); } private Resource[] getResources(ClassLoader classLoader, String name) { String target = name.replace('.', '/'); try {
//類路徑下的 message.properties 和 messages_zh_CN.properties 或 自己指定的xxxx.properties 、xxxx.preperties return (new PathMatchingResourcePatternResolver(classLoader)).getResources("classpath*:" + target + ".properties"); } catch (Exception var5) { return MessageSourceAutoConfiguration.NO_RESOURCES; } } } }
public class MessageSourceProperties { private String basename = "messages";//我們的配置文件可以直接放在類路徑下,默認名稱叫message.properties private Charset encoding; @DurationUnit(ChronoUnit.SECONDS) private Duration cacheDuration; private boolean fallbackToSystemLocale; private boolean alwaysUseMessageFormat; private boolean useCodeAsDefaultMessage; public MessageSourceProperties() { this.encoding = StandardCharsets.UTF_8; this.fallbackToSystemLocale = true; this.alwaysUseMessageFormat = false; this.useCodeAsDefaultMessage = false; } public String getBasename() { return this.basename; } public void setBasename(String basename) { this.basename = basename; }
......
}
<!-- 中英文切換鏈接 -->
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN'}">中文</a> <a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>
是根據瀏覽器的默認語言識別的
不過取出來的中文有亂碼
IDEA中將UTF-8自動組轉為ASSIC碼
File ——》 settings 里的設置只是針對當前項目的設置,要想設置全局的
Settins ——》Other Settings ——》Default Settings 設置全局的默認設置
然后重新編輯有亂碼的properties文件
根據瀏覽器的默認語言設置自動區分國際化字段的顯示
默認請求頭里會有語言的信息
切換默認的語言,請求頭中排在第一位的也就變了
實現原理:
國際化Locale(區域信息對象);LocaleResolver(獲取區域信息對象)
public class WebMvcAutoConfiguration { public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ResourceLoaderAware { @Bean @ConditionalOnMissingBean //當項目中沒有區域解析器的時候,才執行這個SprigBoot默認的配置,所以可以自定義 @ConditionalOnProperty( prefix = "spring.mvc", name = {"locale"} ) // public LocaleResolver localeResolver() { //默認從配置文件中獲取 if (this.mvcProperties.getLocaleResolver() == org.springframework.boot.autoconfigure.web.servlet.WebMvcProperties.LocaleResolver.FIXED) { return new FixedLocaleResolver(this.mvcProperties.getLocale()); } else {//如果配置文件中沒有,則從HttpRequest的header中獲取 AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver(); localeResolver.setDefaultLocale(this.mvcProperties.getLocale()); return localeResolver; } } } public class AcceptHeaderLocaleResolver implements LocaleResolver { public Locale resolveLocale(HttpServletRequest request) { Locale defaultLocale = this.getDefaultLocale(); if (defaultLocale != null && request.getHeader("Accept-Language") == null) { return defaultLocale; } else { Locale requestLocale = request.getLocale(); List<Locale> supportedLocales = this.getSupportedLocales(); if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) { Locale supportedLocale = this.findSupportedLocale(request, supportedLocales); if (supportedLocale != null) { return supportedLocale; } else {//如果默認的區域解析器為空,則從requset請求頭中獲取 return defaultLocale != null ? defaultLocale : requestLocale; } } else { return requestLocale; } } } }
自定義區域解析器,點擊鏈接切換國際化
public class MyLocaleResolver implements LocaleResolver { @Override public Locale resolveLocale(HttpServletRequest request) { String l = request.getParameter("l"); Locale locale = Locale.getDefault(); if (!StringUtils.isEmpty(l)) { String[] split = l.split("_"); locale = new Locale(split[0], split[1]); } return locale; } @Override public void setLocale(HttpServletRequest httpServletRequest, @Nullable HttpServletResponse httpServletResponse, @Nullable Locale locale) { } }
//將自定義的區域解析器加入到容器中來 @Bean public LocaleResolver localeResolver(){ return new MyLocaleResolver(); }