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