X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/46f4442e9a5a4f3b98b7c1083586332f6a8a99a4..b331163bffd790ced0e88b73f44f86d49ccc48a5:/icuSources/i18n/unicode/plurfmt.h?ds=sidebyside diff --git a/icuSources/i18n/unicode/plurfmt.h b/icuSources/i18n/unicode/plurfmt.h index 445db39b..f7099d81 100644 --- a/icuSources/i18n/unicode/plurfmt.h +++ b/icuSources/i18n/unicode/plurfmt.h @@ -1,15 +1,11 @@ /* ******************************************************************************* -* Copyright (C) 2007-2008, International Business Machines Corporation and +* Copyright (C) 2007-2014, International Business Machines Corporation and * others. All Rights Reserved. ******************************************************************************* * * File PLURFMT.H -* -* Modification History:* -* Date Name Description -* ******************************************************************************** */ @@ -25,19 +21,21 @@ #if !UCONFIG_NO_FORMATTING +#include "unicode/messagepattern.h" #include "unicode/numfmt.h" #include "unicode/plurrule.h" U_NAMESPACE_BEGIN class Hashtable; +class NFRule; /** *

* PluralFormat supports the creation of internationalized * messages with plural inflection. It is based on plural * selection, i.e. the caller specifies messages for each - * plural case that can appear in the users language and the + * plural case that can appear in the user's language and the * PluralFormat selects the appropriate message based on * the number. *

@@ -51,7 +49,7 @@ class Hashtable; * each message and selects the message whose interval contains a * given number. This can only handle a finite number of * intervals. But in some languages, like Polish, one plural case - * applies to infinitely many intervals (e.g., paucal applies to + * applies to infinitely many intervals (e.g., the plural case applies to * numbers ending with 2, 3, or 4 except those ending with 12, 13, or * 14). Thus ChoiceFormat is not adequate. *

@@ -62,15 +60,20 @@ class Hashtable; * conditions for a plural case than just a single interval. These plural * rules define both what plural cases exist in a language, and to * which numbers these cases apply. - *

  • It provides predefined plural rules for many locales. Thus, the programmer - * need not worry about the plural cases of a language. On the flip side, - * the localizer does not have to specify the plural cases; he can simply + *
  • It provides predefined plural rules for many languages. Thus, the programmer + * need not worry about the plural cases of a language and + * does not have to define the plural cases; they can simply * use the predefined keywords. The whole plural formatting of messages can - * be done using localized patterns from resource bundles. + * be done using localized patterns from resource bundles. For predefined plural + * rules, see the CLDR Language Plural Rules page at + * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html * *

    *

    Usage of PluralFormat

    - *

    + *

    Note: Typically, plural formatting is done via MessageFormat + * with a plural argument type, + * rather than using a stand-alone PluralFormat. + *

    * This discussion assumes that you use PluralFormat with * a predefined set of plural rules. You can create one using one of * the constructors that takes a locale object. To @@ -83,79 +86,46 @@ class Hashtable; *

    Patterns and Their Interpretation
    *

    * The pattern text defines the message output for each plural case of the - * used locale. The pattern is a sequence of - * caseKeyword{message} clauses, separated by white - * space characters. Each clause assigns the message message - * to the plural case identified by caseKeyword. + * specified locale. Syntax: + *

    + * pluralStyle = [offsetValue] (selector '{' message '}')+
    + * offsetValue = "offset:" number
    + * selector = explicitValue | keyword
    + * explicitValue = '=' number  // adjacent, no white space in between
    + * keyword = [^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+
    + * message: see {@link MessageFormat}
    + * 
    + * Pattern_White_Space between syntax elements is ignored, except + * between the {curly braces} and their sub-message, + * and between the '=' and the number of an explicitValue. + * *

    - * You always have to define a message text for the default plural case - * "other" which is contained in every rule set. If the plural - * rules of the PluralFormat object do not contain a plural case - * identified by caseKeyword, U_DEFAULT_KEYWORD_MISSING - * will be set to status. + * There are 6 predefined casekeyword in CLDR/ICU - 'zero', 'one', 'two', 'few', 'many' and + * 'other'. You always have to define a message text for the default plural case + * other which is contained in every rule set. * If you do not specify a message text for a particular plural case, the - * message text of the plural case "other" gets assigned to this - * plural case. If you specify more than one message for the same plural case, - * U_DUPLICATE_KEYWORD will be set to status. - *
    - * Spaces between caseKeyword and - * message will be ignored; spaces within - * message will be preserved. + * message text of the plural case other gets assigned to this + * plural case. + *

    + * When formatting, the input number is first matched against the explicitValue clauses. + * If there is no exact-number match, then a keyword is selected by calling + * the PluralRules with the input number minus the offset. + * (The offset defaults to 0 if it is omitted from the pattern string.) + * If there is no clause with that keyword, then the "other" clauses is returned. *

    - * The message text for a particular plural case may contain other message - * format patterns. PluralFormat preserves these so that you - * can use the strings produced by PluralFormat with other - * formatters. If you are using PluralFormat inside a - * MessageFormat pattern, MessageFormat will - * automatically evaluate the resulting format pattern.
    - * Thus, curly braces ({, }) are only allowed - * in message texts to define a nested format pattern.
    - * The pound sign (#) will be interpreted as the number placeholder - * in the message text, if it is not contained in curly braces (to preserve - * NumberFormat patterns). PluralFormat will - * replace each of those pound signs by the number passed to the - * format() method. It will be formatted using a + * An unquoted pound sign (#) in the selected sub-message + * itself (i.e., outside of arguments nested in the sub-message) + * is replaced by the input number minus the offset. + * The number-minus-offset value is formatted using a * NumberFormat for the PluralFormat's locale. If you - * need special number formatting, you have to explicitly specify a - * NumberFormat for the PluralFormat to use. - *

    - * Example - *
    - * UErrorCode status = U_ZERO_ERROR;
    - * MessageFormat* msgFmt = new MessageFormat(UnicodeString("{0, plural,
    - *   one{{0, number, C''est #,##0.0#  fichier}} other {Ce sont # fichiers}} dans la liste."),
    - *   Locale("fr"), status);
    - * if (U_FAILURE(status)) {
    - *     return;
    - * }
    - * Formattable args1[] = {(int32_t)0};
    - * Formattable args2[] = {(int32_t)3};
    - * FieldPosition ignore(FieldPosition::DONT_CARE);
    - * UnicodeString result;
    - * msgFmt->format(args1, 1, result, ignore, status);
    - * cout << result << endl;
    - * result.remove();
    - * msgFmt->format(args2, 1, result, ignore, status);
    - * cout << result << endl;
    - * 
    - * Produces the output:
    - * C'est 0,0 fichier dans la liste.
    - * Ce sont 3 fichiers dans la liste." - *

    - * Note:
    - * Currently PluralFormat - * does not make use of quotes like MessageFormat. - * If you use plural format strings with MessageFormat and want - * to use a quote sign "'", you have to write "''". - * MessageFormat unquotes this pattern and passes the unquoted - * pattern to PluralFormat. It's a bit trickier if you use - * nested formats that do quoting. In the example above, we wanted to insert - * "'" in the number format pattern. Since - * NumberFormat supports quotes, we had to insert - * "''". But since MessageFormat unquotes the - * pattern before it gets passed to PluralFormat, we have to - * double these quotes, i.e. write "''''". + * need special number formatting, you have to use a MessageFormat + * and explicitly specify a NumberFormat argument. + * Note: That argument is formatting without subtracting the offset! + * If you need a custom format and have a non-zero offset, then you need to pass the + * number-minus-offset value as a separate parameter. *

    + * For a usage example, see the {@link MessageFormat} class documentation. + * *

    Defining Custom Plural Rules

    *

    If you need to use PluralFormat with custom rules, you can * create a PluralRules object and pass it to @@ -168,30 +138,30 @@ class Hashtable; *

    * * ported from Java - * @draft ICU 4.0 + * @stable ICU 4.0 */ class U_I18N_API PluralFormat : public Format { public: /** - * Creates a new PluralFormat for the default locale. + * Creates a new cardinal-number PluralFormat for the default locale. * This locale will be used to get the set of plural rules and for standard * number formatting. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @stable ICU 4.0 */ PluralFormat(UErrorCode& status); /** - * Creates a new PluralFormat for a given locale. + * Creates a new cardinal-number PluralFormat for a given locale. * @param locale the PluralFormat will be configured with * rules for this locale. This locale will also be used for * standard number formatting. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @stable ICU 4.0 */ PluralFormat(const Locale& locale, UErrorCode& status); @@ -202,7 +172,7 @@ public: * object. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @stable ICU 4.0 */ PluralFormat(const PluralRules& rules, UErrorCode& status); @@ -215,24 +185,41 @@ public: * object. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @stable ICU 4.0 + *

    + *

    Sample code

    + * \snippet samples/plurfmtsample/plurfmtsample.cpp PluralFormatExample1 + * \snippet samples/plurfmtsample/plurfmtsample.cpp PluralFormatExample + *

    */ PluralFormat(const Locale& locale, const PluralRules& rules, UErrorCode& status); /** - * Creates a new PluralFormat for a given pattern string. + * Creates a new PluralFormat for the plural type. + * The standard number formatting will be done using the given locale. + * @param locale the default number formatting will be done using this + * locale. + * @param type The plural type (e.g., cardinal or ordinal). + * @param status output param set to success/failure code on exit, which + * must not indicate a failure before the function call. + * @stable ICU 50 + */ + PluralFormat(const Locale& locale, UPluralType type, UErrorCode& status); + + /** + * Creates a new cardinal-number PluralFormat for a given pattern string. * The default locale will be used to get the set of plural rules and for * standard number formatting. * @param pattern the pattern for this PluralFormat. * errors are returned to status if the pattern is invalid. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @stable ICU 4.0 */ PluralFormat(const UnicodeString& pattern, UErrorCode& status); /** - * Creates a new PluralFormat for a given pattern string and + * Creates a new cardinal-number PluralFormat for a given pattern string and * locale. * The locale will be used to get the set of plural rules and for * standard number formatting. @@ -243,7 +230,7 @@ public: * errors are returned to status if the pattern is invalid. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @stable ICU 4.0 */ PluralFormat(const Locale& locale, const UnicodeString& pattern, UErrorCode& status); @@ -256,7 +243,7 @@ public: * errors are returned to status if the pattern is invalid. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @stable ICU 4.0 */ PluralFormat(const PluralRules& rules, const UnicodeString& pattern, @@ -274,22 +261,40 @@ public: * errors are returned to status if the pattern is invalid. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @stable ICU 4.0 */ PluralFormat(const Locale& locale, const PluralRules& rules, const UnicodeString& pattern, UErrorCode& status); + /** + * Creates a new PluralFormat for a plural type, a + * pattern and a locale. + * @param locale the PluralFormat will be configured with + * rules for this locale. This locale will also be used for + * standard number formatting. + * @param type The plural type (e.g., cardinal or ordinal). + * @param pattern the pattern for this PluralFormat. + * errors are returned to status if the pattern is invalid. + * @param status output param set to success/failure code on exit, which + * must not indicate a failure before the function call. + * @stable ICU 50 + */ + PluralFormat(const Locale& locale, + UPluralType type, + const UnicodeString& pattern, + UErrorCode& status); + /** * copy constructor. - * @draft ICU 4.0 + * @stable ICU 4.0 */ PluralFormat(const PluralFormat& other); /** * Destructor. - * @draft ICU 4.0 + * @stable ICU 4.0 */ virtual ~PluralFormat(); @@ -303,10 +308,13 @@ public: * errors are returned to status if the pattern is invalid. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @stable ICU 4.0 */ void applyPattern(const UnicodeString& pattern, UErrorCode& status); + + using Format::format; + /** * Formats a plural message for a given number. * @@ -317,21 +325,21 @@ public: * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. * @return the string containing the formatted plural message. - * @draft ICU 4.0 + * @stable ICU 4.0 */ - UnicodeString format(int32_t number, UErrorCode& status) const; - + UnicodeString format(int32_t number, UErrorCode& status) const; + /** * Formats a plural message for a given number. * * @param number a number for which the plural message should be formatted * for. If no pattern has been applied to this - * PluralFormat object yet, the formatted number + * PluralFormat object yet, the formatted number * will be returned. - * @param status output param set to success/failure code on exit, which + * @param status output param set to success or failure code on exit, which * must not indicate a failure before the function call. * @return the string containing the formatted plural message. - * @draft ICU 4.0 + * @stable ICU 4.0 */ UnicodeString format(double number, UErrorCode& status) const; @@ -349,19 +357,19 @@ public: * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. * @return the string containing the formatted plural message. - * @draft ICU 4.0 + * @stable ICU 4.0 */ UnicodeString& format(int32_t number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const; - + /** * Formats a plural message for a given number. * * @param number a number for which the plural message should be formatted * for. If no pattern has been applied to this - * PluralFormat object yet, the formatted number + * PluralFormat object yet, the formatted number * will be returned. * @param appendTo output parameter to receive result. * result is appended to existing contents. @@ -370,26 +378,31 @@ public: * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. * @return the string containing the formatted plural message. - * @draft ICU 4.0 + * @stable ICU 4.0 */ UnicodeString& format(double number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const; +#ifndef U_HIDE_DEPRECATED_API /** * Sets the locale used by this PluraFormat object. * Note: Calling this method resets this PluraFormat object, * i.e., a pattern that was applied previously will be removed, * and the NumberFormat is set to the default number format for * the locale. The resulting format behaves the same as one - * constructed from {@link #PluralFormat(locale)}. + * constructed from {@link #PluralFormat(const Locale& locale, UPluralType type, UErrorCode& status)} + * with UPLURAL_TYPE_CARDINAL. * @param locale the locale to use to configure the formatter. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @deprecated ICU 50 This method clears the pattern and might create + * a different kind of PluralRules instance; + * use one of the constructors to create a new instance instead. */ void setLocale(const Locale& locale, UErrorCode& status); +#endif /* U_HIDE_DEPRECATED_API */ /** * Sets the number format used by this formatter. You only need to @@ -398,7 +411,7 @@ public: * @param format the number format to use. * @param status output param set to success/failure code on exit, which * must not indicate a failure before the function call. - * @draft ICU 4.0 + * @stable ICU 4.0 */ void setNumberFormat(const NumberFormat* format, UErrorCode& status); @@ -406,7 +419,7 @@ public: * Assignment operator * * @param other the PluralFormat object to copy from. - * @draft ICU 4.0 + * @stable ICU 4.0 */ PluralFormat& operator=(const PluralFormat& other); @@ -415,7 +428,7 @@ public: * * @param other the PluralFormat object to be compared with. * @return true if other is semantically equal to this. - * @draft ICU 4.0 + * @stable ICU 4.0 */ virtual UBool operator==(const Format& other) const; @@ -424,28 +437,30 @@ public: * * @param other the PluralFormat object to be compared with. * @return true if other is semantically unequal to this. - * @draft ICU 4.0 + * @stable ICU 4.0 */ virtual UBool operator!=(const Format& other) const; /** * Clones this Format object polymorphically. The caller owns the * result and should delete it when done. - * @draft ICU 4.0 + * @stable ICU 4.0 */ virtual Format* clone(void) const; - /** - * Redeclared Format method. + /** + * Formats a plural message for a number taken from a Formattable object. * - * @param obj The object to be formatted into a string. + * @param obj The object containing a number for which the + * plural message should be formatted. + * The object must be of a numeric type. * @param appendTo output parameter to receive result. * Result is appended to existing contents. * @param pos On input: an alignment field, if desired. * On output: the offsets of the alignment field. * @param status output param filled with success/failure status. * @return Reference to 'appendTo' parameter. - * @draft ICU 4.0 + * @stable ICU 4.0 */ UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, @@ -458,7 +473,7 @@ public: * @param appendTo output parameter to receive result. * Result is appended to existing contents. * @return the UnicodeString with inserted pattern. - * @draft ICU 4.0 + * @stable ICU 4.0 */ UnicodeString& toPattern(UnicodeString& appendTo); @@ -482,7 +497,7 @@ public: * last character successfully parsed. If the * source is not parsed successfully, this param * will remain unchanged. - * @draft ICU 4.0 + * @stable ICU 4.0 */ virtual void parseObject(const UnicodeString& source, Formattable& result, @@ -491,7 +506,7 @@ public: /** * ICU "poor man's RTTI", returns a UClassID for this class. * - * @draft ICU 4.0 + * @stable ICU 4.0 * */ static UClassID U_EXPORT2 getStaticClassID(void); @@ -499,38 +514,97 @@ public: /** * ICU "poor man's RTTI", returns a UClassID for the actual class. * - * @draft ICU 4.0 + * @stable ICU 4.0 */ virtual UClassID getDynamicClassID() const; +#if (defined(__xlC__) && (__xlC__ < 0x0C00)) || (U_PLATFORM == U_PF_OS390) || (U_PLATFORM ==U_PF_OS400) +// Work around a compiler bug on xlC 11.1 on AIX 7.1 that would +// prevent PluralSelectorAdapter from implementing private PluralSelector. +// xlC error message: +// 1540-0300 (S) The "private" member "class icu_49::PluralFormat::PluralSelector" cannot be accessed. +public: +#else private: - typedef enum fmtToken { - none, - tLetter, - tNumber, - tSpace, - tNumberSign, - tLeftBrace, - tRightBrace - }fmtToken; +#endif + /** + * @internal + */ + class U_I18N_API PluralSelector : public UMemory { + public: + virtual ~PluralSelector(); + /** + * Given a number, returns the appropriate PluralFormat keyword. + * + * @param context worker object for the selector. + * @param number The number to be plural-formatted. + * @param ec Error code. + * @return The selected PluralFormat keyword. + * @internal + */ + virtual UnicodeString select(void *context, double number, UErrorCode& ec) const = 0; + }; + + /** + * @internal + */ + class U_I18N_API PluralSelectorAdapter : public PluralSelector { + public: + PluralSelectorAdapter() : pluralRules(NULL) { + } + + virtual ~PluralSelectorAdapter(); + + virtual UnicodeString select(void *context, double number, UErrorCode& /*ec*/) const; /**< @internal */ + + void reset(); + PluralRules* pluralRules; + }; + +#if defined(__xlC__) +// End of xlC bug workaround, keep remaining definitions private. +private: +#endif Locale locale; - PluralRules* pluralRules; - UnicodeString pattern; - Hashtable *fParsedValuesHash; + MessagePattern msgPattern; NumberFormat* numberFormat; - NumberFormat* replacedNumberFormat; + double offset; + PluralSelectorAdapter pluralRulesWrapper; PluralFormat(); // default constructor not implemented - void init(const PluralRules* rules, const Locale& curlocale, UErrorCode& status); - UBool inRange(UChar ch, fmtToken& type); - UBool checkSufficientDefinition(); - void parsingFailure(); - UnicodeString insertFormattedNumber(double number, - UnicodeString& message, - UnicodeString& appendTo, - FieldPosition& pos) const; - void copyHashtable(Hashtable *other, UErrorCode& status); + void init(const PluralRules* rules, UPluralType type, UErrorCode& status); + /** + * Copies dynamically allocated values (pointer fields). + * Others are copied using their copy constructors and assignment operators. + */ + void copyObjects(const PluralFormat& other); + + UnicodeString& format(const Formattable& numberObject, double number, + UnicodeString& appendTo, + FieldPosition& pos, + UErrorCode& status) const; /**< @internal */ + + /** + * Finds the PluralFormat sub-message for the given number, or the "other" sub-message. + * @param pattern A MessagePattern. + * @param partIndex the index of the first PluralFormat argument style part. + * @param selector the PluralSelector for mapping the number (minus offset) to a keyword. + * @param context worker object for the selector. + * @param number a number to be matched to one of the PluralFormat argument's explicit values, + * or mapped via the PluralSelector. + * @param ec ICU error code. + * @return the sub-message start part index. + */ + static int32_t findSubMessage( + const MessagePattern& pattern, int32_t partIndex, + const PluralSelector& selector, void *context, double number, UErrorCode& ec); /**< @internal */ + + void parseType(const UnicodeString& source, const NFRule *rbnfLenientScanner, + Formattable& result, FieldPosition& pos) const; + + friend class MessageFormat; + friend class NFRule; }; U_NAMESPACE_END