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 *))) {
50 while (p
!= e
&& (c
= *str
++)) {
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
= 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 static UMutex capitalizationBrkIterLock
;
290 UnicodeString formatOpenParen
;
291 UnicodeString formatReplaceOpenParen
;
292 UnicodeString formatCloseParen
;
293 UnicodeString formatReplaceCloseParen
;
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 UMutex
LocaleDisplayNamesImpl::capitalizationBrkIterLock
= U_MUTEX_INITIALIZER
;
359 LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale
& locale
,
360 UDialectHandling dialectHandling
)
361 : dialectHandling(dialectHandling
)
362 , langData(U_ICUDATA_LANG
, locale
)
363 , regionData(U_ICUDATA_REGION
, locale
)
364 , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE
)
365 , capitalizationBrkIter(NULL
)
366 , nameLength(UDISPCTX_LENGTH_FULL
)
371 LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale
& locale
,
372 UDisplayContext
*contexts
, int32_t length
)
373 : dialectHandling(ULDN_STANDARD_NAMES
)
374 , langData(U_ICUDATA_LANG
, locale
)
375 , regionData(U_ICUDATA_REGION
, locale
)
376 , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE
)
377 , capitalizationBrkIter(NULL
)
378 , nameLength(UDISPCTX_LENGTH_FULL
)
380 while (length
-- > 0) {
381 UDisplayContext value
= *contexts
++;
382 UDisplayContextType selector
= (UDisplayContextType
)((uint32_t)value
>> 8);
384 case UDISPCTX_TYPE_DIALECT_HANDLING
:
385 dialectHandling
= (UDialectHandling
)value
;
387 case UDISPCTX_TYPE_CAPITALIZATION
:
388 capitalizationContext
= value
;
390 case UDISPCTX_TYPE_DISPLAY_LENGTH
:
393 case UADISPCTX_TYPE_LENGTH
: // Apple-specific
394 nameLength
= (value
== UADISPCTX_LENGTH_SHORT
)? UDISPCTX_LENGTH_SHORT
: UDISPCTX_LENGTH_FULL
;
403 struct LocaleDisplayNamesImpl::CapitalizationContextSink
: public ResourceSink
{
404 UBool hasCapitalizationUsage
;
405 LocaleDisplayNamesImpl
& parent
;
407 CapitalizationContextSink(LocaleDisplayNamesImpl
& _parent
)
408 : hasCapitalizationUsage(FALSE
), parent(_parent
) {}
409 virtual ~CapitalizationContextSink();
411 virtual void put(const char *key
, ResourceValue
&value
, UBool
/*noFallback*/,
412 UErrorCode
&errorCode
) {
413 ResourceTable contexts
= value
.getTable(errorCode
);
414 if (U_FAILURE(errorCode
)) { return; }
415 for (int i
= 0; contexts
.getKeyAndValue(i
, key
, value
); ++i
) {
417 CapContextUsage usageEnum
;
418 if (uprv_strcmp(key
, "key") == 0) {
419 usageEnum
= kCapContextUsageKey
;
420 } else if (uprv_strcmp(key
, "keyValue") == 0) {
421 usageEnum
= kCapContextUsageKeyValue
;
422 } else if (uprv_strcmp(key
, "languages") == 0) {
423 usageEnum
= kCapContextUsageLanguage
;
424 } else if (uprv_strcmp(key
, "script") == 0) {
425 usageEnum
= kCapContextUsageScript
;
426 } else if (uprv_strcmp(key
, "territory") == 0) {
427 usageEnum
= kCapContextUsageTerritory
;
428 } else if (uprv_strcmp(key
, "variant") == 0) {
429 usageEnum
= kCapContextUsageVariant
;
435 const int32_t* intVector
= value
.getIntVector(len
, errorCode
);
436 if (U_FAILURE(errorCode
)) { return; }
437 if (len
< 2) { continue; }
439 int32_t titlecaseInt
= (parent
.capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
) ? intVector
[0] : intVector
[1];
440 if (titlecaseInt
== 0) { continue; }
442 parent
.fCapitalization
[usageEnum
] = TRUE
;
443 hasCapitalizationUsage
= TRUE
;
448 // Virtual destructors must be defined out of line.
449 LocaleDisplayNamesImpl::CapitalizationContextSink::~CapitalizationContextSink() {}
452 LocaleDisplayNamesImpl::initialize(void) {
453 LocaleDisplayNamesImpl
*nonConstThis
= (LocaleDisplayNamesImpl
*)this;
454 nonConstThis
->locale
= langData
.getLocale() == Locale::getRoot()
455 ? regionData
.getLocale()
456 : langData
.getLocale();
459 langData
.getNoFallback("localeDisplayPattern", "separator", sep
);
461 sep
= UnicodeString("{0}, {1}", -1, US_INV
);
463 UErrorCode status
= U_ZERO_ERROR
;
464 separatorFormat
.applyPatternMinMaxArguments(sep
, 2, 2, status
);
466 UnicodeString pattern
;
467 langData
.getNoFallback("localeDisplayPattern", "pattern", pattern
);
468 if (pattern
.isBogus()) {
469 pattern
= UnicodeString("{0} ({1})", -1, US_INV
);
471 format
.applyPatternMinMaxArguments(pattern
, 2, 2, status
);
472 if (pattern
.indexOf((UChar
)0xFF08) >= 0) {
473 formatOpenParen
.setTo((UChar
)0xFF08); // fullwidth (
474 formatReplaceOpenParen
.setTo((UChar
)0xFF3B); // fullwidth [
475 formatCloseParen
.setTo((UChar
)0xFF09); // fullwidth )
476 formatReplaceCloseParen
.setTo((UChar
)0xFF3D); // fullwidth ]
478 formatOpenParen
.setTo((UChar
)0x0028); // (
479 formatReplaceOpenParen
.setTo((UChar
)0x005B); // [
480 formatCloseParen
.setTo((UChar
)0x0029); // )
481 formatReplaceCloseParen
.setTo((UChar
)0x005D); // ]
484 UnicodeString ktPattern
;
485 langData
.get("localeDisplayPattern", "keyTypePattern", ktPattern
);
486 if (ktPattern
.isBogus()) {
487 ktPattern
= UnicodeString("{0}={1}", -1, US_INV
);
489 keyTypeFormat
.applyPatternMinMaxArguments(ktPattern
, 2, 2, status
);
491 uprv_memset(fCapitalization
, 0, sizeof(fCapitalization
));
492 #if !UCONFIG_NO_BREAK_ITERATION
493 // Only get the context data if we need it! This is a const object so we know now...
494 // Also check whether we will need a break iterator (depends on the data)
495 UBool needBrkIter
= FALSE
;
496 if (capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
|| capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_STANDALONE
) {
497 LocalUResourceBundlePointer
resource(ures_open(NULL
, locale
.getName(), &status
));
498 if (U_FAILURE(status
)) { return; }
499 CapitalizationContextSink
sink(*this);
500 ures_getAllItemsWithFallback(resource
.getAlias(), "contextTransforms", sink
, status
);
501 if (status
== U_MISSING_RESOURCE_ERROR
) {
502 // Silently ignore. Not every locale has contextTransforms.
503 status
= U_ZERO_ERROR
;
504 } else if (U_FAILURE(status
)) {
507 needBrkIter
= sink
.hasCapitalizationUsage
;
509 // Get a sentence break iterator if we will need it
510 if (needBrkIter
|| capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
) {
511 status
= U_ZERO_ERROR
;
512 capitalizationBrkIter
= BreakIterator::createSentenceInstance(locale
, status
);
513 if (U_FAILURE(status
)) {
514 delete capitalizationBrkIter
;
515 capitalizationBrkIter
= NULL
;
521 LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() {
522 #if !UCONFIG_NO_BREAK_ITERATION
523 delete capitalizationBrkIter
;
528 LocaleDisplayNamesImpl::getLocale() const {
533 LocaleDisplayNamesImpl::getDialectHandling() const {
534 return dialectHandling
;
538 LocaleDisplayNamesImpl::getContext(UDisplayContextType type
) const {
540 case UDISPCTX_TYPE_DIALECT_HANDLING
:
541 return (UDisplayContext
)dialectHandling
;
542 case UDISPCTX_TYPE_CAPITALIZATION
:
543 return capitalizationContext
;
544 case UDISPCTX_TYPE_DISPLAY_LENGTH
:
546 case UADISPCTX_TYPE_LENGTH
: // Apple-specific
547 return (nameLength
== UDISPCTX_LENGTH_SHORT
)? UADISPCTX_LENGTH_SHORT
: UADISPCTX_LENGTH_STANDARD
;
551 return (UDisplayContext
)0;
555 LocaleDisplayNamesImpl::adjustForUsageAndContext(CapContextUsage usage
,
556 UnicodeString
& result
) const {
557 #if !UCONFIG_NO_BREAK_ITERATION
558 // check to see whether we need to titlecase result
559 if ( result
.length() > 0 && u_islower(result
.char32At(0)) && capitalizationBrkIter
!= NULL
&&
560 ( capitalizationContext
==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
|| fCapitalization
[usage
] ) ) {
561 // note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE
562 Mutex
lock(&capitalizationBrkIterLock
);
563 result
.toTitle(capitalizationBrkIter
, locale
, U_TITLECASE_NO_LOWERCASE
| U_TITLECASE_NO_BREAK_ADJUSTMENT
);
570 LocaleDisplayNamesImpl::localeDisplayName(const Locale
& locale
,
571 UnicodeString
& result
) const {
572 if (locale
.isBogus()) {
576 UnicodeString resultName
;
578 const char* lang
= locale
.getLanguage();
579 if (uprv_strlen(lang
) == 0) {
582 const char* script
= locale
.getScript();
583 const char* country
= locale
.getCountry();
584 const char* variant
= locale
.getVariant();
586 UBool hasScript
= uprv_strlen(script
) > 0;
587 UBool hasCountry
= uprv_strlen(country
) > 0;
588 UBool hasVariant
= uprv_strlen(variant
) > 0;
590 if (dialectHandling
== ULDN_DIALECT_NAMES
) {
591 char buffer
[ULOC_FULLNAME_CAPACITY
];
592 do { // loop construct is so we can break early out of search
593 if (hasScript
&& hasCountry
) {
594 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", script
, "_", country
, (char *)0);
595 localeIdName(buffer
, resultName
);
596 if (!resultName
.isBogus()) {
603 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", script
, (char *)0);
604 localeIdName(buffer
, resultName
);
605 if (!resultName
.isBogus()) {
611 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", country
, (char*)0);
612 localeIdName(buffer
, resultName
);
613 if (!resultName
.isBogus()) {
620 if (resultName
.isBogus() || resultName
.isEmpty()) {
621 localeIdName(lang
, resultName
);
624 UnicodeString resultRemainder
;
626 UErrorCode status
= U_ZERO_ERROR
;
629 resultRemainder
.append(scriptDisplayName(script
, temp
, TRUE
));
632 appendWithSep(resultRemainder
, regionShortDisplayName(country
, temp
)); // Apple modification
635 appendWithSep(resultRemainder
, variantDisplayName(variant
, temp
, TRUE
));
637 resultRemainder
.findAndReplace(formatOpenParen
, formatReplaceOpenParen
);
638 resultRemainder
.findAndReplace(formatCloseParen
, formatReplaceCloseParen
);
640 LocalPointer
<StringEnumeration
> e(locale
.createKeywords(status
));
641 if (e
.isValid() && U_SUCCESS(status
)) {
643 char value
[ULOC_KEYWORD_AND_VALUES_CAPACITY
]; // sigh, no ULOC_VALUE_CAPACITY
645 while ((key
= e
->next((int32_t *)0, status
)) != NULL
) {
646 locale
.getKeywordValue(key
, value
, ULOC_KEYWORD_AND_VALUES_CAPACITY
, status
);
647 if (U_FAILURE(status
)) {
650 keyDisplayName(key
, temp
, TRUE
);
651 temp
.findAndReplace(formatOpenParen
, formatReplaceOpenParen
);
652 temp
.findAndReplace(formatCloseParen
, formatReplaceCloseParen
);
653 keyValueDisplayName(key
, value
, temp2
, TRUE
);
654 temp2
.findAndReplace(formatOpenParen
, formatReplaceOpenParen
);
655 temp2
.findAndReplace(formatCloseParen
, formatReplaceCloseParen
);
656 if (temp2
!= UnicodeString(value
, -1, US_INV
)) {
657 appendWithSep(resultRemainder
, temp2
);
658 } else if (temp
!= UnicodeString(key
, -1, US_INV
)) {
660 keyTypeFormat
.format(temp
, temp2
, temp3
, status
);
661 appendWithSep(resultRemainder
, temp3
);
663 appendWithSep(resultRemainder
, temp
)
664 .append((UChar
)0x3d /* = */)
670 if (!resultRemainder
.isEmpty()) {
671 format
.format(resultName
, resultRemainder
, result
.remove(), status
);
672 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
676 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
680 LocaleDisplayNamesImpl::appendWithSep(UnicodeString
& buffer
, const UnicodeString
& src
) const {
681 if (buffer
.isEmpty()) {
684 const UnicodeString
*values
[2] = { &buffer
, &src
};
685 UErrorCode status
= U_ZERO_ERROR
;
686 separatorFormat
.formatAndReplace(values
, 2, buffer
, NULL
, 0, status
);
692 LocaleDisplayNamesImpl::localeDisplayName(const char* localeId
,
693 UnicodeString
& result
) const {
694 return localeDisplayName(Locale(localeId
), result
);
699 LocaleDisplayNamesImpl::localeIdName(const char* localeId
,
700 UnicodeString
& result
) const {
701 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
702 langData
.getNoFallback("Languages%short", localeId
, result
);
703 if (!result
.isBogus()) {
707 return langData
.getNoFallback("Languages", localeId
, result
);
711 LocaleDisplayNamesImpl::languageDisplayName(const char* lang
,
712 UnicodeString
& result
) const {
713 if (uprv_strcmp("root", lang
) == 0 || uprv_strchr(lang
, '_') != NULL
) {
714 return result
= UnicodeString(lang
, -1, US_INV
);
716 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
717 langData
.getNoFallback("Languages%short", lang
, result
);
718 if (!result
.isBogus()) {
719 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
722 langData
.get("Languages", lang
, result
);
723 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
727 LocaleDisplayNamesImpl::scriptDisplayName(const char* script
,
728 UnicodeString
& result
,
729 UBool skipAdjust
) const {
730 if (!skipAdjust
) { // => prefer standalone
731 langData
.getNoFallback("Scripts%stand-alone", script
, result
);
732 if (!result
.isBogus()) {
733 return adjustForUsageAndContext(kCapContextUsageScript
, result
);
736 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
737 langData
.getNoFallback("Scripts%short", script
, result
);
738 if (!result
.isBogus()) {
739 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageScript
, result
);
742 langData
.get("Scripts", script
, result
);
743 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageScript
, result
);
747 LocaleDisplayNamesImpl::scriptDisplayName(const char* script
,
748 UnicodeString
& result
) const {
749 return scriptDisplayName(script
, result
, FALSE
);
753 LocaleDisplayNamesImpl::scriptDisplayName(UScriptCode scriptCode
,
754 UnicodeString
& result
) const {
755 return scriptDisplayName(uscript_getName(scriptCode
), result
, FALSE
);
759 LocaleDisplayNamesImpl::regionDisplayName(const char* region
,
760 UnicodeString
& result
,
761 UBool skipAdjust
) const {
762 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
763 regionData
.getNoFallback("Countries%short", region
, result
);
764 if (!result
.isBogus()) {
765 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageTerritory
, result
);
768 regionData
.get("Countries", region
, result
);
769 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageTerritory
, result
);
772 // private Apple, only for building localeDisplayName
773 // (use short region, don't adjust for context)
775 LocaleDisplayNamesImpl::regionShortDisplayName(const char* region
,
776 UnicodeString
& result
) const {
777 if (uprv_strcmp(region
, "PS") != 0) {
778 regionData
.getNoFallback("Countries%short", region
, result
);
779 if (!result
.isBogus()) {
783 regionData
.get("Countries", region
, result
);
788 LocaleDisplayNamesImpl::regionDisplayName(const char* region
,
789 UnicodeString
& result
) const {
790 return regionDisplayName(region
, result
, FALSE
);
795 LocaleDisplayNamesImpl::variantDisplayName(const char* variant
,
796 UnicodeString
& result
,
797 UBool skipAdjust
) const {
798 // don't have a resource for short variant names
799 langData
.get("Variants", variant
, result
);
800 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageVariant
, result
);
804 LocaleDisplayNamesImpl::variantDisplayName(const char* variant
,
805 UnicodeString
& result
) const {
806 return variantDisplayName(variant
, result
, FALSE
);
810 LocaleDisplayNamesImpl::keyDisplayName(const char* key
,
811 UnicodeString
& result
,
812 UBool skipAdjust
) const {
813 // don't have a resource for short key names
814 langData
.get("Keys", key
, result
);
815 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKey
, result
);
819 LocaleDisplayNamesImpl::keyDisplayName(const char* key
,
820 UnicodeString
& result
) const {
821 return keyDisplayName(key
, result
, FALSE
);
825 LocaleDisplayNamesImpl::keyValueDisplayName(const char* key
,
827 UnicodeString
& result
,
828 UBool skipAdjust
) const {
829 if (uprv_strcmp(key
, "currency") == 0) {
830 // ICU4C does not have ICU4J CurrencyDisplayInfo equivalent for now.
831 UErrorCode sts
= U_ZERO_ERROR
;
832 UnicodeString
ustrValue(value
, -1, US_INV
);
834 UBool isChoice
= FALSE
;
835 const UChar
*currencyName
= ucurr_getName(ustrValue
.getTerminatedBuffer(),
836 locale
.getBaseName(), UCURR_LONG_NAME
, &isChoice
, &len
, &sts
);
837 if (U_FAILURE(sts
)) {
838 // Return the value as is on failure
842 result
.setTo(currencyName
, len
);
843 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKeyValue
, result
);
846 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
847 langData
.get("Types%short", key
, value
, result
);
848 if (!result
.isBogus()) {
849 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKeyValue
, result
);
852 langData
.get("Types", key
, value
, result
);
853 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKeyValue
, result
);
857 LocaleDisplayNamesImpl::keyValueDisplayName(const char* key
,
859 UnicodeString
& result
) const {
860 return keyValueDisplayName(key
, value
, result
, FALSE
);
863 ////////////////////////////////////////////////////////////////////////////////////////////////////
866 LocaleDisplayNames::createInstance(const Locale
& locale
,
867 UDialectHandling dialectHandling
) {
868 return new LocaleDisplayNamesImpl(locale
, dialectHandling
);
872 LocaleDisplayNames::createInstance(const Locale
& locale
,
873 UDisplayContext
*contexts
, int32_t length
) {
874 if (contexts
== NULL
) {
877 return new LocaleDisplayNamesImpl(locale
, contexts
, length
);
882 ////////////////////////////////////////////////////////////////////////////////////////////////////
886 U_CAPI ULocaleDisplayNames
* U_EXPORT2
887 uldn_open(const char * locale
,
888 UDialectHandling dialectHandling
,
889 UErrorCode
*pErrorCode
) {
890 if (U_FAILURE(*pErrorCode
)) {
893 if (locale
== NULL
) {
894 locale
= uloc_getDefault();
896 return (ULocaleDisplayNames
*)LocaleDisplayNames::createInstance(Locale(locale
), dialectHandling
);
899 U_CAPI ULocaleDisplayNames
* U_EXPORT2
900 uldn_openForContext(const char * locale
,
901 UDisplayContext
*contexts
, int32_t length
,
902 UErrorCode
*pErrorCode
) {
903 if (U_FAILURE(*pErrorCode
)) {
906 if (locale
== NULL
) {
907 locale
= uloc_getDefault();
909 return (ULocaleDisplayNames
*)LocaleDisplayNames::createInstance(Locale(locale
), contexts
, length
);
913 U_CAPI
void U_EXPORT2
914 uldn_close(ULocaleDisplayNames
*ldn
) {
915 delete (LocaleDisplayNames
*)ldn
;
918 U_CAPI
const char * U_EXPORT2
919 uldn_getLocale(const ULocaleDisplayNames
*ldn
) {
921 return ((const LocaleDisplayNames
*)ldn
)->getLocale().getName();
926 U_CAPI UDialectHandling U_EXPORT2
927 uldn_getDialectHandling(const ULocaleDisplayNames
*ldn
) {
929 return ((const LocaleDisplayNames
*)ldn
)->getDialectHandling();
931 return ULDN_STANDARD_NAMES
;
934 U_CAPI UDisplayContext U_EXPORT2
935 uldn_getContext(const ULocaleDisplayNames
*ldn
,
936 UDisplayContextType type
,
937 UErrorCode
*pErrorCode
) {
938 if (U_FAILURE(*pErrorCode
)) {
939 return (UDisplayContext
)0;
941 return ((const LocaleDisplayNames
*)ldn
)->getContext(type
);
944 U_CAPI
int32_t U_EXPORT2
945 uldn_localeDisplayName(const ULocaleDisplayNames
*ldn
,
948 int32_t maxResultSize
,
949 UErrorCode
*pErrorCode
) {
950 if (U_FAILURE(*pErrorCode
)) {
953 if (ldn
== NULL
|| locale
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
954 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
957 UnicodeString
temp(result
, 0, maxResultSize
);
958 ((const LocaleDisplayNames
*)ldn
)->localeDisplayName(locale
, temp
);
959 if (temp
.isBogus()) {
960 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
963 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
966 U_CAPI
int32_t U_EXPORT2
967 uldn_languageDisplayName(const ULocaleDisplayNames
*ldn
,
970 int32_t maxResultSize
,
971 UErrorCode
*pErrorCode
) {
972 if (U_FAILURE(*pErrorCode
)) {
975 if (ldn
== NULL
|| lang
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
976 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
979 UnicodeString
temp(result
, 0, maxResultSize
);
980 ((const LocaleDisplayNames
*)ldn
)->languageDisplayName(lang
, temp
);
981 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
984 U_CAPI
int32_t U_EXPORT2
985 uldn_scriptDisplayName(const ULocaleDisplayNames
*ldn
,
988 int32_t maxResultSize
,
989 UErrorCode
*pErrorCode
) {
990 if (U_FAILURE(*pErrorCode
)) {
993 if (ldn
== NULL
|| script
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
994 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
997 UnicodeString
temp(result
, 0, maxResultSize
);
998 ((const LocaleDisplayNames
*)ldn
)->scriptDisplayName(script
, temp
);
999 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1002 U_CAPI
int32_t U_EXPORT2
1003 uldn_scriptCodeDisplayName(const ULocaleDisplayNames
*ldn
,
1004 UScriptCode scriptCode
,
1006 int32_t maxResultSize
,
1007 UErrorCode
*pErrorCode
) {
1008 return uldn_scriptDisplayName(ldn
, uscript_getName(scriptCode
), result
, maxResultSize
, pErrorCode
);
1011 U_CAPI
int32_t U_EXPORT2
1012 uldn_regionDisplayName(const ULocaleDisplayNames
*ldn
,
1015 int32_t maxResultSize
,
1016 UErrorCode
*pErrorCode
) {
1017 if (U_FAILURE(*pErrorCode
)) {
1020 if (ldn
== NULL
|| region
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
1021 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1024 UnicodeString
temp(result
, 0, maxResultSize
);
1025 ((const LocaleDisplayNames
*)ldn
)->regionDisplayName(region
, temp
);
1026 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1029 U_CAPI
int32_t U_EXPORT2
1030 uldn_variantDisplayName(const ULocaleDisplayNames
*ldn
,
1031 const char *variant
,
1033 int32_t maxResultSize
,
1034 UErrorCode
*pErrorCode
) {
1035 if (U_FAILURE(*pErrorCode
)) {
1038 if (ldn
== NULL
|| variant
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
1039 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1042 UnicodeString
temp(result
, 0, maxResultSize
);
1043 ((const LocaleDisplayNames
*)ldn
)->variantDisplayName(variant
, temp
);
1044 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1047 U_CAPI
int32_t U_EXPORT2
1048 uldn_keyDisplayName(const ULocaleDisplayNames
*ldn
,
1051 int32_t maxResultSize
,
1052 UErrorCode
*pErrorCode
) {
1053 if (U_FAILURE(*pErrorCode
)) {
1056 if (ldn
== NULL
|| key
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
1057 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1060 UnicodeString
temp(result
, 0, maxResultSize
);
1061 ((const LocaleDisplayNames
*)ldn
)->keyDisplayName(key
, temp
);
1062 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1065 U_CAPI
int32_t U_EXPORT2
1066 uldn_keyValueDisplayName(const ULocaleDisplayNames
*ldn
,
1070 int32_t maxResultSize
,
1071 UErrorCode
*pErrorCode
) {
1072 if (U_FAILURE(*pErrorCode
)) {
1075 if (ldn
== NULL
|| key
== NULL
|| value
== NULL
|| (result
== NULL
&& maxResultSize
> 0)
1076 || maxResultSize
< 0) {
1077 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1080 UnicodeString
temp(result
, 0, maxResultSize
);
1081 ((const LocaleDisplayNames
*)ldn
)->keyValueDisplayName(key
, value
, temp
);
1082 return temp
.extract(result
, maxResultSize
, *pErrorCode
);