1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
5 * Copyright (C) 2010-2016, International Business Machines Corporation and
6 * others. All Rights Reserved.
7 *******************************************************************************
10 #include "unicode/utypes.h"
12 #if !UCONFIG_NO_FORMATTING
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"
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).
37 static int32_t ncat(char *buffer
, uint32_t buflen
, ...) {
41 const char* e
= buffer
+ buflen
- 1;
43 if (buffer
== NULL
|| buflen
< 1) {
47 va_start(args
, buflen
);
48 while ((str
= va_arg(args
, char *)) != 0) {
50 while (p
!= e
&& (c
= *str
++) != 0) {
57 return static_cast<int32_t>(p
- buffer
);
62 ////////////////////////////////////////////////////////////////////////////////////////////////////
64 // Access resource data for locale components.
65 // Wrap code in uloc.c for now.
71 ICUDataTable(const char* path
, const Locale
& locale
);
74 const Locale
& getLocale();
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;
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;
87 inline UnicodeString
&
88 ICUDataTable::get(const char* tableKey
, const char* itemKey
, UnicodeString
& result
) const {
89 return get(tableKey
, NULL
, itemKey
, result
);
92 inline UnicodeString
&
93 ICUDataTable::getNoFallback(const char* tableKey
, const char* itemKey
, UnicodeString
& result
) const {
94 return getNoFallback(tableKey
, NULL
, itemKey
, result
);
97 ICUDataTable::ICUDataTable(const char* path
, const Locale
& locale
)
98 : path(NULL
), locale(Locale::getRoot())
101 int32_t len
= static_cast<int32_t>(uprv_strlen(path
));
102 this->path
= (const char*) uprv_malloc(len
+ 1);
104 uprv_strcpy((char *)this->path
, path
);
105 this->locale
= locale
;
110 ICUDataTable::~ICUDataTable() {
112 uprv_free((void*) path
);
118 ICUDataTable::getLocale() {
123 ICUDataTable::get(const char* tableKey
, const char* subTableKey
, const char* itemKey
,
124 UnicodeString
&result
) const {
125 UErrorCode status
= U_ZERO_ERROR
;
128 const UChar
*s
= uloc_getTableStringWithFallback(path
, locale
.getName(),
129 tableKey
, subTableKey
, itemKey
,
131 if (U_SUCCESS(status
) && len
> 0) {
132 return result
.setTo(s
, len
);
134 return result
.setTo(UnicodeString(itemKey
, -1, US_INV
));
138 ICUDataTable::getNoFallback(const char* tableKey
, const char* subTableKey
, const char* itemKey
,
139 UnicodeString
& result
) const {
140 UErrorCode status
= U_ZERO_ERROR
;
143 const UChar
*s
= uloc_getTableStringWithFallback(path
, locale
.getName(),
144 tableKey
, subTableKey
, itemKey
,
146 if (U_SUCCESS(status
)) {
147 return result
.setTo(s
, len
);
154 ////////////////////////////////////////////////////////////////////////////////////////////////////
156 LocaleDisplayNames::~LocaleDisplayNames() {}
158 ////////////////////////////////////////////////////////////////////////////////////////////////////
160 #if 0 // currently unused
162 class DefaultLocaleDisplayNames
: public LocaleDisplayNames
{
163 UDialectHandling dialectHandling
;
167 DefaultLocaleDisplayNames(UDialectHandling dialectHandling
);
169 virtual ~DefaultLocaleDisplayNames();
171 virtual const Locale
& getLocale() const;
172 virtual UDialectHandling
getDialectHandling() const;
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
,
192 UnicodeString
& result
) const;
195 DefaultLocaleDisplayNames::DefaultLocaleDisplayNames(UDialectHandling dialectHandling
)
196 : dialectHandling(dialectHandling
) {
199 DefaultLocaleDisplayNames::~DefaultLocaleDisplayNames() {
203 DefaultLocaleDisplayNames::getLocale() const {
204 return Locale::getRoot();
208 DefaultLocaleDisplayNames::getDialectHandling() const {
209 return dialectHandling
;
213 DefaultLocaleDisplayNames::localeDisplayName(const Locale
& locale
,
214 UnicodeString
& result
) const {
215 return result
= UnicodeString(locale
.getName(), -1, US_INV
);
219 DefaultLocaleDisplayNames::localeDisplayName(const char* localeId
,
220 UnicodeString
& result
) const {
221 return result
= UnicodeString(localeId
, -1, US_INV
);
225 DefaultLocaleDisplayNames::languageDisplayName(const char* lang
,
226 UnicodeString
& result
) const {
227 return result
= UnicodeString(lang
, -1, US_INV
);
231 DefaultLocaleDisplayNames::scriptDisplayName(const char* script
,
232 UnicodeString
& result
) const {
233 return result
= UnicodeString(script
, -1, US_INV
);
237 DefaultLocaleDisplayNames::scriptDisplayName(UScriptCode scriptCode
,
238 UnicodeString
& result
) const {
239 const char* name
= uscript_getName(scriptCode
);
241 return result
= UnicodeString(name
, -1, US_INV
);
243 return result
.remove();
247 DefaultLocaleDisplayNames::regionDisplayName(const char* region
,
248 UnicodeString
& result
) const {
249 return result
= UnicodeString(region
, -1, US_INV
);
253 DefaultLocaleDisplayNames::variantDisplayName(const char* variant
,
254 UnicodeString
& result
) const {
255 return result
= UnicodeString(variant
, -1, US_INV
);
259 DefaultLocaleDisplayNames::keyDisplayName(const char* key
,
260 UnicodeString
& result
) const {
261 return result
= UnicodeString(key
, -1, US_INV
);
265 DefaultLocaleDisplayNames::keyValueDisplayName(const char* /* key */,
267 UnicodeString
& result
) const {
268 return result
= UnicodeString(value
, -1, US_INV
);
271 #endif // currently unused class DefaultLocaleDisplayNames
273 ////////////////////////////////////////////////////////////////////////////////////////////////////
275 class LocaleDisplayNamesImpl
: public LocaleDisplayNames
{
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
;
287 UObject
* capitalizationBrkIter
;
289 UnicodeString formatOpenParen
;
290 UnicodeString formatReplaceOpenParen
;
291 UnicodeString formatCloseParen
;
292 UnicodeString formatReplaceCloseParen
;
293 UnicodeString formatParenCloseOpen
;
294 UDisplayContext nameLength
;
296 // Constants for capitalization context usage types.
297 enum CapContextUsage
{
298 kCapContextUsageLanguage
,
299 kCapContextUsageScript
,
300 kCapContextUsageTerritory
,
301 kCapContextUsageVariant
,
303 kCapContextUsageKeyValue
,
304 kCapContextUsageCount
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
];
312 LocaleDisplayNamesImpl(const Locale
& locale
, UDialectHandling dialectHandling
);
313 LocaleDisplayNamesImpl(const Locale
& locale
, UDisplayContext
*contexts
, int32_t length
);
314 virtual ~LocaleDisplayNamesImpl();
316 virtual const Locale
& getLocale() const;
317 virtual UDialectHandling
getDialectHandling() const;
318 virtual UDisplayContext
getContext(UDisplayContextType type
) const;
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
,
338 UnicodeString
& result
) const;
340 UnicodeString
& localeIdName(const char* localeId
,
341 UnicodeString
& result
) const;
342 UnicodeString
& regionShortDisplayName(const char* region
, // Apple-specific
343 UnicodeString
& result
) const;
344 UnicodeString
& appendWithSep(UnicodeString
& buffer
, const UnicodeString
& src
) const;
345 UnicodeString
& adjustForUsageAndContext(CapContextUsage usage
, UnicodeString
& result
) const;
346 UnicodeString
& scriptDisplayName(const char* script
, UnicodeString
& result
, UBool skipAdjust
) const;
347 UnicodeString
& regionDisplayName(const char* region
, UnicodeString
& result
, UBool skipAdjust
) const;
348 UnicodeString
& variantDisplayName(const char* variant
, UnicodeString
& result
, UBool skipAdjust
) const;
349 UnicodeString
& keyDisplayName(const char* key
, UnicodeString
& result
, UBool skipAdjust
) const;
350 UnicodeString
& keyValueDisplayName(const char* key
, const char* value
,
351 UnicodeString
& result
, UBool skipAdjust
) const;
352 void initialize(void);
354 struct CapitalizationContextSink
;
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
)
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
)
378 while (length
-- > 0) {
379 UDisplayContext value
= *contexts
++;
380 UDisplayContextType selector
= (UDisplayContextType
)((uint32_t)value
>> 8);
382 case UDISPCTX_TYPE_DIALECT_HANDLING
:
383 dialectHandling
= (UDialectHandling
)value
;
385 case UDISPCTX_TYPE_CAPITALIZATION
:
386 capitalizationContext
= value
;
388 case UDISPCTX_TYPE_DISPLAY_LENGTH
:
391 case UADISPCTX_TYPE_LENGTH
: // Apple-specific
392 nameLength
= (value
== UADISPCTX_LENGTH_SHORT
)? UDISPCTX_LENGTH_SHORT
: UDISPCTX_LENGTH_FULL
;
401 struct LocaleDisplayNamesImpl::CapitalizationContextSink
: public ResourceSink
{
402 UBool hasCapitalizationUsage
;
403 LocaleDisplayNamesImpl
& parent
;
405 CapitalizationContextSink(LocaleDisplayNamesImpl
& _parent
)
406 : hasCapitalizationUsage(FALSE
), parent(_parent
) {}
407 virtual ~CapitalizationContextSink();
409 virtual void put(const char *key
, ResourceValue
&value
, UBool
/*noFallback*/,
410 UErrorCode
&errorCode
) {
411 ResourceTable contexts
= value
.getTable(errorCode
);
412 if (U_FAILURE(errorCode
)) { return; }
413 for (int i
= 0; contexts
.getKeyAndValue(i
, key
, value
); ++i
) {
415 CapContextUsage usageEnum
;
416 if (uprv_strcmp(key
, "key") == 0) {
417 usageEnum
= kCapContextUsageKey
;
418 } else if (uprv_strcmp(key
, "keyValue") == 0) {
419 usageEnum
= kCapContextUsageKeyValue
;
420 } else if (uprv_strcmp(key
, "languages") == 0) {
421 usageEnum
= kCapContextUsageLanguage
;
422 } else if (uprv_strcmp(key
, "script") == 0) {
423 usageEnum
= kCapContextUsageScript
;
424 } else if (uprv_strcmp(key
, "territory") == 0) {
425 usageEnum
= kCapContextUsageTerritory
;
426 } else if (uprv_strcmp(key
, "variant") == 0) {
427 usageEnum
= kCapContextUsageVariant
;
433 const int32_t* intVector
= value
.getIntVector(len
, errorCode
);
434 if (U_FAILURE(errorCode
)) { return; }
435 if (len
< 2) { continue; }
437 int32_t titlecaseInt
= (parent
.capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
) ? intVector
[0] : intVector
[1];
438 if (titlecaseInt
== 0) { continue; }
440 parent
.fCapitalization
[usageEnum
] = TRUE
;
441 hasCapitalizationUsage
= TRUE
;
446 // Virtual destructors must be defined out of line.
447 LocaleDisplayNamesImpl::CapitalizationContextSink::~CapitalizationContextSink() {}
450 LocaleDisplayNamesImpl::initialize(void) {
451 LocaleDisplayNamesImpl
*nonConstThis
= (LocaleDisplayNamesImpl
*)this;
452 nonConstThis
->locale
= langData
.getLocale() == Locale::getRoot()
453 ? regionData
.getLocale()
454 : langData
.getLocale();
457 langData
.getNoFallback("localeDisplayPattern", "separator", sep
);
459 sep
= UnicodeString("{0}, {1}", -1, US_INV
);
461 UErrorCode status
= U_ZERO_ERROR
;
462 separatorFormat
.applyPatternMinMaxArguments(sep
, 2, 2, status
);
464 UnicodeString pattern
;
465 langData
.getNoFallback("localeDisplayPattern", "pattern", pattern
);
466 if (pattern
.isBogus()) {
467 pattern
= UnicodeString("{0} ({1})", -1, US_INV
);
469 format
.applyPatternMinMaxArguments(pattern
, 2, 2, status
);
470 if (pattern
.indexOf((UChar
)0xFF08) >= 0) {
471 formatOpenParen
.setTo((UChar
)0xFF08); // fullwidth (
472 formatReplaceOpenParen
.setTo((UChar
)0xFF3B); // fullwidth [
473 formatCloseParen
.setTo((UChar
)0xFF09); // fullwidth )
474 formatReplaceCloseParen
.setTo((UChar
)0xFF3D); // fullwidth ]
475 formatParenCloseOpen
.setTo(u
")(", 2); // fullwidth FF09 FF08 redundant parens
478 formatOpenParen
.setTo((UChar
)0x0028); // (
479 formatReplaceOpenParen
.setTo((UChar
)0x005B); // [
480 formatCloseParen
.setTo((UChar
)0x0029); // )
481 formatReplaceCloseParen
.setTo((UChar
)0x005D); // ]
482 formatParenCloseOpen
.setTo(u
") (", 3); // halfwidth redundant parens
485 UnicodeString ktPattern
;
486 langData
.get("localeDisplayPattern", "keyTypePattern", ktPattern
);
487 if (ktPattern
.isBogus()) {
488 ktPattern
= UnicodeString("{0}={1}", -1, US_INV
);
490 keyTypeFormat
.applyPatternMinMaxArguments(ktPattern
, 2, 2, status
);
492 uprv_memset(fCapitalization
, 0, sizeof(fCapitalization
));
493 #if !UCONFIG_NO_BREAK_ITERATION
494 // Only get the context data if we need it! This is a const object so we know now...
495 // Also check whether we will need a break iterator (depends on the data)
496 UBool needBrkIter
= FALSE
;
497 if (capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
|| capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_STANDALONE
) {
498 LocalUResourceBundlePointer
resource(ures_open(NULL
, locale
.getName(), &status
));
499 if (U_FAILURE(status
)) { return; }
500 CapitalizationContextSink
sink(*this);
501 ures_getAllItemsWithFallback(resource
.getAlias(), "contextTransforms", sink
, status
);
502 if (status
== U_MISSING_RESOURCE_ERROR
) {
503 // Silently ignore. Not every locale has contextTransforms.
504 status
= U_ZERO_ERROR
;
505 } else if (U_FAILURE(status
)) {
508 needBrkIter
= sink
.hasCapitalizationUsage
;
510 // Get a sentence break iterator if we will need it
511 if (needBrkIter
|| capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
) {
512 status
= U_ZERO_ERROR
;
513 capitalizationBrkIter
= BreakIterator::createSentenceInstance(locale
, status
);
514 if (U_FAILURE(status
)) {
515 delete capitalizationBrkIter
;
516 capitalizationBrkIter
= NULL
;
522 LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() {
523 #if !UCONFIG_NO_BREAK_ITERATION
524 delete capitalizationBrkIter
;
529 LocaleDisplayNamesImpl::getLocale() const {
534 LocaleDisplayNamesImpl::getDialectHandling() const {
535 return dialectHandling
;
539 LocaleDisplayNamesImpl::getContext(UDisplayContextType type
) const {
541 case UDISPCTX_TYPE_DIALECT_HANDLING
:
542 return (UDisplayContext
)dialectHandling
;
543 case UDISPCTX_TYPE_CAPITALIZATION
:
544 return capitalizationContext
;
545 case UDISPCTX_TYPE_DISPLAY_LENGTH
:
547 case UADISPCTX_TYPE_LENGTH
: // Apple-specific
548 return (nameLength
== UDISPCTX_LENGTH_SHORT
)? UADISPCTX_LENGTH_SHORT
: UADISPCTX_LENGTH_STANDARD
;
552 return (UDisplayContext
)0;
556 LocaleDisplayNamesImpl::adjustForUsageAndContext(CapContextUsage usage
,
557 UnicodeString
& result
) const {
558 #if !UCONFIG_NO_BREAK_ITERATION
559 // check to see whether we need to titlecase result
560 if ( result
.length() > 0 && u_islower(result
.char32At(0)) && capitalizationBrkIter
!= NULL
&&
561 ( capitalizationContext
==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
|| fCapitalization
[usage
] ) ) {
562 // note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE
563 static UMutex
*capitalizationBrkIterLock
= STATIC_NEW(UMutex
);
564 Mutex
lock(capitalizationBrkIterLock
);
565 result
.toTitle(capitalizationBrkIter
, locale
, U_TITLECASE_NO_LOWERCASE
| U_TITLECASE_NO_BREAK_ADJUSTMENT
);
572 LocaleDisplayNamesImpl::localeDisplayName(const Locale
& loc
,
573 UnicodeString
& result
) const {
578 UnicodeString resultName
;
580 const char* lang
= loc
.getLanguage();
581 if (uprv_strlen(lang
) == 0) {
584 const char* script
= loc
.getScript();
585 const char* country
= loc
.getCountry();
586 const char* variant
= loc
.getVariant();
588 UBool hasScript
= uprv_strlen(script
) > 0;
589 UBool hasCountry
= uprv_strlen(country
) > 0;
590 UBool hasVariant
= uprv_strlen(variant
) > 0;
592 // For stylistic reasons, always load dialect names for `zh` and `yue`. <rdar://50750364>
593 // Also for `ks`, 'pa, 'ur'. <rdar://50687287>
594 UBool forceDialect
= (uprv_strcmp(lang
, "zh") == 0 || uprv_strcmp(lang
, "yue") == 0 ||
595 uprv_strcmp(lang
, "ks") == 0 || uprv_strcmp(lang
, "pa") == 0 || uprv_strcmp(lang
, "ur") == 0);
597 if (forceDialect
|| dialectHandling
== ULDN_DIALECT_NAMES
) {
598 char buffer
[ULOC_FULLNAME_CAPACITY
];
599 do { // loop construct is so we can break early out of search
600 if (hasScript
&& hasCountry
) {
601 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", script
, "_", country
, (char *)0);
602 localeIdName(buffer
, resultName
);
603 if (!resultName
.isBogus()) {
610 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", script
, (char *)0);
611 localeIdName(buffer
, resultName
);
612 if (!resultName
.isBogus()) {
618 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", country
, (char*)0);
619 localeIdName(buffer
, resultName
);
620 if (!resultName
.isBogus()) {
627 if (resultName
.isBogus() || resultName
.isEmpty()) {
628 localeIdName(lang
, resultName
);
631 UnicodeString resultRemainder
;
633 UErrorCode status
= U_ZERO_ERROR
;
636 resultRemainder
.append(scriptDisplayName(script
, temp
, TRUE
));
639 appendWithSep(resultRemainder
, regionShortDisplayName(country
, temp
)); // Apple modification
642 appendWithSep(resultRemainder
, variantDisplayName(variant
, temp
, TRUE
));
644 resultRemainder
.findAndReplace(formatOpenParen
, formatReplaceOpenParen
);
645 resultRemainder
.findAndReplace(formatCloseParen
, formatReplaceCloseParen
);
647 LocalPointer
<StringEnumeration
> e(loc
.createKeywords(status
));
648 if (e
.isValid() && U_SUCCESS(status
)) {
650 char value
[ULOC_KEYWORD_AND_VALUES_CAPACITY
]; // sigh, no ULOC_VALUE_CAPACITY
652 while ((key
= e
->next((int32_t *)0, status
)) != NULL
) {
654 loc
.getKeywordValue(key
, value
, ULOC_KEYWORD_AND_VALUES_CAPACITY
, status
);
655 if (U_FAILURE(status
) || status
== U_STRING_NOT_TERMINATED_WARNING
) {
658 keyDisplayName(key
, temp
, TRUE
);
659 temp
.findAndReplace(formatOpenParen
, formatReplaceOpenParen
);
660 temp
.findAndReplace(formatCloseParen
, formatReplaceCloseParen
);
661 keyValueDisplayName(key
, value
, temp2
, TRUE
);
662 temp2
.findAndReplace(formatOpenParen
, formatReplaceOpenParen
);
663 temp2
.findAndReplace(formatCloseParen
, formatReplaceCloseParen
);
664 if (temp2
!= UnicodeString(value
, -1, US_INV
)) {
665 appendWithSep(resultRemainder
, temp2
);
666 } else if (temp
!= UnicodeString(key
, -1, US_INV
)) {
668 keyTypeFormat
.format(temp
, temp2
, temp3
, status
);
669 appendWithSep(resultRemainder
, temp3
);
671 appendWithSep(resultRemainder
, temp
)
672 .append((UChar
)0x3d /* = */)
678 if (!resultRemainder
.isEmpty()) {
679 format
.format(resultName
, resultRemainder
, result
.remove(), status
);
680 int32_t indexCloseOpen
= result
.indexOf(formatParenCloseOpen
);
681 if (indexCloseOpen
>= 0) { // replace redundant close-open parens with separator <rdar://problem/50687287>
682 UnicodeString
tail(result
, indexCloseOpen
+ formatParenCloseOpen
.length()); // section after close-open
683 result
.retainBetween(0, indexCloseOpen
); // section before close-open
684 appendWithSep(result
, tail
); // combine using separator
686 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
690 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
694 LocaleDisplayNamesImpl::appendWithSep(UnicodeString
& buffer
, const UnicodeString
& src
) const {
695 if (buffer
.isEmpty()) {
698 const UnicodeString
*values
[2] = { &buffer
, &src
};
699 UErrorCode status
= U_ZERO_ERROR
;
700 separatorFormat
.formatAndReplace(values
, 2, buffer
, NULL
, 0, status
);
706 LocaleDisplayNamesImpl::localeDisplayName(const char* localeId
,
707 UnicodeString
& result
) const {
708 return localeDisplayName(Locale(localeId
), result
);
713 LocaleDisplayNamesImpl::localeIdName(const char* localeId
,
714 UnicodeString
& result
) const {
715 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
716 langData
.getNoFallback("Languages%short", localeId
, result
);
717 if (!result
.isBogus()) {
721 return langData
.getNoFallback("Languages", localeId
, result
);
725 LocaleDisplayNamesImpl::languageDisplayName(const char* lang
,
726 UnicodeString
& result
) const {
727 if (uprv_strcmp("root", lang
) == 0 || uprv_strchr(lang
, '_') != NULL
) {
728 return result
= UnicodeString(lang
, -1, US_INV
);
730 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
731 langData
.getNoFallback("Languages%short", lang
, result
);
732 if (!result
.isBogus()) {
733 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
736 langData
.get("Languages", lang
, result
);
737 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
741 LocaleDisplayNamesImpl::scriptDisplayName(const char* script
,
742 UnicodeString
& result
,
743 UBool skipAdjust
) const {
744 if (!skipAdjust
) { // => prefer standalone
745 langData
.getNoFallback("Scripts%stand-alone", script
, result
);
746 if (!result
.isBogus()) {
747 return adjustForUsageAndContext(kCapContextUsageScript
, result
);
750 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
751 langData
.getNoFallback("Scripts%short", script
, result
);
752 if (!result
.isBogus()) {
753 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageScript
, result
);
756 langData
.get("Scripts", script
, result
);
757 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageScript
, result
);
761 LocaleDisplayNamesImpl::scriptDisplayName(const char* script
,
762 UnicodeString
& result
) const {
763 return scriptDisplayName(script
, result
, FALSE
);
767 LocaleDisplayNamesImpl::scriptDisplayName(UScriptCode scriptCode
,
768 UnicodeString
& result
) const {
769 return scriptDisplayName(uscript_getName(scriptCode
), result
, FALSE
);
773 LocaleDisplayNamesImpl::regionDisplayName(const char* region
,
774 UnicodeString
& result
,
775 UBool skipAdjust
) const {
776 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
777 regionData
.getNoFallback("Countries%short", region
, result
);
778 if (!result
.isBogus()) {
779 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageTerritory
, result
);
782 regionData
.get("Countries", region
, result
);
783 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageTerritory
, result
);
786 // private Apple, only for building localeDisplayName
787 // (use short region, don't adjust for context)
789 LocaleDisplayNamesImpl::regionShortDisplayName(const char* region
,
790 UnicodeString
& result
) const {
791 if (uprv_strcmp(region
, "PS") != 0) {
792 regionData
.getNoFallback("Countries%short", region
, result
);
793 if (!result
.isBogus()) {
797 regionData
.get("Countries", region
, result
);
802 LocaleDisplayNamesImpl::regionDisplayName(const char* region
,
803 UnicodeString
& result
) const {
804 return regionDisplayName(region
, result
, FALSE
);
809 LocaleDisplayNamesImpl::variantDisplayName(const char* variant
,
810 UnicodeString
& result
,
811 UBool skipAdjust
) const {
812 // don't have a resource for short variant names
813 langData
.get("Variants", variant
, result
);
814 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageVariant
, result
);
818 LocaleDisplayNamesImpl::variantDisplayName(const char* variant
,
819 UnicodeString
& result
) const {
820 return variantDisplayName(variant
, result
, FALSE
);
824 LocaleDisplayNamesImpl::keyDisplayName(const char* key
,
825 UnicodeString
& result
,
826 UBool skipAdjust
) const {
827 // don't have a resource for short key names
828 langData
.get("Keys", key
, result
);
829 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKey
, result
);
833 LocaleDisplayNamesImpl::keyDisplayName(const char* key
,
834 UnicodeString
& result
) const {
835 return keyDisplayName(key
, result
, FALSE
);
839 LocaleDisplayNamesImpl::keyValueDisplayName(const char* key
,
841 UnicodeString
& result
,
842 UBool skipAdjust
) const {
843 if (uprv_strcmp(key
, "currency") == 0) {
844 // ICU4C does not have ICU4J CurrencyDisplayInfo equivalent for now.
845 UErrorCode sts
= U_ZERO_ERROR
;
846 UnicodeString
ustrValue(value
, -1, US_INV
);
848 UBool isChoice
= FALSE
;
849 const UChar
*currencyName
= ucurr_getName(ustrValue
.getTerminatedBuffer(),
850 locale
.getBaseName(), UCURR_LONG_NAME
, &isChoice
, &len
, &sts
);
851 if (U_FAILURE(sts
)) {
852 // Return the value as is on failure
856 result
.setTo(currencyName
, len
);
857 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKeyValue
, result
);
860 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
861 langData
.get("Types%short", key
, value
, result
);
862 if (!result
.isBogus()) {
863 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKeyValue
, result
);
866 langData
.get("Types", key
, value
, result
);
867 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKeyValue
, result
);
871 LocaleDisplayNamesImpl::keyValueDisplayName(const char* key
,
873 UnicodeString
& result
) const {
874 return keyValueDisplayName(key
, value
, result
, FALSE
);
877 ////////////////////////////////////////////////////////////////////////////////////////////////////
880 LocaleDisplayNames::createInstance(const Locale
& locale
,
881 UDialectHandling dialectHandling
) {
882 return new LocaleDisplayNamesImpl(locale
, dialectHandling
);
886 LocaleDisplayNames::createInstance(const Locale
& locale
,
887 UDisplayContext
*contexts
, int32_t length
) {
888 if (contexts
== NULL
) {
891 return new LocaleDisplayNamesImpl(locale
, contexts
, length
);
896 ////////////////////////////////////////////////////////////////////////////////////////////////////
900 U_CAPI ULocaleDisplayNames
* U_EXPORT2
901 uldn_open(const char * locale
,
902 UDialectHandling dialectHandling
,
903 UErrorCode
*pErrorCode
) {
904 if (U_FAILURE(*pErrorCode
)) {
907 if (locale
== NULL
) {
908 locale
= uloc_getDefault();
910 return (ULocaleDisplayNames
*)LocaleDisplayNames::createInstance(Locale(locale
), dialectHandling
);
913 U_CAPI ULocaleDisplayNames
* U_EXPORT2
914 uldn_openForContext(const char * locale
,
915 UDisplayContext
*contexts
, int32_t length
,
916 UErrorCode
*pErrorCode
) {
917 if (U_FAILURE(*pErrorCode
)) {
920 if (locale
== NULL
) {
921 locale
= uloc_getDefault();
923 return (ULocaleDisplayNames
*)LocaleDisplayNames::createInstance(Locale(locale
), contexts
, length
);
927 U_CAPI
void U_EXPORT2
928 uldn_close(ULocaleDisplayNames
*ldn
) {
929 delete (LocaleDisplayNames
*)ldn
;
932 U_CAPI
const char * U_EXPORT2
933 uldn_getLocale(const ULocaleDisplayNames
*ldn
) {
935 return ((const LocaleDisplayNames
*)ldn
)->getLocale().getName();
940 U_CAPI UDialectHandling U_EXPORT2
941 uldn_getDialectHandling(const ULocaleDisplayNames
*ldn
) {
943 return ((const LocaleDisplayNames
*)ldn
)->getDialectHandling();
945 return ULDN_STANDARD_NAMES
;
948 U_CAPI UDisplayContext U_EXPORT2
949 uldn_getContext(const ULocaleDisplayNames
*ldn
,
950 UDisplayContextType type
,
951 UErrorCode
*pErrorCode
) {
952 if (U_FAILURE(*pErrorCode
)) {
953 return (UDisplayContext
)0;
955 return ((const LocaleDisplayNames
*)ldn
)->getContext(type
);
958 U_CAPI
int32_t U_EXPORT2
959 uldn_localeDisplayName(const ULocaleDisplayNames
*ldn
,
962 int32_t maxResultSize
,
963 UErrorCode
*pErrorCode
) {
964 if (U_FAILURE(*pErrorCode
)) {
967 if (ldn
== NULL
|| locale
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
968 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
971 UnicodeString
temp(result
, 0, maxResultSize
);
972 ((const LocaleDisplayNames
*)ldn
)->localeDisplayName(locale
, temp
);
973 if (temp
.isBogus()) {
974 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
977 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
980 U_CAPI
int32_t U_EXPORT2
981 uldn_languageDisplayName(const ULocaleDisplayNames
*ldn
,
984 int32_t maxResultSize
,
985 UErrorCode
*pErrorCode
) {
986 if (U_FAILURE(*pErrorCode
)) {
989 if (ldn
== NULL
|| lang
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
990 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
993 UnicodeString
temp(result
, 0, maxResultSize
);
994 ((const LocaleDisplayNames
*)ldn
)->languageDisplayName(lang
, temp
);
995 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
998 U_CAPI
int32_t U_EXPORT2
999 uldn_scriptDisplayName(const ULocaleDisplayNames
*ldn
,
1002 int32_t maxResultSize
,
1003 UErrorCode
*pErrorCode
) {
1004 if (U_FAILURE(*pErrorCode
)) {
1007 if (ldn
== NULL
|| script
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
1008 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1011 UnicodeString
temp(result
, 0, maxResultSize
);
1012 ((const LocaleDisplayNames
*)ldn
)->scriptDisplayName(script
, temp
);
1013 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1016 U_CAPI
int32_t U_EXPORT2
1017 uldn_scriptCodeDisplayName(const ULocaleDisplayNames
*ldn
,
1018 UScriptCode scriptCode
,
1020 int32_t maxResultSize
,
1021 UErrorCode
*pErrorCode
) {
1022 return uldn_scriptDisplayName(ldn
, uscript_getName(scriptCode
), result
, maxResultSize
, pErrorCode
);
1025 U_CAPI
int32_t U_EXPORT2
1026 uldn_regionDisplayName(const ULocaleDisplayNames
*ldn
,
1029 int32_t maxResultSize
,
1030 UErrorCode
*pErrorCode
) {
1031 if (U_FAILURE(*pErrorCode
)) {
1034 if (ldn
== NULL
|| region
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
1035 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1038 UnicodeString
temp(result
, 0, maxResultSize
);
1039 ((const LocaleDisplayNames
*)ldn
)->regionDisplayName(region
, temp
);
1040 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1043 U_CAPI
int32_t U_EXPORT2
1044 uldn_variantDisplayName(const ULocaleDisplayNames
*ldn
,
1045 const char *variant
,
1047 int32_t maxResultSize
,
1048 UErrorCode
*pErrorCode
) {
1049 if (U_FAILURE(*pErrorCode
)) {
1052 if (ldn
== NULL
|| variant
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
1053 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1056 UnicodeString
temp(result
, 0, maxResultSize
);
1057 ((const LocaleDisplayNames
*)ldn
)->variantDisplayName(variant
, temp
);
1058 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1061 U_CAPI
int32_t U_EXPORT2
1062 uldn_keyDisplayName(const ULocaleDisplayNames
*ldn
,
1065 int32_t maxResultSize
,
1066 UErrorCode
*pErrorCode
) {
1067 if (U_FAILURE(*pErrorCode
)) {
1070 if (ldn
== NULL
|| key
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
1071 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1074 UnicodeString
temp(result
, 0, maxResultSize
);
1075 ((const LocaleDisplayNames
*)ldn
)->keyDisplayName(key
, temp
);
1076 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1079 U_CAPI
int32_t U_EXPORT2
1080 uldn_keyValueDisplayName(const ULocaleDisplayNames
*ldn
,
1084 int32_t maxResultSize
,
1085 UErrorCode
*pErrorCode
) {
1086 if (U_FAILURE(*pErrorCode
)) {
1089 if (ldn
== NULL
|| key
== NULL
|| value
== NULL
|| (result
== NULL
&& maxResultSize
> 0)
1090 || maxResultSize
< 0) {
1091 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1094 UnicodeString
temp(result
, 0, maxResultSize
);
1095 ((const LocaleDisplayNames
*)ldn
)->keyValueDisplayName(key
, value
, temp
);
1096 return temp
.extract(result
, maxResultSize
, *pErrorCode
);