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 8c81cf7461e..7a3f7dc2cd0 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.lang.Nullable; +import org.springframework.util.StringUtils; import org.springframework.web.servlet.LocaleResolver; /** @@ -117,13 +118,25 @@ public class AcceptHeaderLocaleResolver implements LocaleResolver { @Nullable private Locale findSupportedLocale(HttpServletRequest request) { Enumeration requestLocales = request.getLocales(); + List supported = getSupportedLocales(); + Locale languageMatch = null; while (requestLocales.hasMoreElements()) { Locale locale = requestLocales.nextElement(); - if (getSupportedLocales().contains(locale)) { + if (supported.contains(locale)) { + // Full match: typically language + country return locale; } + else if (languageMatch == null) { + // Let's try to find a language-only match as a fallback + for (Locale candidate : supported) { + if (!StringUtils.hasLength(candidate.getCountry()) && + candidate.getLanguage().equals(locale.getLanguage())) { + languageMatch = candidate; + } + } + } } - return null; + return languageMatch; } @Override 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 70695effb54..38d73a1e90c 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,28 +36,34 @@ import static org.junit.Assert.*; */ public class AcceptHeaderLocaleResolverTests { - private AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver(); + private final AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver(); @Test - public void resolve() throws Exception { + public void resolve() { assertEquals(CANADA, this.resolver.resolveLocale(request(CANADA))); assertEquals(US, this.resolver.resolveLocale(request(US, CANADA))); } @Test - public void resolvePreferredSupported() throws Exception { + public void resolvePreferredSupported() { this.resolver.setSupportedLocales(Collections.singletonList(CANADA)); assertEquals(CANADA, this.resolver.resolveLocale(request(US, CANADA))); } @Test - public void resolvePreferredNotSupported() throws Exception { + public void resolvePreferredNotSupported() { this.resolver.setSupportedLocales(Collections.singletonList(CANADA)); assertEquals(US, this.resolver.resolveLocale(request(US, UK))); } + @Test + public void resolvePreferredAgainstLanguageOnly() { + this.resolver.setSupportedLocales(Collections.singletonList(ENGLISH)); + assertEquals(ENGLISH, this.resolver.resolveLocale(request(GERMANY, US, UK))); + } + @Test public void resolvePreferredNotSupportedWithDefault() { this.resolver.setSupportedLocales(Arrays.asList(US, JAPAN)); this.resolver.setDefaultLocale(Locale.JAPAN); @@ -69,7 +75,7 @@ public class AcceptHeaderLocaleResolverTests { } @Test - public void defaultLocale() throws Exception { + public void defaultLocale() { this.resolver.setDefaultLocale(JAPANESE); MockHttpServletRequest request = new MockHttpServletRequest(); assertEquals(JAPANESE, this.resolver.resolveLocale(request));