diff --git a/services/src/main/java/org/keycloak/services/util/LocaleHelper.java b/services/src/main/java/org/keycloak/services/util/LocaleHelper.java index 4c419b3c0d..49466bca68 100755 --- a/services/src/main/java/org/keycloak/services/util/LocaleHelper.java +++ b/services/src/main/java/org/keycloak/services/util/LocaleHelper.java @@ -134,27 +134,7 @@ public class LocaleHelper { } private static Locale findLocale(Set supportedLocales, String... localeStrings) { - for (String localeString : localeStrings) { - if (localeString != null) { - Locale result = null; - Locale search = Locale.forLanguageTag(localeString); - for (String languageTag : supportedLocales) { - Locale locale = Locale.forLanguageTag(languageTag); - if (locale.getLanguage().equals(search.getLanguage())) { - if (locale.getCountry().equals("") && result == null) { - result = locale; - } - if (locale.getCountry().equals(search.getCountry())) { - return locale; - } - } - } - if (result != null) { - return result; - } - } - } - return null; + return new LocaleNegotiator(supportedLocales).invoke(localeStrings); } private static void updateUsersLocale(UserModel user, String locale) { diff --git a/services/src/main/java/org/keycloak/services/util/LocaleNegotiator.java b/services/src/main/java/org/keycloak/services/util/LocaleNegotiator.java new file mode 100644 index 0000000000..6553a77575 --- /dev/null +++ b/services/src/main/java/org/keycloak/services/util/LocaleNegotiator.java @@ -0,0 +1,52 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates + * and other contributors as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.keycloak.services.util; + +import java.util.Locale; +import java.util.Set; + +class LocaleNegotiator { + private Set supportedLocales; + + LocaleNegotiator(Set supportedLocales) { + this.supportedLocales = supportedLocales; + } + + Locale invoke(String... localeStrings) { + for (String localeString : localeStrings) { + if (localeString != null) { + Locale result = null; + Locale search = Locale.forLanguageTag(localeString); + for (String languageTag : supportedLocales) { + Locale locale = Locale.forLanguageTag(languageTag); + if (locale.getLanguage().equals(search.getLanguage())) { + if (search.getCountry().equals("") ^ locale.getCountry().equals("") && result == null) { + result = locale; + } + if (locale.getCountry().equals(search.getCountry())) { + return locale; + } + } + } + if (result != null) { + return result; + } + } + } + return null; + } +} diff --git a/services/src/test/java/org/keycloak/services/util/LocaleNegotiatorTest.java b/services/src/test/java/org/keycloak/services/util/LocaleNegotiatorTest.java new file mode 100644 index 0000000000..02aea7f8db --- /dev/null +++ b/services/src/test/java/org/keycloak/services/util/LocaleNegotiatorTest.java @@ -0,0 +1,49 @@ +package org.keycloak.services.util; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +public class LocaleNegotiatorTest { + + private LocaleNegotiator localeNegotiator; + + @Before + public void setUp() { + Set supportedLocales = new HashSet<>(); + supportedLocales.add("de"); + supportedLocales.add("de-AT"); + supportedLocales.add("de-CH"); + supportedLocales.add("de-DE"); + supportedLocales.add("pt-BR"); + localeNegotiator = new LocaleNegotiator(supportedLocales); + } + + @Test + public void shouldMatchWithoutCountryCode() { + Locale actualLocale = localeNegotiator.invoke("de"); + Assert.assertEquals(Locale.GERMAN, actualLocale); + } + + @Test + public void shouldMatchWithPriorityCountryCode() { + Locale actualLocale = localeNegotiator.invoke("de-CH", "de"); + Assert.assertEquals(new Locale("de", "CH"), actualLocale); + } + + @Test + public void shouldMatchWithPriorityNoCountryCode() { + Locale actualLocale = localeNegotiator.invoke("de", "de-CH"); + Assert.assertEquals(new Locale("de"), actualLocale); + } + + @Test + public void shouldMatchOmittedCountryCodeWithBestFit() { + Locale actualLocale = localeNegotiator.invoke("pt", "es-ES"); + Assert.assertEquals(new Locale("pt", "BR"), actualLocale); + } +}