Revision: 9923
Author:   [email protected]
Date:     Thu Mar 31 14:56:42 2011
Log:      Add support for {#} to mean the right-most plural argument.  Some
translation systems, such as those which represent plural messages
using ICU's plural syntax, lose the argument number and depending
on the processing pipeline it may be hard to add it back.

Providing {#} provides a way to use those messages for GWT translations without
having to do a lot of extra work to use them.

Public review at http://gwt-code-reviews.appspot.com/1385809/

Patch by: jat
Review by: rjrjr

http://code.google.com/p/google-web-toolkit/source/detail?r=9923

Added:
 /trunk/user/test/com/google/gwt/i18n/client/I18N_en_US_Test.java
/trunk/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_en_US.properties
Modified:
 /trunk/user/src/com/google/gwt/i18n/rebind/MessageFormatParser.java
 /trunk/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java
 /trunk/user/src/com/google/gwt/i18n/server/MessageFormatUtils.java
 /trunk/user/test/com/google/gwt/i18n/I18NSuite.java
 /trunk/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java
 /trunk/user/test/com/google/gwt/i18n/server/MessageFormatParserTest.java

=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/i18n/client/I18N_en_US_Test.java Thu Mar 31 14:56:42 2011
@@ -0,0 +1,309 @@
+/*
+ * 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.client;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.TestAnnotatedMessages.Gender;
+import com.google.gwt.junit.client.GWTTestCase;
+import com.google.gwt.safehtml.shared.SafeHtml;
+import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test the same things as I18NTest but with a different module which
+ * uses different locales.
+ */
+public class I18N_en_US_Test extends GWTTestCase {
+
+  @Override
+  public String getModuleName() {
+    return "com.google.gwt.i18n.I18NTest_en";
+  }
+
+  /**
+   * Verifies correct output for multiple, nested selectors, using an enum
+   * for gender selection (and SafeHtml output).
+   */
+  public void testMultiSelectEnum() {
+    TestAnnotatedMessages m = GWT.create(TestAnnotatedMessages.class);
+    List<String> names = new ArrayList<String>();
+
+    // empty list of names
+    assertEquals("test: Nobody liked his message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.MALE).asString());
+    assertEquals("test: Nobody liked his 2 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 2, Gender.MALE).asString());
+    assertEquals("test: Nobody liked her message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.FEMALE).asString());
+    assertEquals("test: Nobody liked her 3 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 3, Gender.FEMALE).asString());
+    assertEquals("test: Nobody liked their message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, null).asString());
+    assertEquals("test: Nobody liked their 4 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 4, Gender.UNKNOWN).asString());
+
+    // one name
+    names.add("John");
+    assertEquals("test: John liked his message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.MALE).asString());
+    assertEquals("test: John liked his 2 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 2, Gender.MALE).asString());
+    assertEquals("test: John liked her message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.FEMALE).asString());
+    assertEquals("test: John liked her 3 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 3, Gender.FEMALE).asString());
+    assertEquals("test: John liked their message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.UNKNOWN).asString());
+    assertEquals("test: John liked their 4 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 4, null).asString());
+
+    // two names
+    names.add("Bob");
+    assertEquals("test: John and Bob liked his message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.MALE).asString());
+    assertEquals("test: John and Bob liked his 2 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 2, Gender.MALE).asString());
+    assertEquals("test: John and Bob liked her message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.FEMALE).asString());
+    assertEquals("test: John and Bob liked her 3 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 3, Gender.FEMALE).asString());
+    assertEquals("test: John and Bob liked their message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, null).asString());
+    assertEquals("test: John and Bob liked their 4 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 4, Gender.UNKNOWN).asString());
+
+    // three names
+    names.add("Alice");
+    assertEquals("test: John, Bob, and one other liked his message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.MALE).asString());
+    assertEquals("test: John, Bob, and one other liked his 2 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 2, Gender.MALE).asString());
+    assertEquals("test: John, Bob, and one other liked her message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.FEMALE).asString());
+    assertEquals("test: John, Bob, and one other liked her 3 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 3, Gender.FEMALE).asString());
+    assertEquals("test: John, Bob, and one other liked their message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.UNKNOWN).asString());
+    assertEquals("test: John, Bob, and one other liked their 4 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 4, null).asString());
+
+    // four names
+    names.add("Carol");
+    assertEquals("test: John, Bob, and 2 others liked his message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.MALE).asString());
+    assertEquals("test: John, Bob, and 2 others liked his 2 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 2, Gender.MALE).asString());
+    assertEquals("test: John, Bob, and 2 others liked her message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.FEMALE).asString());
+    assertEquals("test: John, Bob, and 2 others liked her 3 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 3, Gender.FEMALE).asString());
+    assertEquals("test: John, Bob, and 2 others liked their message",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+ names.size() > 1 ? names.get(1) : null, 1, Gender.UNKNOWN).asString());
+    assertEquals("test: John, Bob, and 2 others liked their 4 messages",
+        m.multiSelectEnum(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 4, null).asString());
+  }
+
+  /**
+   * Verifies correct output for multiple, nested selectors, using a string
+   * for gender selection.
+   */
+  public void testMultiSelectString() {
+    TestAnnotatedMessages m = GWT.create(TestAnnotatedMessages.class);
+    List<String> names = new ArrayList<String>();
+
+    // empty list of names
+    assertEquals("test: Nobody liked his message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "MALE"));
+    assertEquals("test: Nobody liked his 2 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 2, "MALE"));
+    assertEquals("test: Nobody liked her message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "FEMALE"));
+    assertEquals("test: Nobody liked her 3 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 3, "FEMALE"));
+    assertEquals("test: Nobody liked their message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "unknown"));
+    assertEquals("test: Nobody liked their 4 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 4, "unknown"));
+
+    // one name
+    names.add("John");
+    assertEquals("test: John liked his message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "MALE"));
+    assertEquals("test: John liked his 2 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 2, "MALE"));
+    assertEquals("test: John liked her message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "FEMALE"));
+    assertEquals("test: John liked her 3 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 3, "FEMALE"));
+    assertEquals("test: John liked their message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "unknown"));
+    assertEquals("test: John liked their 4 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 4, "unknown"));
+
+    // two names
+    names.add("Bob");
+    assertEquals("test: John and Bob liked his message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "MALE"));
+    assertEquals("test: John and Bob liked his 2 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 2, "MALE"));
+    assertEquals("test: John and Bob liked her message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "FEMALE"));
+    assertEquals("test: John and Bob liked her 3 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 3, "FEMALE"));
+    assertEquals("test: John and Bob liked their message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "unknown"));
+    assertEquals("test: John and Bob liked their 4 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 4, "unknown"));
+
+    // three names
+    names.add("Alice");
+    assertEquals("test: John, Bob, and one other liked his message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "MALE"));
+    assertEquals("test: John, Bob, and one other liked his 2 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 2, "MALE"));
+    assertEquals("test: John, Bob, and one other liked her message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "FEMALE"));
+    assertEquals("test: John, Bob, and one other liked her 3 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 3, "FEMALE"));
+    assertEquals("test: John, Bob, and one other liked their message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "unknown"));
+    assertEquals("test: John, Bob, and one other liked their 4 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 4, "unknown"));
+
+    // four names
+    names.add("Carol");
+    assertEquals("test: John, Bob, and 2 others liked his message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "MALE"));
+    assertEquals("test: John, Bob, and 2 others liked his 2 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 2, "MALE"));
+    assertEquals("test: John, Bob, and 2 others liked her message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "FEMALE"));
+    assertEquals("test: John, Bob, and 2 others liked her 3 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 3, "FEMALE"));
+    assertEquals("test: John, Bob, and 2 others liked their message",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 1, "unknown"));
+    assertEquals("test: John, Bob, and 2 others liked their 4 messages",
+        m.multiSelectString(names, names.size() > 0 ? names.get(0) : null,
+        names.size() > 1 ? names.get(1) : null, 4, "unknown"));
+  }
+
+  public void testSpecialPlurals() {
+    TestAnnotatedMessages m = GWT.create(TestAnnotatedMessages.class);
+    assertEquals("No widgets", m.specialPlurals(0));
+    assertEquals("A widget", m.specialPlurals(1));
+    assertEquals("2 widgets", m.specialPlurals(2));
+ assertEquals("No one has reviewed this movie", m.reviewers(0, null, null));
+    assertEquals(
+ "test: John Doe has reviewed this movie", m.reviewers(1, "test: John Doe", null));
+    assertEquals("test: John Doe and Betty Smith have reviewed this movie",
+        m.reviewers(2, "test: John Doe", "Betty Smith"));
+    assertEquals(
+ "test: John Doe, Betty Smith, and one other have reviewed this movie",
+        m.reviewers(3, "test: John Doe", "Betty Smith"));
+    assertEquals(
+ "test: John Doe, Betty Smith, and 3 others have reviewed this movie",
+        m.reviewers(5, "test: John Doe", "Betty Smith"));
+
+    assertEquals("No widgets", m.specialPluralsAsSafeHtml(0).asString());
+    assertEquals("A widget", m.specialPluralsAsSafeHtml(1).asString());
+    assertEquals("2 widgets", m.specialPluralsAsSafeHtml(2).asString());
+    assertEquals("No one has reviewed this movie",
+        m.reviewersAsSafeHtml(0, null, null).asString());
+ assertEquals("test: John Doe has reviewed this movie", m.reviewersAsSafeHtml(1,
+        "test: John Doe", null).asString());
+    assertEquals("test: John Doe and Betty Smith have reviewed this movie",
+ m.reviewersAsSafeHtml(2, "test: John Doe", sh("Betty Smith")).asString());
+    assertEquals(
+ "test: John Doe, Betty Smith, and one other have reviewed this movie", + m.reviewersAsSafeHtml(3, "test: John Doe", sh("Betty Smith")).asString());
+    assertEquals(
+ "test: John Doe, Betty Smith, and 3 others have reviewed this movie", + m.reviewersAsSafeHtml(5, "test: John Doe", sh("Betty Smith")).asString());
+  }
+
+  /**
+   * Wrapper to easily convert a String literal to a SafeHtml instance.
+   *
+   * @param string
+   * @return a SafeHtml wrapper around the supplied string
+   */
+  private SafeHtml sh(String string) {
+    SafeHtmlBuilder buf = new SafeHtmlBuilder();
+    buf.appendHtmlConstant(string);
+    return buf.toSafeHtml();
+  }
+}
=======================================
--- /dev/null
+++ /trunk/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages_en_US.properties Thu Mar 31 14:56:42 2011
@@ -0,0 +1,60 @@
+multiSelectEnum=test: {1}, {2}, and {0} others liked their {\#} messages
+multiSelectEnum[\=0|other|other]=test: Nobody liked their {3} messages
+multiSelectEnum[\=0|other|FEMALE]=test: Nobody liked her {3} messages
+multiSelectEnum[\=0|other|MALE]=test: Nobody liked his {3} messages
+multiSelectEnum[\=0|one|other]=test: Nobody liked their message
+multiSelectEnum[\=0|one|FEMALE]=test: Nobody liked her message
+multiSelectEnum[\=0|one|MALE]=test: Nobody liked his message
+multiSelectEnum[\=1|other|other]=test: {1} liked their {3} messages
+multiSelectEnum[\=1|other|FEMALE]=test: {1} liked her {3} messages
+multiSelectEnum[\=1|other|MALE]=test: {1} liked his {3} messages
+multiSelectEnum[\=1|one|other]=test: {1} liked their message
+multiSelectEnum[\=1|one|FEMALE]=test: {1} liked her message
+multiSelectEnum[\=1|one|MALE]=test: {1} liked his message
+multiSelectEnum[\=2|other|other]=test: {1} and {2} liked their {\#} messages
+multiSelectEnum[\=2|other|FEMALE]=test: {1} and {2} liked her {3} messages
+multiSelectEnum[\=2|other|MALE]=test: {1} and {2} liked his {3} messages
+multiSelectEnum[\=2|one|other]=test: {1} and {2} liked their message
+multiSelectEnum[\=2|one|FEMALE]=test: {1} and {2} liked her message
+multiSelectEnum[\=2|one|MALE]=test: {1} and {2} liked his message
+multiSelectEnum[one|other|other]=test: {1}, {2}, and one other liked their {3} messages +multiSelectEnum[one|other|FEMALE]=test: {1}, {2}, and one other liked her {3} messages +multiSelectEnum[one|other|MALE]=test: {1}, {2}, and one other liked his {\#} messages +multiSelectEnum[one|one|other]=test: {1}, {2}, and one other liked their message +multiSelectEnum[one|one|FEMALE]=test: {1}, {2}, and one other liked her message +multiSelectEnum[one|one|MALE]=test: {1}, {2}, and one other liked his message +multiSelectEnum[other|one|other]=test: {1}, {2}, and {0} others liked their message +multiSelectEnum[other|one|MALE]=test: {1}, {2}, and {0} others liked his message +multiSelectEnum[other|one|FEMALE]=test: {1}, {2}, and {0} others liked her message +multiSelectEnum[other|other|MALE]=test: {1}, {2}, and {0} others liked his {3} messages +multiSelectEnum[other|other|FEMALE]=test: {1}, {2}, and {0} others liked her {3} messages
+multiSelectString=test: {1}, {2}, and {0} others liked their {\#} messages
+multiSelectString[\=0|other|other]=test: Nobody liked their {3} messages
+multiSelectString[\=0|other|FEMALE]=test: Nobody liked her {3} messages
+multiSelectString[\=0|other|MALE]=test: Nobody liked his {3} messages
+multiSelectString[\=0|one|other]=test: Nobody liked their message
+multiSelectString[\=0|one|FEMALE]=test: Nobody liked her message
+multiSelectString[\=0|one|MALE]=test: Nobody liked his message
+multiSelectString[\=1|other|other]=test: {1} liked their {3} messages
+multiSelectString[\=1|other|FEMALE]=test: {1} liked her {3} messages
+multiSelectString[\=1|other|MALE]=test: {1} liked his {3} messages
+multiSelectString[\=1|one|other]=test: {1} liked their message
+multiSelectString[\=1|one|FEMALE]=test: {1} liked her message
+multiSelectString[\=1|one|MALE]=test: {1} liked his message
+multiSelectString[\=2|other|other]=test: {1} and {2} liked their {\#} messages +multiSelectString[\=2|other|FEMALE]=test: {1} and {2} liked her {3} messages
+multiSelectString[\=2|other|MALE]=test: {1} and {2} liked his {3} messages
+multiSelectString[\=2|one|other]=test: {1} and {2} liked their message
+multiSelectString[\=2|one|FEMALE]=test: {1} and {2} liked her message
+multiSelectString[\=2|one|MALE]=test: {1} and {2} liked his message
+multiSelectString[one|other|other]=test: {1}, {2}, and one other liked their {3} messages +multiSelectString[one|other|FEMALE]=test: {1}, {2}, and one other liked her {3} messages +multiSelectString[one|other|MALE]=test: {1}, {2}, and one other liked his {\#} messages +multiSelectString[one|one|other]=test: {1}, {2}, and one other liked their message +multiSelectString[one|one|FEMALE]=test: {1}, {2}, and one other liked her message +multiSelectString[one|one|MALE]=test: {1}, {2}, and one other liked his message +multiSelectString[other|one|other]=test: {1}, {2}, and {0} others liked their message +multiSelectString[other|one|MALE]=test: {1}, {2}, and {0} others liked his message +multiSelectString[other|one|FEMALE]=test: {1}, {2}, and {0} others liked her message +multiSelectString[other|other|MALE]=test: {1}, {2}, and {0} others liked his {3} messages +multiSelectString[other|other|FEMALE]=test: {1}, {2}, and {0} others liked her {3} messages
=======================================
--- /trunk/user/src/com/google/gwt/i18n/rebind/MessageFormatParser.java Fri Mar 11 11:18:03 2011 +++ /trunk/user/src/com/google/gwt/i18n/rebind/MessageFormatParser.java Thu Mar 31 14:56:42 2011
@@ -57,6 +57,12 @@
       visitor.visit(this);
     }

+    /**
+     * Get the argument number this chunk refers to.
+     *
+     * @return the argument number or -1 to refer to the right-most plural
+     *     argument
+     */
     public int getArgumentNumber() {
       return argNumber;
     }
@@ -91,7 +97,11 @@
     protected String getStringValue(boolean quote) {
       StringBuilder buf = new StringBuilder();
       buf.append('{');
-      buf.append(argNumber);
+      if (argNumber < 0) {
+        buf.append('#');
+      } else {
+        buf.append(argNumber);
+      }
       Map<String, String> map = listArgs;
       if (map != null) {
         buf.append(",list");
@@ -189,8 +199,10 @@
     @Override
     protected String getStringValue(boolean quoted) {
       StringBuilder buf = new StringBuilder();
-      buf.append('{').append(argName).append(',');
-      buf.append(quoteMessageFormatChars(replacement, quoted));
+      buf.append('{').append(argName);
+      if (replacement != null) {
+ buf.append(',').append(quoteMessageFormatChars(replacement, quoted));
+      }
       buf.append('}');
       return buf.toString();
     }
@@ -390,11 +402,14 @@
             format = arg.substring(firstComma + 1);
             arg = arg.substring(0, firstComma);
           }
-          if (!Character.isDigit(arg.charAt(0))) {
+          if (!"#".equals(arg) && !Character.isDigit(arg.charAt(0))) {
             // static argument
             chunks.add(new StaticArgChunk(arg, format));
           } else {
-            int argNumber = Integer.valueOf(arg);
+            int argNumber = -1;
+            if (!"#".equals(arg)) {
+              argNumber = Integer.valueOf(arg);
+            }
             Map<String, String> formatArgs = new HashMap<String, String>();
             Map<String, String> listArgs = null;
             String subFormat = null;
=======================================
--- /trunk/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java Thu Mar 24 08:36:58 2011 +++ /trunk/user/src/com/google/gwt/i18n/rebind/MessagesMethodCreator.java Thu Mar 31 14:56:42 2011
@@ -1038,6 +1038,21 @@
     listPatternCache = new HashMap<GwtLocale, Map<String, String>>();
     this.writer = writer;
   }
+
+  /**
+   * Append an argument to the output without doing any formatting.
+   *
+   * @param buf
+   * @param argExpr Java source for expression to produce argument value
+   * @param argType type of the argument being appended
+   */
+ private void appendUnformattedArg(StringGenerator buf, String argExpr, JType argType) { + boolean isSafeHtmlTyped = SAFE_HTML_FQCN.equals(argType.getQualifiedSourceName());
+    boolean isPrimitiveType = (argType.isPrimitive() != null);
+    boolean needsConversionToString =
+        !("java.lang.String".equals(argType.getQualifiedSourceName()));
+ buf.appendExpression(argExpr, isSafeHtmlTyped, isPrimitiveType, needsConversionToString);
+  }

   @Override
   public void createMethodFor(TreeLogger logger, JMethod m, String key,
@@ -1052,6 +1067,7 @@
     boolean seenSelect = false;

     int numParams = params.length;
+    int lastPluralArgNumber = -1;
List<AlternateFormSelector> selectors = new ArrayList<AlternateFormSelector>();
     // See if any parameter is tagged as a PluralCount or Select parameter.
     for (int i = 0; i < numParams; ++i) {
@@ -1075,6 +1091,7 @@
resourceList.setPluralForms(key, pluralSelector.getPluralForms());
         }
         seenPluralCount = true;
+        lastPluralArgNumber = i;
       }
       if (selector != null) {
         selectors.add(selector);
@@ -1159,8 +1176,8 @@
String[] forms = resourceForms.toArray(new String[resourceForms.size()]);
       Arrays.sort(forms, new ExactValueComparator());

-      generateMessageSelectors(logger, m, locale,
-          resourceEntry, selectors, paramsAccessor, isSafeHtml, forms);
+ generateMessageSelectors(logger, m, locale, resourceEntry, selectors, paramsAccessor,
+          isSafeHtml, forms, lastPluralArgNumber);
       for (AlternateFormSelector selector : selectors) {
         selector.issueWarnings(logger, m, locale);
       }
@@ -1172,7 +1189,7 @@
     }
     writer.print("return ");
     generateString(logger, locale, template, paramsAccessor, writer,
-        isSafeHtml);
+        isSafeHtml, lastPluralArgNumber);
     writer.println(";");

     // Generate an error if any required parameter was not used somewhere.
@@ -1205,11 +1222,7 @@
     }
     // no format specified or unknown format
     // have to ensure that the result is stringified if necessary
- boolean isSafeHtmlTyped = SAFE_HTML_FQCN.equals(paramType.getQualifiedSourceName());
-    boolean isPrimitiveType = (paramType.isPrimitive() != null);
-    boolean needsConversionToString =
-        !("java.lang.String".equals(paramType.getQualifiedSourceName()));
- buf.appendExpression(argExpr, isSafeHtmlTyped, isPrimitiveType, needsConversionToString);
+    appendUnformattedArg(buf, argExpr, paramType);
   }

   /**
@@ -1365,12 +1378,14 @@
    * @param paramsAccessor
    * @param isSafeHtml
    * @param forms
+ * @param lastPluralArgNumber index of most recent plural argument, used for
+   *     processing inner-plural arguments ({#})
    * @throws UnableToCompleteException
    */
   private void generateMessageSelectors(TreeLogger logger, JMethod m,
       GwtLocale locale, ResourceEntry resourceEntry,
       List<AlternateFormSelector> selectors, Parameters paramsAccessor,
-      boolean isSafeHtml, String[] forms)
+      boolean isSafeHtml, String[] forms, int lastPluralArgNumber)
       throws UnableToCompleteException {
     int numSelectors = selectors.size();
     String[] lastForm = new String[numSelectors];
@@ -1424,7 +1439,7 @@
       }
       writer.print("returnVal = ");
       generateString(logger, locale, resourceEntry.getForm(form),
-          paramsAccessor, writer, isSafeHtml);
+          paramsAccessor, writer, isSafeHtml, lastPluralArgNumber);
       writer.println(";");
     }
     for (int i = numSelectors; i-- > 0; ) {
@@ -1442,12 +1457,13 @@
    * @param template
    * @param paramsAccessor
    * @param writer
+ * @param lastPluralArgNumber index of most recent plural argument, used for
+   *     processing inner-plural arguments ({#})
    * @throws UnableToCompleteException
    */
- private void generateString(final TreeLogger logger,final GwtLocale locale,
-      final String template,final Parameters paramsAccessor,
-      SourceWriter writer, final boolean isSafeHtml)
-      throws UnableToCompleteException {
+ private void generateString(final TreeLogger logger, final GwtLocale locale, + final String template, final Parameters paramsAccessor, SourceWriter writer, + final boolean isSafeHtml, final int lastPluralArgNumber) throws UnableToCompleteException {
     StringBuffer outputBuf = new StringBuffer();
     final StringGenerator buf = new StringGenerator(outputBuf, isSafeHtml);
     final int n = paramsAccessor.getCount();
@@ -1458,8 +1474,13 @@
public void visit(ArgumentChunk argChunk) throws UnableToCompleteException {
             int argNumber = argChunk.getArgumentNumber();
             if (argNumber >= n) {
-              throw error(
- logger, "Argument " + argNumber + " beyond range of arguments: " + template); + throw error(logger, "Argument " + argNumber + " beyond range of arguments: " + template);
+            }
+            if (argNumber < 0) {
+              if (lastPluralArgNumber < 0) {
+ throw error(logger, "Inner-plural notation {#} used outside in non-plural message");
+              }
+              argNumber = lastPluralArgNumber;
             }
             JParameter param = paramsAccessor.getParameter(argNumber);
             String arg = "arg" + argNumber;
=======================================
--- /trunk/user/src/com/google/gwt/i18n/server/MessageFormatUtils.java Mon Mar 21 12:22:19 2011 +++ /trunk/user/src/com/google/gwt/i18n/server/MessageFormatUtils.java Thu Mar 31 14:56:42 2011
@@ -53,6 +53,12 @@
       visitor.visit(this);
     }

+    /**
+     * Get the argument number this chunk refers to.
+     *
+     * @return the argument number or -1 to refer to the right-most plural
+     *     argument
+     */
     public int getArgumentNumber() {
       return argNumber;
     }
@@ -87,7 +93,11 @@
     protected String getStringValue(boolean quote) {
       StringBuilder buf = new StringBuilder();
       buf.append('{');
-      buf.append(argNumber);
+      if (argNumber < 0) {
+        buf.append('#');
+      } else {
+        buf.append(argNumber);
+      }
       Map<String, String> map = listArgs;
       if (map != null) {
         buf.append(",list");
@@ -271,11 +281,14 @@
                 format = arg.substring(firstComma + 1);
                 arg = arg.substring(0, firstComma);
               }
-              if (!Character.isDigit(arg.charAt(0))) {
+              if (!"#".equals(arg) && !Character.isDigit(arg.charAt(0))) {
                 // static argument
                 chunks.add(new StaticArgChunk(arg, format));
               } else {
-                int argNumber = Integer.valueOf(arg);
+                int argNumber = -1;
+                if (!"#".equals(arg)) {
+                  argNumber = Integer.valueOf(arg);
+                }
Map<String, String> formatArgs = new HashMap<String, String>();
                 Map<String, String> listArgs = null;
                 String subFormat = null;
@@ -407,8 +420,10 @@
     @Override
     protected String getStringValue(boolean quoted) {
       StringBuilder buf = new StringBuilder();
-      buf.append('{').append(argName).append(',');
-      buf.append(quoteMessageFormatChars(replacement, quoted));
+      buf.append('{').append(argName);
+      if (replacement != null) {
+ buf.append(',').append(quoteMessageFormatChars(replacement, quoted));
+      }
       buf.append('}');
       return buf.toString();
     }
=======================================
--- /trunk/user/test/com/google/gwt/i18n/I18NSuite.java Fri Mar 11 11:18:03 2011 +++ /trunk/user/test/com/google/gwt/i18n/I18NSuite.java Thu Mar 31 14:56:42 2011
@@ -27,6 +27,7 @@
 import com.google.gwt.i18n.client.DateTimeParse_zh_CN_Test;
 import com.google.gwt.i18n.client.I18N2Test;
 import com.google.gwt.i18n.client.I18NTest;
+import com.google.gwt.i18n.client.I18N_en_US_Test;
 import com.google.gwt.i18n.client.I18N_es_MX_RuntimeTest;
 import com.google.gwt.i18n.client.I18N_es_MX_Test;
 import com.google.gwt.i18n.client.I18N_iw_Test;
@@ -92,6 +93,7 @@
     suite.addTestSuite(I18N_iw_Test.class);
     suite.addTestSuite(I18N_es_MX_Test.class);
     suite.addTestSuite(I18N_es_MX_RuntimeTest.class);
+    suite.addTestSuite(I18N_en_US_Test.class);
     suite.addTestSuite(I18N_nb_Test.class);
     suite.addTestSuite(LocaleInfo_ar_Test.class);
     suite.addTestSuite(LocaleInfoTest.class);
=======================================
--- /trunk/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java Fri Mar 11 11:18:03 2011 +++ /trunk/user/test/com/google/gwt/i18n/client/TestAnnotatedMessages.java Thu Mar 31 14:56:42 2011
@@ -26,7 +26,7 @@
 /**
  * Test of Messages generation using annotations.
  */
-@DefaultLocale("en-US")
+@DefaultLocale("en")
 // @GenerateKeys("com.google.gwt.i18n.server.keygen.MD5KeyGenerator")
@GenerateKeys("com.google.gwt.i18n.server.keygen.MethodNameKeyGenerator") // default
 @Generate(format = "com.google.gwt.i18n.server.PropertyCatalogFactory")
@@ -238,7 +238,7 @@
     "=2|one|MALE", "{1} and {2} liked his message",
     "one|other|other", "{1}, {2}, and one other liked their {3} messages",
     "one|other|FEMALE", "{1}, {2}, and one other liked her {3} messages",
-    "one|other|MALE", "{1}, {2}, and one other liked his {3} messages",
+    "one|other|MALE", "{1}, {2}, and one other liked his {#} messages",
     "one|one|other", "{1}, {2}, and one other liked their message",
     "one|one|FEMALE", "{1}, {2}, and one other liked her message",
     "one|one|MALE", "{1}, {2}, and one other liked his message",
=======================================
--- /trunk/user/test/com/google/gwt/i18n/server/MessageFormatParserTest.java Fri Mar 11 11:18:03 2011 +++ /trunk/user/test/com/google/gwt/i18n/server/MessageFormatParserTest.java Thu Mar 31 14:56:42 2011
@@ -60,7 +60,20 @@
     assertEquals(0, args.size());
     args = chunk.getFormatArgs();
     assertEquals(0, args.size());
-}
+  }
+
+  public void testParseInnerPlural() throws ParseException {
+    String str = "You have {#} widgets";
+    List<TemplateChunk> parsed = MessageStyle.MESSAGE_FORMAT.parse(str);
+    assertEquals(3, parsed.size());
+    StringChunk stringChunk = (StringChunk) parsed.get(0);
+    assertEquals("You have ", stringChunk.getString());
+    ArgumentChunk argChunk = (ArgumentChunk) parsed.get(1);
+    assertEquals(-1, argChunk.getArgumentNumber());
+    assertEquals("{#}", argChunk.getAsMessageFormatString());
+    stringChunk = (StringChunk) parsed.get(2);
+    assertEquals(" widgets", stringChunk.getString());
+  }

   public void testParseLiteral() throws ParseException {
     String str = "Simple string literal";

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

Reply via email to