Home | History | Annotate | Download | only in i18n
      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