2 *******************************************************************************
3 * Copyright (C) 2010-2012, 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"
14 #include "unicode/msgfmt.h"
24 * Concatenate a number of null-terminated strings to buffer, leaving a
25 * null-terminated string. The last argument should be the null pointer.
26 * Return the length of the string in the buffer, not counting the trailing
27 * null. Return -1 if there is an error (buffer is null, or buflen < 1).
29 static int32_t ncat(char *buffer
, uint32_t buflen
, ...) {
33 const char* e
= buffer
+ buflen
- 1;
35 if (buffer
== NULL
|| buflen
< 1) {
39 va_start(args
, buflen
);
40 while ((str
= va_arg(args
, char *))) {
42 while (p
!= e
&& (c
= *str
++)) {
54 ////////////////////////////////////////////////////////////////////////////////////////////////////
56 // Access resource data for locale components.
57 // Wrap code in uloc.c for now.
63 ICUDataTable(const char* path
, const Locale
& locale
);
66 const Locale
& getLocale();
68 UnicodeString
& get(const char* tableKey
, const char* itemKey
,
69 UnicodeString
& result
) const;
70 UnicodeString
& get(const char* tableKey
, const char* subTableKey
, const char* itemKey
,
71 UnicodeString
& result
) const;
73 UnicodeString
& getNoFallback(const char* tableKey
, const char* itemKey
,
74 UnicodeString
&result
) const;
75 UnicodeString
& getNoFallback(const char* tableKey
, const char* subTableKey
, const char* itemKey
,
76 UnicodeString
&result
) const;
79 inline UnicodeString
&
80 ICUDataTable::get(const char* tableKey
, const char* itemKey
, UnicodeString
& result
) const {
81 return get(tableKey
, NULL
, itemKey
, result
);
84 inline UnicodeString
&
85 ICUDataTable::getNoFallback(const char* tableKey
, const char* itemKey
, UnicodeString
& result
) const {
86 return getNoFallback(tableKey
, NULL
, itemKey
, result
);
89 ICUDataTable::ICUDataTable(const char* path
, const Locale
& locale
)
90 : path(NULL
), locale(Locale::getRoot())
93 int32_t len
= uprv_strlen(path
);
94 this->path
= (const char*) uprv_malloc(len
+ 1);
96 uprv_strcpy((char *)this->path
, path
);
97 this->locale
= locale
;
102 ICUDataTable::~ICUDataTable() {
104 uprv_free((void*) path
);
110 ICUDataTable::getLocale() {
115 ICUDataTable::get(const char* tableKey
, const char* subTableKey
, const char* itemKey
,
116 UnicodeString
&result
) const {
117 UErrorCode status
= U_ZERO_ERROR
;
120 const UChar
*s
= uloc_getTableStringWithFallback(path
, locale
.getName(),
121 tableKey
, subTableKey
, itemKey
,
123 if (U_SUCCESS(status
) && len
> 0) {
124 return result
.setTo(s
, len
);
126 return result
.setTo(UnicodeString(itemKey
, -1, US_INV
));
130 ICUDataTable::getNoFallback(const char* tableKey
, const char* subTableKey
, const char* itemKey
,
131 UnicodeString
& result
) const {
132 UErrorCode status
= U_ZERO_ERROR
;
135 const UChar
*s
= uloc_getTableStringWithFallback(path
, locale
.getName(),
136 tableKey
, subTableKey
, itemKey
,
138 if (U_SUCCESS(status
)) {
139 return result
.setTo(s
, len
);
146 ////////////////////////////////////////////////////////////////////////////////////////////////////
148 LocaleDisplayNames::~LocaleDisplayNames() {}
150 UOBJECT_DEFINE_NO_RTTI_IMPLEMENTATION(LocaleDisplayNames
)
152 ////////////////////////////////////////////////////////////////////////////////////////////////////
154 #if 0 // currently unused
156 class DefaultLocaleDisplayNames
: public LocaleDisplayNames
{
157 UDialectHandling dialectHandling
;
161 DefaultLocaleDisplayNames(UDialectHandling dialectHandling
);
163 virtual ~DefaultLocaleDisplayNames();
165 virtual const Locale
& getLocale() const;
166 virtual UDialectHandling
getDialectHandling() const;
167 virtual UnicodeString
& localeDisplayName(const Locale
& locale
,
168 UnicodeString
& result
) const;
169 virtual UnicodeString
& localeDisplayName(const char* localeId
,
170 UnicodeString
& result
) const;
171 virtual UnicodeString
& languageDisplayName(const char* lang
,
172 UnicodeString
& result
) const;
173 virtual UnicodeString
& scriptDisplayName(const char* script
,
174 UnicodeString
& result
) const;
175 virtual UnicodeString
& scriptDisplayName(UScriptCode scriptCode
,
176 UnicodeString
& result
) const;
177 virtual UnicodeString
& regionDisplayName(const char* region
,
178 UnicodeString
& result
) const;
179 virtual UnicodeString
& variantDisplayName(const char* variant
,
180 UnicodeString
& result
) const;
181 virtual UnicodeString
& keyDisplayName(const char* key
,
182 UnicodeString
& result
) const;
183 virtual UnicodeString
& keyValueDisplayName(const char* key
,
185 UnicodeString
& result
) const;
188 DefaultLocaleDisplayNames::DefaultLocaleDisplayNames(UDialectHandling dialectHandling
)
189 : dialectHandling(dialectHandling
) {
192 DefaultLocaleDisplayNames::~DefaultLocaleDisplayNames() {
196 DefaultLocaleDisplayNames::getLocale() const {
197 return Locale::getRoot();
201 DefaultLocaleDisplayNames::getDialectHandling() const {
202 return dialectHandling
;
206 DefaultLocaleDisplayNames::localeDisplayName(const Locale
& locale
,
207 UnicodeString
& result
) const {
208 return result
= UnicodeString(locale
.getName(), -1, US_INV
);
212 DefaultLocaleDisplayNames::localeDisplayName(const char* localeId
,
213 UnicodeString
& result
) const {
214 return result
= UnicodeString(localeId
, -1, US_INV
);
218 DefaultLocaleDisplayNames::languageDisplayName(const char* lang
,
219 UnicodeString
& result
) const {
220 return result
= UnicodeString(lang
, -1, US_INV
);
224 DefaultLocaleDisplayNames::scriptDisplayName(const char* script
,
225 UnicodeString
& result
) const {
226 return result
= UnicodeString(script
, -1, US_INV
);
230 DefaultLocaleDisplayNames::scriptDisplayName(UScriptCode scriptCode
,
231 UnicodeString
& result
) const {
232 const char* name
= uscript_getName(scriptCode
);
234 return result
= UnicodeString(name
, -1, US_INV
);
236 return result
.remove();
240 DefaultLocaleDisplayNames::regionDisplayName(const char* region
,
241 UnicodeString
& result
) const {
242 return result
= UnicodeString(region
, -1, US_INV
);
246 DefaultLocaleDisplayNames::variantDisplayName(const char* variant
,
247 UnicodeString
& result
) const {
248 return result
= UnicodeString(variant
, -1, US_INV
);
252 DefaultLocaleDisplayNames::keyDisplayName(const char* key
,
253 UnicodeString
& result
) const {
254 return result
= UnicodeString(key
, -1, US_INV
);
258 DefaultLocaleDisplayNames::keyValueDisplayName(const char* /* key */,
260 UnicodeString
& result
) const {
261 return result
= UnicodeString(value
, -1, US_INV
);
264 #endif // currently unused class DefaultLocaleDisplayNames
266 ////////////////////////////////////////////////////////////////////////////////////////////////////
268 class LocaleDisplayNamesImpl
: public LocaleDisplayNames
{
270 UDialectHandling dialectHandling
;
271 ICUDataTable langData
;
272 ICUDataTable regionData
;
274 MessageFormat
*format
;
275 MessageFormat
*keyTypeFormat
;
279 LocaleDisplayNamesImpl(const Locale
& locale
, UDialectHandling dialectHandling
);
280 virtual ~LocaleDisplayNamesImpl();
282 virtual const Locale
& getLocale() const;
283 virtual UDialectHandling
getDialectHandling() const;
285 virtual UnicodeString
& localeDisplayName(const Locale
& locale
,
286 UnicodeString
& result
) const;
287 virtual UnicodeString
& localeDisplayName(const char* localeId
,
288 UnicodeString
& result
) const;
289 virtual UnicodeString
& languageDisplayName(const char* lang
,
290 UnicodeString
& result
) const;
291 virtual UnicodeString
& scriptDisplayName(const char* script
,
292 UnicodeString
& result
) const;
293 virtual UnicodeString
& scriptDisplayName(UScriptCode scriptCode
,
294 UnicodeString
& result
) const;
295 virtual UnicodeString
& regionDisplayName(const char* region
,
296 UnicodeString
& result
) const;
297 virtual UnicodeString
& variantDisplayName(const char* variant
,
298 UnicodeString
& result
) const;
299 virtual UnicodeString
& keyDisplayName(const char* key
,
300 UnicodeString
& result
) const;
301 virtual UnicodeString
& keyValueDisplayName(const char* key
,
303 UnicodeString
& result
) const;
305 UnicodeString
& localeIdName(const char* localeId
,
306 UnicodeString
& result
) const;
307 UnicodeString
& appendWithSep(UnicodeString
& buffer
, const UnicodeString
& src
) const;
310 LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale
& locale
,
311 UDialectHandling dialectHandling
)
312 : dialectHandling(dialectHandling
)
313 , langData(U_ICUDATA_LANG
, locale
)
314 , regionData(U_ICUDATA_REGION
, locale
)
316 , keyTypeFormat(NULL
)
318 LocaleDisplayNamesImpl
*nonConstThis
= (LocaleDisplayNamesImpl
*)this;
319 nonConstThis
->locale
= langData
.getLocale() == Locale::getRoot()
320 ? regionData
.getLocale()
321 : langData
.getLocale();
323 langData
.getNoFallback("localeDisplayPattern", "separator", sep
);
325 sep
= UnicodeString(", ", -1, US_INV
);
328 UnicodeString pattern
;
329 langData
.getNoFallback("localeDisplayPattern", "pattern", pattern
);
330 if (pattern
.isBogus()) {
331 pattern
= UnicodeString("{0} ({1})", -1, US_INV
);
333 UErrorCode status
= U_ZERO_ERROR
;
334 format
= new MessageFormat(pattern
, status
);
336 UnicodeString ktPattern
;
337 langData
.get("localeDisplayPattern", "keyTypePattern", ktPattern
);
338 if (ktPattern
.isBogus()) {
339 ktPattern
= UnicodeString("{0}={1}", -1, US_INV
);
341 keyTypeFormat
= new MessageFormat(ktPattern
, status
);
344 LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() {
346 delete keyTypeFormat
;
350 LocaleDisplayNamesImpl::getLocale() const {
355 LocaleDisplayNamesImpl::getDialectHandling() const {
356 return dialectHandling
;
360 LocaleDisplayNamesImpl::localeDisplayName(const Locale
& locale
,
361 UnicodeString
& result
) const {
362 UnicodeString resultName
;
364 const char* lang
= locale
.getLanguage();
365 if (uprv_strlen(lang
) == 0) {
368 const char* script
= locale
.getScript();
369 const char* country
= locale
.getCountry();
370 const char* variant
= locale
.getVariant();
372 UBool hasScript
= uprv_strlen(script
) > 0;
373 UBool hasCountry
= uprv_strlen(country
) > 0;
374 UBool hasVariant
= uprv_strlen(variant
) > 0;
376 if (dialectHandling
== ULDN_DIALECT_NAMES
) {
377 char buffer
[ULOC_FULLNAME_CAPACITY
];
378 do { // loop construct is so we can break early out of search
379 if (hasScript
&& hasCountry
) {
380 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", script
, "_", country
, (char *)0);
381 localeIdName(buffer
, resultName
);
382 if (!resultName
.isBogus()) {
389 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", script
, (char *)0);
390 localeIdName(buffer
, resultName
);
391 if (!resultName
.isBogus()) {
397 ncat(buffer
, ULOC_FULLNAME_CAPACITY
, lang
, "_", country
, (char*)0);
398 localeIdName(buffer
, resultName
);
399 if (!resultName
.isBogus()) {
406 if (resultName
.isBogus() || resultName
.isEmpty()) {
407 localeIdName(lang
, resultName
);
410 UnicodeString resultRemainder
;
412 StringEnumeration
*e
= NULL
;
413 UErrorCode status
= U_ZERO_ERROR
;
416 resultRemainder
.append(scriptDisplayName(script
, temp
));
419 appendWithSep(resultRemainder
, regionDisplayName(country
, temp
));
422 appendWithSep(resultRemainder
, variantDisplayName(variant
, temp
));
425 e
= locale
.createKeywords(status
);
426 if (e
&& U_SUCCESS(status
)) {
428 char value
[ULOC_KEYWORD_AND_VALUES_CAPACITY
]; // sigh, no ULOC_VALUE_CAPACITY
430 while ((key
= e
->next((int32_t *)0, status
)) != NULL
) {
431 locale
.getKeywordValue(key
, value
, ULOC_KEYWORD_AND_VALUES_CAPACITY
, status
);
432 keyDisplayName(key
, temp
);
433 keyValueDisplayName(key
, value
, temp2
);
434 if (temp2
!= UnicodeString(value
, -1, US_INV
)) {
435 appendWithSep(resultRemainder
, temp2
);
436 } else if (temp
!= UnicodeString(key
, -1, US_INV
)) {
438 Formattable data
[] = {
443 status
= U_ZERO_ERROR
;
444 keyTypeFormat
->format(data
, 2, temp3
, fpos
, status
);
445 appendWithSep(resultRemainder
, temp3
);
447 appendWithSep(resultRemainder
, temp
)
448 .append((UChar
)0x3d /* = */)
455 if (!resultRemainder
.isEmpty()) {
456 Formattable data
[] = {
461 status
= U_ZERO_ERROR
;
462 format
->format(data
, 2, result
, fpos
, status
);
466 return result
= resultName
;
470 LocaleDisplayNamesImpl::appendWithSep(UnicodeString
& buffer
, const UnicodeString
& src
) const {
471 if (!buffer
.isEmpty()) {
479 LocaleDisplayNamesImpl::localeDisplayName(const char* localeId
,
480 UnicodeString
& result
) const {
481 return localeDisplayName(Locale(localeId
), result
);
485 LocaleDisplayNamesImpl::localeIdName(const char* localeId
,
486 UnicodeString
& result
) const {
487 return langData
.getNoFallback("Languages", localeId
, result
);
491 LocaleDisplayNamesImpl::languageDisplayName(const char* lang
,
492 UnicodeString
& result
) const {
493 if (uprv_strcmp("root", lang
) == 0 || uprv_strchr(lang
, '_') != NULL
) {
494 return result
= UnicodeString(lang
, -1, US_INV
);
496 return langData
.get("Languages", lang
, result
);
500 LocaleDisplayNamesImpl::scriptDisplayName(const char* script
,
501 UnicodeString
& result
) const {
502 return langData
.get("Scripts", script
, result
);
506 LocaleDisplayNamesImpl::scriptDisplayName(UScriptCode scriptCode
,
507 UnicodeString
& result
) const {
508 const char* name
= uscript_getName(scriptCode
);
509 return langData
.get("Scripts", name
, result
);
513 LocaleDisplayNamesImpl::regionDisplayName(const char* region
,
514 UnicodeString
& result
) const {
515 return regionData
.get("Countries", region
, result
);
519 LocaleDisplayNamesImpl::variantDisplayName(const char* variant
,
520 UnicodeString
& result
) const {
521 return langData
.get("Variants", variant
, result
);
525 LocaleDisplayNamesImpl::keyDisplayName(const char* key
,
526 UnicodeString
& result
) const {
527 return langData
.get("Keys", key
, result
);
531 LocaleDisplayNamesImpl::keyValueDisplayName(const char* key
,
533 UnicodeString
& result
) const {
534 return langData
.get("Types", key
, value
, result
);
537 ////////////////////////////////////////////////////////////////////////////////////////////////////
540 LocaleDisplayNames::createInstance(const Locale
& locale
,
541 UDialectHandling dialectHandling
) {
542 return new LocaleDisplayNamesImpl(locale
, dialectHandling
);
547 ////////////////////////////////////////////////////////////////////////////////////////////////////
551 U_DRAFT ULocaleDisplayNames
* U_EXPORT2
552 uldn_open(const char * locale
,
553 UDialectHandling dialectHandling
,
554 UErrorCode
*pErrorCode
) {
555 if (U_FAILURE(*pErrorCode
)) {
558 if (locale
== NULL
) {
559 locale
= uloc_getDefault();
561 return (ULocaleDisplayNames
*)LocaleDisplayNames::createInstance(Locale(locale
), dialectHandling
);
564 U_DRAFT
void U_EXPORT2
565 uldn_close(ULocaleDisplayNames
*ldn
) {
566 delete (LocaleDisplayNames
*)ldn
;
569 U_DRAFT
const char * U_EXPORT2
570 uldn_getLocale(const ULocaleDisplayNames
*ldn
) {
572 return ((const LocaleDisplayNames
*)ldn
)->getLocale().getName();
577 U_DRAFT UDialectHandling U_EXPORT2
578 uldn_getDialectHandling(const ULocaleDisplayNames
*ldn
) {
580 return ((const LocaleDisplayNames
*)ldn
)->getDialectHandling();
582 return ULDN_STANDARD_NAMES
;
585 U_DRAFT
int32_t U_EXPORT2
586 uldn_localeDisplayName(const ULocaleDisplayNames
*ldn
,
589 int32_t maxResultSize
,
590 UErrorCode
*pErrorCode
) {
591 if (U_FAILURE(*pErrorCode
)) {
594 if (ldn
== NULL
|| locale
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
595 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
598 UnicodeString
temp(result
, 0, maxResultSize
);
599 ((const LocaleDisplayNames
*)ldn
)->localeDisplayName(locale
, temp
);
600 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
603 U_DRAFT
int32_t U_EXPORT2
604 uldn_languageDisplayName(const ULocaleDisplayNames
*ldn
,
607 int32_t maxResultSize
,
608 UErrorCode
*pErrorCode
) {
609 if (U_FAILURE(*pErrorCode
)) {
612 if (ldn
== NULL
|| lang
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
613 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
616 UnicodeString
temp(result
, 0, maxResultSize
);
617 ((const LocaleDisplayNames
*)ldn
)->languageDisplayName(lang
, temp
);
618 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
621 U_DRAFT
int32_t U_EXPORT2
622 uldn_scriptDisplayName(const ULocaleDisplayNames
*ldn
,
625 int32_t maxResultSize
,
626 UErrorCode
*pErrorCode
) {
627 if (U_FAILURE(*pErrorCode
)) {
630 if (ldn
== NULL
|| script
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
631 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
634 UnicodeString
temp(result
, 0, maxResultSize
);
635 ((const LocaleDisplayNames
*)ldn
)->scriptDisplayName(script
, temp
);
636 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
639 U_DRAFT
int32_t U_EXPORT2
640 uldn_scriptCodeDisplayName(const ULocaleDisplayNames
*ldn
,
641 UScriptCode scriptCode
,
643 int32_t maxResultSize
,
644 UErrorCode
*pErrorCode
) {
645 return uldn_scriptDisplayName(ldn
, uscript_getName(scriptCode
), result
, maxResultSize
, pErrorCode
);
648 U_DRAFT
int32_t U_EXPORT2
649 uldn_regionDisplayName(const ULocaleDisplayNames
*ldn
,
652 int32_t maxResultSize
,
653 UErrorCode
*pErrorCode
) {
654 if (U_FAILURE(*pErrorCode
)) {
657 if (ldn
== NULL
|| region
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
658 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
661 UnicodeString
temp(result
, 0, maxResultSize
);
662 ((const LocaleDisplayNames
*)ldn
)->regionDisplayName(region
, temp
);
663 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
666 U_DRAFT
int32_t U_EXPORT2
667 uldn_variantDisplayName(const ULocaleDisplayNames
*ldn
,
670 int32_t maxResultSize
,
671 UErrorCode
*pErrorCode
) {
672 if (U_FAILURE(*pErrorCode
)) {
675 if (ldn
== NULL
|| variant
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
676 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
679 UnicodeString
temp(result
, 0, maxResultSize
);
680 ((const LocaleDisplayNames
*)ldn
)->variantDisplayName(variant
, temp
);
681 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
684 U_DRAFT
int32_t U_EXPORT2
685 uldn_keyDisplayName(const ULocaleDisplayNames
*ldn
,
688 int32_t maxResultSize
,
689 UErrorCode
*pErrorCode
) {
690 if (U_FAILURE(*pErrorCode
)) {
693 if (ldn
== NULL
|| key
== NULL
|| (result
== NULL
&& maxResultSize
> 0) || maxResultSize
< 0) {
694 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
697 UnicodeString
temp(result
, 0, maxResultSize
);
698 ((const LocaleDisplayNames
*)ldn
)->keyDisplayName(key
, temp
);
699 return temp
.extract(result
, maxResultSize
, *pErrorCode
);
702 U_DRAFT
int32_t U_EXPORT2
703 uldn_keyValueDisplayName(const ULocaleDisplayNames
*ldn
,
707 int32_t maxResultSize
,
708 UErrorCode
*pErrorCode
) {
709 if (U_FAILURE(*pErrorCode
)) {
712 if (ldn
== NULL
|| key
== NULL
|| value
== NULL
|| (result
== NULL
&& maxResultSize
> 0)
713 || maxResultSize
< 0) {
714 *pErrorCode
= U_ILLEGAL_ARGUMENT_ERROR
;
717 UnicodeString
temp(result
, 0, maxResultSize
);
718 ((const LocaleDisplayNames
*)ldn
)->keyValueDisplayName(key
, value
, temp
);
719 return temp
.extract(result
, maxResultSize
, *pErrorCode
);