1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 *******************************************************************************
6 * Copyright (C) 1997-2016, International Business Machines
7 * Corporation and others. All Rights Reserved.
9 *******************************************************************************
10 * file name: locdispnames.cpp
12 * tab size: 8 (not used)
15 * created on: 2010feb25
16 * created by: Markus W. Scherer
18 * Code for locale display names, separated out from other .cpp files
19 * that then do not depend on resource bundle code and display name data.
22 #include "unicode/utypes.h"
23 #include "unicode/brkiter.h"
24 #include "unicode/locid.h"
25 #include "unicode/uenum.h"
26 #include "unicode/uloc.h"
27 #include "unicode/ures.h"
28 #include "unicode/ustring.h"
29 #include "unicode/uldnames.h"
39 // C++ API ----------------------------------------------------------------- ***
44 Locale::getDisplayLanguage(UnicodeString
& dispLang
) const
46 return this->getDisplayLanguage(getDefault(), dispLang
);
49 /*We cannot make any assumptions on the size of the output display strings
50 * Yet, since we are calling through to a C API, we need to set limits on
51 * buffer size. For all the following getDisplay functions we first attempt
52 * to fill up a stack allocated buffer. If it is to small we heap allocated
53 * the exact buffer we need copy it to the UnicodeString and delete it*/
56 Locale::getDisplayLanguage(const Locale
&displayLocale
,
57 UnicodeString
&result
) const {
59 UErrorCode errorCode
=U_ZERO_ERROR
;
62 buffer
=result
.getBuffer(ULOC_FULLNAME_CAPACITY
);
68 length
=uloc_getDisplayLanguage(fullName
, displayLocale
.fullName
,
69 buffer
, result
.getCapacity(),
71 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
73 if(errorCode
==U_BUFFER_OVERFLOW_ERROR
) {
74 buffer
=result
.getBuffer(length
);
79 errorCode
=U_ZERO_ERROR
;
80 length
=uloc_getDisplayLanguage(fullName
, displayLocale
.fullName
,
81 buffer
, result
.getCapacity(),
83 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
90 Locale::getDisplayScript(UnicodeString
& dispScript
) const
92 return this->getDisplayScript(getDefault(), dispScript
);
96 Locale::getDisplayScript(const Locale
&displayLocale
,
97 UnicodeString
&result
) const {
99 UErrorCode errorCode
=U_ZERO_ERROR
;
102 buffer
=result
.getBuffer(ULOC_FULLNAME_CAPACITY
);
108 length
=uloc_getDisplayScript(fullName
, displayLocale
.fullName
,
109 buffer
, result
.getCapacity(),
111 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
113 if(errorCode
==U_BUFFER_OVERFLOW_ERROR
) {
114 buffer
=result
.getBuffer(length
);
119 errorCode
=U_ZERO_ERROR
;
120 length
=uloc_getDisplayScript(fullName
, displayLocale
.fullName
,
121 buffer
, result
.getCapacity(),
123 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
130 Locale::getDisplayCountry(UnicodeString
& dispCntry
) const
132 return this->getDisplayCountry(getDefault(), dispCntry
);
136 Locale::getDisplayCountry(const Locale
&displayLocale
,
137 UnicodeString
&result
) const {
139 UErrorCode errorCode
=U_ZERO_ERROR
;
142 buffer
=result
.getBuffer(ULOC_FULLNAME_CAPACITY
);
148 length
=uloc_getDisplayCountry(fullName
, displayLocale
.fullName
,
149 buffer
, result
.getCapacity(),
151 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
153 if(errorCode
==U_BUFFER_OVERFLOW_ERROR
) {
154 buffer
=result
.getBuffer(length
);
159 errorCode
=U_ZERO_ERROR
;
160 length
=uloc_getDisplayCountry(fullName
, displayLocale
.fullName
,
161 buffer
, result
.getCapacity(),
163 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
170 Locale::getDisplayVariant(UnicodeString
& dispVar
) const
172 return this->getDisplayVariant(getDefault(), dispVar
);
176 Locale::getDisplayVariant(const Locale
&displayLocale
,
177 UnicodeString
&result
) const {
179 UErrorCode errorCode
=U_ZERO_ERROR
;
182 buffer
=result
.getBuffer(ULOC_FULLNAME_CAPACITY
);
188 length
=uloc_getDisplayVariant(fullName
, displayLocale
.fullName
,
189 buffer
, result
.getCapacity(),
191 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
193 if(errorCode
==U_BUFFER_OVERFLOW_ERROR
) {
194 buffer
=result
.getBuffer(length
);
199 errorCode
=U_ZERO_ERROR
;
200 length
=uloc_getDisplayVariant(fullName
, displayLocale
.fullName
,
201 buffer
, result
.getCapacity(),
203 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
210 Locale::getDisplayName( UnicodeString
& name
) const
212 return this->getDisplayName(getDefault(), name
);
216 Locale::getDisplayName(const Locale
&displayLocale
,
217 UnicodeString
&result
) const {
219 UErrorCode errorCode
=U_ZERO_ERROR
;
222 buffer
=result
.getBuffer(ULOC_FULLNAME_CAPACITY
);
228 length
=uloc_getDisplayName(fullName
, displayLocale
.fullName
,
229 buffer
, result
.getCapacity(),
231 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
233 if(errorCode
==U_BUFFER_OVERFLOW_ERROR
) {
234 buffer
=result
.getBuffer(length
);
239 errorCode
=U_ZERO_ERROR
;
240 length
=uloc_getDisplayName(fullName
, displayLocale
.fullName
,
241 buffer
, result
.getCapacity(),
243 result
.releaseBuffer(U_SUCCESS(errorCode
) ? length
: 0);
249 #if ! UCONFIG_NO_BREAK_ITERATION
251 // -------------------------------------
252 // Gets the objectLocale display name in the default locale language.
253 UnicodeString
& U_EXPORT2
254 BreakIterator::getDisplayName(const Locale
& objectLocale
,
257 return objectLocale
.getDisplayName(name
);
260 // -------------------------------------
261 // Gets the objectLocale display name in the displayLocale language.
262 UnicodeString
& U_EXPORT2
263 BreakIterator::getDisplayName(const Locale
& objectLocale
,
264 const Locale
& displayLocale
,
267 return objectLocale
.getDisplayName(displayLocale
, name
);
275 // C API ------------------------------------------------------------------- ***
279 /* ### Constants **************************************************/
281 /* These strings describe the resources we attempt to load from
282 the locale ResourceBundle data file.*/
283 static const char _kLanguages
[] = "Languages";
284 static const char _kScripts
[] = "Scripts";
285 static const char _kScriptsStandAlone
[] = "Scripts%stand-alone";
286 static const char _kCountries
[] = "Countries";
287 static const char _kVariants
[] = "Variants";
288 static const char _kKeys
[] = "Keys";
289 static const char _kTypes
[] = "Types";
290 //static const char _kRootName[] = "root";
291 static const char _kCurrency
[] = "currency";
292 static const char _kCurrencies
[] = "Currencies";
293 static const char _kLocaleDisplayPattern
[] = "localeDisplayPattern";
294 static const char _kPattern
[] = "pattern";
295 static const char _kSeparator
[] = "separator";
297 /* ### Display name **************************************************/
300 _getStringOrCopyKey(const char *path
, const char *locale
,
301 const char *tableKey
,
302 const char* subTableKey
,
304 const char *substitute
,
305 UChar
*dest
, int32_t destCapacity
,
306 UErrorCode
*pErrorCode
) {
307 const UChar
*s
= NULL
;
311 /* top-level item: normal resource bundle access */
312 icu::LocalUResourceBundlePointer
rb(ures_open(path
, locale
, pErrorCode
));
314 if(U_SUCCESS(*pErrorCode
)) {
315 s
=ures_getStringByKey(rb
.getAlias(), tableKey
, &length
, pErrorCode
);
316 /* see comment about closing rb near "return item;" in _res_getTableStringWithFallback() */
319 /* Language code should not be a number. If it is, set the error code. */
320 if (!uprv_strncmp(tableKey
, "Languages", 9) && uprv_strtol(itemKey
, NULL
, 10)) {
321 *pErrorCode
= U_MISSING_RESOURCE_ERROR
;
323 /* second-level item, use special fallback */
324 s
=uloc_getTableStringWithFallback(path
, locale
,
333 if(U_SUCCESS(*pErrorCode
)) {
334 int32_t copyLength
=uprv_min(length
, destCapacity
);
335 if(copyLength
>0 && s
!= NULL
) {
336 u_memcpy(dest
, s
, copyLength
);
339 /* no string from a resource bundle: convert the substitute */
340 length
=(int32_t)uprv_strlen(substitute
);
341 u_charsToUChars(substitute
, dest
, uprv_min(length
, destCapacity
));
342 *pErrorCode
=U_USING_DEFAULT_WARNING
;
345 return u_terminateUChars(dest
, destCapacity
, length
, pErrorCode
);
348 typedef int32_t U_CALLCONV
UDisplayNameGetter(const char *, char *, int32_t, UErrorCode
*);
351 _getDisplayNameForComponent(const char *locale
,
352 const char *displayLocale
,
353 UChar
*dest
, int32_t destCapacity
,
354 UDisplayNameGetter
*getter
,
356 UErrorCode
*pErrorCode
) {
357 char localeBuffer
[ULOC_FULLNAME_CAPACITY
*4];
359 UErrorCode localStatus
;
360 const char* root
= NULL
;
362 /* argument checking */
363 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
367 if(destCapacity
<0 || (destCapacity
>0 && dest
==NULL
)) {
368 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
372 localStatus
= U_ZERO_ERROR
;
373 length
=(*getter
)(locale
, localeBuffer
, sizeof(localeBuffer
), &localStatus
);
374 if(U_FAILURE(localStatus
) || localStatus
==U_STRING_NOT_TERMINATED_WARNING
) {
375 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
379 return u_terminateUChars(dest
, destCapacity
, 0, pErrorCode
);
382 root
= tag
== _kCountries
? U_ICUDATA_REGION
: U_ICUDATA_LANG
;
384 return _getStringOrCopyKey(root
, displayLocale
,
385 tag
, NULL
, localeBuffer
,
391 U_CAPI
int32_t U_EXPORT2
392 uloc_getDisplayLanguage(const char *locale
,
393 const char *displayLocale
,
394 UChar
*dest
, int32_t destCapacity
,
395 UErrorCode
*pErrorCode
) {
396 return _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
397 uloc_getLanguage
, _kLanguages
, pErrorCode
);
400 U_CAPI
int32_t U_EXPORT2
401 uloc_getDisplayScript(const char* locale
,
402 const char* displayLocale
,
403 UChar
*dest
, int32_t destCapacity
,
404 UErrorCode
*pErrorCode
)
406 UErrorCode err
= U_ZERO_ERROR
;
407 int32_t res
= _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
408 uloc_getScript
, _kScriptsStandAlone
, &err
);
410 if ( err
== U_USING_DEFAULT_WARNING
) {
411 return _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
412 uloc_getScript
, _kScripts
, pErrorCode
);
419 U_INTERNAL
int32_t U_EXPORT2
420 uloc_getDisplayScriptInContext(const char* locale
,
421 const char* displayLocale
,
422 UChar
*dest
, int32_t destCapacity
,
423 UErrorCode
*pErrorCode
)
425 return _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
426 uloc_getScript
, _kScripts
, pErrorCode
);
429 U_CAPI
int32_t U_EXPORT2
430 uloc_getDisplayCountry(const char *locale
,
431 const char *displayLocale
,
432 UChar
*dest
, int32_t destCapacity
,
433 UErrorCode
*pErrorCode
) {
434 return _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
435 uloc_getCountry
, _kCountries
, pErrorCode
);
439 * TODO separate variant1_variant2_variant3...
440 * by getting each tag's display string and concatenating them with ", "
441 * in between - similar to uloc_getDisplayName()
443 U_CAPI
int32_t U_EXPORT2
444 uloc_getDisplayVariant(const char *locale
,
445 const char *displayLocale
,
446 UChar
*dest
, int32_t destCapacity
,
447 UErrorCode
*pErrorCode
) {
448 return _getDisplayNameForComponent(locale
, displayLocale
, dest
, destCapacity
,
449 uloc_getVariant
, _kVariants
, pErrorCode
);
452 /* Instead of having a separate pass for 'special' patterns, reintegrate the two
453 * so we don't get bitten by preflight bugs again. We can be reasonably efficient
454 * without two separate code paths, this code isn't that performance-critical.
456 * This code is general enough to deal with patterns that have a prefix or swap the
457 * language and remainder components, since we gave developers enough rope to do such
458 * things if they futz with the pattern data. But since we don't give them a way to
459 * specify a pattern for arbitrary combinations of components, there's not much use in
460 * that. I don't think our data includes such patterns, the only variable I know if is
461 * whether there is a space before the open paren, or not. Oh, and zh uses different
462 * chars than the standard open/close paren (which ja and ko use, btw).
464 U_CAPI
int32_t U_EXPORT2
465 uloc_getDisplayName(const char *locale
,
466 const char *displayLocale
,
467 UChar
*dest
, int32_t destCapacity
,
468 UErrorCode
*pErrorCode
)
470 static const UChar defaultSeparator
[9] = { 0x007b, 0x0030, 0x007d, 0x002c, 0x0020, 0x007b, 0x0031, 0x007d, 0x0000 }; /* "{0}, {1}" */
471 static const UChar sub0
[4] = { 0x007b, 0x0030, 0x007d , 0x0000 } ; /* {0} */
472 static const UChar sub1
[4] = { 0x007b, 0x0031, 0x007d , 0x0000 } ; /* {1} */
473 static const int32_t subLen
= 3;
474 static const UChar defaultPattern
[10] = {
475 0x007b, 0x0030, 0x007d, 0x0020, 0x0028, 0x007b, 0x0031, 0x007d, 0x0029, 0x0000
477 static const int32_t defaultPatLen
= 9;
478 static const int32_t defaultSub0Pos
= 0;
479 static const int32_t defaultSub1Pos
= 5;
481 int32_t length
; /* of formatted result */
483 const UChar
*separator
;
485 const UChar
*pattern
;
487 int32_t sub0Pos
, sub1Pos
;
489 UChar formatOpenParen
= 0x0028; // (
490 UChar formatReplaceOpenParen
= 0x005B; // [
491 UChar formatCloseParen
= 0x0029; // )
492 UChar formatReplaceCloseParen
= 0x005D; // ]
494 UBool haveLang
= TRUE
; /* assume true, set false if we find we don't have
495 a lang component in the locale */
496 UBool haveRest
= TRUE
; /* assume true, set false if we find we don't have
497 any other component in the locale */
498 UBool retry
= FALSE
; /* set true if we need to retry, see below */
500 int32_t langi
= 0; /* index of the language substitution (0 or 1), virtually always 0 */
502 if(pErrorCode
==NULL
|| U_FAILURE(*pErrorCode
)) {
506 if(destCapacity
<0 || (destCapacity
>0 && dest
==NULL
)) {
507 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
511 { // For select languages + script, route to uldn_localeDisplayName <rdar://problem/51418203>
512 char lang
[ULOC_LANG_CAPACITY
];
513 char script
[ULOC_SCRIPT_CAPACITY
];
514 UErrorCode status
= U_ZERO_ERROR
;
515 int32_t langlen
= uloc_getLanguage(locale
, lang
, ULOC_LANG_CAPACITY
, &status
);
516 int32_t scriptlen
= uloc_getScript(locale
, script
, ULOC_SCRIPT_CAPACITY
, &status
);
517 if ( U_SUCCESS(status
) && scriptlen
>0 && (uprv_strcmp(lang
, "zh") == 0 || uprv_strcmp(lang
, "yue") == 0 ||
518 uprv_strcmp(lang
, "ks") == 0 || uprv_strcmp(lang
, "pa") == 0 || uprv_strcmp(lang
, "ur") == 0) ) {
519 ULocaleDisplayNames
* uldn
= uldn_open(displayLocale
, ULDN_STANDARD_NAMES
, &status
);
520 if ( U_SUCCESS(status
) ) {
521 int32_t namelen
= uldn_localeDisplayName(uldn
, locale
, dest
, destCapacity
, pErrorCode
);
529 UErrorCode status
= U_ZERO_ERROR
;
531 icu::LocalUResourceBundlePointer
locbundle(
532 ures_open(U_ICUDATA_LANG
, displayLocale
, &status
));
533 icu::LocalUResourceBundlePointer
dspbundle(
534 ures_getByKeyWithFallback(locbundle
.getAlias(), _kLocaleDisplayPattern
, NULL
, &status
));
536 separator
=ures_getStringByKeyWithFallback(dspbundle
.getAlias(), _kSeparator
, &sepLen
, &status
);
537 pattern
=ures_getStringByKeyWithFallback(dspbundle
.getAlias(), _kPattern
, &patLen
, &status
);
540 /* If we couldn't find any data, then use the defaults */
542 separator
= defaultSeparator
;
544 /* #10244: Even though separator is now a pattern, it is awkward to handle it as such
545 * here since we are trying to build the display string in place in the dest buffer,
546 * and to handle it as a pattern would entail having separate storage for the
547 * substrings that need to be combined (the first of which may be the result of
548 * previous such combinations). So for now we continue to treat the portion between
549 * {0} and {1} as a string to be appended when joining substrings, ignoring anything
550 * that is before {0} or after {1} (no existing separator pattern has any such thing).
551 * This is similar to how pattern is handled below.
554 UChar
*p0
=u_strstr(separator
, sub0
);
555 UChar
*p1
=u_strstr(separator
, sub1
);
556 if (p0
==NULL
|| p1
==NULL
|| p1
<p0
) {
557 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
560 separator
= (const UChar
*)p0
+ subLen
;
561 sepLen
= static_cast<int32_t>(p1
- separator
);
564 if(patLen
==0 || (patLen
==defaultPatLen
&& !u_strncmp(pattern
, defaultPattern
, patLen
))) {
565 pattern
=defaultPattern
;
566 patLen
=defaultPatLen
;
567 sub0Pos
=defaultSub0Pos
;
568 sub1Pos
=defaultSub1Pos
;
569 // use default formatOpenParen etc. set above
570 } else { /* non-default pattern */
571 UChar
*p0
=u_strstr(pattern
, sub0
);
572 UChar
*p1
=u_strstr(pattern
, sub1
);
573 if (p0
==NULL
|| p1
==NULL
) {
574 *pErrorCode
=U_ILLEGAL_ARGUMENT_ERROR
;
577 sub0Pos
= static_cast<int32_t>(p0
-pattern
);
578 sub1Pos
= static_cast<int32_t>(p1
-pattern
);
579 if (sub1Pos
< sub0Pos
) { /* a very odd pattern */
580 int32_t t
=sub0Pos
; sub0Pos
=sub1Pos
; sub1Pos
=t
;
583 if (u_strchr(pattern
, 0xFF08) != NULL
) {
584 formatOpenParen
= 0xFF08; // fullwidth (
585 formatReplaceOpenParen
= 0xFF3B; // fullwidth [
586 formatCloseParen
= 0xFF09; // fullwidth )
587 formatReplaceCloseParen
= 0xFF3D; // fullwidth ]
591 /* We loop here because there is one case in which after the first pass we could need to
592 * reextract the data. If there's initial padding before the first element, we put in
593 * the padding and then write that element. If it turns out there's no second element,
594 * we didn't need the padding. If we do need the data (no preflight), and the first element
595 * would have fit but for the padding, we need to reextract. In this case (only) we
596 * adjust the parameters so padding is not added, and repeat.
600 int32_t patPos
=0; /* position in the pattern, used for non-substitution portions */
601 int32_t langLen
=0; /* length of language substitution */
602 int32_t langPos
=0; /* position in output of language substitution */
603 int32_t restLen
=0; /* length of 'everything else' substitution */
604 int32_t restPos
=0; /* position in output of 'everything else' substitution */
605 icu::LocalUEnumerationPointer kenum
; /* keyword enumeration */
607 /* prefix of pattern, extremely likely to be empty */
609 if(destCapacity
>= sub0Pos
) {
610 while (patPos
< sub0Pos
) {
611 *p
++ = pattern
[patPos
++];
621 for(int32_t subi
=0,resti
=0;subi
<2;) { /* iterate through patterns 0 and 1*/
622 UBool subdone
= FALSE
; /* set true when ready to move to next substitution */
624 /* prep p and cap for calls to get display components, pin cap to 0 since
625 they complain if cap is negative */
626 int32_t cap
=destCapacity
-length
;
633 if (subi
== langi
) { /* {0}*/
636 langLen
=uloc_getDisplayLanguage(locale
, displayLocale
, p
, cap
, pErrorCode
);
645 int32_t len
; /* length of component (plus other stuff) we just fetched */
649 len
=uloc_getDisplayScriptInContext(locale
, displayLocale
, p
, cap
, pErrorCode
);
652 len
=uloc_getDisplayCountry(locale
, displayLocale
, p
, cap
, pErrorCode
);
655 len
=uloc_getDisplayVariant(locale
, displayLocale
, p
, cap
, pErrorCode
);
658 kenum
.adoptInstead(uloc_openKeywords(locale
, pErrorCode
));
661 const char* kw
=uenum_next(kenum
.getAlias(), &len
, pErrorCode
);
663 len
=0; /* mark that we didn't add a component */
666 /* incorporating this behavior into the loop made it even more complex,
667 so just special case it here */
668 len
= uloc_getDisplayKeyword(kw
, displayLocale
, p
, cap
, pErrorCode
);
671 p
[len
]=0x3d; /* '=', assume we'll need it */
675 /* adjust for call to get keyword */
683 /* reset for call below */
684 if(*pErrorCode
== U_BUFFER_OVERFLOW_ERROR
) {
685 *pErrorCode
=U_ZERO_ERROR
;
687 int32_t vlen
= uloc_getDisplayKeywordValue(locale
, kw
, displayLocale
,
691 --len
; /* remove unneeded '=' */
693 /* restore cap and p to what they were at start */
694 cap
=destCapacity
-length
;
701 len
+=vlen
; /* total we added for key + '=' + value */
707 /* we addeed a component, so add separator and write it if there's room. */
708 if(len
+sepLen
<=cap
) {
709 const UChar
* plimit
= p
+ len
;
710 for (; p
< plimit
; p
++) {
711 if (*p
== formatOpenParen
) {
712 *p
= formatReplaceOpenParen
;
713 } else if (*p
== formatCloseParen
) {
714 *p
= formatReplaceCloseParen
;
717 for(int32_t i
=0;i
<sepLen
;++i
) {
723 /* remove separator if we added it */
724 if (length
!=restPos
) {
727 restLen
=length
-restPos
;
733 if(*pErrorCode
== U_BUFFER_OVERFLOW_ERROR
) {
734 *pErrorCode
=U_ZERO_ERROR
;
738 if(haveLang
&& haveRest
) {
739 /* append internal portion of pattern, the first time,
740 or last portion of pattern the second time */
743 padLen
=(subi
==0 ? sub1Pos
: patLen
)-patPos
;
744 if(length
+padLen
< destCapacity
) {
746 for(int32_t i
=0;i
<padLen
;++i
) {
747 *p
++=pattern
[patPos
++];
754 /* don't have first component, reset for second component */
757 } else if(length
>0) {
758 /* true length is the length of just the component we got. */
759 length
=haveLang
?langLen
:restLen
;
760 if(dest
&& sub0Pos
!=0) {
761 if (sub0Pos
+length
<=destCapacity
) {
762 /* first component not at start of result,
763 but we have full component in buffer. */
764 u_memmove(dest
, dest
+(haveLang
?langPos
:restPos
), length
);
766 /* would have fit, but didn't because of pattern prefix. */
767 sub0Pos
=0; /* stops initial padding (and a second retry,
768 so we won't end up here again) */
774 ++subi
; /* move on to next substitution */
779 return u_terminateUChars(dest
, destCapacity
, length
, pErrorCode
);
782 U_CAPI
int32_t U_EXPORT2
783 uloc_getDisplayKeyword(const char* keyword
,
784 const char* displayLocale
,
786 int32_t destCapacity
,
789 /* argument checking */
790 if(status
==NULL
|| U_FAILURE(*status
)) {
794 if(destCapacity
<0 || (destCapacity
>0 && dest
==NULL
)) {
795 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
800 /* pass itemKey=NULL to look for a top-level item */
801 return _getStringOrCopyKey(U_ICUDATA_LANG
, displayLocale
,
811 #define UCURRENCY_DISPLAY_NAME_INDEX 1
813 U_CAPI
int32_t U_EXPORT2
814 uloc_getDisplayKeywordValue( const char* locale
,
816 const char* displayLocale
,
818 int32_t destCapacity
,
822 char keywordValue
[ULOC_FULLNAME_CAPACITY
*4];
823 int32_t capacity
= ULOC_FULLNAME_CAPACITY
*4;
824 int32_t keywordValueLen
=0;
826 /* argument checking */
827 if(status
==NULL
|| U_FAILURE(*status
)) {
831 if(destCapacity
<0 || (destCapacity
>0 && dest
==NULL
)) {
832 *status
=U_ILLEGAL_ARGUMENT_ERROR
;
836 /* get the keyword value */
838 keywordValueLen
= uloc_getKeywordValue(locale
, keyword
, keywordValue
, capacity
, status
);
839 if (*status
== U_STRING_NOT_TERMINATED_WARNING
)
840 *status
= U_BUFFER_OVERFLOW_ERROR
;
843 * if the keyword is equal to currency .. then to get the display name
844 * we need to do the fallback ourselves
846 if(uprv_stricmp(keyword
, _kCurrency
)==0){
848 int32_t dispNameLen
= 0;
849 const UChar
*dispName
= NULL
;
851 icu::LocalUResourceBundlePointer
bundle(
852 ures_open(U_ICUDATA_CURR
, displayLocale
, status
));
853 icu::LocalUResourceBundlePointer
currencies(
854 ures_getByKey(bundle
.getAlias(), _kCurrencies
, NULL
, status
));
855 icu::LocalUResourceBundlePointer
currency(
856 ures_getByKeyWithFallback(currencies
.getAlias(), keywordValue
, NULL
, status
));
858 dispName
= ures_getStringByIndex(currency
.getAlias(), UCURRENCY_DISPLAY_NAME_INDEX
, &dispNameLen
, status
);
860 if(U_FAILURE(*status
)){
861 if(*status
== U_MISSING_RESOURCE_ERROR
){
862 /* we just want to write the value over if nothing is available */
863 *status
= U_USING_DEFAULT_WARNING
;
869 /* now copy the dispName over if not NULL */
870 if(dispName
!= NULL
){
871 if(dispNameLen
<= destCapacity
){
872 u_memcpy(dest
, dispName
, dispNameLen
);
873 return u_terminateUChars(dest
, destCapacity
, dispNameLen
, status
);
875 *status
= U_BUFFER_OVERFLOW_ERROR
;
879 /* we have not found the display name for the value .. just copy over */
880 if(keywordValueLen
<= destCapacity
){
881 u_charsToUChars(keywordValue
, dest
, keywordValueLen
);
882 return u_terminateUChars(dest
, destCapacity
, keywordValueLen
, status
);
884 *status
= U_BUFFER_OVERFLOW_ERROR
;
885 return keywordValueLen
;
892 return _getStringOrCopyKey(U_ICUDATA_LANG
, displayLocale
,