locdspnm.cpp 40 KB

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