39 * A pair of adjacent apostrophes always results in a single apostrophe in the output, 40 * even when the pair is between two single, text-quoting apostrophes. 41 *
42 * The following table shows examples of desired MessageFormat.format() output 43 * with the pattern strings that yield that output. 44 *
45 *
79 * This is the default behavior starting with ICU 4.8. 80 * @stable ICU 4.8 81 */ 82 UMSGPAT_APOS_DOUBLE_OPTIONAL, 83 /** 84 * A literal apostrophe must be represented by 85 * a double apostrophe pattern character. 86 * A single apostrophe always starts quoted literal text. 87 *
88 * This is the behavior of ICU 4.6 and earlier, and of the JDK. 89 * @stable ICU 4.8 90 */ 91 UMSGPAT_APOS_DOUBLE_REQUIRED 92 }; 93 /** 94 * @stable ICU 4.8 95 */ 96 typedef enum UMessagePatternApostropheMode UMessagePatternApostropheMode; 97 98 /** 99 * MessagePattern::Part type constants. 100 * @stable ICU 4.8 101 */ 102 enum UMessagePatternPartType { 103 /** 104 * Start of a message pattern (main or nested). 105 * The length is 0 for the top-level message 106 * and for a choice argument sub-message, otherwise 1 for the '{'. 107 * The value indicates the nesting level, starting with 0 for the main message. 108 *
109 * There is always a later MSG_LIMIT part. 110 * @stable ICU 4.8 111 */ 112 UMSGPAT_PART_TYPE_MSG_START, 113 /** 114 * End of a message pattern (main or nested). 115 * The length is 0 for the top-level message and 116 * the last sub-message of a choice argument, 117 * otherwise 1 for the '}' or (in a choice argument style) the '|'. 118 * The value indicates the nesting level, starting with 0 for the main message. 119 * @stable ICU 4.8 120 */ 121 UMSGPAT_PART_TYPE_MSG_LIMIT, 122 /** 123 * Indicates a substring of the pattern string which is to be skipped when formatting. 124 * For example, an apostrophe that begins or ends quoted text 125 * would be indicated with such a part. 126 * The value is undefined and currently always 0. 127 * @stable ICU 4.8 128 */ 129 UMSGPAT_PART_TYPE_SKIP_SYNTAX, 130 /** 131 * Indicates that a syntax character needs to be inserted for auto-quoting. 132 * The length is 0. 133 * The value is the character code of the insertion character. (U+0027=APOSTROPHE) 134 * @stable ICU 4.8 135 */ 136 UMSGPAT_PART_TYPE_INSERT_CHAR, 137 /** 138 * Indicates a syntactic (non-escaped) # symbol in a plural variant. 139 * When formatting, replace this part's substring with the 140 * (value-offset) for the plural argument value. 141 * The value is undefined and currently always 0. 142 * @stable ICU 4.8 143 */ 144 UMSGPAT_PART_TYPE_REPLACE_NUMBER, 145 /** 146 * Start of an argument. 147 * The length is 1 for the '{'. 148 * The value is the ordinal value of the ArgType. Use getArgType(). 149 *
150 * This part is followed by either an ARG_NUMBER or ARG_NAME, 151 * followed by optional argument sub-parts (see UMessagePatternArgType constants) 152 * and finally an ARG_LIMIT part. 153 * @stable ICU 4.8 154 */ 155 UMSGPAT_PART_TYPE_ARG_START, 156 /** 157 * End of an argument. 158 * The length is 1 for the '}'. 159 * The value is the ordinal value of the ArgType. Use getArgType(). 160 * @stable ICU 4.8 161 */ 162 UMSGPAT_PART_TYPE_ARG_LIMIT, 163 /** 164 * The argument number, provided by the value. 165 * @stable ICU 4.8 166 */ 167 UMSGPAT_PART_TYPE_ARG_NUMBER, 168 /** 169 * The argument name. 170 * The value is undefined and currently always 0. 171 * @stable ICU 4.8 172 */ 173 UMSGPAT_PART_TYPE_ARG_NAME, 174 /** 175 * The argument type. 176 * The value is undefined and currently always 0. 177 * @stable ICU 4.8 178 */ 179 UMSGPAT_PART_TYPE_ARG_TYPE, 180 /** 181 * The argument style text. 182 * The value is undefined and currently always 0. 183 * @stable ICU 4.8 184 */ 185 UMSGPAT_PART_TYPE_ARG_STYLE, 186 /** 187 * A selector substring in a "complex" argument style. 188 * The value is undefined and currently always 0. 189 * @stable ICU 4.8 190 */ 191 UMSGPAT_PART_TYPE_ARG_SELECTOR, 192 /** 193 * An integer value, for example the offset or an explicit selector value 194 * in a PluralFormat style. 195 * The part value is the integer value. 196 * @stable ICU 4.8 197 */ 198 UMSGPAT_PART_TYPE_ARG_INT, 199 /** 200 * A numeric value, for example the offset or an explicit selector value 201 * in a PluralFormat style. 202 * The part value is an index into an internal array of numeric values; 203 * use getNumericValue(). 204 * @stable ICU 4.8 205 */ 206 UMSGPAT_PART_TYPE_ARG_DOUBLE 207 }; 208 /** 209 * @stable ICU 4.8 210 */ 211 typedef enum UMessagePatternPartType UMessagePatternPartType; 212 213 /** 214 * Argument type constants. 215 * Returned by Part.getArgType() for ARG_START and ARG_LIMIT parts. 216 * 217 * Messages nested inside an argument are each delimited by MSG_START and MSG_LIMIT, 218 * with a nesting level one greater than the surrounding message. 219 * @stable ICU 4.8 220 */ 221 enum UMessagePatternArgType { 222 /** 223 * The argument has no specified type. 224 * @stable ICU 4.8 225 */ 226 UMSGPAT_ARG_TYPE_NONE, 227 /** 228 * The argument has a "simple" type which is provided by the ARG_TYPE part. 229 * An ARG_STYLE part might follow that. 230 * @stable ICU 4.8 231 */ 232 UMSGPAT_ARG_TYPE_SIMPLE, 233 /** 234 * The argument is a ChoiceFormat with one or more 235 * ((ARG_INT | ARG_DOUBLE), ARG_SELECTOR, message) tuples. 236 * @stable ICU 4.8 237 */ 238 UMSGPAT_ARG_TYPE_CHOICE, 239 /** 240 * The argument is a cardinal-number PluralFormat with an optional ARG_INT or ARG_DOUBLE offset 241 * (e.g., offset:1) 242 * and one or more (ARG_SELECTOR [explicit-value] message) tuples. 243 * If the selector has an explicit value (e.g., =2), then 244 * that value is provided by the ARG_INT or ARG_DOUBLE part preceding the message. 245 * Otherwise the message immediately follows the ARG_SELECTOR. 246 * @stable ICU 4.8 247 */ 248 UMSGPAT_ARG_TYPE_PLURAL, 249 /** 250 * The argument is a SelectFormat with one or more (ARG_SELECTOR, message) pairs. 251 * @stable ICU 4.8 252 */ 253 UMSGPAT_ARG_TYPE_SELECT, 254 /** 255 * The argument is an ordinal-number PluralFormat 256 * with the same style parts sequence and semantics as UMSGPAT_ARG_TYPE_PLURAL. 257 * @stable ICU 50 258 */ 259 UMSGPAT_ARG_TYPE_SELECTORDINAL 260 }; 261 /** 262 * @stable ICU 4.8 263 */ 264 typedef enum UMessagePatternArgType UMessagePatternArgType; 265 266 /** 267 * \def UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE 268 * Returns true if the argument type has a plural style part sequence and semantics, 269 * for example UMSGPAT_ARG_TYPE_PLURAL and UMSGPAT_ARG_TYPE_SELECTORDINAL. 270 * @stable ICU 50 271 */ 272 #define UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) \ 273 ((argType)==UMSGPAT_ARG_TYPE_PLURAL || (argType)==UMSGPAT_ARG_TYPE_SELECTORDINAL) 274 275 enum { 276 /** 277 * Return value from MessagePattern.validateArgumentName() for when 278 * the string is a valid "pattern identifier" but not a number. 279 * @stable ICU 4.8 280 */ 281 UMSGPAT_ARG_NAME_NOT_NUMBER=-1, 282 283 /** 284 * Return value from MessagePattern.validateArgumentName() for when 285 * the string is invalid. 286 * It might not be a valid "pattern identifier", 287 * or it have only ASCII digits but there is a leading zero or the number is too large. 288 * @stable ICU 4.8 289 */ 290 UMSGPAT_ARG_NAME_NOT_VALID=-2 291 }; 292 293 /** 294 * Special value that is returned by getNumericValue(Part) when no 295 * numeric value is defined for a part. 296 * @see MessagePattern.getNumericValue() 297 * @stable ICU 4.8 298 */ 299 #define UMSGPAT_NO_NUMERIC_VALUE ((double)(-123456789)) 300 301 U_NAMESPACE_BEGIN 302 303 class MessagePatternDoubleList; 304 class MessagePatternPartsList; 305 306 /** 307 * Parses and represents ICU MessageFormat patterns. 308 * Also handles patterns for ChoiceFormat, PluralFormat and SelectFormat. 309 * Used in the implementations of those classes as well as in tools 310 * for message validation, translation and format conversion. 311 *
312 * The parser handles all syntax relevant for identifying message arguments. 313 * This includes "complex" arguments whose style strings contain 314 * nested MessageFormat pattern substrings. 315 * For "simple" arguments (with no nested MessageFormat pattern substrings), 316 * the argument style is not parsed any further. 317 *
318 * The parser handles named and numbered message arguments and allows both in one message. 319 *
320 * Once a pattern has been parsed successfully, iterate through the parsed data 321 * with countParts(), getPart() and related methods. 322 *
323 * The data logically represents a parse tree, but is stored and accessed 324 * as a list of "parts" for fast and simple parsing and to minimize object allocations. 325 * Arguments and nested messages are best handled via recursion. 326 * For every _START "part", MessagePattern.getLimitPartIndex() efficiently returns 327 * the index of the corresponding _LIMIT "part". 328 *
329 * List of "parts": 330 *
331 * message = MSG_START (SKIP_SYNTAX | INSERT_CHAR | REPLACE_NUMBER | argument)* MSG_LIMIT 332 * argument = noneArg | simpleArg | complexArg 333 * complexArg = choiceArg | pluralArg | selectArg 334 * 335 * noneArg = ARG_START.NONE (ARG_NAME | ARG_NUMBER) ARG_LIMIT.NONE 336 * simpleArg = ARG_START.SIMPLE (ARG_NAME | ARG_NUMBER) ARG_TYPE [ARG_STYLE] ARG_LIMIT.SIMPLE 337 * choiceArg = ARG_START.CHOICE (ARG_NAME | ARG_NUMBER) choiceStyle ARG_LIMIT.CHOICE 338 * pluralArg = ARG_START.PLURAL (ARG_NAME | ARG_NUMBER) pluralStyle ARG_LIMIT.PLURAL 339 * selectArg = ARG_START.SELECT (ARG_NAME | ARG_NUMBER) selectStyle ARG_LIMIT.SELECT 340 * 341 * choiceStyle = ((ARG_INT | ARG_DOUBLE) ARG_SELECTOR message)+ 342 * pluralStyle = [ARG_INT | ARG_DOUBLE] (ARG_SELECTOR [ARG_INT | ARG_DOUBLE] message)+ 343 * selectStyle = (ARG_SELECTOR message)+ 344 *
ARG_START.CHOICE
358 * This class is not intended for public subclassing. 359 * 360 * @stable ICU 4.8 361 */ 362 class U_COMMON_API MessagePattern : public UObject { 363 public: 364 /** 365 * Constructs an empty MessagePattern with default UMessagePatternApostropheMode. 366 * @param errorCode Standard ICU error code. Its input value must 367 * pass the U_SUCCESS() test, or else the function returns 368 * immediately. Check for U_FAILURE() on output or use with 369 * function chaining. (See User Guide for details.) 370 * @stable ICU 4.8 371 */ 372 MessagePattern(UErrorCode &errorCode); 373 374 /** 375 * Constructs an empty MessagePattern. 376 * @param mode Explicit UMessagePatternApostropheMode. 377 * @param errorCode Standard ICU error code. Its input value must 378 * pass the U_SUCCESS() test, or else the function returns 379 * immediately. Check for U_FAILURE() on output or use with 380 * function chaining. (See User Guide for details.) 381 * @stable ICU 4.8 382 */ 383 MessagePattern(UMessagePatternApostropheMode mode, UErrorCode &errorCode); 384 385 /** 386 * Constructs a MessagePattern with default UMessagePatternApostropheMode and 387 * parses the MessageFormat pattern string. 388 * @param pattern a MessageFormat pattern string 389 * @param parseError Struct to receive information on the position 390 * of an error within the pattern. 391 * Can be nullptr. 392 * @param errorCode Standard ICU error code. Its input value must 393 * pass the U_SUCCESS() test, or else the function returns 394 * immediately. Check for U_FAILURE() on output or use with 395 * function chaining. (See User Guide for details.) 396 * TODO: turn @throws into UErrorCode specifics? 397 * @throws IllegalArgumentException for syntax errors in the pattern string 398 * @throws IndexOutOfBoundsException if certain limits are exceeded 399 * (e.g., argument number too high, argument name too long, etc.) 400 * @throws NumberFormatException if a number could not be parsed 401 * @stable ICU 4.8 402 */ 403 MessagePattern(const UnicodeString &pattern, UParseError *parseError, UErrorCode &errorCode); 404 405 /** 406 * Copy constructor. 407 * @param other Object to copy. 408 * @stable ICU 4.8 409 */ 410 MessagePattern(const MessagePattern &other); 411 412 /** 413 * Assignment operator. 414 * @param other Object to copy. 415 * @return *this=other 416 * @stable ICU 4.8 417 */ 418 MessagePattern &operator=(const MessagePattern &other); 419 420 /** 421 * Destructor. 422 * @stable ICU 4.8 423 */ 424 virtual ~MessagePattern(); 425 426 /** 427 * Parses a MessageFormat pattern string. 428 * @param pattern a MessageFormat pattern string 429 * @param parseError Struct to receive information on the position 430 * of an error within the pattern. 431 * Can be nullptr. 432 * @param errorCode Standard ICU error code. Its input value must 433 * pass the U_SUCCESS() test, or else the function returns 434 * immediately. Check for U_FAILURE() on output or use with 435 * function chaining. (See User Guide for details.) 436 * @return *this 437 * @throws IllegalArgumentException for syntax errors in the pattern string 438 * @throws IndexOutOfBoundsException if certain limits are exceeded 439 * (e.g., argument number too high, argument name too long, etc.) 440 * @throws NumberFormatException if a number could not be parsed 441 * @stable ICU 4.8 442 */ 443 MessagePattern &parse(const UnicodeString &pattern, 444 UParseError *parseError, UErrorCode &errorCode); 445 446 /** 447 * Parses a ChoiceFormat pattern string. 448 * @param pattern a ChoiceFormat pattern string 449 * @param parseError Struct to receive information on the position 450 * of an error within the pattern. 451 * Can be nullptr. 452 * @param errorCode Standard ICU error code. Its input value must 453 * pass the U_SUCCESS() test, or else the function returns 454 * immediately. Check for U_FAILURE() on output or use with 455 * function chaining. (See User Guide for details.) 456 * @return *this 457 * @throws IllegalArgumentException for syntax errors in the pattern string 458 * @throws IndexOutOfBoundsException if certain limits are exceeded 459 * (e.g., argument number too high, argument name too long, etc.) 460 * @throws NumberFormatException if a number could not be parsed 461 * @stable ICU 4.8 462 */ 463 MessagePattern &parseChoiceStyle(const UnicodeString &pattern, 464 UParseError *parseError, UErrorCode &errorCode); 465 466 /** 467 * Parses a PluralFormat pattern string. 468 * @param pattern a PluralFormat pattern string 469 * @param parseError Struct to receive information on the position 470 * of an error within the pattern. 471 * Can be nullptr. 472 * @param errorCode Standard ICU error code. Its input value must 473 * pass the U_SUCCESS() test, or else the function returns 474 * immediately. Check for U_FAILURE() on output or use with 475 * function chaining. (See User Guide for details.) 476 * @return *this 477 * @throws IllegalArgumentException for syntax errors in the pattern string 478 * @throws IndexOutOfBoundsException if certain limits are exceeded 479 * (e.g., argument number too high, argument name too long, etc.) 480 * @throws NumberFormatException if a number could not be parsed 481 * @stable ICU 4.8 482 */ 483 MessagePattern &parsePluralStyle(const UnicodeString &pattern, 484 UParseError *parseError, UErrorCode &errorCode); 485 486 /** 487 * Parses a SelectFormat pattern string. 488 * @param pattern a SelectFormat pattern string 489 * @param parseError Struct to receive information on the position 490 * of an error within the pattern. 491 * Can be nullptr. 492 * @param errorCode Standard ICU error code. Its input value must 493 * pass the U_SUCCESS() test, or else the function returns 494 * immediately. Check for U_FAILURE() on output or use with 495 * function chaining. (See User Guide for details.) 496 * @return *this 497 * @throws IllegalArgumentException for syntax errors in the pattern string 498 * @throws IndexOutOfBoundsException if certain limits are exceeded 499 * (e.g., argument number too high, argument name too long, etc.) 500 * @throws NumberFormatException if a number could not be parsed 501 * @stable ICU 4.8 502 */ 503 MessagePattern &parseSelectStyle(const UnicodeString &pattern, 504 UParseError *parseError, UErrorCode &errorCode); 505 506 /** 507 * Clears this MessagePattern. 508 * countParts() will return 0. 509 * @stable ICU 4.8 510 */ 511 void clear(); 512 513 /** 514 * Clears this MessagePattern and sets the UMessagePatternApostropheMode. 515 * countParts() will return 0. 516 * @param mode The new UMessagePatternApostropheMode. 517 * @stable ICU 4.8 518 */ 519 void clearPatternAndSetApostropheMode(UMessagePatternApostropheMode mode) { 520 clear(); 521 aposMode=mode; 522 } 523 524 /** 525 * @param other another object to compare with. 526 * @return true if this object is equivalent to the other one. 527 * @stable ICU 4.8 528 */ 529 bool operator==(const MessagePattern &other) const; 530 531 /** 532 * @param other another object to compare with. 533 * @return false if this object is equivalent to the other one. 534 * @stable ICU 4.8 535 */ 536 inline bool operator!=(const MessagePattern &other) const { 537 return !operator==(other); 538 } 539 540 /** 541 * @return A hash code for this object. 542 * @stable ICU 4.8 543 */ 544 int32_t hashCode() const; 545 546 /** 547 * @return this instance's UMessagePatternApostropheMode. 548 * @stable ICU 4.8 549 */ 550 UMessagePatternApostropheMode getApostropheMode() const { 551 return aposMode; 552 } 553 554 // Java has package-private jdkAposMode() here. 555 // In C++, this is declared in the MessageImpl class. 556 557 /** 558 * @return the parsed pattern string (null if none was parsed). 559 * @stable ICU 4.8 560 */ 561 const UnicodeString &getPatternString() const { 562 return msg; 563 } 564 565 /** 566 * Does the parsed pattern have named arguments like {first_name}? 567 * @return true if the parsed pattern has at least one named argument. 568 * @stable ICU 4.8 569 */ 570 UBool hasNamedArguments() const { 571 return hasArgNames; 572 } 573 574 /** 575 * Does the parsed pattern have numbered arguments like {2}? 576 * @return true if the parsed pattern has at least one numbered argument. 577 * @stable ICU 4.8 578 */ 579 UBool hasNumberedArguments() const { 580 return hasArgNumbers; 581 } 582 583 /** 584 * Validates and parses an argument name or argument number string. 585 * An argument name must be a "pattern identifier", that is, it must contain 586 * no Unicode Pattern_Syntax or Pattern_White_Space characters. 587 * If it only contains ASCII digits, then it must be a small integer with no leading zero. 588 * @param name Input string. 589 * @return >=0 if the name is a valid number, 590 * ARG_NAME_NOT_NUMBER (-1) if it is a "pattern identifier" but not all ASCII digits, 591 * ARG_NAME_NOT_VALID (-2) if it is neither. 592 * @stable ICU 4.8 593 */ 594 static int32_t validateArgumentName(const UnicodeString &name); 595 596 /** 597 * Returns a version of the parsed pattern string where each ASCII apostrophe 598 * is doubled (escaped) if it is not already, and if it is not interpreted as quoting syntax. 599 *
600 * For example, this turns "I don't '{know}' {gender,select,female{h''er}other{h'im}}." 601 * into "I don''t '{know}' {gender,select,female{h''er}other{h''im}}." 602 * @return the deep-auto-quoted version of the parsed pattern string. 603 * @see MessageFormat.autoQuoteApostrophe() 604 * @stable ICU 4.8 605 */ 606 UnicodeString autoQuoteApostropheDeep() const; 607 608 class Part; 609 610 /** 611 * Returns the number of "parts" created by parsing the pattern string. 612 * Returns 0 if no pattern has been parsed or clear() was called. 613 * @return the number of pattern parts. 614 * @stable ICU 4.8 615 */ 616 int32_t countParts() const { 617 return partsLength; 618 } 619 620 /** 621 * Gets the i-th pattern "part". 622 * @param i The index of the Part data. (0..countParts()-1) 623 * @return the i-th pattern "part". 624 * @stable ICU 4.8 625 */ 626 const Part &getPart(int32_t i) const { 627 return parts[i]; 628 } 629 630 /** 631 * Returns the UMessagePatternPartType of the i-th pattern "part". 632 * Convenience method for getPart(i).getType(). 633 * @param i The index of the Part data. (0..countParts()-1) 634 * @return The UMessagePatternPartType of the i-th Part. 635 * @stable ICU 4.8 636 */ 637 UMessagePatternPartType getPartType(int32_t i) const { 638 return getPart(i).type; 639 } 640 641 /** 642 * Returns the pattern index of the specified pattern "part". 643 * Convenience method for getPart(partIndex).getIndex(). 644 * @param partIndex The index of the Part data. (0..countParts()-1) 645 * @return The pattern index of this Part. 646 * @stable ICU 4.8 647 */ 648 int32_t getPatternIndex(int32_t partIndex) const { 649 return getPart(partIndex).index; 650 } 651 652 /** 653 * Returns the substring of the pattern string indicated by the Part. 654 * Convenience method for getPatternString().substring(part.getIndex(), part.getLimit()). 655 * @param part a part of this MessagePattern. 656 * @return the substring associated with part. 657 * @stable ICU 4.8 658 */ 659 UnicodeString getSubstring(const Part &part) const { 660 return msg.tempSubString(part.index, part.length); 661 } 662 663 /** 664 * Compares the part's substring with the input string s. 665 * @param part a part of this MessagePattern. 666 * @param s a string. 667 * @return true if getSubstring(part).equals(s). 668 * @stable ICU 4.8 669 */ 670 UBool partSubstringMatches(const Part &part, const UnicodeString &s) const { 671 return 0==msg.compare(part.index, part.length, s); 672 } 673 674 /** 675 * Returns the numeric value associated with an ARG_INT or ARG_DOUBLE. 676 * @param part a part of this MessagePattern. 677 * @return the part's numeric value, or UMSGPAT_NO_NUMERIC_VALUE if this is not a numeric part. 678 * @stable ICU 4.8 679 */ 680 double getNumericValue(const Part &part) const; 681 682 /** 683 * Returns the "offset:" value of a PluralFormat argument, or 0 if none is specified. 684 * @param pluralStart the index of the first PluralFormat argument style part. (0..countParts()-1) 685 * @return the "offset:" value. 686 * @stable ICU 4.8 687 */ 688 double getPluralOffset(int32_t pluralStart) const; 689 690 /** 691 * Returns the index of the ARG|MSG_LIMIT part corresponding to the ARG|MSG_START at start. 692 * @param start The index of some Part data (0..countParts()-1); 693 * this Part should be of Type ARG_START or MSG_START. 694 * @return The first i>start where getPart(i).getType()==ARG|MSG_LIMIT at the same nesting level, 695 * or start itself if getPartType(msgStart)!=ARG|MSG_START. 696 * @stable ICU 4.8 697 */ 698 int32_t getLimitPartIndex(int32_t start) const { 699 int32_t limit=getPart(start).limitPartIndex; 700 if(limit parts=new ArrayList(); 931 MessagePatternPartsList *partsList; 932 Part *parts; 933 int32_t partsLength; 934 // ArrayList numericValues; 935 MessagePatternDoubleList *numericValuesList; 936 double *numericValues; 937 int32_t numericValuesLength; 938 UBool hasArgNames; 939 UBool hasArgNumbers; 940 UBool needsAutoQuoting; 941 }; 942 943 U_NAMESPACE_END 944 945 #endif // !UCONFIG_NO_FORMATTING 946 947 #endif /* U_SHOW_CPLUSPLUS_API */ 948 949 #endif // __MESSAGEPATTERN_H__