]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/locdspnm.cpp
ICU-531.30.tar.gz
[apple/icu.git] / icuSources / i18n / locdspnm.cpp
CommitLineData
729e4ab9
A
1/*
2*******************************************************************************
57a6839d 3* Copyright (C) 2010-2014, International Business Machines Corporation and
4388f060 4* others. All Rights Reserved.
729e4ab9
A
5*******************************************************************************
6*/
7
8#include "unicode/utypes.h"
9
10#if !UCONFIG_NO_FORMATTING
11
12#include "unicode/locdspnm.h"
729e4ab9 13#include "unicode/msgfmt.h"
51004dcb 14#include "unicode/ures.h"
57a6839d 15#include "unicode/udisplaycontext.h"
51004dcb 16#include "unicode/brkiter.h"
729e4ab9
A
17
18#include "cmemory.h"
19#include "cstring.h"
20#include "ulocimp.h"
21#include "ureslocs.h"
51004dcb 22#include "uresimp.h"
729e4ab9
A
23
24#include <stdarg.h>
25
26/**
27 * Concatenate a number of null-terminated strings to buffer, leaving a
28 * null-terminated string. The last argument should be the null pointer.
29 * Return the length of the string in the buffer, not counting the trailing
30 * null. Return -1 if there is an error (buffer is null, or buflen < 1).
31 */
32static int32_t ncat(char *buffer, uint32_t buflen, ...) {
33 va_list args;
34 char *str;
35 char *p = buffer;
36 const char* e = buffer + buflen - 1;
37
38 if (buffer == NULL || buflen < 1) {
39 return -1;
40 }
41
42 va_start(args, buflen);
43 while ((str = va_arg(args, char *))) {
44 char c;
45 while (p != e && (c = *str++)) {
46 *p++ = c;
47 }
48 }
49 *p = 0;
50 va_end(args);
51
52 return p - buffer;
53}
54
55U_NAMESPACE_BEGIN
56
57////////////////////////////////////////////////////////////////////////////////////////////////////
58
59// Access resource data for locale components.
60// Wrap code in uloc.c for now.
61class ICUDataTable {
51004dcb
A
62 const char* path;
63 Locale locale;
729e4ab9
A
64
65public:
51004dcb
A
66 ICUDataTable(const char* path, const Locale& locale);
67 ~ICUDataTable();
729e4ab9 68
51004dcb 69 const Locale& getLocale();
729e4ab9 70
51004dcb
A
71 UnicodeString& get(const char* tableKey, const char* itemKey,
72 UnicodeString& result) const;
73 UnicodeString& get(const char* tableKey, const char* subTableKey, const char* itemKey,
74 UnicodeString& result) const;
729e4ab9 75
51004dcb
A
76 UnicodeString& getNoFallback(const char* tableKey, const char* itemKey,
77 UnicodeString &result) const;
78 UnicodeString& getNoFallback(const char* tableKey, const char* subTableKey, const char* itemKey,
79 UnicodeString &result) const;
729e4ab9
A
80};
81
82inline UnicodeString &
83ICUDataTable::get(const char* tableKey, const char* itemKey, UnicodeString& result) const {
51004dcb 84 return get(tableKey, NULL, itemKey, result);
729e4ab9
A
85}
86
87inline UnicodeString &
88ICUDataTable::getNoFallback(const char* tableKey, const char* itemKey, UnicodeString& result) const {
51004dcb 89 return getNoFallback(tableKey, NULL, itemKey, result);
729e4ab9
A
90}
91
92ICUDataTable::ICUDataTable(const char* path, const Locale& locale)
51004dcb 93 : path(NULL), locale(Locale::getRoot())
729e4ab9
A
94{
95 if (path) {
96 int32_t len = uprv_strlen(path);
97 this->path = (const char*) uprv_malloc(len + 1);
98 if (this->path) {
99 uprv_strcpy((char *)this->path, path);
100 this->locale = locale;
101 }
102 }
103}
104
105ICUDataTable::~ICUDataTable() {
106 if (path) {
107 uprv_free((void*) path);
108 path = NULL;
109 }
110}
111
112const Locale&
113ICUDataTable::getLocale() {
114 return locale;
115}
116
117UnicodeString &
118ICUDataTable::get(const char* tableKey, const char* subTableKey, const char* itemKey,
119 UnicodeString &result) const {
120 UErrorCode status = U_ZERO_ERROR;
121 int32_t len = 0;
122
123 const UChar *s = uloc_getTableStringWithFallback(path, locale.getName(),
124 tableKey, subTableKey, itemKey,
125 &len, &status);
4388f060 126 if (U_SUCCESS(status) && len > 0) {
729e4ab9
A
127 return result.setTo(s, len);
128 }
129 return result.setTo(UnicodeString(itemKey, -1, US_INV));
130}
131
132UnicodeString &
133ICUDataTable::getNoFallback(const char* tableKey, const char* subTableKey, const char* itemKey,
134 UnicodeString& result) const {
135 UErrorCode status = U_ZERO_ERROR;
136 int32_t len = 0;
137
138 const UChar *s = uloc_getTableStringWithFallback(path, locale.getName(),
139 tableKey, subTableKey, itemKey,
140 &len, &status);
141 if (U_SUCCESS(status)) {
142 return result.setTo(s, len);
143 }
144
145 result.setToBogus();
146 return result;
147}
148
149////////////////////////////////////////////////////////////////////////////////////////////////////
150
4388f060
A
151LocaleDisplayNames::~LocaleDisplayNames() {}
152
729e4ab9
A
153////////////////////////////////////////////////////////////////////////////////////////////////////
154
155#if 0 // currently unused
156
157class DefaultLocaleDisplayNames : public LocaleDisplayNames {
158 UDialectHandling dialectHandling;
159
160public:
161 // constructor
162 DefaultLocaleDisplayNames(UDialectHandling dialectHandling);
163
164 virtual ~DefaultLocaleDisplayNames();
165
166 virtual const Locale& getLocale() const;
167 virtual UDialectHandling getDialectHandling() const;
51004dcb 168
729e4ab9
A
169 virtual UnicodeString& localeDisplayName(const Locale& locale,
170 UnicodeString& result) const;
171 virtual UnicodeString& localeDisplayName(const char* localeId,
172 UnicodeString& result) const;
173 virtual UnicodeString& languageDisplayName(const char* lang,
174 UnicodeString& result) const;
175 virtual UnicodeString& scriptDisplayName(const char* script,
176 UnicodeString& result) const;
177 virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode,
178 UnicodeString& result) const;
179 virtual UnicodeString& regionDisplayName(const char* region,
180 UnicodeString& result) const;
181 virtual UnicodeString& variantDisplayName(const char* variant,
182 UnicodeString& result) const;
183 virtual UnicodeString& keyDisplayName(const char* key,
184 UnicodeString& result) const;
185 virtual UnicodeString& keyValueDisplayName(const char* key,
186 const char* value,
187 UnicodeString& result) const;
188};
189
190DefaultLocaleDisplayNames::DefaultLocaleDisplayNames(UDialectHandling dialectHandling)
191 : dialectHandling(dialectHandling) {
192}
193
194DefaultLocaleDisplayNames::~DefaultLocaleDisplayNames() {
195}
196
197const Locale&
198DefaultLocaleDisplayNames::getLocale() const {
199 return Locale::getRoot();
200}
201
202UDialectHandling
203DefaultLocaleDisplayNames::getDialectHandling() const {
204 return dialectHandling;
205}
206
207UnicodeString&
208DefaultLocaleDisplayNames::localeDisplayName(const Locale& locale,
209 UnicodeString& result) const {
210 return result = UnicodeString(locale.getName(), -1, US_INV);
211}
212
213UnicodeString&
214DefaultLocaleDisplayNames::localeDisplayName(const char* localeId,
215 UnicodeString& result) const {
216 return result = UnicodeString(localeId, -1, US_INV);
217}
218
219UnicodeString&
220DefaultLocaleDisplayNames::languageDisplayName(const char* lang,
221 UnicodeString& result) const {
222 return result = UnicodeString(lang, -1, US_INV);
223}
224
225UnicodeString&
226DefaultLocaleDisplayNames::scriptDisplayName(const char* script,
227 UnicodeString& result) const {
228 return result = UnicodeString(script, -1, US_INV);
229}
230
231UnicodeString&
232DefaultLocaleDisplayNames::scriptDisplayName(UScriptCode scriptCode,
233 UnicodeString& result) const {
234 const char* name = uscript_getName(scriptCode);
235 if (name) {
236 return result = UnicodeString(name, -1, US_INV);
237 }
238 return result.remove();
239}
240
241UnicodeString&
242DefaultLocaleDisplayNames::regionDisplayName(const char* region,
243 UnicodeString& result) const {
244 return result = UnicodeString(region, -1, US_INV);
245}
246
247UnicodeString&
248DefaultLocaleDisplayNames::variantDisplayName(const char* variant,
249 UnicodeString& result) const {
250 return result = UnicodeString(variant, -1, US_INV);
251}
252
253UnicodeString&
254DefaultLocaleDisplayNames::keyDisplayName(const char* key,
255 UnicodeString& result) const {
256 return result = UnicodeString(key, -1, US_INV);
257}
258
259UnicodeString&
260DefaultLocaleDisplayNames::keyValueDisplayName(const char* /* key */,
261 const char* value,
262 UnicodeString& result) const {
263 return result = UnicodeString(value, -1, US_INV);
264}
265
266#endif // currently unused class DefaultLocaleDisplayNames
267
268////////////////////////////////////////////////////////////////////////////////////////////////////
269
270class LocaleDisplayNamesImpl : public LocaleDisplayNames {
51004dcb
A
271 Locale locale;
272 UDialectHandling dialectHandling;
273 ICUDataTable langData;
274 ICUDataTable regionData;
57a6839d 275 MessageFormat *separatorFormat;
51004dcb
A
276 MessageFormat *format;
277 MessageFormat *keyTypeFormat;
278 UDisplayContext capitalizationContext;
57a6839d
A
279 BreakIterator* capitalizationBrkIter;
280 UnicodeString formatOpenParen;
281 UnicodeString formatReplaceOpenParen;
282 UnicodeString formatCloseParen;
283 UnicodeString formatReplaceCloseParen;
284 UDisplayContext nameLength;
51004dcb
A
285
286 // Constants for capitalization context usage types.
287 enum CapContextUsage {
288 kCapContextUsageLanguage,
289 kCapContextUsageScript,
290 kCapContextUsageTerritory,
291 kCapContextUsageVariant,
292 kCapContextUsageKey,
57a6839d 293 kCapContextUsageKeyValue,
51004dcb
A
294 kCapContextUsageCount
295 };
57a6839d
A
296 // Capitalization transforms. For each usage type, indicates whether to titlecase for
297 // the context specified in capitalizationContext (which we know at construction time)
298 UBool fCapitalization[kCapContextUsageCount];
729e4ab9
A
299
300public:
51004dcb
A
301 // constructor
302 LocaleDisplayNamesImpl(const Locale& locale, UDialectHandling dialectHandling);
303 LocaleDisplayNamesImpl(const Locale& locale, UDisplayContext *contexts, int32_t length);
304 virtual ~LocaleDisplayNamesImpl();
305
306 virtual const Locale& getLocale() const;
307 virtual UDialectHandling getDialectHandling() const;
308 virtual UDisplayContext getContext(UDisplayContextType type) const;
309
310 virtual UnicodeString& localeDisplayName(const Locale& locale,
311 UnicodeString& result) const;
312 virtual UnicodeString& localeDisplayName(const char* localeId,
313 UnicodeString& result) const;
314 virtual UnicodeString& languageDisplayName(const char* lang,
315 UnicodeString& result) const;
316 virtual UnicodeString& scriptDisplayName(const char* script,
317 UnicodeString& result) const;
318 virtual UnicodeString& scriptDisplayName(UScriptCode scriptCode,
319 UnicodeString& result) const;
320 virtual UnicodeString& regionDisplayName(const char* region,
321 UnicodeString& result) const;
322 virtual UnicodeString& variantDisplayName(const char* variant,
323 UnicodeString& result) const;
324 virtual UnicodeString& keyDisplayName(const char* key,
325 UnicodeString& result) const;
326 virtual UnicodeString& keyValueDisplayName(const char* key,
327 const char* value,
328 UnicodeString& result) const;
729e4ab9 329private:
51004dcb
A
330 UnicodeString& localeIdName(const char* localeId,
331 UnicodeString& result) const;
57a6839d
A
332 UnicodeString& regionShortDisplayName(const char* region,
333 UnicodeString& result) const;
51004dcb
A
334 UnicodeString& appendWithSep(UnicodeString& buffer, const UnicodeString& src) const;
335 UnicodeString& adjustForUsageAndContext(CapContextUsage usage, UnicodeString& result) const;
336 void initialize(void);
729e4ab9
A
337};
338
339LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
340 UDialectHandling dialectHandling)
51004dcb
A
341 : dialectHandling(dialectHandling)
342 , langData(U_ICUDATA_LANG, locale)
343 , regionData(U_ICUDATA_REGION, locale)
57a6839d 344 , separatorFormat(NULL)
51004dcb
A
345 , format(NULL)
346 , keyTypeFormat(NULL)
347 , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
57a6839d
A
348 , capitalizationBrkIter(NULL)
349 , nameLength(UADISPCTX_LENGTH_STANDARD)
729e4ab9 350{
51004dcb
A
351 initialize();
352}
729e4ab9 353
51004dcb
A
354LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
355 UDisplayContext *contexts, int32_t length)
356 : dialectHandling(ULDN_STANDARD_NAMES)
357 , langData(U_ICUDATA_LANG, locale)
358 , regionData(U_ICUDATA_REGION, locale)
57a6839d 359 , separatorFormat(NULL)
51004dcb
A
360 , format(NULL)
361 , keyTypeFormat(NULL)
362 , capitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
57a6839d
A
363 , capitalizationBrkIter(NULL)
364 , nameLength(UADISPCTX_LENGTH_STANDARD)
51004dcb
A
365{
366 while (length-- > 0) {
367 UDisplayContext value = *contexts++;
368 UDisplayContextType selector = (UDisplayContextType)((uint32_t)value >> 8);
369 switch (selector) {
370 case UDISPCTX_TYPE_DIALECT_HANDLING:
371 dialectHandling = (UDialectHandling)value;
372 break;
373 case UDISPCTX_TYPE_CAPITALIZATION:
374 capitalizationContext = value;
375 break;
57a6839d
A
376 case UADISPCTX_TYPE_LENGTH:
377 nameLength = value;
378 break;
51004dcb
A
379 default:
380 break;
381 }
382 }
383 initialize();
384}
729e4ab9 385
51004dcb
A
386void
387LocaleDisplayNamesImpl::initialize(void) {
388 LocaleDisplayNamesImpl *nonConstThis = (LocaleDisplayNamesImpl *)this;
389 nonConstThis->locale = langData.getLocale() == Locale::getRoot()
390 ? regionData.getLocale()
391 : langData.getLocale();
4388f060 392
57a6839d 393 UnicodeString sep;
51004dcb
A
394 langData.getNoFallback("localeDisplayPattern", "separator", sep);
395 if (sep.isBogus()) {
57a6839d 396 sep = UnicodeString("{0}, {1}", -1, US_INV);
51004dcb 397 }
57a6839d
A
398 UErrorCode status = U_ZERO_ERROR;
399 separatorFormat = new MessageFormat(sep, status);
51004dcb
A
400
401 UnicodeString pattern;
402 langData.getNoFallback("localeDisplayPattern", "pattern", pattern);
403 if (pattern.isBogus()) {
404 pattern = UnicodeString("{0} ({1})", -1, US_INV);
405 }
51004dcb 406 format = new MessageFormat(pattern, status);
57a6839d
A
407 if (pattern.indexOf((UChar)0xFF08) >= 0) {
408 formatOpenParen.setTo((UChar)0xFF08); // fullwidth (
409 formatReplaceOpenParen.setTo((UChar)0xFF3B); // fullwidth [
410 formatCloseParen.setTo((UChar)0xFF09); // fullwidth )
411 formatReplaceCloseParen.setTo((UChar)0xFF3D); // fullwidth ]
412 } else {
413 formatOpenParen.setTo((UChar)0x0028); // (
414 formatReplaceOpenParen.setTo((UChar)0x005B); // [
415 formatCloseParen.setTo((UChar)0x0029); // )
416 formatReplaceCloseParen.setTo((UChar)0x005D); // ]
417 }
51004dcb
A
418
419 UnicodeString ktPattern;
420 langData.get("localeDisplayPattern", "keyTypePattern", ktPattern);
421 if (ktPattern.isBogus()) {
422 ktPattern = UnicodeString("{0}={1}", -1, US_INV);
423 }
424 keyTypeFormat = new MessageFormat(ktPattern, status);
425
426 uprv_memset(fCapitalization, 0, sizeof(fCapitalization));
427#if !UCONFIG_NO_BREAK_ITERATION
428 // The following is basically copied from DateFormatSymbols::initializeData
429 typedef struct {
430 const char * usageName;
431 LocaleDisplayNamesImpl::CapContextUsage usageEnum;
432 } ContextUsageNameToEnum;
433 const ContextUsageNameToEnum contextUsageTypeMap[] = {
434 // Entries must be sorted by usageTypeName; entry with NULL name terminates list.
435 { "key", kCapContextUsageKey },
57a6839d 436 { "keyValue", kCapContextUsageKeyValue },
51004dcb
A
437 { "languages", kCapContextUsageLanguage },
438 { "script", kCapContextUsageScript },
439 { "territory", kCapContextUsageTerritory },
51004dcb
A
440 { "variant", kCapContextUsageVariant },
441 { NULL, (CapContextUsage)0 },
442 };
57a6839d
A
443 // Only get the context data if we need it! This is a const object so we know now...
444 // Also check whether we will need a break iterator (depends on the data)
445 UBool needBrkIter = FALSE;
446 if (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE) {
447 int32_t len = 0;
448 UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &status);
51004dcb 449 if (U_SUCCESS(status)) {
57a6839d
A
450 UResourceBundle *contextTransforms = ures_getByKeyWithFallback(localeBundle, "contextTransforms", NULL, &status);
451 if (U_SUCCESS(status)) {
452 UResourceBundle *contextTransformUsage;
453 while ( (contextTransformUsage = ures_getNextResource(contextTransforms, NULL, &status)) != NULL ) {
454 const int32_t * intVector = ures_getIntVector(contextTransformUsage, &len, &status);
455 if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
456 const char* usageKey = ures_getKey(contextTransformUsage);
457 if (usageKey != NULL) {
458 const ContextUsageNameToEnum * typeMapPtr = contextUsageTypeMap;
459 int32_t compResult = 0;
460 // linear search; list is short and we cannot be sure that bsearch is available
461 while ( typeMapPtr->usageName != NULL && (compResult = uprv_strcmp(usageKey, typeMapPtr->usageName)) > 0 ) {
462 ++typeMapPtr;
463 }
464 if (typeMapPtr->usageName != NULL && compResult == 0) {
465 int32_t titlecaseInt = (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU)? intVector[0]: intVector[1];
466 if (titlecaseInt != 0) {
467 fCapitalization[typeMapPtr->usageEnum] = TRUE;;
468 needBrkIter = TRUE;
469 }
470 }
51004dcb
A
471 }
472 }
57a6839d
A
473 status = U_ZERO_ERROR;
474 ures_close(contextTransformUsage);
51004dcb 475 }
57a6839d 476 ures_close(contextTransforms);
51004dcb 477 }
57a6839d
A
478 ures_close(localeBundle);
479 }
480 }
481 // Get a sentence break iterator if we will need it
482 if (needBrkIter || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE) {
483 status = U_ZERO_ERROR;
484 capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
485 if (U_FAILURE(status)) {
486 delete capitalizationBrkIter;
487 capitalizationBrkIter = NULL;
51004dcb 488 }
51004dcb
A
489 }
490#endif
729e4ab9
A
491}
492
493LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() {
57a6839d 494 delete separatorFormat;
51004dcb
A
495 delete format;
496 delete keyTypeFormat;
57a6839d 497 delete capitalizationBrkIter;
51004dcb 498 }
729e4ab9
A
499
500const Locale&
501LocaleDisplayNamesImpl::getLocale() const {
51004dcb 502 return locale;
729e4ab9
A
503}
504
505UDialectHandling
506LocaleDisplayNamesImpl::getDialectHandling() const {
51004dcb
A
507 return dialectHandling;
508}
509
510UDisplayContext
511LocaleDisplayNamesImpl::getContext(UDisplayContextType type) const {
512 switch (type) {
513 case UDISPCTX_TYPE_DIALECT_HANDLING:
514 return (UDisplayContext)dialectHandling;
515 case UDISPCTX_TYPE_CAPITALIZATION:
516 return capitalizationContext;
57a6839d
A
517 case UADISPCTX_TYPE_LENGTH:
518 return nameLength;
51004dcb
A
519 default:
520 break;
521 }
522 return (UDisplayContext)0;
523}
524
525UnicodeString&
526LocaleDisplayNamesImpl::adjustForUsageAndContext(CapContextUsage usage,
527 UnicodeString& result) const {
528#if !UCONFIG_NO_BREAK_ITERATION
529 // check to see whether we need to titlecase result
57a6839d
A
530 if ( result.length() > 0 && u_islower(result.char32At(0)) && capitalizationBrkIter!= NULL &&
531 ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || fCapitalization[usage] ) ) {
532 // note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE
533 result.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
51004dcb
A
534 }
535#endif
536 return result;
729e4ab9
A
537}
538
539UnicodeString&
540LocaleDisplayNamesImpl::localeDisplayName(const Locale& locale,
541 UnicodeString& result) const {
542 UnicodeString resultName;
543
544 const char* lang = locale.getLanguage();
545 if (uprv_strlen(lang) == 0) {
546 lang = "root";
547 }
548 const char* script = locale.getScript();
549 const char* country = locale.getCountry();
550 const char* variant = locale.getVariant();
551
552 UBool hasScript = uprv_strlen(script) > 0;
553 UBool hasCountry = uprv_strlen(country) > 0;
554 UBool hasVariant = uprv_strlen(variant) > 0;
555
556 if (dialectHandling == ULDN_DIALECT_NAMES) {
557 char buffer[ULOC_FULLNAME_CAPACITY];
558 do { // loop construct is so we can break early out of search
559 if (hasScript && hasCountry) {
560 ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, "_", country, (char *)0);
561 localeIdName(buffer, resultName);
562 if (!resultName.isBogus()) {
563 hasScript = FALSE;
564 hasCountry = FALSE;
565 break;
566 }
567 }
568 if (hasScript) {
569 ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", script, (char *)0);
570 localeIdName(buffer, resultName);
571 if (!resultName.isBogus()) {
572 hasScript = FALSE;
573 break;
574 }
575 }
576 if (hasCountry) {
577 ncat(buffer, ULOC_FULLNAME_CAPACITY, lang, "_", country, (char*)0);
578 localeIdName(buffer, resultName);
579 if (!resultName.isBogus()) {
580 hasCountry = FALSE;
581 break;
582 }
583 }
584 } while (FALSE);
585 }
586 if (resultName.isBogus() || resultName.isEmpty()) {
587 localeIdName(lang, resultName);
588 }
589
590 UnicodeString resultRemainder;
591 UnicodeString temp;
592 StringEnumeration *e = NULL;
593 UErrorCode status = U_ZERO_ERROR;
594
595 if (hasScript) {
596 resultRemainder.append(scriptDisplayName(script, temp));
597 }
598 if (hasCountry) {
57a6839d 599 appendWithSep(resultRemainder, regionShortDisplayName(country, temp));
729e4ab9
A
600 }
601 if (hasVariant) {
602 appendWithSep(resultRemainder, variantDisplayName(variant, temp));
603 }
57a6839d
A
604 resultRemainder.findAndReplace(formatOpenParen, formatReplaceOpenParen);
605 resultRemainder.findAndReplace(formatCloseParen, formatReplaceCloseParen);
729e4ab9
A
606
607 e = locale.createKeywords(status);
608 if (e && U_SUCCESS(status)) {
609 UnicodeString temp2;
610 char value[ULOC_KEYWORD_AND_VALUES_CAPACITY]; // sigh, no ULOC_VALUE_CAPACITY
611 const char* key;
612 while ((key = e->next((int32_t *)0, status)) != NULL) {
613 locale.getKeywordValue(key, value, ULOC_KEYWORD_AND_VALUES_CAPACITY, status);
4388f060 614 keyDisplayName(key, temp);
57a6839d
A
615 temp.findAndReplace(formatOpenParen, formatReplaceOpenParen);
616 temp.findAndReplace(formatCloseParen, formatReplaceCloseParen);
4388f060 617 keyValueDisplayName(key, value, temp2);
57a6839d
A
618 temp2.findAndReplace(formatOpenParen, formatReplaceOpenParen);
619 temp2.findAndReplace(formatCloseParen, formatReplaceCloseParen);
4388f060
A
620 if (temp2 != UnicodeString(value, -1, US_INV)) {
621 appendWithSep(resultRemainder, temp2);
622 } else if (temp != UnicodeString(key, -1, US_INV)) {
623 UnicodeString temp3;
624 Formattable data[] = {
625 temp,
626 temp2
627 };
628 FieldPosition fpos;
629 status = U_ZERO_ERROR;
630 keyTypeFormat->format(data, 2, temp3, fpos, status);
631 appendWithSep(resultRemainder, temp3);
632 } else {
633 appendWithSep(resultRemainder, temp)
634 .append((UChar)0x3d /* = */)
635 .append(temp2);
636 }
729e4ab9
A
637 }
638 delete e;
639 }
640
641 if (!resultRemainder.isEmpty()) {
642 Formattable data[] = {
643 resultName,
644 resultRemainder
645 };
646 FieldPosition fpos;
647 status = U_ZERO_ERROR;
648 format->format(data, 2, result, fpos, status);
51004dcb 649 return adjustForUsageAndContext(kCapContextUsageLanguage, result);
729e4ab9
A
650 }
651
51004dcb
A
652 result = resultName;
653 return adjustForUsageAndContext(kCapContextUsageLanguage, result);
729e4ab9
A
654}
655
656UnicodeString&
657LocaleDisplayNamesImpl::appendWithSep(UnicodeString& buffer, const UnicodeString& src) const {
57a6839d
A
658 if (buffer.isEmpty()) {
659 buffer.setTo(src);
660 } else {
661 UnicodeString combined;
662 Formattable data[] = {
663 buffer,
664 src
665 };
666 FieldPosition fpos;
667 UErrorCode status = U_ZERO_ERROR;
668 separatorFormat->format(data, 2, combined, fpos, status);
669 if (U_SUCCESS(status)) {
670 buffer.setTo(combined);
671 }
51004dcb 672 }
51004dcb 673 return buffer;
729e4ab9
A
674}
675
676UnicodeString&
677LocaleDisplayNamesImpl::localeDisplayName(const char* localeId,
678 UnicodeString& result) const {
51004dcb 679 return localeDisplayName(Locale(localeId), result);
729e4ab9
A
680}
681
51004dcb 682// private
729e4ab9
A
683UnicodeString&
684LocaleDisplayNamesImpl::localeIdName(const char* localeId,
685 UnicodeString& result) const {
57a6839d
A
686 if (nameLength == UADISPCTX_LENGTH_SHORT) {
687 langData.getNoFallback("LanguagesShort", localeId, result);
688 if (!result.isBogus()) {
689 return result;
690 }
691 }
51004dcb 692 return langData.getNoFallback("Languages", localeId, result);
729e4ab9
A
693}
694
695UnicodeString&
696LocaleDisplayNamesImpl::languageDisplayName(const char* lang,
697 UnicodeString& result) const {
51004dcb
A
698 if (uprv_strcmp("root", lang) == 0 || uprv_strchr(lang, '_') != NULL) {
699 return result = UnicodeString(lang, -1, US_INV);
700 }
57a6839d
A
701 if (nameLength == UADISPCTX_LENGTH_SHORT) {
702 langData.getNoFallback("LanguagesShort", lang, result);
703 if (!result.isBogus()) {
704 return adjustForUsageAndContext(kCapContextUsageLanguage, result);
705 }
706 }
51004dcb
A
707 langData.get("Languages", lang, result);
708 return adjustForUsageAndContext(kCapContextUsageLanguage, result);
729e4ab9
A
709}
710
711UnicodeString&
712LocaleDisplayNamesImpl::scriptDisplayName(const char* script,
713 UnicodeString& result) const {
51004dcb
A
714 langData.get("Scripts", script, result);
715 return adjustForUsageAndContext(kCapContextUsageScript, result);
729e4ab9
A
716}
717
718UnicodeString&
719LocaleDisplayNamesImpl::scriptDisplayName(UScriptCode scriptCode,
720 UnicodeString& result) const {
51004dcb
A
721 const char* name = uscript_getName(scriptCode);
722 langData.get("Scripts", name, result);
723 return adjustForUsageAndContext(kCapContextUsageScript, result);
729e4ab9
A
724}
725
726UnicodeString&
727LocaleDisplayNamesImpl::regionDisplayName(const char* region,
728 UnicodeString& result) const {
57a6839d
A
729 if (nameLength == UADISPCTX_LENGTH_SHORT) {
730 regionData.getNoFallback("CountriesShort", region, result);
731 if (!result.isBogus()) {
732 return adjustForUsageAndContext(kCapContextUsageTerritory, result);
733 }
734 }
735 regionData.get("Countries", region, result);
736 return adjustForUsageAndContext(kCapContextUsageTerritory, result);
737}
738
739// private Apple
740UnicodeString&
741LocaleDisplayNamesImpl::regionShortDisplayName(const char* region,
742 UnicodeString& result) const {
743 if (uprv_strcmp(region, "PS") != 0) {
744 regionData.getNoFallback("CountriesShort", region, result);
745 if (!result.isBogus()) {
746 return adjustForUsageAndContext(kCapContextUsageTerritory, result);
747 }
748 }
51004dcb
A
749 regionData.get("Countries", region, result);
750 return adjustForUsageAndContext(kCapContextUsageTerritory, result);
729e4ab9
A
751}
752
753UnicodeString&
754LocaleDisplayNamesImpl::variantDisplayName(const char* variant,
755 UnicodeString& result) const {
51004dcb
A
756 langData.get("Variants", variant, result);
757 return adjustForUsageAndContext(kCapContextUsageVariant, result);
729e4ab9
A
758}
759
760UnicodeString&
761LocaleDisplayNamesImpl::keyDisplayName(const char* key,
762 UnicodeString& result) const {
51004dcb
A
763 langData.get("Keys", key, result);
764 return adjustForUsageAndContext(kCapContextUsageKey, result);
729e4ab9
A
765}
766
767UnicodeString&
768LocaleDisplayNamesImpl::keyValueDisplayName(const char* key,
769 const char* value,
770 UnicodeString& result) const {
51004dcb 771 langData.get("Types", key, value, result);
57a6839d 772 return adjustForUsageAndContext(kCapContextUsageKeyValue, result);
729e4ab9
A
773}
774
775////////////////////////////////////////////////////////////////////////////////////////////////////
776
777LocaleDisplayNames*
778LocaleDisplayNames::createInstance(const Locale& locale,
779 UDialectHandling dialectHandling) {
51004dcb
A
780 return new LocaleDisplayNamesImpl(locale, dialectHandling);
781}
782
783LocaleDisplayNames*
784LocaleDisplayNames::createInstance(const Locale& locale,
785 UDisplayContext *contexts, int32_t length) {
786 if (contexts == NULL) {
787 length = 0;
788 }
789 return new LocaleDisplayNamesImpl(locale, contexts, length);
729e4ab9
A
790}
791
792U_NAMESPACE_END
793
794////////////////////////////////////////////////////////////////////////////////////////////////////
795
796U_NAMESPACE_USE
797
51004dcb 798U_CAPI ULocaleDisplayNames * U_EXPORT2
729e4ab9
A
799uldn_open(const char * locale,
800 UDialectHandling dialectHandling,
801 UErrorCode *pErrorCode) {
802 if (U_FAILURE(*pErrorCode)) {
803 return 0;
804 }
805 if (locale == NULL) {
806 locale = uloc_getDefault();
807 }
808 return (ULocaleDisplayNames *)LocaleDisplayNames::createInstance(Locale(locale), dialectHandling);
809}
810
51004dcb
A
811U_CAPI ULocaleDisplayNames * U_EXPORT2
812uldn_openForContext(const char * locale,
813 UDisplayContext *contexts, int32_t length,
814 UErrorCode *pErrorCode) {
815 if (U_FAILURE(*pErrorCode)) {
816 return 0;
817 }
818 if (locale == NULL) {
819 locale = uloc_getDefault();
820 }
821 return (ULocaleDisplayNames *)LocaleDisplayNames::createInstance(Locale(locale), contexts, length);
822}
823
824
825U_CAPI void U_EXPORT2
729e4ab9
A
826uldn_close(ULocaleDisplayNames *ldn) {
827 delete (LocaleDisplayNames *)ldn;
828}
829
51004dcb 830U_CAPI const char * U_EXPORT2
729e4ab9
A
831uldn_getLocale(const ULocaleDisplayNames *ldn) {
832 if (ldn) {
833 return ((const LocaleDisplayNames *)ldn)->getLocale().getName();
834 }
835 return NULL;
836}
837
51004dcb 838U_CAPI UDialectHandling U_EXPORT2
729e4ab9
A
839uldn_getDialectHandling(const ULocaleDisplayNames *ldn) {
840 if (ldn) {
841 return ((const LocaleDisplayNames *)ldn)->getDialectHandling();
842 }
843 return ULDN_STANDARD_NAMES;
844}
845
51004dcb
A
846U_CAPI UDisplayContext U_EXPORT2
847uldn_getContext(const ULocaleDisplayNames *ldn,
848 UDisplayContextType type,
849 UErrorCode *pErrorCode) {
850 if (U_FAILURE(*pErrorCode)) {
851 return (UDisplayContext)0;
852 }
853 return ((const LocaleDisplayNames *)ldn)->getContext(type);
854}
855
856U_CAPI int32_t U_EXPORT2
729e4ab9
A
857uldn_localeDisplayName(const ULocaleDisplayNames *ldn,
858 const char *locale,
859 UChar *result,
860 int32_t maxResultSize,
861 UErrorCode *pErrorCode) {
862 if (U_FAILURE(*pErrorCode)) {
863 return 0;
864 }
865 if (ldn == NULL || locale == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
866 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
867 return 0;
868 }
869 UnicodeString temp(result, 0, maxResultSize);
870 ((const LocaleDisplayNames *)ldn)->localeDisplayName(locale, temp);
871 return temp.extract(result, maxResultSize, *pErrorCode);
872}
873
51004dcb 874U_CAPI int32_t U_EXPORT2
729e4ab9
A
875uldn_languageDisplayName(const ULocaleDisplayNames *ldn,
876 const char *lang,
877 UChar *result,
878 int32_t maxResultSize,
879 UErrorCode *pErrorCode) {
880 if (U_FAILURE(*pErrorCode)) {
881 return 0;
882 }
883 if (ldn == NULL || lang == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
884 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
885 return 0;
886 }
887 UnicodeString temp(result, 0, maxResultSize);
888 ((const LocaleDisplayNames *)ldn)->languageDisplayName(lang, temp);
889 return temp.extract(result, maxResultSize, *pErrorCode);
890}
891
51004dcb 892U_CAPI int32_t U_EXPORT2
729e4ab9
A
893uldn_scriptDisplayName(const ULocaleDisplayNames *ldn,
894 const char *script,
895 UChar *result,
896 int32_t maxResultSize,
897 UErrorCode *pErrorCode) {
898 if (U_FAILURE(*pErrorCode)) {
899 return 0;
900 }
901 if (ldn == NULL || script == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
902 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
903 return 0;
904 }
905 UnicodeString temp(result, 0, maxResultSize);
906 ((const LocaleDisplayNames *)ldn)->scriptDisplayName(script, temp);
907 return temp.extract(result, maxResultSize, *pErrorCode);
908}
909
51004dcb 910U_CAPI int32_t U_EXPORT2
729e4ab9
A
911uldn_scriptCodeDisplayName(const ULocaleDisplayNames *ldn,
912 UScriptCode scriptCode,
913 UChar *result,
914 int32_t maxResultSize,
915 UErrorCode *pErrorCode) {
916 return uldn_scriptDisplayName(ldn, uscript_getName(scriptCode), result, maxResultSize, pErrorCode);
917}
918
51004dcb 919U_CAPI int32_t U_EXPORT2
729e4ab9
A
920uldn_regionDisplayName(const ULocaleDisplayNames *ldn,
921 const char *region,
922 UChar *result,
923 int32_t maxResultSize,
924 UErrorCode *pErrorCode) {
925 if (U_FAILURE(*pErrorCode)) {
926 return 0;
927 }
928 if (ldn == NULL || region == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
929 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
930 return 0;
931 }
932 UnicodeString temp(result, 0, maxResultSize);
933 ((const LocaleDisplayNames *)ldn)->regionDisplayName(region, temp);
934 return temp.extract(result, maxResultSize, *pErrorCode);
935}
936
51004dcb 937U_CAPI int32_t U_EXPORT2
729e4ab9
A
938uldn_variantDisplayName(const ULocaleDisplayNames *ldn,
939 const char *variant,
940 UChar *result,
941 int32_t maxResultSize,
942 UErrorCode *pErrorCode) {
943 if (U_FAILURE(*pErrorCode)) {
944 return 0;
945 }
946 if (ldn == NULL || variant == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
947 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
948 return 0;
949 }
950 UnicodeString temp(result, 0, maxResultSize);
951 ((const LocaleDisplayNames *)ldn)->variantDisplayName(variant, temp);
952 return temp.extract(result, maxResultSize, *pErrorCode);
953}
954
51004dcb 955U_CAPI int32_t U_EXPORT2
729e4ab9
A
956uldn_keyDisplayName(const ULocaleDisplayNames *ldn,
957 const char *key,
958 UChar *result,
959 int32_t maxResultSize,
960 UErrorCode *pErrorCode) {
961 if (U_FAILURE(*pErrorCode)) {
962 return 0;
963 }
964 if (ldn == NULL || key == NULL || (result == NULL && maxResultSize > 0) || maxResultSize < 0) {
965 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
966 return 0;
967 }
968 UnicodeString temp(result, 0, maxResultSize);
969 ((const LocaleDisplayNames *)ldn)->keyDisplayName(key, temp);
970 return temp.extract(result, maxResultSize, *pErrorCode);
971}
972
51004dcb 973U_CAPI int32_t U_EXPORT2
729e4ab9
A
974uldn_keyValueDisplayName(const ULocaleDisplayNames *ldn,
975 const char *key,
976 const char *value,
977 UChar *result,
978 int32_t maxResultSize,
979 UErrorCode *pErrorCode) {
980 if (U_FAILURE(*pErrorCode)) {
981 return 0;
982 }
983 if (ldn == NULL || key == NULL || value == NULL || (result == NULL && maxResultSize > 0)
984 || maxResultSize < 0) {
985 *pErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
986 return 0;
987 }
988 UnicodeString temp(result, 0, maxResultSize);
989 ((const LocaleDisplayNames *)ldn)->keyValueDisplayName(key, value, temp);
990 return temp.extract(result, maxResultSize, *pErrorCode);
991}
992
993#endif