1 /* 2 ******************************************************************************* 3 * Copyright (C) 2010-2014, International Business Machines Corporation and 4 * others. All Rights Reserved. 5 ******************************************************************************* 6 */ 7 8 #include "unicode/utypes.h" 9 10 #if !UCONFIG_NO_FORMATTING 11 12 #include "unicode/locdspnm.h" 13 #include "unicode/msgfmt.h" 14 #include "unicode/ures.h" 15 #include "unicode/udisplaycontext.h" 16 #include "unicode/brkiter.h" 17 18 #include "cmemory.h" 19 #include "cstring.h" 20 #include "mutex.h" 21 #include "ulocimp.h" 22 #include "umutex.h" 23 #include "ureslocs.h" 24 #include "uresimp.h" 25 26 #include <stdarg.h> 27 28 /** 29 * Concatenate a number of null-terminated strings to buffer, leaving a 30 * null-terminated string. The last argument should be the null pointer. 31 * Return the length of the string in the buffer, not counting the trailing 32 * null. Return -1 if there is an error (buffer is null, or buflen < 1). 33 */ 34 static int32_t ncat(char *buffer, uint32_t buflen, ...) { 35 va_list args; 36 char *str; 37 char *p = buffer; 38 const char* e = buffer + buflen - 1; 39 40 if (buffer == NULL || buflen < 1) { 41 return -1; 42 } 43 44 va_start(args, buflen); 45 while ((str = va_arg(args, char *))) { 46 char c; 47 while (p != e && (c = *str++)) { 48 *p++ = c; 49 } 50 } 51 *p = 0; 52 va_end(args); 53 54 return p - buffer; 55 } 56 57 U_NAMESPACE_BEGIN 58 59 //////////////////////////////////////////////////////////////////////////////////////////////////// 60 61 // Access resource data for locale components. 62 // Wrap code in uloc.c for now. 63 class ICUDataTable { 64 const char* path; 65 Locale locale; 66 67 public: 68 ICUDataTable(const char* path, const Locale& locale); 69 ~ICUDataTable(); 70 71 const Locale& getLocale(); 72 73 UnicodeString& get(const char* tableKey, const char* itemKey, 74 UnicodeString& result) const; 75 UnicodeString& get(const char* tableKey, const char* subTableKey, const char* itemKey, 76 UnicodeString& result) const; 77 78 UnicodeString& getNoFallback(const char* tableKey, const char* itemKey, 79 UnicodeString &result) const; 80 UnicodeString& getNoFallback(const char* tableKey, const char* subTableKey, const char* itemKey, 81 UnicodeString &result) const; 82 }; 83 84 inline UnicodeString & 85 ICUDataTable::get(const char* tableKey, const char* itemKey, UnicodeString& result) const { 86 return get(tableKey, NULL, itemKey, result); 87 } 88 89 inline UnicodeString & 90 ICUDataTable::getNoFallback(const char* tableKey, const char* itemKey, UnicodeString& result) const { 91 return getNoFallback(tableKey, NULL, itemKey, result); 92 } 93 94 ICUDataTable::ICUDataTable(const char* path, const Locale& locale) 95 : path(NULL), locale(Locale::getRoot()) 96 { 97 if (path) { 98 int32_t len = uprv_strlen(path); 99 this->path = (const char*) uprv_malloc(len + 1); 100 if (this->path) { 101 uprv_strcpy((char *)this->path, path); 102 this->locale = locale; 103 } 104 } 105 } 106 107 ICUDataTable::~ICUDataTable() { 108 if (path) { 109 uprv_free((void*) path); 110 path = NULL; 111 } 112 } 113 114 const Locale& 115 ICUDataTable::getLocale() { 116 return locale; 117 } 118 119 UnicodeString & 120 ICUDataTable::get(const char* tableKey, const char* subTableKey, const char* itemKey, 121 UnicodeString &result) const { 122 UErrorCode status = U_ZERO_ERROR; 123 int32_t len = 0; 124 125 const UChar *s = uloc_getTableStringWithFallback(path, locale.getName(), 126 tableKey, subTableKey, itemKey, 127 &len, &status); 128 if (U_SUCCESS(status) && len > 0) { 129 return result.setTo(s, len); 130 } 131 return result.setTo(UnicodeString(itemKey, -1, US_INV)); 132 } 133 134 UnicodeString & 135 ICUDataTable::getNoFallback(const char* tableKey, const char* subTableKey, const char* itemKey, 136 UnicodeString& result) const { 137 UErrorCode status = U_ZERO_ERROR; 138 int32_t len = 0; 139 140 const UChar *s = uloc_getTableStringWithFallback(path, locale.getName(), 141 tableKey, subTableKey, itemKey, 142 &len, &status); 143 if (U_SUCCESS(status)) { 144 return result.setTo(s, len); 145 } 146 147 result.setToBogus(); 148 return result; 149 } 150 151 //////////////////////////////////////////////////////////////////////////////////////////////////// 152 153 LocaleDisplayNames::~LocaleDisplayNames() {} 154 155 //////////////////////////////////////////////////////////////////////////////////////////////////// 156 157 #if 0 // currently unused 158 159 class DefaultLocaleDisplayNames : public LocaleDisplayNames { 160 UDialectHandling dialectHandling; 161 162 public: 163 // constructor 164 DefaultLocaleDisplayNames(UDialectHandling dialectHandling); 165 166 virtual ~DefaultLocaleDisplayNames(); 167 168 virtual const Locale& getLocale() const; 169 virtual UDialectHandling getDialectHandling() const; 170 171 virtual UnicodeString& localeDisplayName(const Locale& locale, 172 UnicodeString& result) const; 173 virtual UnicodeString& localeDisplayName(const char* localeId, 174 UnicodeString& result) const; 175 virtual UnicodeString& languageDisplayName(const char* lang, 176 UnicodeString& result) const; 177 virtual UnicodeString& scriptDisplayName(const char* script, 178 UnicodeString& result) const; 179 virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode, 180 UnicodeString& result) const; 181 virtual UnicodeString& regionDisplayName(const char* region, 182 UnicodeString& result) const; 183 virtual UnicodeString& variantDisplayName(const char* variant, 184 UnicodeString& result) const; 185 virtual UnicodeString& keyDisplayName(const char* key, 186 UnicodeString& result) const; 187 virtual UnicodeString& keyValueDisplayName(const char* key, 188 const char* value, 189 UnicodeString& result) const; 190 }; 191 192 DefaultLocaleDisplayNames::DefaultLocaleDisplayNames(UDialectHandling dialectHandling) 193 : dialectHandling(dialectHandling) { 194 } 195 196 DefaultLocaleDisplayNames::~DefaultLocaleDisplayNames() { 197 } 198 199 const Locale& 200 DefaultLocaleDisplayNames::getLocale() const { 201 return Locale::getRoot(); 202 } 203 204 UDialectHandling 205 DefaultLocaleDisplayNames::getDialectHandling() const { 206 return dialectHandling; 207 } 208 209 UnicodeString& 210 DefaultLocaleDisplayNames::localeDisplayName(const Locale& locale, 211 UnicodeString& result) const { 212 return result = UnicodeString(locale.getName(), -1, US_INV); 213 } 214 215 UnicodeString& 216 DefaultLocaleDisplayNames::localeDisplayName(const char* localeId, 217 UnicodeString& result) const { 218 return result = UnicodeString(localeId, -1, US_INV); 219 } 220 221 UnicodeString& 222 DefaultLocaleDisplayNames::languageDisplayName(const char* lang, 223 UnicodeString& result) const { 224 return result = UnicodeString(lang, -1, US_INV); 225 } 226 227 UnicodeString& 228 DefaultLocaleDisplayNames::scriptDisplayName(const char* script, 229 UnicodeString& result) const { 230 return result = UnicodeString(script, -1, US_INV); 231 } 232 233 UnicodeString& 234 DefaultLocaleDisplayNames::scriptDisplayName(UScriptCode scriptCode, 235 UnicodeString& result) const { 236 const char* name = uscript_getName(scriptCode); 237 if (name) { 238 return result = UnicodeString(name, -1, US_INV); 239 } 240 return result.remove(); 241 } 242 243 UnicodeString& 244 DefaultLocaleDisplayNames::regionDisplayName(const char* region, 245 UnicodeString& result) const { 246 return result = UnicodeString(region, -1, US_INV); 247 } 248 249 UnicodeString& 250 DefaultLocaleDisplayNames::variantDisplayName(const char* variant, 251 UnicodeString& result) const { 252 return result = UnicodeString(variant, -1, US_INV); 253 } 254 255 UnicodeString& 256 DefaultLocaleDisplayNames::keyDisplayName(const char* key, 257 UnicodeString& result) const { 258 return result = UnicodeString(key, -1, US_INV); 259 } 260 261 UnicodeString& 262 DefaultLocaleDisplayNames::keyValueDisplayName(const char* /* key */, 263 const char* value, 264 UnicodeString& result) const { 265 return result = UnicodeString(value, -1, US_INV); 266 } 267 268 #endif // currently unused class DefaultLocaleDisplayNames 269 270 //////////////////////////////////////////////////////////////////////////////////////////////////// 271 272 class LocaleDisplayNamesImpl : public LocaleDisplayNames { 273 Locale locale; 274 UDialectHandling dialectHandling; 275 ICUDataTable langData; 276 ICUDataTable regionData; 277 MessageFormat *separatorFormat; 278 MessageFormat *format; 279 MessageFormat *keyTypeFormat; 280 UDisplayContext capitalizationContext; 281 BreakIterator* capitalizationBrkIter; 282 static UMutex capitalizationBrkIterLock; 283 UnicodeString formatOpenParen; 284 UnicodeString formatReplaceOpenParen; 285 UnicodeString formatCloseParen; 286 UnicodeString formatReplaceCloseParen; 287 UDisplayContext nameLength; 288 289 // Constants for capitalization context usage types. 290 enum CapContextUsage { 291 kCapContextUsageLanguage, 292 kCapContextUsageScript, 293 kCapContextUsageTerritory, 294 kCapContextUsageVariant, 295 kCapContextUsageKey, 296 kCapContextUsageKeyValue, 297 kCapContextUsageCount 298 }; 299 // Capitalization transforms. For each usage type, indicates whether to titlecase for 300 // the context specified in capitalizationContext (which we know at construction time) 301 UBool fCapitalization[kCapContextUsageCount]; 302 303 public: 304 // constructor 305 LocaleDisplayNamesImpl(const Locale& locale, UDialectHandling dialectHandling); 306 LocaleDisplayNamesImpl(const Locale& locale, UDisplayContext *contexts, int32_t length); 307 virtual ~LocaleDisplayNamesImpl(); 308 309 virtual const Locale& getLocale() const; 310 virtual UDialectHandling getDialectHandling() const; 311 virtual UDisplayContext getContext(UDisplayContextType type) const; 312 313 virtual UnicodeString& localeDisplayName(const Locale& locale, 314 UnicodeString& result) const; 315 virtual UnicodeString& localeDisplayName(const char* localeId, 316 UnicodeString& result) const; 317 virtual UnicodeString& languageDisplayName(const char* lang, 318 UnicodeString& result) const; 319 virtual UnicodeString& scriptDisplayName(const char* script, 320 UnicodeString& result) const; 321 virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode, 322 UnicodeString& result) const; 323 virtual UnicodeString& regionDisplayName(const char* region, 324 UnicodeString& result) const; 325 virtual UnicodeString& variantDisplayName(const char* variant, 326 UnicodeString& result) const; 327 virtual UnicodeString& keyDisplayName(const char* key, 328 UnicodeString& result) const; 329 virtual UnicodeString& keyValueDisplayName(const char* key, 330 const char* value, 331 UnicodeString& result) const; 332 private: 333 UnicodeString& localeIdName(const char* localeId, 334 UnicodeString& result) const; 335 UnicodeString& appendWithSep(UnicodeString& buffer, const UnicodeString& src) const; 336 UnicodeString& adjustForUsageAndContext(CapContextUsage usage, UnicodeString& result) const; 337 void initialize(void); 338 }; 339 340 UMutex LocaleDisplayNamesImpl::capitalizationBrkIterLock = U_MUTEX_INITIALIZER; 341 342 LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale, 343 UDialectHandling dialectHandling) 344 : dialectHandling(dialectHandling) 345 , langData(U_ICUDATA_LANG, locale) 346 , regionData(U_ICUDATA_REGION, locale) 347 , separatorFormat(NULL) 348 , format(NULL) 349 , keyTypeFormat(NULL) 350 , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 351 , capitalizationBrkIter(NULL) 352 , nameLength(UDISPCTX_LENGTH_FULL) 353 { 354 initialize(); 355 } 356 357 LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale, 358 UDisplayContext *contexts, int32_t length) 359 : dialectHandling(ULDN_STANDARD_NAMES) 360 , langData(U_ICUDATA_LANG, locale) 361 , regionData(U_ICUDATA_REGION, locale) 362 , separatorFormat(NULL) 363 , format(NULL) 364 , keyTypeFormat(NULL) 365 , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE) 366 , capitalizationBrkIter(NULL) 367 , nameLength(UDISPCTX_LENGTH_FULL) 368 { 369 while (length-- > 0) { 370 UDisplayContext value = *contexts++; 371 UDisplayContextType selector = (UDisplayContextType)((uint32_t)value >> 8); 372 switch (selector) { 373 case UDISPCTX_TYPE_DIALECT_HANDLING: 374 dialectHandling = (UDialectHandling)value; 375 break; 376 case UDISPCTX_TYPE_CAPITALIZATION: 377 capitalizationContext = value; 378 break; 379 case UDISPCTX_TYPE_DISPLAY_LENGTH: 380 nameLength = value; 381 break; 382 default: 383 break; 384 } 385 } 386 initialize(); 387 } 388 389 void 390 LocaleDisplayNamesImpl::initialize(void) { 391 LocaleDisplayNamesImpl *nonConstThis = (LocaleDisplayNamesImpl *)this; 392 nonConstThis->locale = langData.getLocale() == Locale::getRoot() 393 ? regionData.getLocale() 394 : langData.getLocale(); 395 396 UnicodeString sep; 397 langData.getNoFallback("localeDisplayPattern", "separator", sep); 398 if (sep.isBogus()) { 399 sep = UnicodeString("{0}, {1}", -1, US_INV); 400 } 401 UErrorCode status = U_ZERO_ERROR; 402 separatorFormat = new MessageFormat(sep, status); 403 404 UnicodeString pattern; 405 langData.getNoFallback("localeDisplayPattern", "pattern", pattern); 406 if (pattern.isBogus()) { 407 pattern = UnicodeString("{0} ({1})", -1, US_INV); 408 } 409 format = new MessageFormat(pattern, status); 410 if (pattern.indexOf((UChar)0xFF08) >= 0) { 411 formatOpenParen.setTo((UChar)0xFF08); // fullwidth ( 412 formatReplaceOpenParen.setTo((UChar)0xFF3B); // fullwidth [ 413 formatCloseParen.setTo((UChar)0xFF09); // fullwidth ) 414 formatReplaceCloseParen.setTo((UChar)0xFF3D); // fullwidth ] 415 } else { 416 formatOpenParen.setTo((UChar)0x0028); // ( 417 formatReplaceOpenParen.setTo((UChar)0x005B); // [ 418 formatCloseParen.setTo((UChar)0x0029); // ) 419 formatReplaceCloseParen.setTo((UChar)0x005D); // ] 420 } 421 422 UnicodeString ktPattern; 423 langData.get("localeDisplayPattern", "keyTypePattern", ktPattern); 424 if (ktPattern.isBogus()) { 425 ktPattern = UnicodeString("{0}={1}", -1, US_INV); 426 } 427 keyTypeFormat = new MessageFormat(ktPattern, status); 428 429 uprv_memset(fCapitalization, 0, sizeof(fCapitalization)); 430 #if !UCONFIG_NO_BREAK_ITERATION 431 // The following is basically copied from DateFormatSymbols::initializeData 432 typedef struct { 433 const char * usageName; 434 LocaleDisplayNamesImpl::CapContextUsage usageEnum; 435 } ContextUsageNameToEnum; 436 const ContextUsageNameToEnum contextUsageTypeMap[] = { 437 // Entries must be sorted by usageTypeName; entry with NULL name terminates list. 438 { "key", kCapContextUsageKey }, 439 { "keyValue", kCapContextUsageKeyValue }, 440 { "languages", kCapContextUsageLanguage }, 441 { "script", kCapContextUsageScript }, 442 { "territory", kCapContextUsageTerritory }, 443 { "variant", kCapContextUsageVariant }, 444 { NULL, (CapContextUsage)0 }, 445 }; 446 // Only get the context data if we need it! This is a const object so we know now... 447 // Also check whether we will need a break iterator (depends on the data) 448 UBool needBrkIter = FALSE; 449 if (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE) { 450 int32_t len = 0; 451 UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &status); 452 if (U_SUCCESS(status)) { 453 UResourceBundle *contextTransforms = ures_getByKeyWithFallback(localeBundle, "contextTransforms", NULL, &status); 454 if (U_SUCCESS(status)) { 455 UResourceBundle *contextTransformUsage; 456 while ( (contextTransformUsage = ures_getNextResource(contextTransforms, NULL, &status)) != NULL ) { 457 const int32_t * intVector = ures_getIntVector(contextTransformUsage, &len, &status); 458 if (U_SUCCESS(status) && intVector != NULL && len >= 2) { 459 const char* usageKey = ures_getKey(contextTransformUsage); 460 if (usageKey != NULL) { 461 const ContextUsageNameToEnum * typeMapPtr = contextUsageTypeMap; 462 int32_t compResult = 0; 463 // linear search; list is short and we cannot be sure that bsearch is available 464 while ( typeMapPtr->usageName != NULL && (compResult = uprv_strcmp(usageKey, typeMapPtr->usageName)) > 0 ) { 465 ++typeMapPtr; 466 } 467 if (typeMapPtr->usageName != NULL && compResult == 0) { 468 int32_t titlecaseInt = (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU)? intVector[0]: intVector[1]; 469 if (titlecaseInt != 0) { 470 fCapitalization[typeMapPtr->usageEnum] = TRUE;; 471 needBrkIter = TRUE; 472 } 473 } 474 } 475 } 476 status = U_ZERO_ERROR; 477 ures_close(contextTransformUsage); 478 } 479 ures_close(contextTransforms); 480 } 481 ures_close(localeBundle); 482 } 483 } 484 // Get a sentence break iterator if we will need it 485 if (needBrkIter || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE) { 486 status = U_ZERO_ERROR; 487 capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status); 488 if (U_FAILURE(status)) { 489 delete capitalizationBrkIter; 490 capitalizationBrkIter = NULL; 491 } 492 } 493 #endif 494 } 495 496 LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() { 497 delete separatorFormat; 498 delete format; 499 delete keyTypeFormat; 500 delete capitalizationBrkIter; 501 } 502 503 const Locale& 504 LocaleDisplayNamesImpl::getLocale() const { 505 return locale; 506 } 507 508 UDialectHandling 509 LocaleDisplayNamesImpl::getDialectHandling() const { 510 return dialectHandling; 511 } 512 513 UDisplayContext 514 LocaleDisplayNamesImpl::getContext(UDisplayContextType type) const { 515 switch (type) { 516 case UDISPCTX_TYPE_DIALECT_HANDLING: 517 return (UDisplayContext)dialectHandling; 518 case UDISPCTX_TYPE_CAPITALIZATION: 519 return capitalizationContext; 520 case UDISPCTX_TYPE_DISPLAY_LENGTH: 521 return nameLength; 522 default: 523 break; 524 } 525 return (UDisplayContext)0; 526 } 527 528 UnicodeString& 529 LocaleDisplayNamesImpl::adjustForUsageAndContext(CapContextUsage usage, 530 UnicodeString& result) const { 531 #if !UCONFIG_NO_BREAK_ITERATION 532 // check to see whether we need to titlecase result 533 if ( result.length() > 0 && u_islower(result.char32At(0)) && capitalizationBrkIter!= NULL && 534 ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || fCapitalization[usage] ) ) { 535 // note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE 536 Mutex lock(&capitalizationBrkIterLock); 537 result.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT); 538 } 539 #endif 540 return result; 541 } 542 543 UnicodeString& 544 LocaleDisplayNamesImpl::localeDisplayName(const Locale& locale, 545 UnicodeString& result) const { 546 UnicodeString resultName; 547 548 const char* lang = locale.getLanguage(); 549 if (uprv_strlen(lang) == 0) { 550 lang = "root"; 551 } 552 const char* script = locale.getScript(); 553 const char* country = locale.getCountry(); 554 const char* variant = locale.getVariant(); 555 556 UBool hasScript = uprv_strlen(script) > 0; 557 UBool hasCountry = uprv_strlen(country) > 0; 558 UBool hasVariant = uprv_strlen(variant) > 0; 559 560 if (dialectHandling == ULDN_DIALECT_NAMES) { 561 char buffer[ULOC_FULLNAME_CAPACITY]; 562 do { // loop construct is so we can break early out of search 563 if (hasScript && hasCountry) { 564 ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, "_", country, (char *)0); 565 localeIdName(buffer, resultName); 566 if (!resultName.isBogus()) { 567 hasScript = FALSE; 568 hasCountry = FALSE; 569 break; 570 } 571 } 572 if (hasScript) { 573 ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, (char *)0); 574 localeIdName(buffer, resultName); 575 if (!resultName.isBogus()) { 576 hasScript = FALSE; 577 break; 578 } 579 } 580 if (hasCountry) { 581 ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", country, (char*)0); 582 localeIdName(buffer, resultName); 583 if (!resultName.isBogus()) { 584 hasCountry = FALSE; 585 break; 586 } 587 } 588 } while (FALSE); 589 } 590 if (resultName.isBogus() || resultName.isEmpty()) { 591 localeIdName(lang, resultName); 592 } 593 594 UnicodeString resultRemainder; 595 UnicodeString temp; 596 StringEnumeration *e = NULL; 597 UErrorCode status = U_ZERO_ERROR; 598 599 if (hasScript) { 600 resultRemainder.append(scriptDisplayName(script, temp)); 601 } 602 if (hasCountry) { 603 appendWithSep(resultRemainder, regionDisplayName(country, temp)); 604 } 605 if (hasVariant) { 606 appendWithSep(resultRemainder, variantDisplayName(variant, temp)); 607 } 608 resultRemainder.findAndReplace(formatOpenParen, formatReplaceOpenParen); 609 resultRemainder.findAndReplace(formatCloseParen, formatReplaceCloseParen); 610 611 e = locale.createKeywords(status); 612 if (e && U_SUCCESS(status)) { 613 UnicodeString temp2; 614 char value[ULOC_KEYWORD_AND_VALUES_CAPACITY]; // sigh, no ULOC_VALUE_CAPACITY 615 const char* key; 616 while ((key = e->next((int32_t *)0, status)) != NULL) { 617 locale.getKeywordValue(key, value, ULOC_KEYWORD_AND_VALUES_CAPACITY, status); 618 keyDisplayName(key, temp); 619 temp.findAndReplace(formatOpenParen, formatReplaceOpenParen); 620 temp.findAndReplace(formatCloseParen, formatReplaceCloseParen); 621 keyValueDisplayName(key, value, temp2); 622 temp2.findAndReplace(formatOpenParen, formatReplaceOpenParen); 623 temp2.findAndReplace(formatCloseParen, formatReplaceCloseParen); 624 if (temp2 != UnicodeString(value, -1, US_INV)) { 625 appendWithSep(resultRemainder, temp2); 626 } else if (temp != UnicodeString(key, -1, US_INV)) { 627 UnicodeString temp3; 628 Formattable data[] = { 629 temp, 630 temp2 631 }; 632 FieldPosition fpos; 633 status = U_ZERO_ERROR; 634 keyTypeFormat->format(data, 2, temp3, fpos, status); 635 appendWithSep(resultRemainder, temp3); 636 } else { 637 appendWithSep(resultRemainder, temp) 638 .append((UChar)0x3d /* = */) 639 .append(temp2); 640 } 641 } 642 delete e; 643 } 644 645 if (!resultRemainder.isEmpty()) { 646 Formattable data[] = { 647 resultName, 648 resultRemainder 649 }; 650 FieldPosition fpos; 651 status = U_ZERO_ERROR; 652 format->format(data, 2, result, fpos, status); 653 return adjustForUsageAndContext(kCapContextUsageLanguage, result); 654 } 655 656 result = resultName; 657 return adjustForUsageAndContext(kCapContextUsageLanguage, result); 658 } 659 660 UnicodeString& 661 LocaleDisplayNamesImpl::appendWithSep(UnicodeString& buffer, const UnicodeString& src) const { 662 if (buffer.isEmpty()) { 663 buffer.setTo(src); 664 } else { 665 UnicodeString combined; 666 Formattable data[] = { 667 buffer, 668 src 669 }; 670 FieldPosition fpos; 671 UErrorCode status = U_ZERO_ERROR; 672 separatorFormat->format(data, 2, combined, fpos, status); 673 if (U_SUCCESS(status)) { 674 buffer.setTo(combined); 675 } 676 } 677 return buffer; 678 } 679 680 UnicodeString& 681 LocaleDisplayNamesImpl::localeDisplayName(const char* localeId, 682 UnicodeString& result) const { 683 return localeDisplayName(Locale(localeId), result); 684 } 685 686 // private 687 UnicodeString& 688 LocaleDisplayNamesImpl::localeIdName(const char* localeId, 689 UnicodeString& result) const { 690 if (nameLength == UDISPCTX_LENGTH_SHORT) { 691 langData.getNoFallback("Languages%short", localeId, result); 692 if (!result.isBogus()) { 693 return result; 694 } 695 } 696 return langData.getNoFallback("Languages", localeId, result); 697 } 698 699 UnicodeString& 700 LocaleDisplayNamesImpl::languageDisplayName(const char* lang, 701 UnicodeString& result) const { 702 if (uprv_strcmp("root", lang) == 0 || uprv_strchr(lang, '_') != NULL) { 703 return result = UnicodeString(lang, -1, US_INV); 704 } 705 if (nameLength == UDISPCTX_LENGTH_SHORT) { 706 langData.get("Languages%short", lang, result); 707 if (!result.isBogus()) { 708 return adjustForUsageAndContext(kCapContextUsageLanguage, result); 709 } 710 } 711 langData.get("Languages", lang, result); 712 return adjustForUsageAndContext(kCapContextUsageLanguage, result); 713 } 714 715 UnicodeString& 716 LocaleDisplayNamesImpl::scriptDisplayName(const char* script, 717 UnicodeString& result) const { 718 if (nameLength == UDISPCTX_LENGTH_SHORT) { 719 langData.get("Scripts%short", script, result); 720 if (!result.isBogus()) { 721 return adjustForUsageAndContext(kCapContextUsageScript, result); 722 } 723 } 724 langData.get("Scripts", script, result); 725 return adjustForUsageAndContext(kCapContextUsageScript, result); 726 } 727 728 UnicodeString& 729 LocaleDisplayNamesImpl::scriptDisplayName(UScriptCode scriptCode, 730 UnicodeString& result) const { 731 return scriptDisplayName(uscript_getName(scriptCode), result); 732 } 733 734 UnicodeString& 735 LocaleDisplayNamesImpl::regionDisplayName(const char* region, 736 UnicodeString& result) const { 737 if (nameLength == UDISPCTX_LENGTH_SHORT) { 738 regionData.get("Countries%short", region, result); 739 if (!result.isBogus()) { 740 return adjustForUsageAndContext(kCapContextUsageTerritory, result); 741 } 742 } 743 regionData.get("Countries", region, result); 744 return adjustForUsageAndContext(kCapContextUsageTerritory, result); 745 } 746 747 UnicodeString& 748 LocaleDisplayNamesImpl::variantDisplayName(const char* variant, 749 UnicodeString& result) const { 750 // don't have a resource for short variant names 751 langData.get("Variants", variant, result); 752 return adjustForUsageAndContext(kCapContextUsageVariant, result); 753 } 754 755 UnicodeString& 756 LocaleDisplayNamesImpl::keyDisplayName(const char* key, 757 UnicodeString& result) const { 758 // don't have a resource for short key names 759 langData.get("Keys", key, result); 760 return adjustForUsageAndContext(kCapContextUsageKey, result); 761 } 762 763 UnicodeString& 764 LocaleDisplayNamesImpl::keyValueDisplayName(const char* key, 765 const char* value, 766 UnicodeString& result) const { 767 if (uprv_strcmp(key, "currency") == 0) { 768 // ICU4C does not have ICU4J CurrencyDisplayInfo equivalent for now. 769 UErrorCode sts = U_ZERO_ERROR; 770 UnicodeString ustrValue(value, -1, US_INV); 771 int32_t len; 772 UBool isChoice = FALSE; 773 const UChar *currencyName = ucurr_getName(ustrValue.getTerminatedBuffer(), 774 locale.getBaseName(), UCURR_LONG_NAME, &isChoice, &len, &sts); 775 if (U_FAILURE(sts)) { 776 // Return the value as is on failure 777 result = ustrValue; 778 return result; 779 } 780 result.setTo(currencyName, len); 781 return adjustForUsageAndContext(kCapContextUsageKeyValue, result); 782 } 783 784 if (nameLength == UDISPCTX_LENGTH_SHORT) { 785 langData.get("Types%short", key, value, result); 786 if (!result.isBogus()) { 787 return adjustForUsageAndContext(kCapContextUsageKeyValue, result); 788 } 789 } 790 langData.get("Types", key, value, result); 791 return adjustForUsageAndContext(kCapContextUsageKeyValue, result); 792 } 793 794 //////////////////////////////////////////////////////////////////////////////////////////////////// 795 796 LocaleDisplayNames* 797 LocaleDisplayNames::createInstance(const Locale& locale, 798 UDialectHandling dialectHandling) { 799 return new LocaleDisplayNamesImpl(locale, dialectHandling); 800 } 801 802 LocaleDisplayNames* 803 LocaleDisplayNames::createInstance(const Locale& locale, 804 UDisplayContext *contexts, int32_t length) { 805 if (contexts == NULL) { 806 length = 0; 807 } 808 return new LocaleDisplayNamesImpl(locale, contexts, length); 809 } 810 811 U_NAMESPACE_END 812 813 //////////////////////////////////////////////////////////////////////////////////////////////////// 814 815 U_NAMESPACE_USE 816 817 U_CAPI ULocaleDisplayNames * U_EXPORT2 818 uldn_open(const char * locale, 819 UDialectHandling dialectHandling, 820 UErrorCode *pErrorCode) { 821 if (U_FAILURE(*pErrorCode)) { 822 return 0; 823 } 824 if (locale == NULL) { 825 locale = uloc_getDefault(); 826 } 827 return (ULocaleDisplayNames *)LocaleDisplayNames::createInstance(Locale(locale), dialectHandling); 828 } 829 830 U_CAPI ULocaleDisplayNames * U_EXPORT2 831 uldn_openForContext(const char * locale, 832 UDisplayContext *contexts, int32_t length, 833 UErrorCode *pErrorCode) { 834 if (U_FAILURE(*pErrorCode)) { 835 return 0; 836 } 837 if (locale == NULL) { 838 locale = uloc_getDefault(); 839 } 840 return (ULocaleDisplayNames *)LocaleDisplayNames::createInstance(Locale(locale), contexts, length); 841 } 842 843 844 U_CAPI void U_EXPORT2 845 uldn_close(ULocaleDisplayNames *ldn) { 846 delete (LocaleDisplayNames *)ldn; 847 } 848 849 U_CAPI const char * U_EXPORT2 850 uldn_getLocale(const ULocaleDisplayNames *ldn) { 851 if (ldn) { 852 return ((const LocaleDisplayNames *)ldn)->getLocale().getName(); 853 } 854 return NULL; 855 } 856 857 U_CAPI UDialectHandling U_EXPORT2 858 uldn_getDialectHandling(const ULocaleDisplayNames *ldn) { 859 if (ldn) { 860 return ((const LocaleDisplayNames *)ldn)->getDialectHandling(); 861 } 862 return ULDN_STANDARD_NAMES; 863 } 864 865 U_CAPI UDisplayContext U_EXPORT2 866 uldn_getContext(const ULocaleDisplayNames *ldn, 867 UDisplayContextType type, 868 UErrorCode *pErrorCode) { 869 if (U_FAILURE(*pErrorCode)) { 870 return (UDisplayContext)0; 871 } 872 return ((const LocaleDisplayNames *)ldn)->getContext(type); 873 } 874 875 U_CAPI int32_t U_EXPORT2 876 uldn_localeDisplayName(const ULocaleDisplayNames *ldn, 877 const char *locale, 878 UChar *result, 879 int32_t maxResultSize, 880 UErrorCode *pErrorCode) { 881 if (U_FAILURE(*pErrorCode)) { 882 return 0; 883 } 884 if (ldn == NULL || locale == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) { 885 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; 886 return 0; 887 } 888 UnicodeString temp(result, 0, maxResultSize); 889 ((const LocaleDisplayNames *)ldn)->localeDisplayName(locale, temp); 890 return temp.extract(result, maxResultSize, *pErrorCode); 891 } 892 893 U_CAPI int32_t U_EXPORT2 894 uldn_languageDisplayName(const ULocaleDisplayNames *ldn, 895 const char *lang, 896 UChar *result, 897 int32_t maxResultSize, 898 UErrorCode *pErrorCode) { 899 if (U_FAILURE(*pErrorCode)) { 900 return 0; 901 } 902 if (ldn == NULL || lang == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) { 903 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; 904 return 0; 905 } 906 UnicodeString temp(result, 0, maxResultSize); 907 ((const LocaleDisplayNames *)ldn)->languageDisplayName(lang, temp); 908 return temp.extract(result, maxResultSize, *pErrorCode); 909 } 910 911 U_CAPI int32_t U_EXPORT2 912 uldn_scriptDisplayName(const ULocaleDisplayNames *ldn, 913 const char *script, 914 UChar *result, 915 int32_t maxResultSize, 916 UErrorCode *pErrorCode) { 917 if (U_FAILURE(*pErrorCode)) { 918 return 0; 919 } 920 if (ldn == NULL || script == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) { 921 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; 922 return 0; 923 } 924 UnicodeString temp(result, 0, maxResultSize); 925 ((const LocaleDisplayNames *)ldn)->scriptDisplayName(script, temp); 926 return temp.extract(result, maxResultSize, *pErrorCode); 927 } 928 929 U_CAPI int32_t U_EXPORT2 930 uldn_scriptCodeDisplayName(const ULocaleDisplayNames *ldn, 931 UScriptCode scriptCode, 932 UChar *result, 933 int32_t maxResultSize, 934 UErrorCode *pErrorCode) { 935 return uldn_scriptDisplayName(ldn, uscript_getName(scriptCode), result, maxResultSize, pErrorCode); 936 } 937 938 U_CAPI int32_t U_EXPORT2 939 uldn_regionDisplayName(const ULocaleDisplayNames *ldn, 940 const char *region, 941 UChar *result, 942 int32_t maxResultSize, 943 UErrorCode *pErrorCode) { 944 if (U_FAILURE(*pErrorCode)) { 945 return 0; 946 } 947 if (ldn == NULL || region == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) { 948 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; 949 return 0; 950 } 951 UnicodeString temp(result, 0, maxResultSize); 952 ((const LocaleDisplayNames *)ldn)->regionDisplayName(region, temp); 953 return temp.extract(result, maxResultSize, *pErrorCode); 954 } 955 956 U_CAPI int32_t U_EXPORT2 957 uldn_variantDisplayName(const ULocaleDisplayNames *ldn, 958 const char *variant, 959 UChar *result, 960 int32_t maxResultSize, 961 UErrorCode *pErrorCode) { 962 if (U_FAILURE(*pErrorCode)) { 963 return 0; 964 } 965 if (ldn == NULL || variant == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) { 966 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; 967 return 0; 968 } 969 UnicodeString temp(result, 0, maxResultSize); 970 ((const LocaleDisplayNames *)ldn)->variantDisplayName(variant, temp); 971 return temp.extract(result, maxResultSize, *pErrorCode); 972 } 973 974 U_CAPI int32_t U_EXPORT2 975 uldn_keyDisplayName(const ULocaleDisplayNames *ldn, 976 const char *key, 977 UChar *result, 978 int32_t maxResultSize, 979 UErrorCode *pErrorCode) { 980 if (U_FAILURE(*pErrorCode)) { 981 return 0; 982 } 983 if (ldn == NULL || key == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) { 984 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; 985 return 0; 986 } 987 UnicodeString temp(result, 0, maxResultSize); 988 ((const LocaleDisplayNames *)ldn)->keyDisplayName(key, temp); 989 return temp.extract(result, maxResultSize, *pErrorCode); 990 } 991 992 U_CAPI int32_t U_EXPORT2 993 uldn_keyValueDisplayName(const ULocaleDisplayNames *ldn, 994 const char *key, 995 const char *value, 996 UChar *result, 997 int32_t maxResultSize, 998 UErrorCode *pErrorCode) { 999 if (U_FAILURE(*pErrorCode)) { 1000 return 0; 1001 } 1002 if (ldn == NULL || key == NULL || value == NULL || (result == NULL && maxResultSize > 0) 1003 || maxResultSize < 0) { 1004 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR; 1005 return 0; 1006 } 1007 UnicodeString temp(result, 0, maxResultSize); 1008 ((const LocaleDisplayNames *)ldn)->keyValueDisplayName(key, value, temp); 1009 return temp.extract(result, maxResultSize, *pErrorCode); 1010 } 1011 1012 #endif 1013