2 *******************************************************************************
3 * Copyright (C) 2010-2016, International Business Machines Corporation and
4 * others. All Rights Reserved.
5 *******************************************************************************
8 #include "unicode/utypes.h"
10 #if !UCONFIG_NO_FORMATTING
12 #include "unicode/locdspnm.h"
13 #include "unicode/simpleformatter.h"
14 #include "unicode/ures.h"
15 #include "unicode/udisplaycontext.h"
16 #include "unicode/brkiter.h"
17 #include "unicode/ucurr.h"
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).
34 static int32_t ncat(char *buffer
, uint32_t buflen
, ...) {
38 const char* e
= buffer
+ buflen
- 1;
40 if (buffer
== NULL
|| buflen
< 1) {
44 va_start(args
, buflen
);
45 while ((str
= va_arg(args
, char *))) {
47 while (p
!= e
&& (c
= *str
++)) {
59 ////////////////////////////////////////////////////////////////////////////////////////////////////
61 // Access resource data for locale components.
62 // Wrap code in uloc.c for now.
68 ICUDataTable(const char* path
, const Locale
& locale
);
71 const Locale
& getLocale();
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;
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;
84 inline UnicodeString
&
85 ICUDataTable::get(const char* tableKey
, const char* itemKey
, UnicodeString
& result
) const {
86 return get(tableKey
, NULL
, itemKey
, result
);
89 inline UnicodeString
&
90 ICUDataTable::getNoFallback(const char* tableKey
, const char* itemKey
, UnicodeString
& result
) const {
91 return getNoFallback(tableKey
, NULL
, itemKey
, result
);
94 ICUDataTable::ICUDataTable(const char* path
, const Locale
& locale
)
95 : path(NULL
), locale(Locale::getRoot())
98 int32_t len
= uprv_strlen(path
);
99 this->path
= (const char*) uprv_malloc(len
+ 1);
101 uprv_strcpy((char *)this->path
, path
);
102 this->locale
= locale
;
107 ICUDataTable::~ICUDataTable() {
109 uprv_free((void*) path
);
115 ICUDataTable::getLocale() {
120 ICUDataTable::get(const char* tableKey
, const char* subTableKey
, const char* itemKey
,
121 UnicodeString
&result
) const {
122 UErrorCode status
= U_ZERO_ERROR
;
125 const UChar
*s
= uloc_getTableStringWithFallback(path
, locale
.getName(),
126 tableKey
, subTableKey
, itemKey
,
128 if (U_SUCCESS(status
) && len
> 0) {
129 return result
.setTo(s
, len
);
131 return result
.setTo(UnicodeString(itemKey
, -1, US_INV
));
135 ICUDataTable::getNoFallback(const char* tableKey
, const char* subTableKey
, const char* itemKey
,
136 UnicodeString
& result
) const {
137 UErrorCode status
= U_ZERO_ERROR
;
140 const UChar
*s
= uloc_getTableStringWithFallback(path
, locale
.getName(),
141 tableKey
, subTableKey
, itemKey
,
143 if (U_SUCCESS(status
)) {
144 return result
.setTo(s
, len
);
151 ////////////////////////////////////////////////////////////////////////////////////////////////////
153 LocaleDisplayNames::~LocaleDisplayNames() {}
155 ////////////////////////////////////////////////////////////////////////////////////////////////////
157 #if 0 // currently unused
159 class DefaultLocaleDisplayNames
: public LocaleDisplayNames
{
160 UDialectHandling dialectHandling
;
164 DefaultLocaleDisplayNames(UDialectHandling dialectHandling
);
166 virtual ~DefaultLocaleDisplayNames();
168 virtual const Locale
& getLocale() const;
169 virtual UDialectHandling
getDialectHandling() const;
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
,
189 UnicodeString
& result
) const;
192 DefaultLocaleDisplayNames::DefaultLocaleDisplayNames(UDialectHandling dialectHandling
)
193 : dialectHandling(dialectHandling
) {
196 DefaultLocaleDisplayNames::~DefaultLocaleDisplayNames() {
200 DefaultLocaleDisplayNames::getLocale() const {
201 return Locale::getRoot();
205 DefaultLocaleDisplayNames::getDialectHandling() const {
206 return dialectHandling
;
210 DefaultLocaleDisplayNames::localeDisplayName(const Locale
& locale
,
211 UnicodeString
& result
) const {
212 return result
= UnicodeString(locale
.getName(), -1, US_INV
);
216 DefaultLocaleDisplayNames::localeDisplayName(const char* localeId
,
217 UnicodeString
& result
) const {
218 return result
= UnicodeString(localeId
, -1, US_INV
);
222 DefaultLocaleDisplayNames::languageDisplayName(const char* lang
,
223 UnicodeString
& result
) const {
224 return result
= UnicodeString(lang
, -1, US_INV
);
228 DefaultLocaleDisplayNames::scriptDisplayName(const char* script
,
229 UnicodeString
& result
) const {
230 return result
= UnicodeString(script
, -1, US_INV
);
234 DefaultLocaleDisplayNames::scriptDisplayName(UScriptCode scriptCode
,
235 UnicodeString
& result
) const {
236 const char* name
= uscript_getName(scriptCode
);
238 return result
= UnicodeString(name
, -1, US_INV
);
240 return result
.remove();
244 DefaultLocaleDisplayNames::regionDisplayName(const char* region
,
245 UnicodeString
& result
) const {
246 return result
= UnicodeString(region
, -1, US_INV
);
250 DefaultLocaleDisplayNames::variantDisplayName(const char* variant
,
251 UnicodeString
& result
) const {
252 return result
= UnicodeString(variant
, -1, US_INV
);
256 DefaultLocaleDisplayNames::keyDisplayName(const char* key
,
257 UnicodeString
& result
) const {
258 return result
= UnicodeString(key
, -1, US_INV
);
262 DefaultLocaleDisplayNames::keyValueDisplayName(const char* /* key */,
264 UnicodeString
& result
) const {
265 return result
= UnicodeString(value
, -1, US_INV
);
268 #endif // currently unused class DefaultLocaleDisplayNames
270 ////////////////////////////////////////////////////////////////////////////////////////////////////
272 class LocaleDisplayNamesImpl
: public LocaleDisplayNames
{
274 UDialectHandling dialectHandling
;
275 ICUDataTable langData
;
276 ICUDataTable regionData
;
277 SimpleFormatter separatorFormat
;
278 SimpleFormatter format
;
279 SimpleFormatter 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
;
289 // Constants for capitalization context usage types.
290 enum CapContextUsage
{
291 kCapContextUsageLanguage
,
292 kCapContextUsageScript
,
293 kCapContextUsageTerritory
,
294 kCapContextUsageVariant
,
296 kCapContextUsageKeyValue
,
297 kCapContextUsageCount
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
];
305 LocaleDisplayNamesImpl(const Locale
& locale
, UDialectHandling dialectHandling
);
306 LocaleDisplayNamesImpl(const Locale
& locale
, UDisplayContext
*contexts
, int32_t length
);
307 virtual ~LocaleDisplayNamesImpl();
309 virtual const Locale
& getLocale() const;
310 virtual UDialectHandling
getDialectHandling() const;
311 virtual UDisplayContext
getContext(UDisplayContextType type
) const;
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
,
331 UnicodeString
& result
) const;
333 UnicodeString
& localeIdName(const char* localeId
,
334 UnicodeString
& result
) const;
335 UnicodeString
& regionShortDisplayName(const char* region
, // Apple-specific
336 UnicodeString
& result
) const;
337 UnicodeString
& appendWithSep(UnicodeString
& buffer
, const UnicodeString
& src
) const;
338 UnicodeString
& adjustForUsageAndContext(CapContextUsage usage
, UnicodeString
& result
) const;
339 UnicodeString
& scriptDisplayName(const char* script
, UnicodeString
& result
, UBool skipAdjust
) const;
340 UnicodeString
& regionDisplayName(const char* region
, UnicodeString
& result
, UBool skipAdjust
) const;
341 UnicodeString
& variantDisplayName(const char* variant
, UnicodeString
& result
, UBool skipAdjust
) const;
342 UnicodeString
& keyDisplayName(const char* key
, UnicodeString
& result
, UBool skipAdjust
) const;
343 UnicodeString
& keyValueDisplayName(const char* key
, const char* value
,
344 UnicodeString
& result
, UBool skipAdjust
) const;
345 void initialize(void);
348 UMutex
LocaleDisplayNamesImpl::capitalizationBrkIterLock
= U_MUTEX_INITIALIZER
;
350 LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale
& locale
,
351 UDialectHandling dialectHandling
)
352 : dialectHandling(dialectHandling
)
353 , langData(U_ICUDATA_LANG
, locale
)
354 , regionData(U_ICUDATA_REGION
, locale
)
355 , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE
)
356 , capitalizationBrkIter(NULL
)
357 , nameLength(UDISPCTX_LENGTH_FULL
)
362 LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale
& locale
,
363 UDisplayContext
*contexts
, int32_t length
)
364 : dialectHandling(ULDN_STANDARD_NAMES
)
365 , langData(U_ICUDATA_LANG
, locale
)
366 , regionData(U_ICUDATA_REGION
, locale
)
367 , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE
)
368 , capitalizationBrkIter(NULL
)
369 , nameLength(UDISPCTX_LENGTH_FULL
)
371 while (length
-- > 0) {
372 UDisplayContext value
= *contexts
++;
373 UDisplayContextType selector
= (UDisplayContextType
)((uint32_t)value
>> 8);
375 case UDISPCTX_TYPE_DIALECT_HANDLING
:
376 dialectHandling
= (UDialectHandling
)value
;
378 case UDISPCTX_TYPE_CAPITALIZATION
:
379 capitalizationContext
= value
;
381 case UDISPCTX_TYPE_DISPLAY_LENGTH
:
384 case UADISPCTX_TYPE_LENGTH
: // Apple-specific
385 nameLength
= (value
== UADISPCTX_LENGTH_SHORT
)? UDISPCTX_LENGTH_SHORT
: UDISPCTX_LENGTH_FULL
;
395 LocaleDisplayNamesImpl::initialize(void) {
396 LocaleDisplayNamesImpl
*nonConstThis
= (LocaleDisplayNamesImpl
*)this;
397 nonConstThis
->locale
= langData
.getLocale() == Locale::getRoot()
398 ? regionData
.getLocale()
399 : langData
.getLocale();
402 langData
.getNoFallback("localeDisplayPattern", "separator", sep
);
404 sep
= UnicodeString("{0}, {1}", -1, US_INV
);
406 UErrorCode status
= U_ZERO_ERROR
;
407 separatorFormat
.applyPatternMinMaxArguments(sep
, 2, 2, status
);
409 UnicodeString pattern
;
410 langData
.getNoFallback("localeDisplayPattern", "pattern", pattern
);
411 if (pattern
.isBogus()) {
412 pattern
= UnicodeString("{0} ({1})", -1, US_INV
);
414 format
.applyPatternMinMaxArguments(pattern
, 2, 2, status
);
415 if (pattern
.indexOf((UChar
)0xFF08) >= 0) {
416 formatOpenParen
.setTo((UChar
)0xFF08); // fullwidth (
417 formatReplaceOpenParen
.setTo((UChar
)0xFF3B); // fullwidth [
418 formatCloseParen
.setTo((UChar
)0xFF09); // fullwidth )
419 formatReplaceCloseParen
.setTo((UChar
)0xFF3D); // fullwidth ]
421 formatOpenParen
.setTo((UChar
)0x0028); // (
422 formatReplaceOpenParen
.setTo((UChar
)0x005B); // [
423 formatCloseParen
.setTo((UChar
)0x0029); // )
424 formatReplaceCloseParen
.setTo((UChar
)0x005D); // ]
427 UnicodeString ktPattern
;
428 langData
.get("localeDisplayPattern", "keyTypePattern", ktPattern
);
429 if (ktPattern
.isBogus()) {
430 ktPattern
= UnicodeString("{0}={1}", -1, US_INV
);
432 keyTypeFormat
.applyPatternMinMaxArguments(ktPattern
, 2, 2, status
);
434 uprv_memset(fCapitalization
, 0, sizeof(fCapitalization
));
435 #if !UCONFIG_NO_BREAK_ITERATION
436 // The following is basically copied from DateFormatSymbols::initializeData
438 const char * usageName
;
439 LocaleDisplayNamesImpl::CapContextUsage usageEnum
;
440 } ContextUsageNameToEnum
;
441 const ContextUsageNameToEnum contextUsageTypeMap
[] = {
442 // Entries must be sorted by usageTypeName; entry with NULL name terminates list.
443 { "key", kCapContextUsageKey
},
444 { "keyValue", kCapContextUsageKeyValue
},
445 { "languages", kCapContextUsageLanguage
},
446 { "script", kCapContextUsageScript
},
447 { "territory", kCapContextUsageTerritory
},
448 { "variant", kCapContextUsageVariant
},
449 { NULL
, (CapContextUsage
)0 },
451 // Only get the context data if we need it! This is a const object so we know now...
452 // Also check whether we will need a break iterator (depends on the data)
453 UBool needBrkIter
= FALSE
;
454 if (capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
|| capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_STANDALONE
) {
456 UResourceBundle
*localeBundle
= ures_open(NULL
, locale
.getName(), &status
);
457 if (U_SUCCESS(status
)) {
458 UResourceBundle
*contextTransforms
= ures_getByKeyWithFallback(localeBundle
, "contextTransforms", NULL
, &status
);
459 if (U_SUCCESS(status
)) {
460 UResourceBundle
*contextTransformUsage
;
461 while ( (contextTransformUsage
= ures_getNextResource(contextTransforms
, NULL
, &status
)) != NULL
) {
462 const int32_t * intVector
= ures_getIntVector(contextTransformUsage
, &len
, &status
);
463 if (U_SUCCESS(status
) && intVector
!= NULL
&& len
>= 2) {
464 const char* usageKey
= ures_getKey(contextTransformUsage
);
465 if (usageKey
!= NULL
) {
466 const ContextUsageNameToEnum
* typeMapPtr
= contextUsageTypeMap
;
467 int32_t compResult
= 0;
468 // linear search; list is short and we cannot be sure that bsearch is available
469 while ( typeMapPtr
->usageName
!= NULL
&& (compResult
= uprv_strcmp(usageKey
, typeMapPtr
->usageName
)) > 0 ) {
472 if (typeMapPtr
->usageName
!= NULL
&& compResult
== 0) {
473 int32_t titlecaseInt
= (capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU
)? intVector
[0]: intVector
[1];
474 if (titlecaseInt
!= 0) {
475 fCapitalization
[typeMapPtr
->usageEnum
] = TRUE
;;
481 status
= U_ZERO_ERROR
;
482 ures_close(contextTransformUsage
);
484 ures_close(contextTransforms
);
486 ures_close(localeBundle
);
489 // Get a sentence break iterator if we will need it
490 if (needBrkIter
|| capitalizationContext
== UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
) {
491 status
= U_ZERO_ERROR
;
492 capitalizationBrkIter
= BreakIterator::createSentenceInstance(locale
, status
);
493 if (U_FAILURE(status
)) {
494 delete capitalizationBrkIter
;
495 capitalizationBrkIter
= NULL
;
501 LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() {
502 delete capitalizationBrkIter
;
506 LocaleDisplayNamesImpl::getLocale() const {
511 LocaleDisplayNamesImpl::getDialectHandling() const {
512 return dialectHandling
;
516 LocaleDisplayNamesImpl::getContext(UDisplayContextType type
) const {
518 case UDISPCTX_TYPE_DIALECT_HANDLING
:
519 return (UDisplayContext
)dialectHandling
;
520 case UDISPCTX_TYPE_CAPITALIZATION
:
521 return capitalizationContext
;
522 case UDISPCTX_TYPE_DISPLAY_LENGTH
:
524 case UADISPCTX_TYPE_LENGTH
: // Apple-specific
525 return (nameLength
== UDISPCTX_LENGTH_SHORT
)? UADISPCTX_LENGTH_SHORT
: UADISPCTX_LENGTH_STANDARD
;
529 return (UDisplayContext
)0;
533 LocaleDisplayNamesImpl::adjustForUsageAndContext(CapContextUsage usage
,
534 UnicodeString
& result
) const {
535 #if !UCONFIG_NO_BREAK_ITERATION
536 // check to see whether we need to titlecase result
537 if ( result
.length() > 0 && u_islower(result
.char32At(0)) && capitalizationBrkIter
!= NULL
&&
538 ( capitalizationContext
==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE
|| fCapitalization
[usage
] ) ) {
539 // note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE
540 Mutex
lock(&capitalizationBrkIterLock
);
541 result
.toTitle(capitalizationBrkIter
, locale
, U_TITLECASE_NO_LOWERCASE
| U_TITLECASE_NO_BREAK_ADJUSTMENT
);
548 LocaleDisplayNamesImpl::localeDisplayName(const Locale
& locale
,
549 UnicodeString
& result
) const {
550 if (locale
.isBogus()) {
554 UnicodeString resultName
;
556 const char* lang
= locale
.getLanguage();
557 if (uprv_strlen(lang
) == 0) {
560 const char* script
= locale
.getScript();
561 const char* country
= locale
.getCountry();
562 const char* variant
= locale
.getVariant();
564 UBool hasScript
= uprv_strlen(script
) > 0;
565 UBool hasCountry
= uprv_strlen(country
) > 0;
566 UBool hasVariant
= uprv_strlen(variant
) > 0;
568 if (dialectHandling
== ULDN_DIALECT_NAMES
) {
569 char buffer
[ULOC_FULLNAME_CAPACITY
];
570 do { // loop construct is so we can break early out of search
571 if (hasScript
&& hasCountry
) {
572 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", script
, "_", country
, (char *)0);
573 localeIdName(buffer
, resultName
);
574 if (!resultName
.isBogus()) {
581 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", script
, (char *)0);
582 localeIdName(buffer
, resultName
);
583 if (!resultName
.isBogus()) {
589 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", country
, (char*)0);
590 localeIdName(buffer
, resultName
);
591 if (!resultName
.isBogus()) {
598 if (resultName
.isBogus() || resultName
.isEmpty()) {
599 localeIdName(lang
, resultName
);
602 UnicodeString resultRemainder
;
604 UErrorCode status
= U_ZERO_ERROR
;
607 resultRemainder
.append(scriptDisplayName(script
, temp
, TRUE
));
610 appendWithSep(resultRemainder
, regionShortDisplayName(country
, temp
)); // Apple modification
613 appendWithSep(resultRemainder
, variantDisplayName(variant
, temp
, TRUE
));
615 resultRemainder
.findAndReplace(formatOpenParen
, formatReplaceOpenParen
);
616 resultRemainder
.findAndReplace(formatCloseParen
, formatReplaceCloseParen
);
618 LocalPointer
<StringEnumeration
> e(locale
.createKeywords(status
));
619 if (e
.isValid() && U_SUCCESS(status
)) {
621 char value
[ULOC_KEYWORD_AND_VALUES_CAPACITY
]; // sigh, no ULOC_VALUE_CAPACITY
623 while ((key
= e
->next((int32_t *)0, status
)) != NULL
) {
624 locale
.getKeywordValue(key
, value
, ULOC_KEYWORD_AND_VALUES_CAPACITY
, status
);
625 if (U_FAILURE(status
)) {
628 keyDisplayName(key
, temp
, TRUE
);
629 temp
.findAndReplace(formatOpenParen
, formatReplaceOpenParen
);
630 temp
.findAndReplace(formatCloseParen
, formatReplaceCloseParen
);
631 keyValueDisplayName(key
, value
, temp2
, TRUE
);
632 temp2
.findAndReplace(formatOpenParen
, formatReplaceOpenParen
);
633 temp2
.findAndReplace(formatCloseParen
, formatReplaceCloseParen
);
634 if (temp2
!= UnicodeString(value
, -1, US_INV
)) {
635 appendWithSep(resultRemainder
, temp2
);
636 } else if (temp
!= UnicodeString(key
, -1, US_INV
)) {
638 keyTypeFormat
.format(temp
, temp2
, temp3
, status
);
639 appendWithSep(resultRemainder
, temp3
);
641 appendWithSep(resultRemainder
, temp
)
642 .append((UChar
)0x3d /* = */)
648 if (!resultRemainder
.isEmpty()) {
649 format
.format(resultName
, resultRemainder
, result
.remove(), status
);
650 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
654 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
658 LocaleDisplayNamesImpl::appendWithSep(UnicodeString
& buffer
, const UnicodeString
& src
) const {
659 if (buffer
.isEmpty()) {
662 const UnicodeString
*values
[2] = { &buffer
, &src
};
663 UErrorCode status
= U_ZERO_ERROR
;
664 separatorFormat
.formatAndReplace(values
, 2, buffer
, NULL
, 0, status
);
670 LocaleDisplayNamesImpl::localeDisplayName(const char* localeId
,
671 UnicodeString
& result
) const {
672 return localeDisplayName(Locale(localeId
), result
);
677 LocaleDisplayNamesImpl::localeIdName(const char* localeId
,
678 UnicodeString
& result
) const {
679 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
680 langData
.getNoFallback("Languages%short", localeId
, result
);
681 if (!result
.isBogus()) {
685 return langData
.getNoFallback("Languages", localeId
, result
);
689 LocaleDisplayNamesImpl::languageDisplayName(const char* lang
,
690 UnicodeString
& result
) const {
691 if (uprv_strcmp("root", lang
) == 0 || uprv_strchr(lang
, '_') != NULL
) {
692 return result
= UnicodeString(lang
, -1, US_INV
);
694 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
695 langData
.getNoFallback("Languages%short", lang
, result
);
696 if (!result
.isBogus()) {
697 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
700 langData
.get("Languages", lang
, result
);
701 return adjustForUsageAndContext(kCapContextUsageLanguage
, result
);
705 LocaleDisplayNamesImpl::scriptDisplayName(const char* script
,
706 UnicodeString
& result
,
707 UBool skipAdjust
) const {
708 if (!skipAdjust
) { // => prefer standalone
709 langData
.getNoFallback("Scripts%stand-alone", script
, result
);
710 if (!result
.isBogus()) {
711 return adjustForUsageAndContext(kCapContextUsageScript
, result
);
714 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
715 langData
.getNoFallback("Scripts%short", script
, result
);
716 if (!result
.isBogus()) {
717 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageScript
, result
);
720 langData
.get("Scripts", script
, result
);
721 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageScript
, result
);
725 LocaleDisplayNamesImpl::scriptDisplayName(const char* script
,
726 UnicodeString
& result
) const {
727 return scriptDisplayName(script
, result
, FALSE
);
731 LocaleDisplayNamesImpl::scriptDisplayName(UScriptCode scriptCode
,
732 UnicodeString
& result
) const {
733 return scriptDisplayName(uscript_getName(scriptCode
), result
, FALSE
);
737 LocaleDisplayNamesImpl::regionDisplayName(const char* region
,
738 UnicodeString
& result
,
739 UBool skipAdjust
) const {
740 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
741 regionData
.getNoFallback("Countries%short", region
, result
);
742 if (!result
.isBogus()) {
743 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageTerritory
, result
);
746 regionData
.get("Countries", region
, result
);
747 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageTerritory
, result
);
750 // private Apple, only for building localeDisplayName
751 // (use short region, don't adjust for context)
753 LocaleDisplayNamesImpl::regionShortDisplayName(const char* region
,
754 UnicodeString
& result
) const {
755 if (uprv_strcmp(region
, "PS") != 0) {
756 regionData
.getNoFallback("Countries%short", region
, result
);
757 if (!result
.isBogus()) {
761 regionData
.get("Countries", region
, result
);
766 LocaleDisplayNamesImpl::regionDisplayName(const char* region
,
767 UnicodeString
& result
) const {
768 return regionDisplayName(region
, result
, FALSE
);
773 LocaleDisplayNamesImpl::variantDisplayName(const char* variant
,
774 UnicodeString
& result
,
775 UBool skipAdjust
) const {
776 // don't have a resource for short variant names
777 langData
.get("Variants", variant
, result
);
778 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageVariant
, result
);
782 LocaleDisplayNamesImpl::variantDisplayName(const char* variant
,
783 UnicodeString
& result
) const {
784 return variantDisplayName(variant
, result
, FALSE
);
788 LocaleDisplayNamesImpl::keyDisplayName(const char* key
,
789 UnicodeString
& result
,
790 UBool skipAdjust
) const {
791 // don't have a resource for short key names
792 langData
.get("Keys", key
, result
);
793 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKey
, result
);
797 LocaleDisplayNamesImpl::keyDisplayName(const char* key
,
798 UnicodeString
& result
) const {
799 return keyDisplayName(key
, result
, FALSE
);
803 LocaleDisplayNamesImpl::keyValueDisplayName(const char* key
,
805 UnicodeString
& result
,
806 UBool skipAdjust
) const {
807 if (uprv_strcmp(key
, "currency") == 0) {
808 // ICU4C does not have ICU4J CurrencyDisplayInfo equivalent for now.
809 UErrorCode sts
= U_ZERO_ERROR
;
810 UnicodeString
ustrValue(value
, -1, US_INV
);
812 UBool isChoice
= FALSE
;
813 const UChar
*currencyName
= ucurr_getName(ustrValue
.getTerminatedBuffer(),
814 locale
.getBaseName(), UCURR_LONG_NAME
, &isChoice
, &len
, &sts
);
815 if (U_FAILURE(sts
)) {
816 // Return the value as is on failure
820 result
.setTo(currencyName
, len
);
821 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKeyValue
, result
);
824 if (nameLength
== UDISPCTX_LENGTH_SHORT
) {
825 langData
.get("Types%short", key
, value
, result
);
826 if (!result
.isBogus()) {
827 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKeyValue
, result
);
830 langData
.get("Types", key
, value
, result
);
831 return skipAdjust
? result
: adjustForUsageAndContext(kCapContextUsageKeyValue
, result
);
835 LocaleDisplayNamesImpl::keyValueDisplayName(const char* key
,
837 UnicodeString
& result
) const {
838 return keyValueDisplayName(key
, value
, result
, FALSE
);
841 ////////////////////////////////////////////////////////////////////////////////////////////////////
844 LocaleDisplayNames::createInstance(const Locale
& locale
,
845 UDialectHandling dialectHandling
) {
846 return new LocaleDisplayNamesImpl(locale
, dialectHandling
);
850 LocaleDisplayNames::createInstance(const Locale
& locale
,
851 UDisplayContext
*contexts
, int32_t length
) {
852 if (contexts
== NULL
) {
855 return new LocaleDisplayNamesImpl(locale
, contexts
, length
);
860 ////////////////////////////////////////////////////////////////////////////////////////////////////
864 U_CAPI ULocaleDisplayNames
* U_EXPORT2
865 uldn_open(const char * locale
,
866 UDialectHandling dialectHandling
,
867 UErrorCode
*pErrorCode
) {
868 if (U_FAILURE(*pErrorCode
)) {
871 if (locale
== NULL
) {
872 locale
= uloc_getDefault();
874 return (ULocaleDisplayNames
*)LocaleDisplayNames::createInstance(Locale(locale
), dialectHandling
);
877 U_CAPI ULocaleDisplayNames
* U_EXPORT2
878 uldn_openForContext(const char * locale
,
879 UDisplayContext
*contexts
, int32_t length
,
880 UErrorCode
*pErrorCode
) {
881 if (U_FAILURE(*pErrorCode
)) {
884 if (locale
== NULL
) {
885 locale
= uloc_getDefault();
887 return (ULocaleDisplayNames
*)LocaleDisplayNames::createInstance(Locale(locale
), contexts
, length
);
891 U_CAPI
void U_EXPORT2
892 uldn_close(ULocaleDisplayNames
*ldn
) {
893 delete (LocaleDisplayNames
*)ldn
;
896 U_CAPI
const char * U_EXPORT2
897 uldn_getLocale(const ULocaleDisplayNames
*ldn
) {
899 return ((const LocaleDisplayNames
*)ldn
)->getLocale().getName();
904 U_CAPI UDialectHandling U_EXPORT2
905 uldn_getDialectHandling(const ULocaleDisplayNames
*ldn
) {
907 return ((const LocaleDisplayNames
*)ldn
)->getDialectHandling();
909 return ULDN_STANDARD_NAMES
;
912 U_CAPI UDisplayContext U_EXPORT2
913 uldn_getContext(const ULocaleDisplayNames
*ldn
,
914 UDisplayContextType type
,
915 UErrorCode
*pErrorCode
) {
916 if (U_FAILURE(*pErrorCode
)) {
917 return (UDisplayContext
)0;
919 return ((const LocaleDisplayNames
*)ldn
)->getContext(type
);
922 U_CAPI
int32_t U_EXPORT2
923 uldn_localeDisplayName(const ULocaleDisplayNames
*ldn
,
926 int32_t maxResultSize
,
927 UErrorCode
*pErrorCode
) {
928 if (U_FAILURE(*pErrorCode
)) {
931 if (ldn
== NULL
|| locale
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
932 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
935 UnicodeString
temp(result
, 0, maxResultSize
);
936 ((const LocaleDisplayNames
*)ldn
)->localeDisplayName(locale
, temp
);
937 if (temp
.isBogus()) {
938 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
941 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
944 U_CAPI
int32_t U_EXPORT2
945 uldn_languageDisplayName(const ULocaleDisplayNames
*ldn
,
948 int32_t maxResultSize
,
949 UErrorCode
*pErrorCode
) {
950 if (U_FAILURE(*pErrorCode
)) {
953 if (ldn
== NULL
|| lang
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
954 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
957 UnicodeString
temp(result
, 0, maxResultSize
);
958 ((const LocaleDisplayNames
*)ldn
)->languageDisplayName(lang
, temp
);
959 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
962 U_CAPI
int32_t U_EXPORT2
963 uldn_scriptDisplayName(const ULocaleDisplayNames
*ldn
,
966 int32_t maxResultSize
,
967 UErrorCode
*pErrorCode
) {
968 if (U_FAILURE(*pErrorCode
)) {
971 if (ldn
== NULL
|| script
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
972 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
975 UnicodeString
temp(result
, 0, maxResultSize
);
976 ((const LocaleDisplayNames
*)ldn
)->scriptDisplayName(script
, temp
);
977 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
980 U_CAPI
int32_t U_EXPORT2
981 uldn_scriptCodeDisplayName(const ULocaleDisplayNames
*ldn
,
982 UScriptCode scriptCode
,
984 int32_t maxResultSize
,
985 UErrorCode
*pErrorCode
) {
986 return uldn_scriptDisplayName(ldn
, uscript_getName(scriptCode
), result
, maxResultSize
, pErrorCode
);
989 U_CAPI
int32_t U_EXPORT2
990 uldn_regionDisplayName(const ULocaleDisplayNames
*ldn
,
993 int32_t maxResultSize
,
994 UErrorCode
*pErrorCode
) {
995 if (U_FAILURE(*pErrorCode
)) {
998 if (ldn
== NULL
|| region
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
999 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1002 UnicodeString
temp(result
, 0, maxResultSize
);
1003 ((const LocaleDisplayNames
*)ldn
)->regionDisplayName(region
, temp
);
1004 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1007 U_CAPI
int32_t U_EXPORT2
1008 uldn_variantDisplayName(const ULocaleDisplayNames
*ldn
,
1009 const char *variant
,
1011 int32_t maxResultSize
,
1012 UErrorCode
*pErrorCode
) {
1013 if (U_FAILURE(*pErrorCode
)) {
1016 if (ldn
== NULL
|| variant
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
1017 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1020 UnicodeString
temp(result
, 0, maxResultSize
);
1021 ((const LocaleDisplayNames
*)ldn
)->variantDisplayName(variant
, temp
);
1022 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1025 U_CAPI
int32_t U_EXPORT2
1026 uldn_keyDisplayName(const ULocaleDisplayNames
*ldn
,
1029 int32_t maxResultSize
,
1030 UErrorCode
*pErrorCode
) {
1031 if (U_FAILURE(*pErrorCode
)) {
1034 if (ldn
== NULL
|| key
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
1035 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1038 UnicodeString
temp(result
, 0, maxResultSize
);
1039 ((const LocaleDisplayNames
*)ldn
)->keyDisplayName(key
, temp
);
1040 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
1043 U_CAPI
int32_t U_EXPORT2
1044 uldn_keyValueDisplayName(const ULocaleDisplayNames
*ldn
,
1048 int32_t maxResultSize
,
1049 UErrorCode
*pErrorCode
) {
1050 if (U_FAILURE(*pErrorCode
)) {
1053 if (ldn
== NULL
|| key
== NULL
|| value
== NULL
|| (result
== NULL
&& maxResultSize
> 0)
1054 || maxResultSize
< 0) {
1055 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
1058 UnicodeString
temp(result
, 0, maxResultSize
);
1059 ((const LocaleDisplayNames
*)ldn
)->keyValueDisplayName(key
, value
, temp
);
1060 return temp
.extract(result
, maxResultSize
, *pErrorCode
);