locdspnm.cpp 41 KB

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