Revision: 10128
Author:   j...@google.com
Date:     Mon May  2 20:14:38 2011
Log: Improve runtime locales support, so runtime locales that are under a
more specific compile-time locale do not appear under a more general
one.  An example would be compile locales of [es, es-419] and runtime
locales of [es-es, es-co, es-ar] -- the runtime locales for es should
not include es-co and es-ar since they are also under es-419.

Review at http://gwt-code-reviews.appspot.com/1421812

Review by: unn...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=10128

Added:
 /trunk/user/test/com/google/gwt/i18n/rebind/LocaleUtilsTest.java
Modified:
 /trunk/user/src/com/google/gwt/i18n/rebind/LocaleUtils.java
 /trunk/user/src/com/google/gwt/i18n/server/GwtLocaleImpl.java
 /trunk/user/test/com/google/gwt/i18n/I18NSuite.java

=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/i18n/rebind/LocaleUtilsTest.java Mon May 2 20:14:38 2011
@@ -0,0 +1,321 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * 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 com.google.gwt.i18n.rebind;
+
+import com.google.gwt.core.ext.BadPropertyValueException;
+import com.google.gwt.core.ext.ConfigurationProperty;
+import com.google.gwt.core.ext.DefaultConfigurationProperty;
+import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.PropertyOracle;
+import com.google.gwt.core.ext.SelectionProperty;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.shell.FailErrorLogger;
+import com.google.gwt.i18n.shared.GwtLocale;
+import com.google.gwt.i18n.shared.GwtLocaleFactory;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * Test for {@link LocaleUtils}.
+ */
+public class LocaleUtilsTest extends TestCase {
+
+  /**
+   * Mock config property that gets the values in the constructor.
+   */
+  public class MockConfigProperty extends DefaultConfigurationProperty {
+
+    /**
+     * @param name
+     * @param values
+     */
+    public MockConfigProperty(String name, String... values) {
+      super(name, Arrays.asList(values));
+    }
+  }
+
+  private static class MockPropertyOracle implements PropertyOracle {
+
+    private final Map<String, ConfigurationProperty> configProperties;
+    private final Map<String, SelectionProperty> selectionProperties;
+
+    /**
+     *
+     */
+    public MockPropertyOracle() {
+      configProperties = new TreeMap<String, ConfigurationProperty>();
+      selectionProperties = new TreeMap<String, SelectionProperty>();
+    }
+
+ public ConfigurationProperty getConfigurationProperty(String propertyName)
+        throws BadPropertyValueException {
+      ConfigurationProperty prop = configProperties.get(propertyName);
+      if (prop == null) {
+        throw new BadPropertyValueException(propertyName);
+      }
+      return prop;
+    }
+
+    @Deprecated
+    public String getPropertyValue(TreeLogger logger, String propertyName)
+        throws BadPropertyValueException {
+     SelectionProperty prop = getSelectionProperty(logger, propertyName);
+     return prop.getCurrentValue();
+    }
+
+    @Deprecated
+ public String[] getPropertyValueSet(TreeLogger logger, String propertyName)
+        throws BadPropertyValueException {
+      SelectionProperty prop = getSelectionProperty(logger, propertyName);
+      SortedSet<String> possibleValues = prop.getPossibleValues();
+      return possibleValues.toArray(new String[possibleValues.size()]);
+    }
+
+ public SelectionProperty getSelectionProperty(TreeLogger logger, String propertyName)
+        throws BadPropertyValueException {
+      SelectionProperty prop = selectionProperties.get(propertyName);
+      if (prop == null) {
+        throw new BadPropertyValueException(propertyName);
+      }
+      return prop;
+    }
+
+    public void setProperty(ConfigurationProperty prop) {
+      configProperties.put(prop.getName(), prop);
+    }
+
+    public void setProperty(SelectionProperty prop) {
+      selectionProperties.put(prop.getName(), prop);
+    }
+  }
+
+  /**
+   * Mock selection property;
+   */
+  private static class MockSelectionProperty implements SelectionProperty {
+
+    private String fallbackValue;
+    private final String name;
+    private final SortedSet<String> possibleValues;
+    private String value;
+
+    /**
+     * Initialize mock selection property.
+     */
+    public MockSelectionProperty(String name, String... possibleValues) {
+      this.name = name;
+      this.possibleValues = new TreeSet<String>();
+      this.possibleValues.addAll(Arrays.asList(possibleValues));
+      if (possibleValues.length > 0) {
+        value = possibleValues[0];
+      }
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj) {
+        return true;
+      }
+      if (obj == null || getClass() != obj.getClass()) {
+        return false;
+      }
+      MockSelectionProperty other = (MockSelectionProperty) obj;
+      if (fallbackValue == null) {
+        if (other.fallbackValue != null) {
+          return false;
+        }
+      } else if (!fallbackValue.equals(other.fallbackValue)) {
+        return false;
+      }
+ if (!name.equals(other.name) | | !possibleValues.equals(other.possibleValues)) {
+        return false;
+      }
+      if (value == null) {
+        if (other.value != null) {
+          return false;
+        }
+      } else if (!value.equals(other.value)) {
+        return false;
+      }
+      return true;
+    }
+
+    public String getCurrentValue() {
+      return value;
+    }
+
+    public String getFallbackValue() {
+      return fallbackValue;
+    }
+
+    public List<? extends Set<String>> getFallbackValues(String value) {
+      return Collections.emptyList();
+    }
+
+    public String getName() {
+      return name;
+    }
+
+    public SortedSet<String> getPossibleValues() {
+      return possibleValues;
+    }
+
+    @Override
+    public int hashCode() {
+      final int prime = 31;
+      int result = 1;
+ result = prime * result + ((fallbackValue == null) ? 0 : fallbackValue.hashCode());
+      result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((possibleValues == null) ? 0 : possibleValues.hashCode());
+      result = prime * result + ((value == null) ? 0 : value.hashCode());
+      return result;
+    }
+
+    /**
+     * @param value the value to set
+     */
+    public void setCurrentValue(String value) {
+      this.value = value;
+    }
+  }
+
+  /**
+   * @param set
+   * @param key
+   */
+  private static <T> void assertContains(Set<T> set, T key) {
+    assertTrue(set + " should have contained " + key, set.contains(key));
+  }
+  private GeneratorContext ctx;
+  private MockConfigProperty localeCookieParam;
+  private MockSelectionProperty localeProp;
+  private MockConfigProperty localeQueryParam;
+  private TreeLogger logger = new FailErrorLogger();
+  private PropertyOracle props;
+
+  private MockConfigProperty rtLocaleProp;
+
+  /**
+   * Initialize mocks for tests.
+   */
+  public LocaleUtilsTest() {
+    MockPropertyOracle mock = new MockPropertyOracle();
+ localeProp = new MockSelectionProperty(LocaleUtils.PROP_LOCALE, "es_419", "es", "en");
+    mock.setProperty(localeProp);
+ localeQueryParam = new MockConfigProperty(LocaleUtils.PROP_LOCALE_QUERY_PARAM, "query-param");
+    mock.setProperty(localeQueryParam);
+ localeCookieParam = new MockConfigProperty(LocaleUtils.PROP_LOCALE_COOKIE, "cookie-name");
+    mock.setProperty(localeCookieParam);
+ rtLocaleProp = new MockConfigProperty(LocaleUtils.PROP_RUNTIME_LOCALES, "es_AR", "es_CO",
+        "es_ES", "es_GB", "en_Dsrt");
+    mock.setProperty(rtLocaleProp);
+    props = mock;
+  }
+
+  /**
+ * Test method for {@link com.google.gwt.i18n.rebind.LocaleUtils#getAllCompileLocales()}.
+   */
+  public void testGetAllCompileLocales() {
+    LocaleUtils localeUtils = LocaleUtils.getInstance(logger, props, ctx);
+    GwtLocaleFactory factory = LocaleUtils.getLocaleFactory();
+    Set<GwtLocale> locales = localeUtils.getAllCompileLocales();
+    assertEquals(3, locales.size());
+    assertContains(locales, factory.fromString("es_419"));
+    assertContains(locales, factory.fromString("es"));
+    assertContains(locales, factory.fromString("en"));
+  }
+
+  /**
+ * Test method for {@link com.google.gwt.i18n.rebind.LocaleUtils#getAllLocales()}.
+   */
+  public void testGetAllLocales() {
+    LocaleUtils localeUtils = LocaleUtils.getInstance(logger, props, ctx);
+    GwtLocaleFactory factory = LocaleUtils.getLocaleFactory();
+    Set<GwtLocale> locales = localeUtils.getAllLocales();
+    assertEquals(7, locales.size());
+    assertContains(locales, factory.fromString("es_419"));
+    assertContains(locales, factory.fromString("es"));
+    assertContains(locales, factory.fromString("en"));
+    assertContains(locales, factory.fromString("es_AR"));
+    assertContains(locales, factory.fromString("es_CO"));
+    assertContains(locales, factory.fromString("es_ES"));
+    assertContains(locales, factory.fromString("es_GB"));
+  }
+
+  /**
+ * Test method for {@link com.google.gwt.i18n.rebind.LocaleUtils#getCompileLocale()}.
+   */
+  public void testGetCompileLocale() {
+    LocaleUtils localeUtils = LocaleUtils.getInstance(logger, props, ctx);
+    assertEquals("es_419", localeUtils.getCompileLocale().toString());
+  }
+
+  /**
+ * Test method for {@link com.google.gwt.i18n.rebind.LocaleUtils#getCookie()}.
+   */
+  public void testGetCookie() {
+    LocaleUtils localeUtils = LocaleUtils.getInstance(logger, props, ctx);
+    assertEquals("cookie-name", localeUtils.getCookie());
+  }
+
+  /**
+   * Test caching of {@link LocaleUtils} instances.
+   */
+  public void testGetInstanceCaching() {
+    LocaleUtils localeUtils = LocaleUtils.getInstance(logger, props, ctx);
+    assertSame(localeUtils, LocaleUtils.getInstance(logger, props, ctx));
+  }
+
+  /**
+ * Test method for {@link com.google.gwt.i18n.rebind.LocaleUtils#getQueryParam()}.
+   */
+  public void testGetQueryParam() {
+    LocaleUtils localeUtils = LocaleUtils.getInstance(logger, props, ctx);
+    assertEquals("query-param", localeUtils.getQueryParam());
+  }
+
+  /**
+ * Test method for {@link com.google.gwt.i18n.rebind.LocaleUtils#getRuntimeLocales()}.
+   */
+  public void testGetRuntimeLocales() {
+    LocaleUtils localeUtils = LocaleUtils.getInstance(logger, props, ctx);
+    GwtLocaleFactory factory = LocaleUtils.getLocaleFactory();
+    Set<GwtLocale> locales = localeUtils.getRuntimeLocales();
+    assertEquals(2, locales.size());
+    assertContains(locales, factory.fromString("es_AR"));
+    assertContains(locales, factory.fromString("es_CO"));
+
+    localeProp.setCurrentValue("es");
+    LocaleUtils localeUtils2 = LocaleUtils.getInstance(logger, props, ctx);
+    localeProp.setCurrentValue("es_419");
+    assertNotSame(localeUtils, localeUtils2);
+
+ // check that we don't pick up runtime locales that are under a more-specific compile locale
+    locales = localeUtils2.getRuntimeLocales();
+    assertEquals(2, locales.size());
+    assertContains(locales, factory.fromString("es_ES"));
+    assertContains(locales, factory.fromString("es_GB"));
+  }
+}
=======================================
--- /trunk/user/src/com/google/gwt/i18n/rebind/LocaleUtils.java Wed Jan 5 11:56:03 2011 +++ /trunk/user/src/com/google/gwt/i18n/rebind/LocaleUtils.java Mon May 2 20:14:38 2011
@@ -41,24 +41,28 @@
   /**
    * The token representing the locale property controlling Localization.
    */
-  private static final String PROP_LOCALE = "locale";
+  // @VisibleForTesting
+  static final String PROP_LOCALE = "locale";

   /**
* The config property identifying the URL query paramter name to possibly get
    * the value of the locale property.
    */
- private static final String PROP_LOCALE_QUERY_PARAM = "locale.queryparam";
+  // @VisibleForTesting
+  static final String PROP_LOCALE_QUERY_PARAM = "locale.queryparam";

   /**
* The config property identifying the cookie name to possibly get the value
    * of the locale property.
    */
-  private static final String PROP_LOCALE_COOKIE = "locale.cookie";
+  // @VisibleForTesting
+  static final String PROP_LOCALE_COOKIE = "locale.cookie";

   /**
    * The token representing the runtime.locales configuration property.
    */
-  private static final String PROP_RUNTIME_LOCALES = "runtime.locales";
+  // @VisibleForTesting
+  static final String PROP_RUNTIME_LOCALES = "runtime.locales";

   /**
    * Multiple generators need to access the shared cache state of
@@ -145,25 +149,20 @@

     List<String> rtLocaleNames = prop.getValues();
     if (rtLocaleNames != null) {
-      for (String rtLocale : rtLocaleNames) {
-        GwtLocale locale = factoryInstance.fromString(rtLocale);
-        // TODO(jat): remove use of labels
-        existingLocales:
-        for (GwtLocale existing : allCompileLocales) {
-          for (GwtLocale alias : existing.getAliases()) {
-            if (!alias.isDefault() && locale.inheritsFrom(alias)
-                && locale.usesSameScript(alias)) {
-              allLocales.add(locale);
-              break existingLocales;
-            }
-          }
-        }
-        if (!compileLocale.isDefault()
-            && locale.inheritsFrom(compileLocale)
-            && locale.usesSameScript(compileLocale)) {
-          // TODO(jat): don't include runtime locales which also inherit
-          // from a more-specific compile locale than this one
-          runtimeLocales.add(locale);
+      for (String rtLocaleName : rtLocaleNames) {
+        GwtLocale rtLocale = factoryInstance.fromString(rtLocaleName);
+        if (rtLocale.isDefault()) {
+          continue;
+        }
+        for (GwtLocale search : rtLocale.getCompleteSearchList()) {
+ if (search.equals(compileLocale) && rtLocale.usesSameScript(compileLocale)) {
+            runtimeLocales.add(rtLocale);
+            allLocales.add(rtLocale);
+            break;
+ } else if (allCompileLocales.contains(search) && rtLocale.usesSameScript(search)) {
+            allLocales.add(rtLocale);
+            break;
+          }
         }
       }
     }
=======================================
--- /trunk/user/src/com/google/gwt/i18n/server/GwtLocaleImpl.java Mon Oct 25 12:23:11 2010 +++ /trunk/user/src/com/google/gwt/i18n/server/GwtLocaleImpl.java Mon May 2 20:14:38 2011
@@ -577,17 +577,17 @@
    * @return true if the scripts are the same
    */
   public boolean usesSameScript(GwtLocale other) {
-    // The number of aliases is very small, so n^2 isn't a problem here.
-    List<GwtLocale> myAliases = getAliases();
-    List<GwtLocale> otherAliases = other.getAliases();
-    for (GwtLocale alias : myAliases) {
-      for (GwtLocale otherAlias : otherAliases) {
-        if (equalsNullCheck(alias.getScript(), otherAlias.getScript())) {
-          return true;
-        }
-      }
-    }
-    return false;
+ String myScript = script != null ? script : DefaultLanguageScripts.getDefaultScript(language,
+        region);
+    String otherScript = other.getScript() != null ? other.getScript()
+ : DefaultLanguageScripts.getDefaultScript(other.getLanguage(), other.getRegion()); + // two locales with an unspecified script and no default for the language
+    // match only if the language is the same
+    if (myScript == null) {
+      return equalsNullCheck(language, other.getLanguage());
+    } else {
+      return myScript.equals(otherScript);
+    }
   }

   /**
=======================================
--- /trunk/user/test/com/google/gwt/i18n/I18NSuite.java Thu Mar 31 14:56:42 2011 +++ /trunk/user/test/com/google/gwt/i18n/I18NSuite.java Mon May 2 20:14:38 2011
@@ -46,6 +46,7 @@
 import com.google.gwt.i18n.client.RuntimeLocalesTest;
 import com.google.gwt.i18n.client.TimeZoneInfoTest;
 import com.google.gwt.i18n.client.TimeZoneTest;
+import com.google.gwt.i18n.rebind.LocaleUtilsTest;
 import com.google.gwt.i18n.server.GwtLocaleTest;
 import com.google.gwt.i18n.server.MessageFormatParserTest;
 import com.google.gwt.i18n.server.PropertyCatalogFactoryTest;
@@ -97,6 +98,7 @@
     suite.addTestSuite(I18N_nb_Test.class);
     suite.addTestSuite(LocaleInfo_ar_Test.class);
     suite.addTestSuite(LocaleInfoTest.class);
+    suite.addTestSuite(LocaleUtilsTest.class);
     suite.addTestSuite(LocalizedNames_default_Test.class);
     suite.addTestSuite(LocalizedNames_en_Test.class);
     suite.addTestSuite(MessageFormatParserTest.class);

--
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to