keycloak-uncached

Merge pull request #4958 from iilei/missing_accept_language_country_code_fallback Fix

2/8/2018 5:55:19 PM

Details

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 4c419b3..49466bc 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<String> 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 0000000..6553a77
--- /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<String> supportedLocales;
+
+    LocaleNegotiator(Set<String> 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 0000000..02aea7f
--- /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<String> 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);
+    }
+}