Add new plural rules, correct Arabic and add Arabic plurals test, add
UnableToCompleteException to the MessageCatalogFormat write method, improve
error handling in AbstractLocalizableImplCreator.
Patch by: jat
Review by: rdayal
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2435 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_ar.java b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_ar.java
index b58c722..839ec99 100644
--- a/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_ar.java
+++ b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_ar.java
@@ -17,7 +17,7 @@
package com.google.gwt.i18n.client.impl.plurals;
/**
- * Plural forms for Arabic are 0, 1, 2, 3-10, 11-99, and n.
+ * Plural forms for Arabic are 0, 1, 2, x03-x10, x11-x99.
*/
public class DefaultRule_ar extends DefaultRule {
@@ -28,14 +28,14 @@
new PluralForm("none", "Count is 0"),
new PluralForm("one", "Count is 1"),
new PluralForm("two", "Count is 2"),
- new PluralForm("few", "Count is between 3 and 10"),
- new PluralForm("many", "Count is between 11 and 99"),
+ new PluralForm("few", "Count is between x03 and x10"),
+ new PluralForm("many", "Count is between x11 and x99"),
};
}
@Override
public int select(int n) {
- return n == 0 ? 1 : n == 1 ? 2 : n == 2 ? 3
- : n >= 3 && n <= 10 ? 4 : n >= 11 && n <= 99 ? 5 : 0;
+ return n == 0 ? 1 : n == 1 ? 2 : n == 2 ? 3 : n % 100 >= 3 && n % 100 <= 10 ? 4 : n % 100 >= 11
+ && n % 100 <= 99 ? 5 : 0;
}
}
diff --git a/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_nb.java b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_nb.java
index 50a1066..faf554b 100644
--- a/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_nb.java
+++ b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_nb.java
@@ -18,7 +18,7 @@
/**
- * Plural forms for Norwegian Bokmal are 1 and n, with 0 treated as plural.
+ * Plural forms for Norwegian Bokmål are 1 and n, with 0 treated as plural.
*/
public class DefaultRule_nb extends DefaultRule {
diff --git a/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_se.java b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_se.java
new file mode 100644
index 0000000..c96cfdd
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_se.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008 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.client.impl.plurals;
+
+
+/**
+ * Plural forms for Northern Sami are 1, 2, and n.
+ */
+public class DefaultRule_se extends DefaultRule {
+
+ @Override
+ public PluralForm[] pluralForms() {
+ return DefaultRule_1_2_n.pluralForms();
+ }
+
+ @Override
+ public int select(int n) {
+ return DefaultRule_1_2_n.select(n);
+ }
+}
diff --git a/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_smi.java b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_smi.java
new file mode 100644
index 0000000..f3a9b45
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_smi.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008 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.client.impl.plurals;
+
+
+/**
+ * Plural forms for Sami are 1, 2, and n.
+ */
+public class DefaultRule_smi extends DefaultRule {
+
+ @Override
+ public PluralForm[] pluralForms() {
+ return DefaultRule_1_2_n.pluralForms();
+ }
+
+ @Override
+ public int select(int n) {
+ return DefaultRule_1_2_n.select(n);
+ }
+}
diff --git a/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_smj.java b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_smj.java
new file mode 100644
index 0000000..49990e6
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_smj.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008 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.client.impl.plurals;
+
+
+/**
+ * Plural forms for Lule Sami are 1, 2, and n.
+ */
+public class DefaultRule_smj extends DefaultRule {
+
+ @Override
+ public PluralForm[] pluralForms() {
+ return DefaultRule_1_2_n.pluralForms();
+ }
+
+ @Override
+ public int select(int n) {
+ return DefaultRule_1_2_n.select(n);
+ }
+}
diff --git a/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_sms.java b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_sms.java
new file mode 100644
index 0000000..82dcdb7
--- /dev/null
+++ b/user/src/com/google/gwt/i18n/client/impl/plurals/DefaultRule_sms.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2008 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.client.impl.plurals;
+
+
+/**
+ * Plural forms for Skolt Sami are 1, 2, and n.
+ */
+public class DefaultRule_sms extends DefaultRule {
+
+ @Override
+ public PluralForm[] pluralForms() {
+ return DefaultRule_1_2_n.pluralForms();
+ }
+
+ @Override
+ public int select(int n) {
+ return DefaultRule_1_2_n.select(n);
+ }
+}
diff --git a/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java b/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java
index 3b1f1b8..71104da 100644
--- a/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/AbstractLocalizableImplCreator.java
@@ -54,6 +54,7 @@
JClassType constantsClass;
JClassType messagesClass;
JClassType constantsWithLookupClass;
+ boolean seenError = false;
try {
constantsClass = oracle.getType(LocalizableGenerator.CONSTANTS_NAME);
constantsWithLookupClass = oracle.getType(LocalizableGenerator.CONSTANTS_WITH_LOOKUP_NAME);
@@ -133,59 +134,79 @@
// Generate a translatable output file if requested.
Generate generate = targetClass.getAnnotation(Generate.class);
if (generate != null) {
- try {
- String path = generate.fileName();
- if (Generate.DEFAULT.equals(path)) {
- path = targetClass.getPackage().getName() + "."
- + targetClass.getName().replace('.', '_');
- } else if (path.endsWith(File.pathSeparator)) {
- path = path + targetClass.getName().replace('.', '_');
- }
- String[] genLocales = generate.locales();
- boolean found = false;
- if (genLocales.length != 0) {
- // verify the current locale is in the list
- for (String genLocale : genLocales) {
- if (genLocale.equals(locale)) {
- found = true;
- break;
- }
+ String path = generate.fileName();
+ if (Generate.DEFAULT.equals(path)) {
+ path = targetClass.getPackage().getName() + "."
+ + targetClass.getName().replace('.', '_');
+ } else if (path.endsWith(File.pathSeparator)) {
+ path = path + targetClass.getName().replace('.', '_');
+ }
+ String[] genLocales = generate.locales();
+ boolean found = false;
+ if (genLocales.length != 0) {
+ // verify the current locale is in the list
+ for (String genLocale : genLocales) {
+ if (genLocale.equals(locale)) {
+ found = true;
+ break;
}
- } else {
- // Since they want all locales, this is guaranteed to be one of them.
- found = true;
}
- if (found) {
- for (String genClassName : generate.format()) {
+ } else {
+ // Since they want all locales, this is guaranteed to be one of them.
+ found = true;
+ }
+ if (found) {
+ for (String genClassName : generate.format()) {
+ MessageCatalogFormat msgWriter = null;
+ try {
Class<? extends MessageCatalogFormat> msgFormatClass = Class.forName(
genClassName).asSubclass(MessageCatalogFormat.class);
- MessageCatalogFormat msgWriter = msgFormatClass.newInstance();
- // Make generator-specific changes to a temporary copy of the path.
- String genPath = path;
- if (genLocales.length != 1) {
- // If the user explicitly specified only one locale, do not add the locale.
- genPath += '_' + locale;
- }
- genPath += msgWriter.getExtension();
- OutputStream outStr = context.tryCreateResource(logger, genPath);
- if (outStr != null) {
- logger.log(TreeLogger.INFO, "Generating " + genPath + " from "
- + className + " for locale " + locale, null);
- PrintWriter out = new PrintWriter(new BufferedWriter(
+ msgWriter = msgFormatClass.newInstance();
+ } catch (InstantiationException e) {
+ logger.log(TreeLogger.WARN, "Error instantiating @Generate class " + genClassName, e);
+ continue;
+ } catch (IllegalAccessException e) {
+ logger.log(TreeLogger.WARN, "@Generate class " + genClassName + " illegal access", e);
+ continue;
+ } catch (ClassNotFoundException e) {
+ logger.log(TreeLogger.WARN, "@Generate class " + genClassName + " not found");
+ continue;
+ }
+ // Make generator-specific changes to a temporary copy of the path.
+ String genPath = path;
+ if (genLocales.length != 1) {
+ // If the user explicitly specified only one locale, do not add the locale.
+ genPath += '_' + locale;
+ }
+ genPath += msgWriter.getExtension();
+ OutputStream outStr = context.tryCreateResource(logger, genPath);
+ if (outStr != null) {
+ TreeLogger branch = logger.branch(TreeLogger.INFO, "Generating " + genPath
+ + " from " + className + " for locale " + locale, null);
+ PrintWriter out = null;
+ try {
+ out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(outStr, "UTF-8")), false);
- msgWriter.write(logger, resource, out, targetClass);
+ } catch (UnsupportedEncodingException e) {
+ throw error(logger, e.getMessage());
+ }
+ try {
+ msgWriter.write(branch, resource, out, targetClass);
out.flush();
context.commitResource(logger, outStr).setPrivate(true);
+ } catch (UnableToCompleteException e) {
+ // msgWriter should have already logged an error message.
+ // Keep going for now so we can find other errors.
+ seenError = true;
}
}
}
- } catch (InstantiationException e) {
- } catch (IllegalAccessException e) {
- } catch (ClassNotFoundException e) {
- } catch (UnsupportedEncodingException e) {
- throw error(logger, e.getMessage());
}
}
+ if (seenError) {
+ // If one of our generators had a fatal error, don't complete normally.
+ throw new UnableToCompleteException();
+ }
return packageName + "." + className;
}
@@ -208,7 +229,7 @@
* True if the class being generated uses Constants-style annotations/quoting.
*/
private boolean isConstants;
-
+
/**
* Constructor for <code>AbstractLocalizableImplCreator</code>.
*
diff --git a/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java b/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
index 06bd300..5f81269 100644
--- a/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
+++ b/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
@@ -51,17 +51,17 @@
private static class StringGenerator {
/**
- * True if we are in the middle of a string literal
+ * True if we are in the middle of a string literal.
*/
private boolean inString;
/**
- * True if we have produced any output
+ * True if we have produced any output.
*/
private boolean producedOutput;
/**
- * Output string buffer
+ * Output string buffer.
*/
private StringBuffer buf;
diff --git a/user/src/com/google/gwt/i18n/rebind/format/MessageCatalogFormat.java b/user/src/com/google/gwt/i18n/rebind/format/MessageCatalogFormat.java
index a3ff4b2..c61ac17 100644
--- a/user/src/com/google/gwt/i18n/rebind/format/MessageCatalogFormat.java
+++ b/user/src/com/google/gwt/i18n/rebind/format/MessageCatalogFormat.java
@@ -16,6 +16,7 @@
package com.google.gwt.i18n.rebind.format;
import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.i18n.rebind.AbstractResource;
@@ -43,9 +44,12 @@
* @param out the PrintWriter to generate output on
* @param messageInterface the interface to create (so additional
* annotations may be accessed)
+ * @throws UnableToCompleteException if a fatal error prevents generating
+ * the output file. In this case, the implementation must have already
+ * logged an appropriate ERROR message to the logger.
*/
void write(TreeLogger logger, AbstractResource resource, PrintWriter out,
- JClassType messageInterface);
+ JClassType messageInterface) throws UnableToCompleteException;
/**
* @return the extension to use for this file type, including the dot
diff --git a/user/test/com/google/gwt/i18n/I18NSuite.java b/user/test/com/google/gwt/i18n/I18NSuite.java
index dc2c553..77155de 100644
--- a/user/test/com/google/gwt/i18n/I18NSuite.java
+++ b/user/test/com/google/gwt/i18n/I18NSuite.java
@@ -15,6 +15,7 @@
*/
package com.google.gwt.i18n;
+import com.google.gwt.i18n.client.ArabicPluralsTest;
import com.google.gwt.i18n.client.DateTimeFormat_de_Test;
import com.google.gwt.i18n.client.DateTimeParse_en_Test;
import com.google.gwt.i18n.client.DateTimeParse_zh_CN_Test;
@@ -40,6 +41,7 @@
// $JUnit-BEGIN$
suite.addTestSuite(AbstractResourceTest.class);
+ suite.addTestSuite(ArabicPluralsTest.class);
suite.addTestSuite(ConstantMapTest.class);
suite.addTestSuite(DateTimeFormat_de_Test.class);
suite.addTestSuite(DateTimeParse_en_Test.class);
diff --git a/user/test/com/google/gwt/i18n/client/ArabicPluralsTest.java b/user/test/com/google/gwt/i18n/client/ArabicPluralsTest.java
new file mode 100644
index 0000000..4144016
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/ArabicPluralsTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2008 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.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests Arabic plurals, which are one of the most complicated.
+ */
+public class ArabicPluralsTest extends GWTTestCase {
+
+ public String getModuleName() {
+ return "com.google.gwt.i18n.I18NTest_ar";
+ }
+
+ public void testPlurals() {
+ // Note that all text is actually in English, but written according to
+ // Arabic plural rules.
+ TestAnnotatedMessages m = GWT.create(TestAnnotatedMessages.class);
+ assertEquals("No widgets", m.pluralWidgetsOther(0));
+ assertEquals("A widget", m.pluralWidgetsOther(1));
+ assertEquals("Both widgets", m.pluralWidgetsOther(2));
+ assertEquals("A few widgets - 3", m.pluralWidgetsOther(3));
+ assertEquals("A few widgets - 10", m.pluralWidgetsOther(10));
+ assertEquals("Many widgets - 11", m.pluralWidgetsOther(11));
+ assertEquals("Many widgets - 99", m.pluralWidgetsOther(99));
+ assertEquals("100 widgets", m.pluralWidgetsOther(100));
+ assertEquals("101 widgets", m.pluralWidgetsOther(101));
+ assertEquals("102 widgets", m.pluralWidgetsOther(102));
+ assertEquals("A few widgets - 103", m.pluralWidgetsOther(103));
+ }
+}
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotatedConstants.java b/user/test/com/google/gwt/i18n/client/TestAnnotatedConstants.java
index 352d7e9..9520a81 100644
--- a/user/test/com/google/gwt/i18n/client/TestAnnotatedConstants.java
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotatedConstants.java
@@ -27,7 +27,7 @@
*/
@DefaultLocale("en-US")
@GenerateKeys("com.google.gwt.i18n.rebind.keygen.MethodNameKeyGenerator") // default
-@Generate(format = "com.google.gwt.i18n.rebind.format.Properties")
+@Generate(format = "com.google.gwt.i18n.rebind.format.PropertiesFormat")
public interface TestAnnotatedConstants extends Constants {
@DefaultIntValue(14)
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotatedConstantsGenMD5.java b/user/test/com/google/gwt/i18n/client/TestAnnotatedConstantsGenMD5.java
index 77ec6ac..896b2e2 100644
--- a/user/test/com/google/gwt/i18n/client/TestAnnotatedConstantsGenMD5.java
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotatedConstantsGenMD5.java
@@ -27,7 +27,7 @@
*/
@DefaultLocale("en-US")
@GenerateKeys // ("com.google.gwt.i18n.rebind.MD5") - default
-@Generate(format = "com.google.gwt.i18n.rebind.format.Properties")
+@Generate(format = "com.google.gwt.i18n.rebind.format.PropertiesFormat")
public interface TestAnnotatedConstantsGenMD5 extends Constants {
@DefaultIntValue(14)
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java
index 0dbe991..437a559 100644
--- a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java
@@ -28,7 +28,7 @@
@DefaultLocale("en-US")
//@GenerateKeys("com.google.gwt.i18n.rebind.keygen.MD5KeyGenerator")
@GenerateKeys("com.google.gwt.i18n.rebind.keygen.MethodNameKeyGenerator") // default
-@Generate(format = "com.google.gwt.i18n.rebind.format.Properties")
+@Generate(format = "com.google.gwt.i18n.rebind.format.PropertiesFormat")
public interface TestAnnotatedMessages extends Messages {
@DefaultMessage("Test me")
diff --git a/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_ar.properties b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_ar.properties
new file mode 100644
index 0000000..1433ab0
--- /dev/null
+++ b/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_ar.properties
@@ -0,0 +1,7 @@
+pluralWidgetsOther={0} widgets
+pluralWidgetsOther[none]=No widgets
+pluralWidgetsOther[one]=A widget
+pluralWidgetsOther[two]=Both widgets
+pluralWidgetsOther[few]=A few widgets - {0}
+pluralWidgetsOther[many]=Many widgets - {0}
+
\ No newline at end of file