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