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