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