Is it possible to chain locale resolvers?
I'd like to take the locale value from:
The session if maps with my accepted languages
The cookie if maps with my accepted languages
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?
Explanation: The default locale resolver used by Spring is AcceptHeaderLocaleResolver.
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.
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.
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>
* <bean id="localeResolver" class="org.lds.stack.web.spring.i18n.ChainedLocaleResolver">
* <property name="localeResolvers">
* <list>
* <bean class="org.lds.stack.web.spring.i18n.UrlLocaleResolver" />
* <bean class="org.lds.stack.web.spring.i18n.NoDefaultSessionLocaleResolver" />
* <bean class="org.lds.stack.web.spring.i18n.NoDefaultCookieLocaleResolver">
* <property name="cookieMaxAge" value="31536000"/>
* </bean>
* <bean class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver" />
* <bean class="org.springframework.web.servlet.i18n.FixedLocaleResolver" />
* </list>
* </property>
* </bean>
* </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>
* <stack-web:locale-resolver />
* </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>
* <mvc:interceptors>
* <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" />
* </mvc:interceptors>
* </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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With