blob: 6889ec75cd995d46d3183afc56883edc9ff63d6c [file] [log] [blame]
/*
* 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 java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* A tag interface that facilitates locale-sensitive, compile-time binding of
* messages supplied from various sources.Using
* <code>GWT.create(<i>class</i>)</code> to "instantiate" an interface that
* extends <code>Messages</code> returns an instance of an automatically
* generated subclass that is implemented using message templates selected based
* on locale. Message templates are based on a subset of the format used by <a
* href="http://java.sun.com/j2se/1.5.0/docs/api/java/text/MessageFormat.html">
* <code>MessageFormat</code></a>. Note in particular that single quotes are
* used to quote other characters, and should be doubled for a literal single
* quote.
*
* <p>
* Locale is specified at run time using a meta tag or query string as described
* for {@link com.google.gwt.i18n.client.Localizable}.
* </p>
*
* <h3>Extending <code>Messages</code></h3>
* To use <code>Messages</code>, begin by defining an interface that extends
* it. Each interface method is referred to as a <i>message accessor</i>, and
* its corresponding message template is loaded based on the key for that
* method. The default key is simply the unqualified name of the method, but can
* be specified directly with an {@code @Key} annotation or a different
* generation method using {@code @GenerateKeys}. Additionally, if
* plural forms are used on a given method the plural form is added as a suffix
* to the key, such as <code>widgets[one]</code> for the singular version of
* the <code>widgets</code> message. The resulting key is used to find
* translated versions of the message from any supported input file, such as
* Java properties files. For example,
*
* {@example com.google.gwt.examples.i18n.GameStatusMessages}
*
* expects to find properties named <code>turnsLeft</code> and
* <code>currentScore</code> in an associated properties file, formatted as
* message templates taking two arguments and one argument, respectively. For
* example, the following properties would correctly bind to the
* <code>GameStatusMessages</code> interface:
*
* {@gwt.include com/google/gwt/examples/i18n/GameStatusMessages.properties}
*
* <p>
* The following example demonstrates how to use constant accessors defined in
* the interface above:
*
* {@example com.google.gwt.examples.i18n.GameStatusMessagesExample#beginNewGameRound(String)}
* </p>
*
* <p>The following example shows how to use annotations to store the default strings
* in the source file itself, rather than needing a properties file (you still need
* properties files for the translated strings):
*
* {@example com.google.gwt.examples.i18n.GameStatusMessagesAnnot}
* </p>
*
* <p>In this example, calling <code>msg.turnsLeft("John", 13)</code> would
* return the string <code>"Turns left for player 'John': 13"</code>.
* </p>
*
* <h3>Defining Message Accessors</h3>
* Message accessors must be of the form
*
* <pre>String methodName(<i>optional-params</i>)</pre>
*
* and parameters may be of any type. Arguments are converted into strings at
* runtime using Java string concatenation syntax (the '+' operator), which
* uniformly handles primitives, <code>null</code>, and invoking
* <code>toString()</code> to format objects.
*
* <p>
* Compile-time checks are performed to ensure that the number of placeholders
* in a message template (e.g. <code>{0}</code>) matches the number of
* parameters supplied.
* </p>
*
* <p>
* Integral arguments may be used to select the proper plural form to use for
* different locales. To do this, mark the particular argument with
* {@code @PluralCount} (a plural rule may be specified with
* {@code @PluralCount} if necessary, but you will almost never need to
* do this). The actual plural forms for the default locale can be supplied in a
* {@code @PluralText} annotation on the method, such as
* <code>@PluralText({"one", "You have one widget"})</code>, or they can be
* supplied in the properties file as {@code methodkey[one]=You have one widget}. Note
* that non-default plural forms are not inherited between locales, because the
* different locales may have different plural rules (especially {@code default} and
* anything else and those which use different scripts such as {@code sr_Cyrl} and
* {@code sr_Latn} [one of which would likely be the default], but also subtle cases
* like {@code pt} and {@code pt_BR}).
* </p>
*
* <p>
* Additionally, individual arguments can be marked as optional (ie, GWT will
* not give an error if a particular translation does not reference the
* argument) with the {@code @Optional} annotation, and an example may be supplied to
* the translator with the {@code @Example(String)} annotation.
* </p>
*
* <h3>Complete Annotations Example</h3>
* In addition to the default properties file, default text and additional
* metadata may be stored in the source file itself using annotations. A
* complete example of using annotations in this way is:
*
* <code><pre>
* &#64;Generate(format = "com.google.gwt.i18n.rebind.format.PropertiesFormat")
* &#64;DefaultLocale("en_US")
* public interface MyMessages extends Messages {
* &#64;Key("1234")
* &#64;DefaultText("This is a plain string.")
* String oneTwoThreeFour();
*
* &#64;DefaultText("You have {0} widgets")
* &#64;PluralText({"one", "You have one widget")
* String widgetCount(&#64;PluralCount int count);
*
* &#64;DefaultText("No reference to the argument")
* String optionalArg(&#64;Optional String ignored);
*
* &#64;DefaultText("Your cart total is {0,number,currency}")
* &#64;Description("The total value of the items in the shopping cart in local currency")
* String totalAmount(&#64;Example("$5.00") double amount);
*
* &#64;Meaning("the color")
* &#64;DefaultMessage("orange")
* String orangeColor();
*
* &#64;Meaning("the fruit")
* &#64;DefaultMessage("orange")
* String orangeFruit();
* }
* </pre></code>
*
* <h3>Binding to Properties Files</h3>
* Interfaces extending <code>Messages</code> are bound to resource files
* using the same algorithm as interfaces extending <code>Constants</code>.
* See the documentation for {@link Constants} for a description of the
* algorithm.
*
* <h3>Required Module</h3>
* Modules that use this interface should inherit
* <code>com.google.gwt.i18n.I18N</code>.
*
* {@gwt.include com/google/gwt/examples/i18n/InheritsExample.gwt.xml}
*
* <h3>Note</h3>
* You should not directly implement this interface or interfaces derived from
* it since an implementation is generated automatically when message interfaces
* are created using {@link com.google.gwt.core.client.GWT#create(Class)}.
*/
public interface Messages extends LocalizableResource {
/**
* Default text to be used if no translation is found (and also used as the
* source for translation). Format should be that expected by
* {@link java.text.MessageFormat}.
*
* <p>Example:
* <code><pre>
* &#64;DefaultMessage("Don''t panic - you have {0} widgets left")
* String example(int count)
* </pre></code>
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface DefaultMessage {
String value();
}
/**
* An example of the annotated parameter to assist translators.
*
* <p>Example:
* <code><pre>
* String example(&#64;Example("/etc/passwd") String fileName)
* </pre></code>
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Example {
String value();
}
/**
* Ignored except on parameters also tagged with {@link PluralCount}, and
* provides an offset to be subtracted from the value before a plural rule
* is chosen or the value is formatted. Note that "=n" forms are evaluated
* before this offset is applied.
*
* <p>Example:
* <code><pre>
* &#64;PluralText({"=0", "No one has recommended this movie",
* "=1", "{0} has recommended this movie",
* "=2", "{0} and {1} have recommended this movie",
* "one", "{0}, {1} and one other have recommended this movie"})
* &#64;DefaultMessage("{0}, {1} and {2,number} others have recommended this movie")
* String recommenders(&#64;Optional String rec1, &#64;Optional String rec2,
* &#64;PluralCount &#64;Offset(2) int count);
* </pre></code>
* would result in
* <code><pre>
* recommenders("John", null, 1) => "John has..."
* recommenders("John", "Jane", 3) => "John, Jane, and one other..."
* recommenders("John", "Jane", 1402) => "John, Jane, and 1,400 others..."
* </pre></code>
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Offset {
int value();
}
/**
* Indicates the specified parameter is optional and need not appear in a
* particular translation of this message.
*
* <p>Example:
* <code><pre>
* String example(&#64;Optional int count)
* </pre></code>
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Optional {
}
/**
* Provides multiple plural forms based on a count. The selection of which
* plural form is performed by a PluralRule implementation.
*
* This annotation is applied to a single parameter of a Messages subinterface
* and indicates that parameter is to be used to choose the proper plural form
* of the message. The parameter chosen must be of type short or int.
*
* Optionally, a class literal referring to a PluralRule implementation can be
* supplied as the argument if the standard implementation is insufficient.
*
* <p>Example:
* <code><pre>
* &#64;DefaultMessage("You have {0} widgets.")
* &#64;PluralText({"one", "You have one widget.")
* String example(&#64;PluralCount int count)
* </pre></code>
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface PluralCount {
/**
* The PluralRule implementation to use for this message. If not specified,
* the GWT-supplied one is used instead, which should cover most use cases.
*
* <p>{@code PluralRule.class} is used as a default value here, which will
* be replaced during code generation with the default implementation.
* </p>
*/
Class<? extends PluralRule> value() default PluralRule.class;
}
/**
* Provides multiple plural forms based on a count. The selection of which
* plural form to use is based on the value of the argument marked
* PluralCount, which may also specify an alternate plural rule to use.
*
* <p>Example:
* <code><pre>
* &#64;DefaultMessage("You have {0} widgets.")
* &#64;PluralText({"one", "You have one widget.")
* String example(&#64;PluralCount int count)
* </pre></code>
* </p>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface PluralText {
/**
* An array of pairs of strings containing the strings for different plural
* forms.
*
* Each pair is the name of the plural form (as returned by
* PluralForm.toString) followed by the string for that plural form. An
* example for a locale that has "none", "one", and "other" plural forms:
*
* <code><pre>
* &#64;DefaultMessage("{0} widgets")
* &#64;PluralText({"none", "No widgets", "one", "One widget"})
* </pre>
*
* "other" must not be included in this array as it will map to the
* DefaultMessage value.
*/
String[] value();
}
}