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 f8c9b221f28..9984b65b802 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. @@ -23,6 +23,7 @@ import java.util.Locale; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.springframework.util.StringUtils; import org.springframework.web.servlet.LocaleResolver; /** @@ -113,13 +114,25 @@ public class AcceptHeaderLocaleResolver implements LocaleResolver { 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 b22100b559c..0ed502a5731 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));