diff --git a/spring-web/src/main/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolver.java b/spring-web/src/main/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolver.java index 165835599bb..280b47f61bf 100644 --- a/spring-web/src/main/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolver.java +++ b/spring-web/src/main/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolver.java @@ -100,23 +100,26 @@ public class AcceptHeaderLocaleContextResolver implements LocaleContextResolver if (CollectionUtils.isEmpty(requestLocales)) { return this.defaultLocale; // may be null } - List supported = getSupportedLocales(); - if (supported.isEmpty()) { + List supportedLocales = getSupportedLocales(); + if (supportedLocales.isEmpty()) { return requestLocales.get(0); // never null } Locale languageMatch = null; for (Locale locale : requestLocales) { - if (supported.contains(locale)) { - // Full match: typically language + country - return locale; + if (supportedLocales.contains(locale)) { + if (languageMatch == null || languageMatch.getLanguage().equals(locale.getLanguage())) { + // Full match: language + country, possibly narrowed from earlier language-only match + return locale; + } } else if (languageMatch == null) { // Let's try to find a language-only match as a fallback - for (Locale candidate : supported) { + for (Locale candidate : supportedLocales) { if (!StringUtils.hasLength(candidate.getCountry()) && candidate.getLanguage().equals(locale.getLanguage())) { languageMatch = candidate; + break; } } } diff --git a/spring-web/src/test/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolverTests.java b/spring-web/src/test/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolverTests.java index 22ede5a4d3a..b30b7d434e7 100644 --- a/spring-web/src/test/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolverTests.java +++ b/spring-web/src/test/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolverTests.java @@ -72,6 +72,18 @@ public class AcceptHeaderLocaleContextResolverTests { assertEquals(ENGLISH, this.resolver.resolveLocaleContext(exchange(GERMANY, US, UK)).getLocale()); } + @Test + public void resolvePreferredAgainstCountryIfPossible() { + this.resolver.setSupportedLocales(Arrays.asList(ENGLISH, UK)); + assertEquals(UK, this.resolver.resolveLocaleContext(exchange(GERMANY, US, UK)).getLocale()); + } + + @Test + public void resolvePreferredAgainstLanguageWithMultipleSupportedLocales() { + this.resolver.setSupportedLocales(Arrays.asList(GERMAN, US)); + assertEquals(GERMAN, this.resolver.resolveLocaleContext(exchange(GERMANY, US, UK)).getLocale()); + } + @Test public void resolveMissingAcceptLanguageHeader() { MockServerHttpRequest request = MockServerHttpRequest.get("/").build(); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolver.java index d1ee4d81a38..57a273fb510 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolver.java @@ -98,38 +98,36 @@ public class AcceptHeaderLocaleResolver implements LocaleResolver { return defaultLocale; } Locale requestLocale = request.getLocale(); - if (isSupportedLocale(requestLocale)) { + List supportedLocales = getSupportedLocales(); + if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) { return requestLocale; } - Locale supportedLocale = findSupportedLocale(request); + Locale supportedLocale = findSupportedLocale(request, supportedLocales); if (supportedLocale != null) { return supportedLocale; } return (defaultLocale != null ? defaultLocale : requestLocale); } - private boolean isSupportedLocale(Locale locale) { - List supportedLocales = getSupportedLocales(); - return (supportedLocales.isEmpty() || supportedLocales.contains(locale)); - } - @Nullable - private Locale findSupportedLocale(HttpServletRequest request) { + private Locale findSupportedLocale(HttpServletRequest request, List supportedLocales) { Enumeration requestLocales = request.getLocales(); - List supported = getSupportedLocales(); Locale languageMatch = null; while (requestLocales.hasMoreElements()) { Locale locale = requestLocales.nextElement(); - if (supported.contains(locale)) { - // Full match: typically language + country - return locale; + if (supportedLocales.contains(locale)) { + if (languageMatch == null || languageMatch.getLanguage().equals(locale.getLanguage())) { + // Full match: language + country, possibly narrowed from earlier language-only match + return locale; + } } else if (languageMatch == null) { // Let's try to find a language-only match as a fallback - for (Locale candidate : supported) { + for (Locale candidate : supportedLocales) { if (!StringUtils.hasLength(candidate.getCountry()) && candidate.getLanguage().equals(locale.getLanguage())) { languageMatch = candidate; + break; } } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolverTests.java index 38d73a1e90c..4e5f2708f70 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolverTests.java @@ -63,6 +63,18 @@ public class AcceptHeaderLocaleResolverTests { assertEquals(ENGLISH, this.resolver.resolveLocale(request(GERMANY, US, UK))); } + @Test + public void resolvePreferredAgainstCountryIfPossible() { + this.resolver.setSupportedLocales(Arrays.asList(ENGLISH, UK)); + assertEquals(UK, this.resolver.resolveLocale(request(GERMANY, US, UK))); + } + + @Test + public void resolvePreferredAgainstLanguageWithMultipleSupportedLocales() { + this.resolver.setSupportedLocales(Arrays.asList(GERMAN, US)); + assertEquals(GERMAN, this.resolver.resolveLocale(request(GERMANY, US, UK))); + } + @Test public void resolvePreferredNotSupportedWithDefault() { this.resolver.setSupportedLocales(Arrays.asList(US, JAPAN));