Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring LocaleResolver chaining

Is it possible to chain locale resolvers?

I'd like to take the locale value from:

  1. The session if maps with my accepted languages

  2. The cookie if maps with my accepted languages

  3. If both don't contain locale information extract it from the accept language and do the best match with my accepted locales.

How would you do that?

like image 239
Jordi P.S. Avatar asked Aug 24 '12 10:08

Jordi P.S.


People also ask

What is LocaleResolver used by Spring MVC?

Explanation: The default locale resolver used by Spring is AcceptHeaderLocaleResolver.

What is LocaleResolver?

Interface LocaleResolverInterface for web-based locale resolution strategies that allows for both locale resolution via the request and locale modification via request and response. This interface allows for implementations based on request, session, cookies, etc.

What is LocaleResolver spring boot?

LocaleResolverThe LocaleResolver interface has implementations that determine the current locale based on the session, cookies, the Accept-Language header, or a fixed value. In our example, we have used the session based resolver SessionLocaleResolver and set a default locale with value US.


1 Answers

I think you need to write your own LocaleResolver that wraps a list of Spring's locale resolvers. You call them one after the other until a Locale is resolved. If the list does not produce a Locale, you provide a default behavior in your LocaleResolver.

Here are some links you might find useful:

http://code.lds.org/maven-sites/stack/modules/web-spring/3.0.8-SNAPSHOT/apidocs/org/lds/stack/web/spring/i18n/ChainedLocaleResolver.html

https://mvnrepository.com/artifact/org.lds.stack.web/stack-web-spring/3.0.8

Or if you prefer a view from both the links:

package org.lds.stack.web.spring.i18n;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
import org.springframework.web.servlet.i18n.FixedLocaleResolver;

/**
 * This locale resolver provides the ability to define a list of resolvers from which to determine
 * the locale.  This allows us to give preference to certain locale resolution schemes by putting
 * them earlier in the list.  
 * <p/>
 * 
 * The order of resolvers from which to find the given locale (or set a specified locale) could be
 * defined in the spring context file with something like:
 * 
 * <pre>
 * &lt;bean id=&quot;localeResolver&quot; class=&quot;org.lds.stack.web.spring.i18n.ChainedLocaleResolver&quot;&gt;
 *      &lt;property name=&quot;localeResolvers&quot;&gt;
 *          &lt;list&gt;
 *              &lt;bean class=&quot;org.lds.stack.web.spring.i18n.UrlLocaleResolver&quot; /&gt;
 *              &lt;bean class=&quot;org.lds.stack.web.spring.i18n.NoDefaultSessionLocaleResolver&quot; /&gt;
 *              &lt;bean class=&quot;org.lds.stack.web.spring.i18n.NoDefaultCookieLocaleResolver&quot;&gt;
 *                  &lt;property name=&quot;cookieMaxAge&quot; value=&quot;31536000&quot;/&gt;
 *              &lt;/bean&gt;
 *              &lt;bean class=&quot;org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver&quot; /&gt;
 *              &lt;bean class=&quot;org.springframework.web.servlet.i18n.FixedLocaleResolver&quot; /&gt;
 *          &lt;/list&gt;
 *      &lt;/property&gt;
 *  &lt;/bean&gt;
 * </pre>
 * 
 * This allows you to remove, or re-order the locale resolution schemes to meet your needs.
 * Also note that the id of localeResolver is significant.  The Spring Framework knows to use this
 * resolver as the LocaleResolver by virtue of the id being "localeResolver".
 * <p/>
 * 
 * NOTE: If the default resolver order, shown above, will work for your application, then you can 
 * skip this verbose definition by utilizing the stack-web namespace handler, providing any exposed 
 * attribute values for minor customizations.  The namespace handler is defined as follows:
 * 
 * <pre>
 * &lt;stack-web:locale-resolver /&gt;
 * </pre>
 * 
 * Additionally, in order to change the locale based on a url parameter, you can configure a
 * LocaleChangeInterceptor, which will call the set method of all of the locales in the chained
 * resolver, so that they can be found when resolveLocale(...) is called on them.  
 * <p/>
 * 
 * The interceptor configuration might look as follows:
 * <pre>
 *  &lt;mvc:interceptors&gt;
 *      &lt;bean id=&quot;localeChangeInterceptor&quot; class=&quot;org.springframework.web.servlet.i18n.LocaleChangeInterceptor&quot; /&gt;
 *  &lt;/mvc:interceptors&gt;
 * </pre>
 */
public class ChainedLocaleResolver implements LocaleResolver {

    private List<LocaleResolver> localeResolvers;

    public ChainedLocaleResolver() {
        //if anything other than this default order or set is desired, the list of resolvers
        //to be chained should be set up in the bean definition as shown above
        localeResolvers = new ArrayList<LocaleResolver>();
        //TODO: Is the Url resolver necessary if we have an interceptor that changes the locale from the url?
        localeResolvers.add(new UrlLocaleResolver());
        localeResolvers.add(new NoDefaultSessionLocaleResolver());
        NoDefaultCookieLocaleResolver cookieLocaleResolver = new NoDefaultCookieLocaleResolver();
        cookieLocaleResolver.setCookieMaxAge(31536000);
        localeResolvers.add(cookieLocaleResolver);
        //TODO: may need to create a NoDefault, but that seems difficult as the implementation is provided
        //by the javax.servlet, ..., Also, maybe we could just remove the fixedLocaleResolver, as this one
        //gets the default, and then if people did not use this one, they could add the fixed one back in.
        localeResolvers.add(new AcceptHeaderLocaleResolver());
        localeResolvers.add(new FixedLocaleResolver());
    }

    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        Locale locale = null;
        for (LocaleResolver resolver : getLocaleResolvers()) {
            locale = resolver.resolveLocale(request);
            if (locale != null) {
                return locale;
            }
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
        for (LocaleResolver resolver : getLocaleResolvers()) {
            try {
                resolver.setLocale(request, response, locale);
            } catch (UnsupportedOperationException uoe) {}
        }
    }

    public List<LocaleResolver> getLocaleResolvers() {
        return localeResolvers;
    }
    public void setLocaleResolvers(List<LocaleResolver> localeResolvers) {
        this.localeResolvers = localeResolvers;
    }
}
like image 105
Bogdan Avatar answered Nov 09 '22 14:11

Bogdan