spring boot + thymeleaf 3 國際化

** 原創文章,請勿轉載 **html

在給spring boot 1.5.6 + thymeleaf 3進行國際化時,踩了一個坑(其實不止一個)。 現象:web


 

看到了吧, 就是取值的key, 後面被加了_en_US 或 _zh_CN, 以及先後的問號。spring

 

先看下代碼,首先兩個資源文件:數據庫

messages_en_US.propertiesapp

page.content=this is a test string.

message_zh_CN.properties, 在eclipse裏打開的,內容是: 這是一個測試字符串eclipse

page.content=\u8FD9\u662F\u4E00\u4E2A\u6D4B\u5B57\u7B26\u4E32\u3002

 

i18n.html:ide

<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <h1>spring boot, thymeleaf 3 國際化</h1>
       <hr>
    <a href="/i18n?lang=en_US">English</a> | <a href="/i18n?lang=zh_CN">中文</a>
   
    <br>
    <br>
    <br>
    <br>
    from thymeleaf engine:      <span th:text="#{page.content}"></span> 
    <br>
    <br>
    from controller model:      <span th:text="${content}"></span> 
</body>
</html>

其中, #{page.content} 來源於thymeleaf 3,  ${content} 則由controller的Model返回,代碼是hardcode, 返回的都是中文測試

 

controller:ui

@Controller
public class I18nController {
    @Autowired
    private MessageSource messageSource;

    @GetMapping("/i18n")
    public String i18n(Model model) {
        String message = messageSource.getMessage("page.content", null, Locale.SIMPLIFIED_CHINESE);
        System.out.println("message=" + message);
        model.addAttribute("content", message);
        return "/i18n";
    }
}

 

從現象看, ${content}這個是沒有問題的, 也就是controller裏messageSource.getMessage() 是正常的,再也就是說,資源文件是成功加載的,可見,問題出在thymeleaf 3.this

再看下thymeleaf 3的配置:

@Configuration
public class ThymeleafConfig implements ApplicationContextAware {
    private static final String UTF8 = "UTF-8";
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    
    
    private SpringResourceTemplateResolver htmlTemplateResolver() {
        SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
        templateResolver.setApplicationContext(this.applicationContext);
        templateResolver.setPrefix("classpath:/templates/");
        templateResolver.setSuffix(".html");
        templateResolver.setTemplateMode(TemplateMode.HTML);
        templateResolver.setCacheable(false);
        templateResolver.setCharacterEncoding("UTF-8");
        return templateResolver;
    }
    
    @Autowired
    private MessageSource messageSource;

    // 若是顯示 ??x_zh_CN??, 缺乏spring-context-support
    private SpringTemplateEngine templateEngine(SpringResourceTemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        templateEngine.setEnableSpringELCompiler(false); 
        
        return templateEngine;
    }

    @Bean
    public ViewResolver htmlViewResolver(SpringTemplateEngine templateEngine) {
        ThymeleafViewResolver resolver = new ThymeleafViewResolver();
        resolver.setApplicationContext(applicationContext);
        resolver.setTemplateEngine(templateEngine(htmlTemplateResolver()));
        resolver.setCharacterEncoding("UTF-8");
        return resolver;
    }

}

** 臨時補一句,國際化要spring-context-support包的支持。

web的配置:

@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {

    @Bean
    public LocaleResolver localeResolver() {
        SessionLocaleResolver slr = new SessionLocaleResolver();
        // 默認語言
        slr.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
        return slr;
    }

    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
        // 參數名
        lci.setParamName("lang");
        return lci;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localeChangeInterceptor());
    }
    
// 這個MessageSource無關緊要,spring boot默認是有一個的。 
// 若是沒有自定義messageSource, 要有一個messages.properties文件。
// 若是有這個定義, 就不須要messages.properites
// @Bean // public ResourceBundleMessageSource messageSource() { // ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); // messageSource.setBasename("messages"); // return messageSource; // } }

 

查找緣由, 在thymeleaf.org上看到這樣一段:(在線文檔3.1: Using th:text and externalizing text)

thymeleaf叫外部文本,不管是在外部的文件裏,或者是在數據庫,固然國際化使用的是外部文件。

從這段信息看, thymeleaf使用IMessageResolver接口來加載外部文本的,並且有一個標準的實現:

org.thymeleaf.messageresolver.StandardMessageResolver,因此加載.properties文件應該是和這些信息相關。

但 thymeleaf-spring4 裏是怎麼用的呢,看下代碼吧:

org.thymeleaf.spring4.messageresolver.SpringMessageResolver:  

    private final StandardMessageResolver standardMessageResolver;
    private MessageSource messageSource;


    public SpringMessageResolver() {
        super();
        this.standardMessageResolver = new StandardMessageResolver();
    }

它就是使用 org.thymeleaf.messageresolver.StandardMessageResolver, 這樣看來,我只要在模板引擎的設置里加上這個IMessageResolver的實現便可,新的代碼是這樣:

private SpringTemplateEngine templateEngine(SpringResourceTemplateResolver templateResolver) {
        SpringTemplateEngine  templateEngine  = new SpringTemplateEngine();
        SpringMessageResolver messageResolver = new SpringMessageResolver();  //
        messageResolver.setMessageSource(messageSource);                      // 加入這三行,即爲解決方案
        templateEngine.setMessageResolver(messageResolver);                   //
        templateEngine.setTemplateResolver(templateResolver);
        templateEngine.setEnableSpringELCompiler(false); 
        return templateEngine;
}

 

最終呈現:

相關文章
相關標籤/搜索