parent
cad2ce0ac2
commit
0dd320f92e
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2015 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -81,6 +81,8 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
|
||||||
public static final String DEFAULT_COOKIE_NAME = CookieLocaleResolver.class.getName() + ".LOCALE";
|
public static final String DEFAULT_COOKIE_NAME = CookieLocaleResolver.class.getName() + ".LOCALE";
|
||||||
|
|
||||||
|
|
||||||
|
private boolean languageTagCompliant = false;
|
||||||
|
|
||||||
private Locale defaultLocale;
|
private Locale defaultLocale;
|
||||||
|
|
||||||
private TimeZone defaultTimeZone;
|
private TimeZone defaultTimeZone;
|
||||||
|
@ -94,6 +96,30 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
|
||||||
setCookieName(DEFAULT_COOKIE_NAME);
|
setCookieName(DEFAULT_COOKIE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify whether this resolver's cookies should be compliant with BCP 47
|
||||||
|
* language tags instead of Java's legacy locale specification format.
|
||||||
|
* The default is {@code false}.
|
||||||
|
* <p>Note: This mode requires JDK 7 or higher. Set this flag to {@code true}
|
||||||
|
* for BCP 47 compliance on JDK 7+ only.
|
||||||
|
* @since 4.3
|
||||||
|
* @see Locale#forLanguageTag(String)
|
||||||
|
* @see Locale#toLanguageTag()
|
||||||
|
*/
|
||||||
|
public void setLanguageTagCompliant(boolean languageTagCompliant) {
|
||||||
|
this.languageTagCompliant = languageTagCompliant;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether this resolver's cookies should be compliant with BCP 47
|
||||||
|
* language tags instead of Java's legacy locale specification format.
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
public boolean isLanguageTagCompliant() {
|
||||||
|
return this.languageTagCompliant;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a fixed Locale that this resolver will return if no cookie found.
|
* Set a fixed Locale that this resolver will return if no cookie found.
|
||||||
*/
|
*/
|
||||||
|
@ -111,6 +137,7 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a fixed TimeZone that this resolver will return if no cookie found.
|
* Set a fixed TimeZone that this resolver will return if no cookie found.
|
||||||
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
public void setDefaultTimeZone(TimeZone defaultTimeZone) {
|
public void setDefaultTimeZone(TimeZone defaultTimeZone) {
|
||||||
this.defaultTimeZone = defaultTimeZone;
|
this.defaultTimeZone = defaultTimeZone;
|
||||||
|
@ -119,6 +146,7 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
|
||||||
/**
|
/**
|
||||||
* Return the fixed TimeZone that this resolver will return if no cookie found,
|
* Return the fixed TimeZone that this resolver will return if no cookie found,
|
||||||
* if any.
|
* if any.
|
||||||
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
protected TimeZone getDefaultTimeZone() {
|
protected TimeZone getDefaultTimeZone() {
|
||||||
return this.defaultTimeZone;
|
return this.defaultTimeZone;
|
||||||
|
@ -161,7 +189,7 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
|
||||||
localePart = value.substring(0, spaceIndex);
|
localePart = value.substring(0, spaceIndex);
|
||||||
timeZonePart = value.substring(spaceIndex + 1);
|
timeZonePart = value.substring(spaceIndex + 1);
|
||||||
}
|
}
|
||||||
locale = (!"-".equals(localePart) ? StringUtils.parseLocaleString(localePart) : null);
|
locale = (!"-".equals(localePart) ? parseLocaleValue(localePart) : null);
|
||||||
if (timeZonePart != null) {
|
if (timeZonePart != null) {
|
||||||
timeZone = StringUtils.parseTimeZoneString(timeZonePart);
|
timeZone = StringUtils.parseTimeZoneString(timeZonePart);
|
||||||
}
|
}
|
||||||
|
@ -191,7 +219,8 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
|
||||||
if (localeContext instanceof TimeZoneAwareLocaleContext) {
|
if (localeContext instanceof TimeZoneAwareLocaleContext) {
|
||||||
timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
|
timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
|
||||||
}
|
}
|
||||||
addCookie(response, (locale != null ? locale : "-") + (timeZone != null ? ' ' + timeZone.getID() : ""));
|
addCookie(response,
|
||||||
|
(locale != null ? toLocaleValue(locale) : "-") + (timeZone != null ? ' ' + timeZone.getID() : ""));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
removeCookie(response);
|
removeCookie(response);
|
||||||
|
@ -203,6 +232,32 @@ public class CookieLocaleResolver extends CookieGenerator implements LocaleConte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the given locale value coming from an incoming cookie.
|
||||||
|
* <p>The default implementation calls {@link StringUtils#parseLocaleString(String)}
|
||||||
|
* or JDK 7's {@link Locale#forLanguageTag(String)}, depending on the
|
||||||
|
* {@link #setLanguageTagCompliant "languageTagCompliant"} configuration property.
|
||||||
|
* @param locale the locale value to parse
|
||||||
|
* @return the corresponding {@code Locale} instance
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
protected Locale parseLocaleValue(String locale) {
|
||||||
|
return (isLanguageTagCompliant() ? Locale.forLanguageTag(locale) : StringUtils.parseLocaleString(locale));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the given locale as a text value for inclusion in a cookie.
|
||||||
|
* <p>The default implementation calls {@link Locale#toString()}
|
||||||
|
* or JDK 7's {@link Locale#toLanguageTag()}, depending on the
|
||||||
|
* {@link #setLanguageTagCompliant "languageTagCompliant"} configuration property.
|
||||||
|
* @param locale the locale to stringify
|
||||||
|
* @return a String representation for the given locale
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
protected String toLocaleValue(Locale locale) {
|
||||||
|
return (isLanguageTagCompliant() ? locale.toLanguageTag() : locale.toString());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the default locale for the given request,
|
* Determine the default locale for the given request,
|
||||||
* Called if no locale cookie has been found.
|
* Called if no locale cookie has been found.
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.web.servlet.i18n;
|
package org.springframework.web.servlet.i18n;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
@ -54,6 +55,8 @@ public class LocaleChangeInterceptor extends HandlerInterceptorAdapter {
|
||||||
|
|
||||||
private boolean ignoreInvalidLocale = false;
|
private boolean ignoreInvalidLocale = false;
|
||||||
|
|
||||||
|
private boolean languageTagCompliant = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the name of the parameter that contains a locale specification
|
* Set the name of the parameter that contains a locale specification
|
||||||
|
@ -104,6 +107,29 @@ public class LocaleChangeInterceptor extends HandlerInterceptorAdapter {
|
||||||
return this.ignoreInvalidLocale;
|
return this.ignoreInvalidLocale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify whether to parse request parameter values as BCP 47 language tags
|
||||||
|
* instead of Java's legacy locale specification format.
|
||||||
|
* The default is {@code false}.
|
||||||
|
* <p>Note: This mode requires JDK 7 or higher. Set this flag to {@code true}
|
||||||
|
* for BCP 47 compliance on JDK 7+ only.
|
||||||
|
* @since 4.3
|
||||||
|
* @see Locale#forLanguageTag(String)
|
||||||
|
* @see Locale#toLanguageTag()
|
||||||
|
*/
|
||||||
|
public void setLanguageTagCompliant(boolean languageTagCompliant) {
|
||||||
|
this.languageTagCompliant = languageTagCompliant;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether to use BCP 47 language tags instead of Java's legacy
|
||||||
|
* locale specification format.
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
public boolean isLanguageTagCompliant() {
|
||||||
|
return this.languageTagCompliant;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||||
|
@ -118,7 +144,7 @@ public class LocaleChangeInterceptor extends HandlerInterceptorAdapter {
|
||||||
"No LocaleResolver found: not in a DispatcherServlet request?");
|
"No LocaleResolver found: not in a DispatcherServlet request?");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
localeResolver.setLocale(request, response, StringUtils.parseLocaleString(newLocale));
|
localeResolver.setLocale(request, response, parseLocaleValue(newLocale));
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException ex) {
|
catch (IllegalArgumentException ex) {
|
||||||
if (isIgnoreInvalidLocale()) {
|
if (isIgnoreInvalidLocale()) {
|
||||||
|
@ -147,4 +173,17 @@ public class LocaleChangeInterceptor extends HandlerInterceptorAdapter {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the given locale value as coming from a request parameter.
|
||||||
|
* <p>The default implementation calls {@link StringUtils#parseLocaleString(String)}
|
||||||
|
* or JDK 7's {@link Locale#forLanguageTag(String)}, depending on the
|
||||||
|
* {@link #setLanguageTagCompliant "languageTagCompliant"} configuration property.
|
||||||
|
* @param locale the locale value to parse
|
||||||
|
* @return the corresponding {@code Locale} instance
|
||||||
|
* @since 4.3
|
||||||
|
*/
|
||||||
|
protected Locale parseLocaleValue(String locale) {
|
||||||
|
return (isLanguageTagCompliant() ? Locale.forLanguageTag(locale) : StringUtils.parseLocaleString(locale));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2013 the original author or authors.
|
* Copyright 2002-2015 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -164,6 +164,58 @@ public class CookieLocaleResolverTests {
|
||||||
assertEquals(TimeZone.getTimeZone("GMT+1"), ((TimeZoneAwareLocaleContext) loc).getTimeZone());
|
assertEquals(TimeZone.getTimeZone("GMT+1"), ((TimeZoneAwareLocaleContext) loc).getTimeZone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetAndResolveLocaleWithCountry() {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
|
CookieLocaleResolver resolver = new CookieLocaleResolver();
|
||||||
|
resolver.setLocale(request, response, new Locale("de", "AT"));
|
||||||
|
|
||||||
|
Cookie cookie = response.getCookie(CookieLocaleResolver.DEFAULT_COOKIE_NAME);
|
||||||
|
assertNotNull(cookie);
|
||||||
|
assertEquals(CookieLocaleResolver.DEFAULT_COOKIE_NAME, cookie.getName());
|
||||||
|
assertEquals(null, cookie.getDomain());
|
||||||
|
assertEquals(CookieLocaleResolver.DEFAULT_COOKIE_PATH, cookie.getPath());
|
||||||
|
assertFalse(cookie.getSecure());
|
||||||
|
assertEquals("de_AT", cookie.getValue());
|
||||||
|
|
||||||
|
request = new MockHttpServletRequest();
|
||||||
|
request.setCookies(cookie);
|
||||||
|
|
||||||
|
resolver = new CookieLocaleResolver();
|
||||||
|
Locale loc = resolver.resolveLocale(request);
|
||||||
|
assertEquals("de", loc.getLanguage());
|
||||||
|
assertEquals("AT", loc.getCountry());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetAndResolveLocaleWithCountryAsLanguageTag() {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
|
CookieLocaleResolver resolver = new CookieLocaleResolver();
|
||||||
|
resolver.setLanguageTagCompliant(true);
|
||||||
|
resolver.setLocale(request, response, new Locale("de", "AT"));
|
||||||
|
|
||||||
|
Cookie cookie = response.getCookie(CookieLocaleResolver.DEFAULT_COOKIE_NAME);
|
||||||
|
assertNotNull(cookie);
|
||||||
|
assertEquals(CookieLocaleResolver.DEFAULT_COOKIE_NAME, cookie.getName());
|
||||||
|
assertEquals(null, cookie.getDomain());
|
||||||
|
assertEquals(CookieLocaleResolver.DEFAULT_COOKIE_PATH, cookie.getPath());
|
||||||
|
assertFalse(cookie.getSecure());
|
||||||
|
assertEquals("de-AT", cookie.getValue());
|
||||||
|
|
||||||
|
request = new MockHttpServletRequest();
|
||||||
|
request.setCookies(cookie);
|
||||||
|
|
||||||
|
resolver = new CookieLocaleResolver();
|
||||||
|
resolver.setLanguageTagCompliant(true);
|
||||||
|
Locale loc = resolver.resolveLocale(request);
|
||||||
|
assertEquals("de", loc.getLanguage());
|
||||||
|
assertEquals("AT", loc.getCountry());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomCookie() {
|
public void testCustomCookie() {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
|
Loading…
Reference in New Issue