Question

I would like to use multiple resources bundles within a Spring MVC application using Thymeleaf. I am unable to access

Project structure (EAR)

  • MyProject (includes both projects below through the Deployment Assembly)
  • MyProjectEJB
  • MyProjectWeb

    • src

      • baseproject
        • configuration
          • ThymeleafConfig
          • WebConfig
    • WebContent

      • WEB-INF

        • lib
          • my libs...
        • messages

          • global
            • GlobalResources (got both GlobalResources_fr.properties and GlobalResources_en.properties).
          • user
            • UserResources (got both UserResources_fr.properties and UserResources_en.properties).
        • views

          • user
            • createOrUpdateUserForm.html

WebConfig.java

package baseproject.configuration;

import java.util.Locale;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "baseproject.controller")
public class WebConfig extends WebMvcConfigurerAdapter {

    public ResourceBundleMessageSource messageSource() {

        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();

        String[] strBaseNames = {
                "/WEB-INF/messages/global/GlobalResources",
                "/WEB-INF/messages/user/UserResources",
        };

        messageSource.setUseCodeAsDefaultMessage(true);
        messageSource.setDefaultEncoding("UTF-8");

        // # -1 : never reload, 0 always reload
        messageSource.setCacheSeconds(0);
        messageSource.setBasenames(strBaseNames);

        return messageSource;
    }

    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {

        LocaleChangeInterceptor result = new LocaleChangeInterceptor();
        result.setParamName("lang");

        return result;
    }       

    @Bean
    public LocaleResolver localeResolver() {

        SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
        sessionLocaleResolver.setDefaultLocale(Locale.ENGLISH);

        return sessionLocaleResolver;
    }

    @Override
    public void addInterceptors(InterceptorRegistry interceptorRegistry) {

        interceptorRegistry.addInterceptor(localeChangeInterceptor());
    }

}

ThymeleafConfig.java

package baseproject.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.view.ThymeleafViewResolver;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

@Configuration
public class ThymeleafConfig {

    @Bean
    public ServletContextTemplateResolver templateResolver() {

        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();

        templateResolver.setPrefix("/WEB-INF/views/");
        templateResolver.setSuffix(".html");

        //NB, selecting HTML5 as the template mode.
        templateResolver.setTemplateMode("HTML5");
        templateResolver.setCacheable(false);

        return templateResolver;
    }

    public SpringTemplateEngine templateEngine() {

      SpringTemplateEngine templateEngine = new SpringTemplateEngine();
      templateEngine.setTemplateResolver(templateResolver());

      return templateEngine;
    }

    @Bean
    public ViewResolver viewResolver() {

      ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();

      viewResolver.setTemplateEngine(templateEngine());
      viewResolver.setOrder(1);
      viewResolver.setViewNames(new String[]{"*"});
      viewResolver.setCache(false);

      return viewResolver;
    }
}

Application Context XML files

<context:annotation-config />
<context:component-scan base-package="baseproject.controller" />

HTML file code

<label for="strFirstName" th:text="#{first.name} + #{:}">First Name</label>
<input type="text" id="strFirstName" name="strFirstName" th:value="*{strFirstName}" />

When it comes to the #{first.name}, I always see ??first.name_en??. I would like to be able to use multiple bundles, like the first name (#{first.name}) would come from UserResources and ${:} would come from GlobalResources (as it is used across the entire application). I am coming from Struts 1.3.5, and I was using the following tag:

<bean:message bundle="Bundle name from the struts-config.xml file)" key="first.name" />

I am looking for the equivalent using Spring and Thymeleaf.

Many thanks for help.

Was it helpful?

Solution

Problem fixed.

Two things:

  1. I had to put my resource bundles in my classpath, so I needed to change the following code to point to the right place:

    String[] strBaseNames = {
            "ca.gc.baseproject.messages.global.GlobalResources",
            "ca.gc.baseproject.messages.user.UserResources",
    };
    
  2. Missing @Bean annotation on the following method:

    @Bean
    public SpringTemplateEngine templateEngine()
    

I have also tried to let my resource bundles in the WEB-INF folder but no success. I am comfortable in putting my bundles in the classpath, so they can also be used across the Java application.

OTHER TIPS

Put your resource files into "WebContent/WEB-INF/messages/global or user" instead of "WebContent/messages/global or user".

Hope this helps.

If it still is actual problem: The fix is:

Just remove @EnableWebMvc and LocaleChangeInterceptor will work fine!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top