]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/locdspnm.cpp
ICU-66108.tar.gz
[apple/icu.git] / icuSources / common / locdspnm.cpp
index d271bebd204f5076868505401266dfaa9841f950..c54c1415dcd75592b00977b3e22a855b08fe4249 100644 (file)
@@ -292,6 +292,7 @@ class LocaleDisplayNamesImpl : public LocaleDisplayNames {
     UnicodeString formatReplaceCloseParen;
     UnicodeString formatParenCloseOpen;
     UDisplayContext nameLength;
+    UDisplayContext substitute;
 
     // Constants for capitalization context usage types.
     enum CapContextUsage {
@@ -338,7 +339,7 @@ public:
                                                 UnicodeString& result) const;
 private:
     UnicodeString& localeIdName(const char* localeId,
-                                UnicodeString& result) const;
+                                UnicodeString& result, bool substitute) const;
     UnicodeString& regionShortDisplayName(const char* region,                   // Apple-specific
                                                 UnicodeString& result) const;
     UnicodeString& appendWithSep(UnicodeString& buffer, const UnicodeString& src) const;
@@ -362,6 +363,7 @@ LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
     , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
     , capitalizationBrkIter(NULL)
     , nameLength(UDISPCTX_LENGTH_FULL)
+    , substitute(UDISPCTX_SUBSTITUTE)
 {
     initialize();
 }
@@ -374,6 +376,7 @@ LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
     , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
     , capitalizationBrkIter(NULL)
     , nameLength(UDISPCTX_LENGTH_FULL)
+    , substitute(UDISPCTX_SUBSTITUTE)
 {
     while (length-- > 0) {
         UDisplayContext value = *contexts++;
@@ -388,6 +391,9 @@ LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
             case UDISPCTX_TYPE_DISPLAY_LENGTH:
                 nameLength = value;
                 break;
+            case UDISPCTX_TYPE_SUBSTITUTE_HANDLING:
+                substitute = value;
+                break;
             case UADISPCTX_TYPE_LENGTH: // Apple-specific
                 nameLength = (value == UADISPCTX_LENGTH_SHORT)? UDISPCTX_LENGTH_SHORT: UDISPCTX_LENGTH_FULL;
                 break;
@@ -544,6 +550,8 @@ LocaleDisplayNamesImpl::getContext(UDisplayContextType type) const {
             return capitalizationContext;
         case UDISPCTX_TYPE_DISPLAY_LENGTH:
             return nameLength;
+        case UDISPCTX_TYPE_SUBSTITUTE_HANDLING:
+            return substitute;
         case UADISPCTX_TYPE_LENGTH: // Apple-specific
             return (nameLength == UDISPCTX_LENGTH_SHORT)? UADISPCTX_LENGTH_SHORT: UADISPCTX_LENGTH_STANDARD;
         default:
@@ -556,12 +564,23 @@ UnicodeString&
 LocaleDisplayNamesImpl::adjustForUsageAndContext(CapContextUsage usage,
                                                 UnicodeString& result) const {
 #if !UCONFIG_NO_BREAK_ITERATION
-    // check to see whether we need to titlecase result
-    if ( result.length() > 0 && u_islower(result.char32At(0)) && capitalizationBrkIter!= NULL &&
+    // check to see whether we need to titlecase result-- we check the first word (up to the first space),
+    // and only titlecase the result if that first word contains no capital letters
+    UBool needToTitlecase = TRUE;
+    for (int32_t i = 0; needToTitlecase && i < result.length(); i++) {
+        UChar32 c = result.char32At(i);
+        if (u_isupper(c) || u_istitle(c)) {
+            needToTitlecase = FALSE;
+        } else if (u_isspace(c)) {
+            break;
+        }
+    }
+    
+    if (needToTitlecase && capitalizationBrkIter!= NULL &&
           ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || fCapitalization[usage] ) ) {
         // note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE
-        static UMutex *capitalizationBrkIterLock = STATIC_NEW(UMutex);
-        Mutex lock(capitalizationBrkIterLock);
+        static UMutex capitalizationBrkIterLock;
+        Mutex lock(&capitalizationBrkIterLock);
         result.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
     }
 #endif
@@ -599,7 +618,7 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
     do { // loop construct is so we can break early out of search
       if (hasScript && hasCountry) {
         ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, "_", country, (char *)0);
-        localeIdName(buffer, resultName);
+        localeIdName(buffer, resultName, false);
         if (!resultName.isBogus()) {
           hasScript = FALSE;
           hasCountry = FALSE;
@@ -608,7 +627,7 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
       }
       if (hasScript) {
         ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, (char *)0);
-        localeIdName(buffer, resultName);
+        localeIdName(buffer, resultName, false);
         if (!resultName.isBogus()) {
           hasScript = FALSE;
           break;
@@ -616,7 +635,7 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
       }
       if (hasCountry) {
         ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", country, (char*)0);
-        localeIdName(buffer, resultName);
+        localeIdName(buffer, resultName, false);
         if (!resultName.isBogus()) {
           hasCountry = FALSE;
           break;
@@ -625,7 +644,11 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
     } while (FALSE);
   }
   if (resultName.isBogus() || resultName.isEmpty()) {
-    localeIdName(lang, resultName);
+    localeIdName(lang, resultName, substitute == UDISPCTX_SUBSTITUTE);
+    if (resultName.isBogus()) {
+      result.setToBogus();
+      return result;
+    }
   }
 
   UnicodeString resultRemainder;
@@ -633,13 +656,28 @@ LocaleDisplayNamesImpl::localeDisplayName(const Locale& loc,
   UErrorCode status = U_ZERO_ERROR;
 
   if (hasScript) {
-    resultRemainder.append(scriptDisplayName(script, temp, TRUE));
+    UnicodeString script_str = scriptDisplayName(script, temp, TRUE);
+    if (script_str.isBogus()) {
+      result.setToBogus();
+      return result;
+    }
+    resultRemainder.append(script_str);
   }
   if (hasCountry) {
-    appendWithSep(resultRemainder, regionShortDisplayName(country, temp)); // Apple modification
+    UnicodeString region_str = regionShortDisplayName(country, temp); // Apple modification
+    if (region_str.isBogus()) {
+      result.setToBogus();
+      return result;
+    }
+    appendWithSep(resultRemainder, region_str);
   }
   if (hasVariant) {
-    appendWithSep(resultRemainder, variantDisplayName(variant, temp, TRUE));
+    UnicodeString variant_str = variantDisplayName(variant, temp, TRUE);
+    if (variant_str.isBogus()) {
+      result.setToBogus();
+      return result;
+    }
+    appendWithSep(resultRemainder, variant_str);
   }
   resultRemainder.findAndReplace(formatOpenParen, formatReplaceOpenParen);
   resultRemainder.findAndReplace(formatCloseParen, formatReplaceCloseParen);
@@ -711,14 +749,18 @@ LocaleDisplayNamesImpl::localeDisplayName(const char* localeId,
 // private
 UnicodeString&
 LocaleDisplayNamesImpl::localeIdName(const char* localeId,
-                                     UnicodeString& result) const {
+                                     UnicodeString& result, bool substitute) const {
     if (nameLength == UDISPCTX_LENGTH_SHORT) {
         langData.getNoFallback("Languages%short", localeId, result);
         if (!result.isBogus()) {
             return result;
         }
     }
-    return langData.getNoFallback("Languages", localeId, result);
+    if (substitute) {
+        return langData.get("Languages", localeId, result);
+    } else {
+        return langData.getNoFallback("Languages", localeId, result);
+    }
 }
 
 UnicodeString&
@@ -733,7 +775,11 @@ LocaleDisplayNamesImpl::languageDisplayName(const char* lang,
             return adjustForUsageAndContext(kCapContextUsageLanguage, result);
         }
     }
-    langData.get("Languages", lang, result);
+    if (substitute == UDISPCTX_SUBSTITUTE) {
+        langData.get("Languages", lang, result);
+    } else {
+        langData.getNoFallback("Languages", lang, result);
+    }
     return adjustForUsageAndContext(kCapContextUsageLanguage, result);
 }
 
@@ -753,7 +799,11 @@ LocaleDisplayNamesImpl::scriptDisplayName(const char* script,
             return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageScript, result);
         }
     }
-    langData.get("Scripts", script, result);
+    if (substitute == UDISPCTX_SUBSTITUTE) {
+        langData.get("Scripts", script, result);
+    } else {
+        langData.getNoFallback("Scripts", script, result);
+    }
     return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageScript, result);
 }
 
@@ -779,7 +829,11 @@ LocaleDisplayNamesImpl::regionDisplayName(const char* region,
             return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageTerritory, result);
         }
     }
-    regionData.get("Countries", region, result);
+    if (substitute == UDISPCTX_SUBSTITUTE) {
+        regionData.get("Countries", region, result);
+    } else {
+        regionData.getNoFallback("Countries", region, result);
+    }
     return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageTerritory, result);
 }
 
@@ -794,7 +848,11 @@ LocaleDisplayNamesImpl::regionShortDisplayName(const char* region,
             return result;
         }
     }
-    regionData.get("Countries", region, result);
+    if (substitute == UDISPCTX_SUBSTITUTE) {
+        regionData.get("Countries", region, result);
+    } else {
+        regionData.getNoFallback("Countries", region, result);
+    }
     return result;
 }
 
@@ -810,7 +868,11 @@ LocaleDisplayNamesImpl::variantDisplayName(const char* variant,
                                            UnicodeString& result,
                                            UBool skipAdjust) const {
     // don't have a resource for short variant names
-    langData.get("Variants", variant, result);
+    if (substitute == UDISPCTX_SUBSTITUTE) {
+        langData.get("Variants", variant, result);
+    } else {
+        langData.getNoFallback("Variants", variant, result);
+    }
     return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageVariant, result);
 }
 
@@ -825,7 +887,11 @@ LocaleDisplayNamesImpl::keyDisplayName(const char* key,
                                        UnicodeString& result,
                                        UBool skipAdjust) const {
     // don't have a resource for short key names
-    langData.get("Keys", key, result);
+    if (substitute == UDISPCTX_SUBSTITUTE) {
+        langData.get("Keys", key, result);
+    } else {
+        langData.getNoFallback("Keys", key, result);
+    }
     return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageKey, result);
 }
 
@@ -845,9 +911,8 @@ LocaleDisplayNamesImpl::keyValueDisplayName(const char* key,
         UErrorCode sts = U_ZERO_ERROR;
         UnicodeString ustrValue(value, -1, US_INV);
         int32_t len;
-        UBool isChoice = FALSE;
         const UChar *currencyName = ucurr_getName(ustrValue.getTerminatedBuffer(),
-            locale.getBaseName(), UCURR_LONG_NAME, &isChoice, &len, &sts);
+            locale.getBaseName(), UCURR_LONG_NAME, nullptr /* isChoiceFormat */, &len, &sts);
         if (U_FAILURE(sts)) {
             // Return the value as is on failure
             result = ustrValue;
@@ -858,12 +923,16 @@ LocaleDisplayNamesImpl::keyValueDisplayName(const char* key,
     }
 
     if (nameLength == UDISPCTX_LENGTH_SHORT) {
-        langData.get("Types%short", key, value, result);
+        langData.getNoFallback("Types%short", key, value, result);
         if (!result.isBogus()) {
             return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageKeyValue, result);
         }
     }
-    langData.get("Types", key, value, result);
+    if (substitute == UDISPCTX_SUBSTITUTE) {
+        langData.get("Types", key, value, result);
+    } else {
+        langData.getNoFallback("Types", key, value, result);
+    }
     return skipAdjust? result: adjustForUsageAndContext(kCapContextUsageKeyValue, result);
 }