Coverage Report

Created: 2025-06-13 06:34

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