Skip to content

Commit f8588e3

Browse files
committed
AcceptHeaderLocaleResolver keeps language match among supported locales
Issue: SPR-16599
1 parent 7de2650 commit f8588e3

File tree

4 files changed

+44
-19
lines changed

4 files changed

+44
-19
lines changed

spring-web/src/main/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolver.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,23 +100,26 @@ private Locale resolveSupportedLocale(@Nullable List<Locale> requestLocales) {
100100
if (CollectionUtils.isEmpty(requestLocales)) {
101101
return this.defaultLocale; // may be null
102102
}
103-
List<Locale> supported = getSupportedLocales();
104-
if (supported.isEmpty()) {
103+
List<Locale> supportedLocales = getSupportedLocales();
104+
if (supportedLocales.isEmpty()) {
105105
return requestLocales.get(0); // never null
106106
}
107107

108108
Locale languageMatch = null;
109109
for (Locale locale : requestLocales) {
110-
if (supported.contains(locale)) {
111-
// Full match: typically language + country
112-
return locale;
110+
if (supportedLocales.contains(locale)) {
111+
if (languageMatch == null || languageMatch.getLanguage().equals(locale.getLanguage())) {
112+
// Full match: language + country, possibly narrowed from earlier language-only match
113+
return locale;
114+
}
113115
}
114116
else if (languageMatch == null) {
115117
// Let's try to find a language-only match as a fallback
116-
for (Locale candidate : supported) {
118+
for (Locale candidate : supportedLocales) {
117119
if (!StringUtils.hasLength(candidate.getCountry()) &&
118120
candidate.getLanguage().equals(locale.getLanguage())) {
119121
languageMatch = candidate;
122+
break;
120123
}
121124
}
122125
}

spring-web/src/test/java/org/springframework/web/server/i18n/AcceptHeaderLocaleContextResolverTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,18 @@ public void resolvePreferredAgainstLanguageOnly() {
7272
assertEquals(ENGLISH, this.resolver.resolveLocaleContext(exchange(GERMANY, US, UK)).getLocale());
7373
}
7474

75+
@Test
76+
public void resolvePreferredAgainstCountryIfPossible() {
77+
this.resolver.setSupportedLocales(Arrays.asList(ENGLISH, UK));
78+
assertEquals(UK, this.resolver.resolveLocaleContext(exchange(GERMANY, US, UK)).getLocale());
79+
}
80+
81+
@Test
82+
public void resolvePreferredAgainstLanguageWithMultipleSupportedLocales() {
83+
this.resolver.setSupportedLocales(Arrays.asList(GERMAN, US));
84+
assertEquals(GERMAN, this.resolver.resolveLocaleContext(exchange(GERMANY, US, UK)).getLocale());
85+
}
86+
7587
@Test
7688
public void resolveMissingAcceptLanguageHeader() {
7789
MockServerHttpRequest request = MockServerHttpRequest.get("/").build();

spring-webmvc/src/main/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolver.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -98,38 +98,36 @@ public Locale resolveLocale(HttpServletRequest request) {
9898
return defaultLocale;
9999
}
100100
Locale requestLocale = request.getLocale();
101-
if (isSupportedLocale(requestLocale)) {
101+
List<Locale> supportedLocales = getSupportedLocales();
102+
if (supportedLocales.isEmpty() || supportedLocales.contains(requestLocale)) {
102103
return requestLocale;
103104
}
104-
Locale supportedLocale = findSupportedLocale(request);
105+
Locale supportedLocale = findSupportedLocale(request, supportedLocales);
105106
if (supportedLocale != null) {
106107
return supportedLocale;
107108
}
108109
return (defaultLocale != null ? defaultLocale : requestLocale);
109110
}
110111

111-
private boolean isSupportedLocale(Locale locale) {
112-
List<Locale> supportedLocales = getSupportedLocales();
113-
return (supportedLocales.isEmpty() || supportedLocales.contains(locale));
114-
}
115-
116112
@Nullable
117-
private Locale findSupportedLocale(HttpServletRequest request) {
113+
private Locale findSupportedLocale(HttpServletRequest request, List<Locale> supportedLocales) {
118114
Enumeration<Locale> requestLocales = request.getLocales();
119-
List<Locale> supported = getSupportedLocales();
120115
Locale languageMatch = null;
121116
while (requestLocales.hasMoreElements()) {
122117
Locale locale = requestLocales.nextElement();
123-
if (supported.contains(locale)) {
124-
// Full match: typically language + country
125-
return locale;
118+
if (supportedLocales.contains(locale)) {
119+
if (languageMatch == null || languageMatch.getLanguage().equals(locale.getLanguage())) {
120+
// Full match: language + country, possibly narrowed from earlier language-only match
121+
return locale;
122+
}
126123
}
127124
else if (languageMatch == null) {
128125
// Let's try to find a language-only match as a fallback
129-
for (Locale candidate : supported) {
126+
for (Locale candidate : supportedLocales) {
130127
if (!StringUtils.hasLength(candidate.getCountry()) &&
131128
candidate.getLanguage().equals(locale.getLanguage())) {
132129
languageMatch = candidate;
130+
break;
133131
}
134132
}
135133
}

spring-webmvc/src/test/java/org/springframework/web/servlet/i18n/AcceptHeaderLocaleResolverTests.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ public void resolvePreferredAgainstLanguageOnly() {
6363
assertEquals(ENGLISH, this.resolver.resolveLocale(request(GERMANY, US, UK)));
6464
}
6565

66+
@Test
67+
public void resolvePreferredAgainstCountryIfPossible() {
68+
this.resolver.setSupportedLocales(Arrays.asList(ENGLISH, UK));
69+
assertEquals(UK, this.resolver.resolveLocale(request(GERMANY, US, UK)));
70+
}
71+
72+
@Test
73+
public void resolvePreferredAgainstLanguageWithMultipleSupportedLocales() {
74+
this.resolver.setSupportedLocales(Arrays.asList(GERMAN, US));
75+
assertEquals(GERMAN, this.resolver.resolveLocale(request(GERMANY, US, UK)));
76+
}
77+
6678
@Test
6779
public void resolvePreferredNotSupportedWithDefault() {
6880
this.resolver.setSupportedLocales(Arrays.asList(US, JAPAN));

0 commit comments

Comments
 (0)