Configuring locale switching with Spring MVC 3

Posted: July 21, 2010 in Java, Spring, Web2

Spring MVC supports a built-in support of locales which allows:

  • specifying where are stored messages
  • specifying where to find and store current locale
  • specifying the interceptor responsible to change the current locale based on the presence of a particular parameter

You firstly need to configure all these aspects within the Spring Web application context associated with your DispatcherServlet servlet.
Spring provides several message source entities implementing the MessageSource interface. One of these is the ResourceBundleMessageSource which looks for properties files within the classpath. It can be configured as described below where messages*.properties files are used to store i18n messages:

<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>messages</value>
        </list>
    </property>
</bean>

You need then to specify how to resolve the current locale. Several strategies are also provided within Spring and all implement the LocaleResolver. They are based on Accept-Language header, session, cookie and so on. In the following code, we describe how to configured the session-based approach with the SessionLocaleResolver class with English as default language:

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
    <property name="defaultLocale" value="en_UK" />
</bean>

The last aspect to configure corresponds to entity in order to allow locale change. Spring MVC provides an interceptor (class LocaleChangeInterceptor) to do that. When a specified parameter is present for a request, Spring MVC automagically changes the current locale for current and later requests. The following code describes how to configure this aspect with the parameter siteLanguage:

<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    <property name="paramName" value="siteLanguage"/>
</bean>

To access the current locale within your application, Spring provides two different ways according to the place you want to access it. The first one uses the RequestContextUtils class and its getLocale method. The latter requires the request parameter of type HttpServletRequest. For this reason, the approach needs to be only use in the Web tier (controller, filter, interceptor…) to have access to this object. The following code describes how to use this first approach.

Locale locale = RequestContextUtils.getLocale(request);
String country = locale.getCountry();
String language = locale.getLanguage();

You can notice that the RequestContextUtils class also provides a getLocaleResolver method to give access to the configured entity to resolve locales.
The last approach is independent from the Servlet API and is based on a thread local in order to provide the current locale in any entity of your architecture. The getLocale method of the LocaleContextHolder class is provided for this purpose, as described in the following code:

Locale locale = LocaleContextHolder.getLocale();
String country = locale.getCountry();
String language = locale.getLanguage();

You must be aware that the content of the LocaleContextHolder corresponds by default to the locale specified within the Web request. In order to change this behaviour, you need to implement a custom interceptor or filter. The following code describes the implementation of such filter using configured LocaleResolver:

public class LocaleConfigurerFilter extends OncePerRequestFilter {
    private LocaleResolver localeResolver;

    protected void initFilterBean() throws ServletException {
        WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(
                     getServletContext());
        Map resolvers = wac.getBeansOfType(LocaleResolver.class);
        if (resolvers.size()==1) {
            localeResolver = resolvers.values().iterator().next();
        }
    }

    protected void doFilterInternal(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        if (localeResolver!=null) {
            Locale locale = localeResolver.resolveLocale(request);
            LocaleContextHolder.setLocale(locale);
        }

        chain.doFilter(request, response);

        if (localeResolver!=null) {
            LocaleContextHolder.resetLocaleContext();
        }
    }
}

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s