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