title: Spring Boot internationalization (messages.properties)
body: <p>I'm trying to simply add the version number of an application to a Thymeleaf fragment.  I'm using Spring Boot 1.2.5.  If I have a file named <strong>/resources/messages.properties</strong> defined like this:</p>
  
  <pre><code>application.version=1.0.0
  </code></pre>
  
  <p>And I have a Thymeleaf view with the following fragment:</p>
  
  <pre><code>Application Version: &lt;span th:text="#{application.version}"&gt;
  </code></pre>
  
  <p>It's displaying something like <strong>??application.version_en_US??</strong> instead of 1.0.0.  (I also have files named <strong>messages_en.properties</strong> and <strong>messages_en_US.properties</strong> in the classpath with the same contents too.)  I am really not sure how to resolve this problem...  I've spent hours on something which seems incredibly trivial...</p>
  
  <p><strong>Application.java</strong></p>
  
  <pre><code>@SpringBootApplication
  @ComponentScan(basePackages = {"org.application"})
  @EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class, ThymeleafAutoConfiguration.class})
  @PropertySources(value = {@PropertySource("classpath:website.properties")})
  public class Application extends SpringBootServletInitializer {
  
      public static void main(String[] args) throws Exception {
          SpringApplication.run(Application.class, args);
      }
  
      @Override
      protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
          return application.sources(Application.class);
      }
  
  }
  </code></pre>
  
  <p><strong>WebConfig.java</strong></p>
  
  <pre><code>@EnableWebMvc
  @Configuration
  public class WebConfig extends WebMvcConfigurerAdapter {
  
  @Bean
  public SpelAwareProxyProjectionFactory projectionFactory() {
      return new SpelAwareProxyProjectionFactory();
  }
  
  @Bean
  public SessionHandler sessionHandler() {
      return new SessionHandler();
  }
  
  @Override
  public void addViewControllers(ViewControllerRegistry registry) {
      registry.addViewController("/web/auth/login").setViewName("auth/login");
      registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
  }
  
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
      registry.addResourceHandler("/resources/**").addResourceLocations(
              "/resources/");
  }
  
  @Bean
  public LocaleChangeInterceptor localeChangeInterceptor() {
      LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
      localeChangeInterceptor.setParamName("language");
      return localeChangeInterceptor;
  }
  
  @Bean
  public CookieLocaleResolver localeResolver() {
      CookieLocaleResolver localeResolver = new CookieLocaleResolver();
      localeResolver.setDefaultLocale(Locale.ENGLISH);
      return localeResolver;
  }
  
  @Bean
  public ResourceBundleMessageSource messageSource() {
      return new ResourceBundleMessageSource();
  }
  
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
      // Locale change interceptor
      registry.addInterceptor(localeChangeInterceptor());
  
      // Utility interceptor which helps with the "active" link styles in the navigation.  --mm
      registry.addInterceptor(new BaseInterceptor());
  
      // Expire session after a period of time
      registry.addInterceptor(sessionHandler());
  }
  }
  </code></pre>
  
  <p><strong>ThymeleafConfig.java</strong></p>
  
  <pre><code>@Configuration
  public class ThymeleafConfig {
  
  @Bean
  public ServletContextTemplateResolver templateResolver() {
      ServletContextTemplateResolver resolver = new ServletContextTemplateResolver();
      resolver.setPrefix("/WEB-INF/views/");
      resolver.setSuffix(".html");
  
      // must use Legacy HTML5 as the template, otherwise Handlebars will not parse!
      //
      // this should hopefully be fixed in Thymeleaf 3.0
      resolver.setTemplateMode("LEGACYHTML5");
      resolver.setCacheable(false);
      return resolver;
  }
  
  public SpringTemplateEngine templateEngine() {
      SpringTemplateEngine engine = new SpringTemplateEngine();
      engine.setTemplateResolver(templateResolver());
  
      // Add Spring security
      Set&lt;IDialect&gt; dialects = new HashSet&lt;IDialect&gt;();
      engine.setAdditionalDialects(dialects);
      engine.addDialect(new SpringSecurityDialect());
      return engine;
  }
  
  @Bean
  public ViewResolver viewResolver() {
      ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
      viewResolver.setTemplateEngine(templateEngine());
      viewResolver.setOrder(1);
      viewResolver.setViewNames(new String[]{"*"});
      viewResolver.setCache(false);
      return viewResolver;
  }
  }
  </code></pre>
  
  <p>Will buy a virtual round of shots to whomever can resolve this issue...  </p>