@ui5/webcomponents-localization 1.22.0-rc.1 → 1.22.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/generated/assets/cldr/ar.json +102 -62
  4. package/dist/generated/assets/cldr/ar_EG.json +102 -62
  5. package/dist/generated/assets/cldr/ar_SA.json +102 -62
  6. package/dist/generated/assets/cldr/bg.json +364 -325
  7. package/dist/generated/assets/cldr/ca.json +491 -453
  8. package/dist/generated/assets/cldr/cs.json +431 -324
  9. package/dist/generated/assets/cldr/cy.json +608 -340
  10. package/dist/generated/assets/cldr/da.json +290 -227
  11. package/dist/generated/assets/cldr/de.json +348 -241
  12. package/dist/generated/assets/cldr/de_AT.json +348 -241
  13. package/dist/generated/assets/cldr/de_CH.json +347 -240
  14. package/dist/generated/assets/cldr/el.json +128 -100
  15. package/dist/generated/assets/cldr/el_CY.json +128 -100
  16. package/dist/generated/assets/cldr/en.json +538 -512
  17. package/dist/generated/assets/cldr/en_AU.json +583 -520
  18. package/dist/generated/assets/cldr/en_GB.json +485 -441
  19. package/dist/generated/assets/cldr/en_HK.json +519 -474
  20. package/dist/generated/assets/cldr/en_IE.json +485 -440
  21. package/dist/generated/assets/cldr/en_IN.json +465 -420
  22. package/dist/generated/assets/cldr/en_NZ.json +505 -460
  23. package/dist/generated/assets/cldr/en_PG.json +505 -460
  24. package/dist/generated/assets/cldr/en_SG.json +505 -460
  25. package/dist/generated/assets/cldr/en_ZA.json +485 -440
  26. package/dist/generated/assets/cldr/es.json +709 -456
  27. package/dist/generated/assets/cldr/es_AR.json +687 -434
  28. package/dist/generated/assets/cldr/es_BO.json +721 -468
  29. package/dist/generated/assets/cldr/es_CL.json +567 -422
  30. package/dist/generated/assets/cldr/es_CO.json +485 -339
  31. package/dist/generated/assets/cldr/es_MX.json +734 -481
  32. package/dist/generated/assets/cldr/es_PE.json +409 -372
  33. package/dist/generated/assets/cldr/es_UY.json +433 -396
  34. package/dist/generated/assets/cldr/es_VE.json +453 -416
  35. package/dist/generated/assets/cldr/et.json +340 -307
  36. package/dist/generated/assets/cldr/fa.json +96 -34
  37. package/dist/generated/assets/cldr/fi.json +359 -308
  38. package/dist/generated/assets/cldr/fr.json +347 -321
  39. package/dist/generated/assets/cldr/fr_BE.json +347 -321
  40. package/dist/generated/assets/cldr/fr_CA.json +458 -432
  41. package/dist/generated/assets/cldr/fr_CH.json +290 -264
  42. package/dist/generated/assets/cldr/fr_LU.json +347 -321
  43. package/dist/generated/assets/cldr/he.json +241 -130
  44. package/dist/generated/assets/cldr/hi.json +103 -53
  45. package/dist/generated/assets/cldr/hr.json +467 -410
  46. package/dist/generated/assets/cldr/hu.json +246 -195
  47. package/dist/generated/assets/cldr/id.json +478 -406
  48. package/dist/generated/assets/cldr/it.json +418 -362
  49. package/dist/generated/assets/cldr/it_CH.json +418 -362
  50. package/dist/generated/assets/cldr/ja.json +58 -18
  51. package/dist/generated/assets/cldr/kk.json +562 -398
  52. package/dist/generated/assets/cldr/ko.json +36 -15
  53. package/dist/generated/assets/cldr/lt.json +320 -231
  54. package/dist/generated/assets/cldr/lv.json +184 -120
  55. package/dist/generated/assets/cldr/ms.json +460 -388
  56. package/dist/generated/assets/cldr/nb.json +160 -92
  57. package/dist/generated/assets/cldr/nl.json +621 -373
  58. package/dist/generated/assets/cldr/nl_BE.json +621 -373
  59. package/dist/generated/assets/cldr/pl.json +590 -279
  60. package/dist/generated/assets/cldr/pt.json +696 -334
  61. package/dist/generated/assets/cldr/pt_PT.json +730 -454
  62. package/dist/generated/assets/cldr/ro.json +409 -339
  63. package/dist/generated/assets/cldr/ru.json +317 -279
  64. package/dist/generated/assets/cldr/ru_UA.json +312 -274
  65. package/dist/generated/assets/cldr/sk.json +454 -413
  66. package/dist/generated/assets/cldr/sl.json +118 -80
  67. package/dist/generated/assets/cldr/sr.json +294 -142
  68. package/dist/generated/assets/cldr/sr_Latn.json +972 -824
  69. package/dist/generated/assets/cldr/sv.json +382 -338
  70. package/dist/generated/assets/cldr/th.json +56 -36
  71. package/dist/generated/assets/cldr/tr.json +371 -320
  72. package/dist/generated/assets/cldr/uk.json +340 -290
  73. package/dist/generated/assets/cldr/vi.json +352 -328
  74. package/dist/generated/assets/cldr/zh_CN.json +34 -10
  75. package/dist/generated/assets/cldr/zh_HK.json +33 -9
  76. package/dist/generated/assets/cldr/zh_SG.json +33 -9
  77. package/dist/generated/assets/cldr/zh_TW.json +32 -8
  78. package/dist/sap/base/Event.js +59 -0
  79. package/dist/sap/base/Eventing.js +146 -0
  80. package/dist/sap/base/Log.js +2 -239
  81. package/dist/sap/base/assert.js +28 -1
  82. package/dist/sap/base/config/MemoryConfigurationProvider.js +20 -0
  83. package/dist/sap/base/config.js +17 -0
  84. package/dist/sap/base/i18n/Formatting.js +1130 -0
  85. package/dist/sap/base/i18n/LanguageTag.js +168 -30
  86. package/dist/sap/base/i18n/date/CalendarType.js +36 -1
  87. package/dist/sap/base/i18n/date/CalendarWeekNumbering.js +76 -1
  88. package/dist/sap/base/i18n/date/TimezoneUtils.js +242 -12
  89. package/dist/sap/base/strings/camelize.js +30 -0
  90. package/dist/sap/base/strings/formatMessage.js +88 -15
  91. package/dist/sap/base/util/ObjectPath.js +95 -3
  92. package/dist/sap/base/util/Version.js +157 -0
  93. package/dist/sap/base/util/_merge.js +83 -26
  94. package/dist/sap/base/util/array/uniqueSort.js +37 -15
  95. package/dist/sap/base/util/deepClone.js +102 -0
  96. package/dist/sap/base/util/deepEqual.js +75 -51
  97. package/dist/sap/base/util/extend.js +58 -7
  98. package/dist/sap/base/util/isEmptyObject.js +34 -0
  99. package/dist/sap/base/util/isPlainObject.js +35 -1
  100. package/dist/sap/base/util/now.js +24 -3
  101. package/dist/sap/base/util/resolveReference.js +157 -0
  102. package/dist/sap/base/util/uid.js +27 -0
  103. package/dist/sap/ui/base/DataType.js +657 -0
  104. package/dist/sap/ui/base/Interface.js +47 -1
  105. package/dist/sap/ui/base/Metadata.js +433 -180
  106. package/dist/sap/ui/base/Object.js +284 -48
  107. package/dist/sap/ui/core/CalendarType.js +23 -1
  108. package/dist/sap/ui/core/Locale.js +189 -57
  109. package/dist/sap/ui/core/LocaleData.js +2670 -1380
  110. package/dist/sap/ui/core/Supportability.js +5 -0
  111. package/dist/sap/ui/core/Theming.js +539 -0
  112. package/dist/sap/ui/core/date/Buddhist.js +162 -87
  113. package/dist/sap/ui/core/date/CalendarUtils.js +61 -21
  114. package/dist/sap/ui/core/date/CalendarWeekNumbering.js +29 -1
  115. package/dist/sap/ui/core/date/Gregorian.js +25 -10
  116. package/dist/sap/ui/core/date/Islamic.js +298 -185
  117. package/dist/sap/ui/core/date/Japanese.js +210 -115
  118. package/dist/sap/ui/core/date/Persian.js +324 -195
  119. package/dist/sap/ui/core/date/UI5Date.js +923 -237
  120. package/dist/sap/ui/core/date/UniversalDate.js +1238 -245
  121. package/dist/sap/ui/core/date/_Calendars.js +10 -1
  122. package/dist/sap/ui/core/format/DateFormat.js +3163 -2145
  123. package/dist/sap/ui/core/format/TimezoneUtil.js +23 -1
  124. package/package-scripts.cjs +4 -10
  125. package/package.json +9 -5
  126. package/used-modules.txt +20 -1
  127. package/dist/sap/ui/Device.js +0 -5
@@ -1,1427 +1,2717 @@
1
- import Core from './Core.js';
2
- import CalendarType from './CalendarType.js';
3
- import Locale from './Locale.js';
4
- import assert from '../../base/assert.js';
5
- import Localization from '../../base/i18n/Localization.js';
6
- import extend from '../../base/util/extend.js';
7
- import LoaderExtensions from '../../base/util/LoaderExtensions.js';
8
- import BaseObject from '../base/Object.js';
9
- import Configuration from './Configuration.js';
10
- import CalendarWeekNumbering from './date/CalendarWeekNumbering.js';
11
- var rCIgnoreCase = /c/i, rEIgnoreCase = /e/i, mLegacyUnit2CurrentUnit = {
12
- 'acceleration-meter-per-second-squared': 'acceleration-meter-per-square-second',
13
- 'concentr-milligram-per-deciliter': 'concentr-milligram-ofglucose-per-deciliter',
14
- 'concentr-part-per-million': 'concentr-permillion',
15
- 'consumption-liter-per-100kilometers': 'consumption-liter-per-100-kilometer',
16
- 'pressure-millimeter-of-mercury': 'pressure-millimeter-ofhg',
17
- 'pressure-pound-per-square-inch': 'pressure-pound-force-per-square-inch',
18
- 'pressure-inch-hg': 'pressure-inch-ofhg',
19
- 'torque-pound-foot': 'torque-pound-force-foot'
20
- }, rNumberInScientificNotation = /^([+-]?)((\d+)(?:\.(\d+))?)[eE]([+-]?\d+)$/, rTrailingZeroes = /0+$/;
21
- var LocaleData = BaseObject.extend('sap.ui.core.LocaleData', {
22
- constructor: function (oLocale) {
23
- this.oLocale = Locale._getCoreLocale(oLocale);
24
- BaseObject.apply(this);
25
- var oDataLoaded = getData(this.oLocale);
26
- this.mData = oDataLoaded.mData;
27
- this.sCLDRLocaleId = oDataLoaded.sCLDRLocaleId;
28
- },
29
- _get: function () {
30
- return this._getDeep(this.mData, arguments);
31
- },
32
- _getMerged: function () {
33
- return this._get.apply(this, arguments);
34
- },
35
- _getDeep: function (oObject, aPropertyNames) {
36
- var oResult = oObject;
37
- for (var i = 0; i < aPropertyNames.length; i++) {
38
- oResult = oResult[aPropertyNames[i]];
39
- if (oResult === undefined) {
40
- break;
41
- }
42
- }
43
- return oResult;
44
- },
45
- getOrientation: function () {
46
- return this._get('orientation');
47
- },
48
- getCurrentLanguageName: function () {
49
- var oLanguages = this.getLanguages();
50
- var sCurrentLanguage;
51
- var sLanguage = Localization.getModernLanguage(this.oLocale.language);
52
- var sScript = this.oLocale.getScript();
53
- if (sLanguage === 'sr' && sScript === 'Latn') {
54
- sLanguage = 'sh';
55
- sScript = null;
56
- }
57
- if (this.oLocale.getRegion()) {
58
- sCurrentLanguage = oLanguages[sLanguage + '_' + this.oLocale.getRegion()];
59
- }
60
- if (!sCurrentLanguage && sScript) {
61
- sCurrentLanguage = oLanguages[sLanguage + '_' + sScript];
62
- }
63
- if (!sCurrentLanguage) {
64
- sCurrentLanguage = oLanguages[sLanguage];
65
- }
66
- return sCurrentLanguage;
67
- },
68
- getLanguages: function () {
69
- return this._get('languages');
70
- },
71
- getScripts: function () {
72
- return this._get('scripts');
73
- },
74
- getTerritories: function () {
75
- return this._get('territories');
76
- },
77
- getMonths: function (sWidth, sCalendarType) {
78
- assert(sWidth == 'narrow' || sWidth == 'abbreviated' || sWidth == 'wide', 'sWidth must be narrow, abbreviated or wide');
79
- return this._get(getCLDRCalendarName(sCalendarType), 'months', 'format', sWidth);
80
- },
81
- getMonthsStandAlone: function (sWidth, sCalendarType) {
82
- assert(sWidth == 'narrow' || sWidth == 'abbreviated' || sWidth == 'wide', 'sWidth must be narrow, abbreviated or wide');
83
- return this._get(getCLDRCalendarName(sCalendarType), 'months', 'stand-alone', sWidth);
84
- },
85
- getDays: function (sWidth, sCalendarType) {
86
- assert(sWidth == 'narrow' || sWidth == 'abbreviated' || sWidth == 'wide' || sWidth == 'short', 'sWidth must be narrow, abbreviate, wide or short');
87
- return this._get(getCLDRCalendarName(sCalendarType), 'days', 'format', sWidth);
88
- },
89
- getDaysStandAlone: function (sWidth, sCalendarType) {
90
- assert(sWidth == 'narrow' || sWidth == 'abbreviated' || sWidth == 'wide' || sWidth == 'short', 'sWidth must be narrow, abbreviated, wide or short');
91
- return this._get(getCLDRCalendarName(sCalendarType), 'days', 'stand-alone', sWidth);
92
- },
93
- getQuarters: function (sWidth, sCalendarType) {
94
- assert(sWidth == 'narrow' || sWidth == 'abbreviated' || sWidth == 'wide', 'sWidth must be narrow, abbreviated or wide');
95
- return this._get(getCLDRCalendarName(sCalendarType), 'quarters', 'format', sWidth);
96
- },
97
- getQuartersStandAlone: function (sWidth, sCalendarType) {
98
- assert(sWidth == 'narrow' || sWidth == 'abbreviated' || sWidth == 'wide', 'sWidth must be narrow, abbreviated or wide');
99
- return this._get(getCLDRCalendarName(sCalendarType), 'quarters', 'stand-alone', sWidth);
100
- },
101
- getDayPeriods: function (sWidth, sCalendarType) {
102
- assert(sWidth == 'narrow' || sWidth == 'abbreviated' || sWidth == 'wide', 'sWidth must be narrow, abbreviated or wide');
103
- return this._get(getCLDRCalendarName(sCalendarType), 'dayPeriods', 'format', sWidth);
104
- },
105
- getDayPeriodsStandAlone: function (sWidth, sCalendarType) {
106
- assert(sWidth == 'narrow' || sWidth == 'abbreviated' || sWidth == 'wide', 'sWidth must be narrow, abbreviated or wide');
107
- return this._get(getCLDRCalendarName(sCalendarType), 'dayPeriods', 'stand-alone', sWidth);
108
- },
109
- getDatePattern: function (sStyle, sCalendarType) {
110
- assert(sStyle == 'short' || sStyle == 'medium' || sStyle == 'long' || sStyle == 'full', 'sStyle must be short, medium, long or full');
111
- return this._get(getCLDRCalendarName(sCalendarType), 'dateFormats', sStyle);
112
- },
113
- getFlexibleDayPeriods: function (sWidth, sCalendarType) {
114
- return this._get(getCLDRCalendarName(sCalendarType), 'flexibleDayPeriods', 'format', sWidth);
115
- },
116
- getFlexibleDayPeriodsStandAlone: function (sWidth, sCalendarType) {
117
- return this._get(getCLDRCalendarName(sCalendarType), 'flexibleDayPeriods', 'stand-alone', sWidth);
118
- },
119
- getFlexibleDayPeriodOfTime: function (iHour, iMinute) {
120
- var iAbsoluteMinutes, oDayPeriodRules, sPeriodMatch;
121
- iAbsoluteMinutes = (iHour * 60 + iMinute) % 1440;
122
- oDayPeriodRules = this._get('dayPeriodRules');
123
- function parseToAbsoluteMinutes(sValue) {
124
- var aSplit = sValue.split(':'), sHour = aSplit[0], sMinute = aSplit[1];
125
- return parseInt(sHour) * 60 + parseInt(sMinute);
126
- }
127
- sPeriodMatch = Object.keys(oDayPeriodRules).find(function (sDayPeriodRule) {
128
- var oDayPeriodRule = oDayPeriodRules[sDayPeriodRule];
129
- return oDayPeriodRule['_at'] && parseToAbsoluteMinutes(oDayPeriodRule['_at']) === iAbsoluteMinutes;
130
- });
131
- if (sPeriodMatch) {
132
- return sPeriodMatch;
133
- }
134
- return Object.keys(oDayPeriodRules).find(function (sDayPeriodRule) {
135
- var iEndValue, aIntervals, iStartValue, oDayPeriodRule = oDayPeriodRules[sDayPeriodRule];
136
- if (oDayPeriodRule['_at']) {
137
- return false;
138
- }
139
- iStartValue = parseToAbsoluteMinutes(oDayPeriodRule['_from']);
140
- iEndValue = parseToAbsoluteMinutes(oDayPeriodRule['_before']);
141
- if (iStartValue > iEndValue) {
142
- aIntervals = [
143
- {
144
- start: iStartValue,
145
- end: 1440
146
- },
147
- {
148
- start: 0,
149
- end: iEndValue
150
- }
151
- ];
152
- } else {
153
- aIntervals = [{
154
- start: iStartValue,
155
- end: iEndValue
156
- }];
157
- }
158
- return aIntervals.some(function (oInterval) {
159
- return oInterval.start <= iAbsoluteMinutes && oInterval.end > iAbsoluteMinutes;
160
- });
161
- });
162
- },
163
- getTimePattern: function (sStyle, sCalendarType) {
164
- assert(sStyle == 'short' || sStyle == 'medium' || sStyle == 'long' || sStyle == 'full', 'sStyle must be short, medium, long or full');
165
- return this._get(getCLDRCalendarName(sCalendarType), 'timeFormats', sStyle);
166
- },
167
- getDateTimePattern: function (sStyle, sCalendarType) {
168
- assert(sStyle == 'short' || sStyle == 'medium' || sStyle == 'long' || sStyle == 'full', 'sStyle must be short, medium, long or full');
169
- return this._get(getCLDRCalendarName(sCalendarType), 'dateTimeFormats', sStyle);
170
- },
171
- getCombinedDateTimePattern: function (sDateStyle, sTimeStyle, sCalendarType) {
172
- assert(sDateStyle == 'short' || sDateStyle == 'medium' || sDateStyle == 'long' || sDateStyle == 'full', 'sStyle must be short, medium, long or full');
173
- assert(sTimeStyle == 'short' || sTimeStyle == 'medium' || sTimeStyle == 'long' || sTimeStyle == 'full', 'sStyle must be short, medium, long or full');
174
- var sDateTimePattern = this.getDateTimePattern(sDateStyle, sCalendarType), sDatePattern = this.getDatePattern(sDateStyle, sCalendarType), sTimePattern = this.getTimePattern(sTimeStyle, sCalendarType);
175
- return sDateTimePattern.replace('{0}', sTimePattern).replace('{1}', sDatePattern);
176
- },
177
- getCombinedDateTimeWithTimezonePattern: function (sDateStyle, sTimeStyle, sCalendarType) {
178
- return this.applyTimezonePattern(this.getCombinedDateTimePattern(sDateStyle, sTimeStyle, sCalendarType));
179
- },
180
- applyTimezonePattern: function (sPattern) {
181
- var aPatterns = [sPattern];
182
- var aMissingTokens = [{
183
- group: 'Timezone',
184
- length: 2,
185
- field: 'zone',
186
- symbol: 'V'
187
- }];
188
- this._appendItems(aPatterns, aMissingTokens);
189
- return aPatterns[0];
190
- },
191
- getTimezoneTranslations: function () {
192
- this.mTimezoneTranslations = this.mTimezoneTranslations || _resolveTimezoneTranslationStructure(this._get('timezoneNames'));
193
- return Object.assign({}, this.mTimezoneTranslations);
194
- },
195
- getCustomDateTimePattern: function (sSkeleton, sCalendarType) {
196
- var oAvailableFormats = this._get(getCLDRCalendarName(sCalendarType), 'dateTimeFormats', 'availableFormats');
197
- return this._getFormatPattern(sSkeleton, oAvailableFormats, sCalendarType);
198
- },
199
- getIntervalPattern: function (sId, sCalendarType) {
200
- var oIntervalFormats = this._get(getCLDRCalendarName(sCalendarType), 'dateTimeFormats', 'intervalFormats'), aIdParts, sIntervalId, sDifference, oInterval, sPattern;
201
- if (sId) {
202
- aIdParts = sId.split('-');
203
- sIntervalId = aIdParts[0];
204
- sDifference = aIdParts[1];
205
- oInterval = oIntervalFormats[sIntervalId];
206
- if (oInterval) {
207
- sPattern = oInterval[sDifference];
208
- if (sPattern) {
209
- return sPattern;
210
- }
211
- }
212
- }
213
- return oIntervalFormats.intervalFormatFallback;
214
- },
215
- getCombinedIntervalPattern: function (sPattern, sCalendarType) {
216
- var oIntervalFormats = this._get(getCLDRCalendarName(sCalendarType), 'dateTimeFormats', 'intervalFormats'), sFallbackPattern = oIntervalFormats.intervalFormatFallback;
217
- return sFallbackPattern.replace(/\{(0|1)\}/g, sPattern);
218
- },
219
- getCustomIntervalPattern: function (sSkeleton, vGreatestDiff, sCalendarType) {
220
- var oAvailableFormats = this._get(getCLDRCalendarName(sCalendarType), 'dateTimeFormats', 'intervalFormats');
221
- return this._getFormatPattern(sSkeleton, oAvailableFormats, sCalendarType, vGreatestDiff);
222
- },
223
- _getFormatPattern: function (sSkeleton, oAvailableFormats, sCalendarType, vDiff) {
224
- var vPattern, aPatterns, oIntervalFormats;
225
- if (!vDiff) {
226
- vPattern = oAvailableFormats[sSkeleton];
227
- } else if (typeof vDiff === 'string') {
228
- if (vDiff == 'j' || vDiff == 'J') {
229
- vDiff = this.getPreferredHourSymbol();
230
- }
231
- oIntervalFormats = oAvailableFormats[sSkeleton];
232
- vPattern = oIntervalFormats && oIntervalFormats[vDiff];
233
- }
234
- if (vPattern) {
235
- if (typeof vPattern === 'object') {
236
- aPatterns = Object.keys(vPattern).map(function (sKey) {
237
- return vPattern[sKey];
238
- });
239
- } else {
240
- return vPattern;
241
- }
242
- }
243
- if (!aPatterns) {
244
- aPatterns = this._createFormatPattern(sSkeleton, oAvailableFormats, sCalendarType, vDiff);
245
- }
246
- if (aPatterns && aPatterns.length === 1) {
247
- return aPatterns[0];
248
- }
249
- return aPatterns;
250
- },
251
- _createFormatPattern: function (sSkeleton, oAvailableFormats, sCalendarType, vDiff) {
252
- var aTokens = this._parseSkeletonFormat(sSkeleton), aPatterns, oBestMatch = this._findBestMatch(aTokens, sSkeleton, oAvailableFormats), oToken, oAvailableDateTimeFormats, oSymbol, oGroup, sPattern, sSinglePattern, sDiffSymbol, sDiffGroup, rMixedSkeleton = /^([GyYqQMLwWEecdD]+)([hHkKjJmszZvVOXx]+)$/, bSingleDate, i;
253
- if (vDiff) {
254
- if (typeof vDiff === 'string') {
255
- sDiffGroup = mCLDRSymbols[vDiff] ? mCLDRSymbols[vDiff].group : '';
256
- if (sDiffGroup) {
257
- bSingleDate = mCLDRSymbolGroups[sDiffGroup].index > aTokens[aTokens.length - 1].index;
258
- }
259
- sDiffSymbol = vDiff;
260
- } else {
261
- bSingleDate = true;
262
- if (aTokens[0].symbol === 'y' && oBestMatch && oBestMatch.pattern.G) {
263
- oSymbol = mCLDRSymbols['G'];
264
- oGroup = mCLDRSymbolGroups[oSymbol.group];
265
- aTokens.splice(0, 0, {
266
- symbol: 'G',
267
- group: oSymbol.group,
268
- match: oSymbol.match,
269
- index: oGroup.index,
270
- field: oGroup.field,
271
- length: 1
272
- });
273
- }
274
- for (i = aTokens.length - 1; i >= 0; i--) {
275
- oToken = aTokens[i];
276
- if (vDiff[oToken.group]) {
277
- bSingleDate = false;
278
- break;
279
- }
280
- }
281
- for (i = 0; i < aTokens.length; i++) {
282
- oToken = aTokens[i];
283
- if (vDiff[oToken.group]) {
284
- sDiffSymbol = oToken.symbol;
285
- break;
286
- }
287
- }
288
- if ((sDiffSymbol == 'h' || sDiffSymbol == 'K') && vDiff.DayPeriod) {
289
- sDiffSymbol = 'a';
290
- }
291
- }
292
- if (bSingleDate) {
293
- return [this.getCustomDateTimePattern(sSkeleton, sCalendarType)];
294
- }
295
- if (oBestMatch && oBestMatch.missingTokens.length === 0) {
296
- sPattern = oBestMatch.pattern[sDiffSymbol];
297
- if (sPattern && oBestMatch.distance > 0) {
298
- sPattern = this._expandFields(sPattern, oBestMatch.patternTokens, aTokens);
299
- }
300
- }
301
- if (!sPattern) {
302
- oAvailableDateTimeFormats = this._get(getCLDRCalendarName(sCalendarType), 'dateTimeFormats', 'availableFormats');
303
- if (rMixedSkeleton.test(sSkeleton) && 'ahHkKjJms'.indexOf(sDiffSymbol) >= 0) {
304
- sPattern = this._getMixedFormatPattern(sSkeleton, oAvailableDateTimeFormats, sCalendarType, vDiff);
305
- } else {
306
- sSinglePattern = this._getFormatPattern(sSkeleton, oAvailableDateTimeFormats, sCalendarType);
307
- sPattern = this.getCombinedIntervalPattern(sSinglePattern, sCalendarType);
308
- }
309
- }
310
- aPatterns = [sPattern];
311
- } else if (!oBestMatch) {
312
- sPattern = sSkeleton;
313
- aPatterns = [sPattern];
314
- } else {
315
- if (typeof oBestMatch.pattern === 'string') {
316
- aPatterns = [oBestMatch.pattern];
317
- } else if (typeof oBestMatch.pattern === 'object') {
318
- aPatterns = [];
319
- for (var sKey in oBestMatch.pattern) {
320
- sPattern = oBestMatch.pattern[sKey];
321
- aPatterns.push(sPattern);
322
- }
323
- }
324
- if (oBestMatch.distance > 0) {
325
- if (oBestMatch.missingTokens.length > 0) {
326
- if (rMixedSkeleton.test(sSkeleton)) {
327
- aPatterns = [this._getMixedFormatPattern(sSkeleton, oAvailableFormats, sCalendarType)];
328
- } else {
329
- aPatterns = this._expandFields(aPatterns, oBestMatch.patternTokens, aTokens);
330
- aPatterns = this._appendItems(aPatterns, oBestMatch.missingTokens, sCalendarType);
331
- }
332
- } else {
333
- aPatterns = this._expandFields(aPatterns, oBestMatch.patternTokens, aTokens);
334
- }
335
- }
336
- }
337
- if (sSkeleton.indexOf('J') >= 0) {
338
- aPatterns.forEach(function (sPattern, iIndex) {
339
- aPatterns[iIndex] = sPattern.replace(/ ?[abB](?=([^']*'[^']*')*[^']*)$/g, '');
340
- });
341
- }
342
- return aPatterns;
343
- },
344
- _parseSkeletonFormat: function (sSkeleton) {
345
- var aTokens = [], oToken = { index: -1 }, sSymbol, oSymbol, oGroup;
346
- for (var i = 0; i < sSkeleton.length; i++) {
347
- sSymbol = sSkeleton.charAt(i);
348
- if (sSymbol == 'j' || sSymbol == 'J') {
349
- sSymbol = this.getPreferredHourSymbol();
350
- }
351
- if (sSymbol == oToken.symbol) {
352
- oToken.length++;
353
- continue;
354
- }
355
- oSymbol = mCLDRSymbols[sSymbol];
356
- oGroup = mCLDRSymbolGroups[oSymbol.group];
357
- if (oSymbol.group == 'Other' || oGroup.diffOnly) {
358
- throw new Error('Symbol \'' + sSymbol + '\' is not allowed in skeleton format \'' + sSkeleton + '\'');
359
- }
360
- if (oGroup.index <= oToken.index) {
361
- throw new Error('Symbol \'' + sSymbol + '\' at wrong position or duplicate in skeleton format \'' + sSkeleton + '\'');
362
- }
363
- oToken = {
364
- symbol: sSymbol,
365
- group: oSymbol.group,
366
- match: oSymbol.match,
367
- index: oGroup.index,
368
- field: oGroup.field,
369
- length: 1
370
- };
371
- aTokens.push(oToken);
372
- }
373
- return aTokens;
374
- },
375
- _findBestMatch: function (aTokens, sSkeleton, oAvailableFormats) {
376
- var aTestTokens, aMissingTokens, oToken, oTestToken, iTest, iDistance, bMatch, iFirstDiffPos, oTokenSymbol, oTestTokenSymbol, oBestMatch = {
377
- distance: 10000,
378
- firstDiffPos: -1
379
- };
380
- for (var sTestSkeleton in oAvailableFormats) {
381
- if (sTestSkeleton === 'intervalFormatFallback' || sTestSkeleton.indexOf('B') > -1) {
382
- continue;
383
- }
384
- aTestTokens = this._parseSkeletonFormat(sTestSkeleton);
385
- iDistance = 0;
386
- aMissingTokens = [];
387
- bMatch = true;
388
- if (aTokens.length < aTestTokens.length) {
389
- continue;
390
- }
391
- iTest = 0;
392
- iFirstDiffPos = aTokens.length;
393
- for (var i = 0; i < aTokens.length; i++) {
394
- oToken = aTokens[i];
395
- oTestToken = aTestTokens[iTest];
396
- if (iFirstDiffPos === aTokens.length) {
397
- iFirstDiffPos = i;
398
- }
399
- if (oTestToken) {
400
- oTokenSymbol = mCLDRSymbols[oToken.symbol];
401
- oTestTokenSymbol = mCLDRSymbols[oTestToken.symbol];
402
- if (oToken.symbol === oTestToken.symbol) {
403
- if (oToken.length === oTestToken.length) {
404
- if (iFirstDiffPos === i) {
405
- iFirstDiffPos = aTokens.length;
406
- }
407
- } else {
408
- if (oToken.length < oTokenSymbol.numericCeiling ? oTestToken.length < oTestTokenSymbol.numericCeiling : oTestToken.length >= oTestTokenSymbol.numericCeiling) {
409
- iDistance += Math.abs(oToken.length - oTestToken.length);
410
- } else {
411
- iDistance += 5;
412
- }
413
- }
414
- iTest++;
415
- continue;
416
- } else {
417
- if (oToken.match == oTestToken.match) {
418
- iDistance += Math.abs(oToken.length - oTestToken.length) + 10;
419
- iTest++;
420
- continue;
421
- }
422
- }
423
- }
424
- aMissingTokens.push(oToken);
425
- iDistance += 50 - i;
426
- }
427
- if (iTest < aTestTokens.length) {
428
- bMatch = false;
429
- }
430
- if (bMatch && (iDistance < oBestMatch.distance || iDistance === oBestMatch.distance && iFirstDiffPos > oBestMatch.firstDiffPos)) {
431
- oBestMatch.distance = iDistance;
432
- oBestMatch.firstDiffPos = iFirstDiffPos;
433
- oBestMatch.missingTokens = aMissingTokens;
434
- oBestMatch.pattern = oAvailableFormats[sTestSkeleton];
435
- oBestMatch.patternTokens = aTestTokens;
436
- }
437
- }
438
- if (oBestMatch.pattern) {
439
- return oBestMatch;
440
- }
441
- },
442
- _expandFields: function (vPattern, aPatternTokens, aTokens) {
443
- var bSinglePattern = typeof vPattern === 'string';
444
- var aPatterns;
445
- if (bSinglePattern) {
446
- aPatterns = [vPattern];
447
- } else {
448
- aPatterns = vPattern;
449
- }
450
- var aResult = aPatterns.map(function (sPattern) {
451
- var mGroups = {}, mPatternGroups = {}, sResultPatterm = '', bQuoted = false, i = 0, iSkeletonLength, iPatternLength, iBestLength, iNewLength, oSkeletonToken, oBestToken, oSymbol, sChar;
452
- aTokens.forEach(function (oToken) {
453
- mGroups[oToken.group] = oToken;
454
- });
455
- aPatternTokens.forEach(function (oToken) {
456
- mPatternGroups[oToken.group] = oToken;
457
- });
458
- while (i < sPattern.length) {
459
- sChar = sPattern.charAt(i);
460
- if (bQuoted) {
461
- sResultPatterm += sChar;
462
- if (sChar == '\'') {
463
- bQuoted = false;
464
- }
465
- } else {
466
- oSymbol = mCLDRSymbols[sChar];
467
- if (oSymbol && mGroups[oSymbol.group] && mPatternGroups[oSymbol.group]) {
468
- oSkeletonToken = mGroups[oSymbol.group];
469
- oBestToken = mPatternGroups[oSymbol.group];
470
- iSkeletonLength = oSkeletonToken.length;
471
- iBestLength = oBestToken.length;
472
- iPatternLength = 1;
473
- while (sPattern.charAt(i + 1) == sChar) {
474
- i++;
475
- iPatternLength++;
476
- }
477
- if (iSkeletonLength === iBestLength || (iSkeletonLength < oSymbol.numericCeiling ? iPatternLength >= oSymbol.numericCeiling : iPatternLength < oSymbol.numericCeiling)) {
478
- iNewLength = iPatternLength;
479
- } else {
480
- iNewLength = Math.max(iPatternLength, iSkeletonLength);
481
- }
482
- for (var j = 0; j < iNewLength; j++) {
483
- sResultPatterm += sChar;
484
- }
485
- } else {
486
- sResultPatterm += sChar;
487
- if (sChar == '\'') {
488
- bQuoted = true;
489
- }
490
- }
491
- }
492
- i++;
493
- }
494
- return sResultPatterm;
495
- });
496
- return bSinglePattern ? aResult[0] : aResult;
497
- },
498
- _appendItems: function (aPatterns, aMissingTokens, sCalendarType) {
499
- var oAppendItems = this._get(getCLDRCalendarName(sCalendarType), 'dateTimeFormats', 'appendItems');
500
- aPatterns.forEach(function (sPattern, iIndex) {
501
- var sDisplayName, sAppendPattern, sAppendField;
502
- aMissingTokens.forEach(function (oToken) {
503
- sAppendPattern = oAppendItems[oToken.group];
504
- sDisplayName = '\'' + this.getDisplayName(oToken.field) + '\'';
505
- sAppendField = '';
506
- for (var i = 0; i < oToken.length; i++) {
507
- sAppendField += oToken.symbol;
508
- }
509
- aPatterns[iIndex] = sAppendPattern.replace(/\{0\}/, sPattern).replace(/\{1\}/, sAppendField).replace(/\{2\}/, sDisplayName);
510
- }.bind(this));
511
- }.bind(this));
512
- return aPatterns;
513
- },
514
- _getMixedFormatPattern: function (sSkeleton, oAvailableFormats, sCalendarType, vDiff) {
515
- var rMixedSkeleton = /^([GyYqQMLwWEecdD]+)([hHkKjJmszZvVOXx]+)$/, rWideMonth = /MMMM|LLLL/, rAbbrevMonth = /MMM|LLL/, rWeekDay = /E|e|c/, oResult, sDateSkeleton, sTimeSkeleton, sStyle, sDatePattern, sTimePattern, sDateTimePattern, sResultPattern;
516
- oResult = rMixedSkeleton.exec(sSkeleton);
517
- sDateSkeleton = oResult[1];
518
- sTimeSkeleton = oResult[2];
519
- sDatePattern = this._getFormatPattern(sDateSkeleton, oAvailableFormats, sCalendarType);
520
- if (vDiff) {
521
- sTimePattern = this.getCustomIntervalPattern(sTimeSkeleton, vDiff, sCalendarType);
522
- } else {
523
- sTimePattern = this._getFormatPattern(sTimeSkeleton, oAvailableFormats, sCalendarType);
524
- }
525
- if (rWideMonth.test(sDateSkeleton)) {
526
- sStyle = rWeekDay.test(sDateSkeleton) ? 'full' : 'long';
527
- } else if (rAbbrevMonth.test(sDateSkeleton)) {
528
- sStyle = 'medium';
529
- } else {
530
- sStyle = 'short';
531
- }
532
- sDateTimePattern = this.getDateTimePattern(sStyle, sCalendarType);
533
- sResultPattern = sDateTimePattern.replace(/\{1\}/, sDatePattern).replace(/\{0\}/, sTimePattern);
534
- return sResultPattern;
535
- },
536
- getNumberSymbol: function (sType) {
537
- assert(sType == 'decimal' || sType == 'group' || sType == 'plusSign' || sType == 'minusSign' || sType == 'percentSign', 'sType must be decimal, group, plusSign, minusSign or percentSign');
538
- return this._get('symbols-latn-' + sType);
539
- },
540
- getLenientNumberSymbols: function (sType) {
541
- assert(sType == 'plusSign' || sType == 'minusSign', 'sType must be plusSign or minusSign');
542
- return this._get('lenient-scope-number')[sType];
543
- },
544
- getDecimalPattern: function () {
545
- return this._get('decimalFormat').standard;
546
- },
547
- getCurrencyPattern: function (sContext) {
548
- return this._get('currencyFormat')[sContext] || this._get('currencyFormat').standard;
549
- },
550
- getCurrencySpacing: function (sPosition) {
551
- return this._get('currencyFormat', 'currencySpacing', sPosition === 'after' ? 'afterCurrency' : 'beforeCurrency');
552
- },
553
- getPercentPattern: function () {
554
- return this._get('percentFormat').standard;
555
- },
556
- getMiscPattern: function (sName) {
557
- assert(sName == 'approximately' || sName == 'atLeast' || sName == 'atMost' || sName == 'range', 'sName must be approximately, atLeast, atMost or range');
558
- return this._get('miscPattern')[sName];
559
- },
560
- getMinimalDaysInFirstWeek: function () {
561
- return this._get('weekData-minDays');
562
- },
563
- getFirstDayOfWeek: function () {
564
- return this._get('weekData-firstDay');
565
- },
566
- getWeekendStart: function () {
567
- return this._get('weekData-weekendStart');
568
- },
569
- getWeekendEnd: function () {
570
- return this._get('weekData-weekendEnd');
571
- },
572
- getCustomCurrencyCodes: function () {
573
- var mCustomCurrencies = this._get('currency') || {}, mCustomCurrencyCodes = {};
574
- Object.keys(mCustomCurrencies).forEach(function (sCurrencyKey) {
575
- mCustomCurrencyCodes[sCurrencyKey] = sCurrencyKey;
1
+ import Core from "./Core.js"; /*!
2
+ * OpenUI5
3
+ * (c) Copyright 2009-2024 SAP SE or an SAP affiliate company.
4
+ * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
5
+ */
6
+ //Provides the locale object sap.ui.core.LocaleData
7
+ import CalendarType from "./CalendarType.js";
8
+ import Locale from "./Locale.js";
9
+ import assert from "../../base/assert.js";
10
+ import LanguageTag from "../../base/i18n/LanguageTag.js";
11
+ import Localization from "../../base/i18n/Localization.js";
12
+ import extend from "../../base/util/extend.js";
13
+ import LoaderExtensions from "../../base/util/LoaderExtensions.js";
14
+ import BaseObject from "../base/Object.js";
15
+ import Configuration from "./Configuration.js";
16
+ import CalendarWeekNumbering from "./date/CalendarWeekNumbering.js";
17
+ var rCIgnoreCase = /c/i,
18
+ rEIgnoreCase = /e/i,
19
+ /*
20
+ * With the upgrade of the CLDR to version 41 some unit keys have changed.
21
+ * For compatibility reasons this map is used for formatting units.
22
+ * It maps a legacy unit key to its renamed key.
23
+ */
24
+ mLegacyUnit2CurrentUnit = {
25
+ "acceleration-meter-per-second-squared": "acceleration-meter-per-square-second",
26
+ "concentr-milligram-per-deciliter": "concentr-milligram-ofglucose-per-deciliter",
27
+ "concentr-part-per-million": "concentr-permillion",
28
+ "consumption-liter-per-100kilometers": "consumption-liter-per-100-kilometer",
29
+ "mass-metric-ton": "mass-tonne",
30
+ "pressure-millimeter-of-mercury": "pressure-millimeter-ofhg",
31
+ "pressure-pound-per-square-inch": "pressure-pound-force-per-square-inch",
32
+ "pressure-inch-hg": "pressure-inch-ofhg",
33
+ "torque-pound-foot": "torque-pound-force-foot"
34
+ },
35
+ rNumberInScientificNotation = /^([+-]?)((\d+)(?:\.(\d+))?)[eE]([+-]?\d+)$/,
36
+ rTrailingZeroes = /0+$/;
37
+ const rFallbackPatternTextParts = /(.*)?\{[0|1]}(.*)?\{[0|1]}(.*)?/;
38
+ const aSupportedWidths = ["narrow", "abbreviated", "wide"];
39
+
40
+ /**
41
+ * Creates an instance of LocaleData for the given locale.
42
+ *
43
+ * @class Provides access to locale-specific data, such as, date formats, number formats, and currencies.
44
+ *
45
+ * @param {sap.ui.core.Locale} oLocale the locale
46
+ *
47
+ * @extends sap.ui.base.Object
48
+ * @author SAP SE
49
+ * @version 1.120.3
50
+ * @public
51
+ * @alias sap.ui.core.LocaleData
52
+ */
53
+ var LocaleData = BaseObject.extend("sap.ui.core.LocaleData", /** @lends sap.ui.core.LocaleData.prototype */{
54
+ constructor: function (oLocale) {
55
+ BaseObject.apply(this);
56
+ this.oLocale = Locale._getCoreLocale(oLocale);
57
+ var oDataLoaded = getData(this.oLocale);
58
+ this.mData = oDataLoaded.mData;
59
+ this.sCLDRLocaleId = oDataLoaded.sCLDRLocaleId;
60
+ },
61
+ /**
62
+ * @private
63
+ * @ui5-restricted UI5 Web Components
64
+ */
65
+ _get: function () {
66
+ return this._getDeep(this.mData, arguments);
67
+ },
68
+ /**
69
+ * Retrieves merged object if overlay data is available
70
+ * @private
71
+ * @return {object} merged object
72
+ */
73
+ _getMerged: function () {
74
+ return this._get.apply(this, arguments);
75
+ },
76
+ /**
77
+ * Get month names in width "narrow", "abbreviated" or "wide". Result may contain alternative month names.
78
+ *
79
+ * @param {"narrow"|"abbreviated"|"wide"} sWidth
80
+ * The required width for the month names
81
+ * @param {sap.ui.core.CalendarType} [sCalendarType]
82
+ * The type of calendar; defaults to the calendar type either set in configuration or calculated from locale
83
+ * @returns {array}
84
+ * The array of month names; if no alternative exists the entry for the month is its name as a string; if
85
+ * there are alternative month names the entry for the month is an array of strings with the alternative names
86
+ * @private
87
+ */
88
+ _getMonthsWithAlternatives: function (sWidth, sCalendarType) {
89
+ return this._get(getCLDRCalendarName(sCalendarType), "months", "format", sWidth);
90
+ },
91
+ /**
92
+ * Get standalone month names in width "narrow", "abbreviated" or "wide". Result may contain alternative month
93
+ * names.
94
+ *
95
+ * @param {"narrow"|"abbreviated"|"wide"} sWidth
96
+ * The required width for the month names
97
+ * @param {sap.ui.core.CalendarType} [sCalendarType]
98
+ * The type of calendar; defaults to the calendar type either set in configuration or calculated from locale
99
+ * @returns {array}
100
+ * The array of month names; if no alternative exists the entry for the month is its name as a string; if
101
+ * there are alternative month names the entry for the month is an array of strings with the alternative names
102
+ * @private
103
+ */
104
+ _getMonthsStandAloneWithAlternatives: function (sWidth, sCalendarType) {
105
+ return this._get(getCLDRCalendarName(sCalendarType), "months", "stand-alone", sWidth);
106
+ },
107
+ _getDeep: function (oObject, aPropertyNames) {
108
+ var oResult = oObject;
109
+ for (var i = 0; i < aPropertyNames.length; i++) {
110
+ oResult = oResult[aPropertyNames[i]];
111
+ if (oResult === undefined) {
112
+ break;
113
+ }
114
+ }
115
+ return oResult;
116
+ },
117
+ /**
118
+ * Get orientation (left-to-right or right-to-left).
119
+ *
120
+ * @returns {string} character orientation for this locale
121
+ * @public
122
+ */
123
+ getOrientation: function () {
124
+ return this._get("orientation");
125
+ },
126
+ /**
127
+ * Get a display name for the language of the Locale of this LocaleData, using
128
+ * the CLDR display names for languages.
129
+ *
130
+ * The lookup logic works as follows:
131
+ * 1. language code and region is checked (e.g. "en-GB")
132
+ * 2. If not found: language code and script is checked (e.g. "zh-Hant")
133
+ * 3. If not found language code is checked (e.g. "en")
134
+ * 4. If it is then still not found <code>undefined</code> is returned.
135
+ *
136
+ * @returns {string} language name, e.g. "English", "British English", "American English"
137
+ * or <code>undefined</code> if language cannot be found
138
+ * @private
139
+ * @ui5-restricted sap.ushell
140
+ */
141
+ getCurrentLanguageName: function () {
142
+ return this.getLanguageName(this.oLocale.toString());
143
+ },
144
+ /**
145
+ * Gets the locale-specific language name for the given language tag.
146
+ *
147
+ * The languages returned by {@link #getLanguages} from the CLDR raw data do not contain the
148
+ * language names if they can be derived from the language and the script or the territory.
149
+ * If the map of languages contains no entry for the given language tag, derive the language
150
+ * name from the used script or region.
151
+ *
152
+ * @param {string} sLanguageTag
153
+ * The language tag, for example "en", "en-US", "en_US", "zh-Hant", or "zh_Hant"
154
+ * @returns {string|undefined}
155
+ * The language name, or <code>undefined</code> if the name cannot be determined
156
+ * @throws {TypeError} When the given language tag isn't valid
157
+ *
158
+ * @public
159
+ */
160
+ getLanguageName: function (sLanguageTag) {
161
+ const oLanguageTag = new LanguageTag(sLanguageTag);
162
+ let sLanguage = Localization.getModernLanguage(oLanguageTag.language);
163
+ let sScript = oLanguageTag.script;
164
+ // special case for "sr_Latn" language: "sh" should then be used
165
+ if (sLanguage === "sr" && sScript === "Latn") {
166
+ sLanguage = "sh";
167
+ sScript = null;
168
+ }
169
+ const sRegion = oLanguageTag.region;
170
+ const oLanguages = this._get("languages");
171
+ const sLanguageText = oLanguages[sLanguage];
172
+ if (!sScript && !sRegion || !sLanguageText) {
173
+ return sLanguageText;
174
+ }
175
+ const sResult = oLanguages[sLanguage + "_" + sRegion] || oLanguages[sLanguage + "_" + sScript];
176
+ if (sResult) {
177
+ return sResult;
178
+ }
179
+ if (sScript) {
180
+ const sScriptText = this._get("scripts")[sScript];
181
+ if (sScriptText) {
182
+ return sLanguageText + " (" + sScriptText + ")";
183
+ }
184
+ }
185
+ if (sRegion) {
186
+ const sRegionText = this._get("territories")[sRegion];
187
+ if (sRegionText) {
188
+ return sLanguageText + " (" + sRegionText + ")";
189
+ }
190
+ }
191
+ return sLanguageText;
192
+ },
193
+ /**
194
+ * Gets locale-specific language names, as available in the CLDR raw data.
195
+ *
196
+ * To avoid redundancies, with CLDR version 43 only language names are contained which cannot be derived from
197
+ * the language and the script or the territory. If a language tag is not contained in the map, use
198
+ * {@link #getLanguageName} to get the derived locale-specific language name for that language tag.
199
+ *
200
+ * @returns {Object<string, string>} Maps a language tag to the locale-specific language name
201
+ *
202
+ * @public
203
+ */
204
+ getLanguages: function () {
205
+ const oLanguages = this._get("languages");
206
+ /** @deprecated As of version 1.120.0 */
207
+ ["ar_001", "de_AT", "de_CH", "en_AU", "en_CA", "en_GB", "en_US", "es_419", "es_ES", "es_MX", "fa_AF", "fr_CA", "fr_CH", "nds_NL", "nl_BE", "pt_BR", "pt_PT", "ro_MD", "sw_CD", "zh_Hans", "zh_Hant"].forEach(sLanguageTag => {
208
+ // for compatibility reasons, ensure that for these language tags the corresponding language names are
209
+ // available
210
+ if (!oLanguages[sLanguageTag]) {
211
+ oLanguages[sLanguageTag] = this.getLanguageName(sLanguageTag);
212
+ }
213
+ });
214
+ return oLanguages;
215
+ },
216
+ /**
217
+ * Gets locale-specific script names, as available in the CLDR raw data.
218
+ *
219
+ * To avoid redundancies, with CLDR version 43 only scripts are contained for which the language-specific name
220
+ * is different from the script key. If a script key is not contained in the map, use the script key as script
221
+ * name.
222
+ *
223
+ * @returns {Object<string, string>} Maps a script key to the locale-specific script name
224
+ *
225
+ * @public
226
+ */
227
+ getScripts: function () {
228
+ return this._get("scripts");
229
+ },
230
+ /**
231
+ * Gets locale-specific territory names, as available in the CLDR raw data.
232
+ *
233
+ * To avoid redundancies, with CLDR version 43 only territories are contained for which the language-specific
234
+ * name is different from the territory key.
235
+ *
236
+ * @returns {Object<string, string>} Maps a territory key to the locale-specific territory name
237
+ *
238
+ * @public
239
+ */
240
+ getTerritories: function () {
241
+ return this._get("territories");
242
+ },
243
+ /**
244
+ * Get month names in width "narrow", "abbreviated" or "wide".
245
+ *
246
+ * @param {"narrow"|"abbreviated"|"wide"} sWidth
247
+ * The required width for the month names
248
+ * @param {sap.ui.core.CalendarType} [sCalendarType]
249
+ * The type of calendar; defaults to the calendar type either set in configuration or calculated from locale
250
+ * @returns {string[]}
251
+ * The array of month names
252
+ * @public
253
+ */
254
+ getMonths: function (sWidth, sCalendarType) {
255
+ assert(aSupportedWidths.includes(sWidth), "sWidth must be narrow, abbreviated or wide");
256
+ return this._get(getCLDRCalendarName(sCalendarType), "months", "format", sWidth).map(vMonthName => {
257
+ return Array.isArray(vMonthName) ? vMonthName[0] : vMonthName;
258
+ });
259
+ },
260
+ /**
261
+ * Get standalone month names in width "narrow", "abbreviated" or "wide".
262
+ *
263
+ * @param {"narrow"|"abbreviated"|"wide"} sWidth
264
+ * The required width for the month names
265
+ * @param {sap.ui.core.CalendarType} [sCalendarType]
266
+ * The type of calendar; defaults to the calendar type either set in configuration or calculated from locale
267
+ * @returns {string[]}
268
+ * The array of standalone month names
269
+ * @public
270
+ */
271
+ getMonthsStandAlone: function (sWidth, sCalendarType) {
272
+ assert(aSupportedWidths.includes(sWidth), "sWidth must be narrow, abbreviated or wide");
273
+ return this._get(getCLDRCalendarName(sCalendarType), "months", "stand-alone", sWidth).map(vMonthName => {
274
+ return Array.isArray(vMonthName) ? vMonthName[0] : vMonthName;
275
+ });
276
+ },
277
+ /**
278
+ * Get day names in width "narrow", "abbreviated" or "wide".
279
+ *
280
+ * @param {string} sWidth the required width for the day names
281
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
282
+ * @returns {array} array of day names (starting with Sunday)
283
+ * @public
284
+ */
285
+ getDays: function (sWidth, sCalendarType) {
286
+ assert(sWidth == "narrow" || sWidth == "abbreviated" || sWidth == "wide" || sWidth == "short", "sWidth must be narrow, abbreviate, wide or short");
287
+ return this._get(getCLDRCalendarName(sCalendarType), "days", "format", sWidth);
288
+ },
289
+ /**
290
+ * Get standalone day names in width "narrow", "abbreviated" or "wide".
291
+ *
292
+ * @param {string} sWidth the required width for the day names
293
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
294
+ * @returns {array} array of day names (starting with Sunday)
295
+ * @public
296
+ */
297
+ getDaysStandAlone: function (sWidth, sCalendarType) {
298
+ assert(sWidth == "narrow" || sWidth == "abbreviated" || sWidth == "wide" || sWidth == "short", "sWidth must be narrow, abbreviated, wide or short");
299
+ return this._get(getCLDRCalendarName(sCalendarType), "days", "stand-alone", sWidth);
300
+ },
301
+ /**
302
+ * Get quarter names in width "narrow", "abbreviated" or "wide".
303
+ *
304
+ * @param {string} sWidth the required width for the quarter names
305
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
306
+ * @returns {array} array of quarters
307
+ * @public
308
+ */
309
+ getQuarters: function (sWidth, sCalendarType) {
310
+ assert(sWidth == "narrow" || sWidth == "abbreviated" || sWidth == "wide", "sWidth must be narrow, abbreviated or wide");
311
+ return this._get(getCLDRCalendarName(sCalendarType), "quarters", "format", sWidth);
312
+ },
313
+ /**
314
+ * Get standalone quarter names in width "narrow", "abbreviated" or "wide".
315
+ *
316
+ * @param {string} sWidth the required width for the quarter names
317
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
318
+ * @returns {array} array of quarters
319
+ * @public
320
+ */
321
+ getQuartersStandAlone: function (sWidth, sCalendarType) {
322
+ assert(sWidth == "narrow" || sWidth == "abbreviated" || sWidth == "wide", "sWidth must be narrow, abbreviated or wide");
323
+ return this._get(getCLDRCalendarName(sCalendarType), "quarters", "stand-alone", sWidth);
324
+ },
325
+ /**
326
+ * Get day periods in width "narrow", "abbreviated" or "wide".
327
+ *
328
+ * @param {string} sWidth the required width for the day period names
329
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
330
+ * @returns {array} array of day periods (AM, PM)
331
+ * @public
332
+ */
333
+ getDayPeriods: function (sWidth, sCalendarType) {
334
+ assert(sWidth == "narrow" || sWidth == "abbreviated" || sWidth == "wide", "sWidth must be narrow, abbreviated or wide");
335
+ return this._get(getCLDRCalendarName(sCalendarType), "dayPeriods", "format", sWidth);
336
+ },
337
+ /**
338
+ * Get standalone day periods in width "narrow", "abbreviated" or "wide".
339
+ *
340
+ * @param {string} sWidth the required width for the day period names
341
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
342
+ * @returns {array} array of day periods (AM, PM)
343
+ * @public
344
+ */
345
+ getDayPeriodsStandAlone: function (sWidth, sCalendarType) {
346
+ assert(sWidth == "narrow" || sWidth == "abbreviated" || sWidth == "wide", "sWidth must be narrow, abbreviated or wide");
347
+ return this._get(getCLDRCalendarName(sCalendarType), "dayPeriods", "stand-alone", sWidth);
348
+ },
349
+ /**
350
+ * Get date pattern in format "short", "medium", "long" or "full".
351
+ *
352
+ * @param {string} sStyle the required style for the date pattern
353
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
354
+ * @returns {string} the selected date pattern
355
+ * @public
356
+ */
357
+ getDatePattern: function (sStyle, sCalendarType) {
358
+ assert(sStyle == "short" || sStyle == "medium" || sStyle == "long" || sStyle == "full", "sStyle must be short, medium, long or full");
359
+ return this._get(getCLDRCalendarName(sCalendarType), "dateFormats", sStyle);
360
+ },
361
+ /**
362
+ * Get flexible day periods in style format "abbreviated", "narrow" or "wide".
363
+ *
364
+ * @param {string} sWidth
365
+ * The required width for the flexible day period names
366
+ * @param {sap.ui.core.CalendarType} [sCalendarType]
367
+ * The type of calendar. If it's not set, it falls back to the calendar type either set in
368
+ * configuration or calculated from locale.
369
+ * @returns {object|undefined}
370
+ * Object of flexible day periods or 'undefined' if none can be found
371
+ *
372
+ * @example <caption>Output</caption>
373
+ * {
374
+ * "midnight": "midnight",
375
+ * "noon": "noon",
376
+ * "morning1": "in the morning",
377
+ * "afternoon1": "in the afternoon",
378
+ * "evening1": "in the evening",
379
+ * "night1": "at night"
380
+ * }
381
+ *
382
+ * @private
383
+ */
384
+ getFlexibleDayPeriods: function (sWidth, sCalendarType) {
385
+ return this._get(getCLDRCalendarName(sCalendarType), "flexibleDayPeriods", "format", sWidth);
386
+ },
387
+ /**
388
+ * Get flexible day periods in style format "abbreviated", "narrow" or "wide" for case
389
+ * "stand-alone".
390
+ *
391
+ * @param {string} sWidth
392
+ * The required width for the flexible day period names
393
+ * @param {sap.ui.core.CalendarType} [sCalendarType]
394
+ * The type of calendar. If it's not set, it falls back to the calendar type either set in
395
+ * configuration or calculated from locale.
396
+ * @returns {object|undefined}
397
+ * Object of flexible day periods or 'undefined' if none can be found
398
+ *
399
+ * @example <caption>Output</caption>
400
+ * {
401
+ * "midnight": "midnight",
402
+ * "noon": "noon",
403
+ * "morning1": "in the morning",
404
+ * "afternoon1": "in the afternoon",
405
+ * "evening1": "in the evening",
406
+ * "night1": "at night"
407
+ * }
408
+ *
409
+ * @private
410
+ */
411
+ getFlexibleDayPeriodsStandAlone: function (sWidth, sCalendarType) {
412
+ return this._get(getCLDRCalendarName(sCalendarType), "flexibleDayPeriods", "stand-alone", sWidth);
413
+ },
414
+ /**
415
+ * Get flexible day period of time or a point in time
416
+ *
417
+ * @param {int} iHour Hour
418
+ * @param {int} iMinute Minute
419
+ * @returns {string} Key of flexible day period of time e.g. <code>afternoon2</code>
420
+ *
421
+ * @private
422
+ */
423
+ getFlexibleDayPeriodOfTime: function (iHour, iMinute) {
424
+ var iAbsoluteMinutes, oDayPeriodRules, sPeriodMatch;
425
+ iAbsoluteMinutes = (iHour * 60 + iMinute) % 1440;
426
+ oDayPeriodRules = this._get("dayPeriodRules");
427
+ function parseToAbsoluteMinutes(sValue) {
428
+ var aSplit = sValue.split(":"),
429
+ sHour = aSplit[0],
430
+ sMinute = aSplit[1];
431
+ return parseInt(sHour) * 60 + parseInt(sMinute);
432
+ }
433
+
434
+ // unfortunately there are some overlaps:
435
+ // e.g. en.json
436
+ // "afternoon1": {
437
+ // "_before": "18:00",
438
+ // "_from": "12:00"
439
+ // },
440
+ // "noon": {
441
+ // "_at": "12:00"
442
+ // }
443
+ // -> 12:00 can be either "noon" or "afternoon1" because "_from" is inclusive
444
+ // therefore first check all exact periods
445
+
446
+ sPeriodMatch = Object.keys(oDayPeriodRules).find(function (sDayPeriodRule) {
447
+ var oDayPeriodRule = oDayPeriodRules[sDayPeriodRule];
448
+ return oDayPeriodRule["_at"] && parseToAbsoluteMinutes(oDayPeriodRule["_at"]) === iAbsoluteMinutes;
449
+ });
450
+ if (sPeriodMatch) {
451
+ return sPeriodMatch;
452
+ }
453
+ return Object.keys(oDayPeriodRules).find(function (sDayPeriodRule) {
454
+ var iEndValue,
455
+ aIntervals,
456
+ iStartValue,
457
+ oDayPeriodRule = oDayPeriodRules[sDayPeriodRule];
458
+ if (oDayPeriodRule["_at"]) {
459
+ return false;
460
+ }
461
+ iStartValue = parseToAbsoluteMinutes(oDayPeriodRule["_from"]);
462
+ iEndValue = parseToAbsoluteMinutes(oDayPeriodRule["_before"]);
463
+
464
+ // periods which span across days need to be split into individual intervals
465
+ // e.g. "22:00 - 03:00" becomes "22:00 - 24:00" and "00:00 - 03:00"
466
+ if (iStartValue > iEndValue) {
467
+ aIntervals = [{
468
+ start: iStartValue,
469
+ end: 1440
470
+ },
471
+ // 24 * 60
472
+ {
473
+ start: 0,
474
+ end: iEndValue
475
+ }];
476
+ } else {
477
+ aIntervals = [{
478
+ start: iStartValue,
479
+ end: iEndValue
480
+ }];
481
+ }
482
+ return aIntervals.some(function (oInterval) {
483
+ return oInterval.start <= iAbsoluteMinutes && oInterval.end > iAbsoluteMinutes;
484
+ });
485
+ });
486
+ },
487
+ /**
488
+ * Get time pattern in style "short", "medium", "long" or "full".
489
+ *
490
+ * @param {string} sStyle the required style for the date pattern
491
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
492
+ * @returns {string} the selected time pattern
493
+ * @public
494
+ */
495
+ getTimePattern: function (sStyle, sCalendarType) {
496
+ assert(sStyle == "short" || sStyle == "medium" || sStyle == "long" || sStyle == "full", "sStyle must be short, medium, long or full");
497
+ return this._get(getCLDRCalendarName(sCalendarType), "timeFormats", sStyle);
498
+ },
499
+ /**
500
+ * Get datetime pattern in style "short", "medium", "long" or "full".
501
+ *
502
+ * @param {string} sStyle the required style for the datetime pattern
503
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
504
+ * @returns {string} the selected datetime pattern
505
+ * @public
506
+ */
507
+ getDateTimePattern: function (sStyle, sCalendarType) {
508
+ assert(sStyle == "short" || sStyle == "medium" || sStyle == "long" || sStyle == "full", "sStyle must be short, medium, long or full");
509
+ return this._get(getCLDRCalendarName(sCalendarType), "dateTimeFormats", sStyle);
510
+ },
511
+ /**
512
+ * Get combined datetime pattern with given date and time style.
513
+ *
514
+ * @param {string} sDateStyle the required style for the date part
515
+ * @param {string} sTimeStyle the required style for the time part
516
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
517
+ * @returns {string} the combined datetime pattern
518
+ * @public
519
+ */
520
+ getCombinedDateTimePattern: function (sDateStyle, sTimeStyle, sCalendarType) {
521
+ assert(sDateStyle == "short" || sDateStyle == "medium" || sDateStyle == "long" || sDateStyle == "full", "sStyle must be short, medium, long or full");
522
+ assert(sTimeStyle == "short" || sTimeStyle == "medium" || sTimeStyle == "long" || sTimeStyle == "full", "sStyle must be short, medium, long or full");
523
+ var sDateTimePattern = this.getDateTimePattern(sDateStyle, sCalendarType),
524
+ sDatePattern = this.getDatePattern(sDateStyle, sCalendarType),
525
+ sTimePattern = this.getTimePattern(sTimeStyle, sCalendarType);
526
+ return sDateTimePattern.replace("{0}", sTimePattern).replace("{1}", sDatePattern);
527
+ },
528
+ /**
529
+ * Get combined pattern with datetime and timezone for the given date and time style.
530
+ *
531
+ * @example
532
+ * // locale de
533
+ * oLocaleData.getCombinedDateTimeWithTimezonePattern("long", "long");
534
+ * // "d. MMMM y 'um' HH:mm:ss z VV"
535
+ *
536
+ * // locale en_GB
537
+ * oLocaleData.getCombinedDateTimeWithTimezonePattern("long", "long");
538
+ * // "d MMMM y 'at' HH:mm:ss z VV"
539
+ *
540
+ * @param {string} sDateStyle The required style for the date part
541
+ * @param {string} sTimeStyle The required style for the time part
542
+ * @param {sap.ui.core.CalendarType} [sCalendarType] The type of calendar. If it's not set,
543
+ * it falls back to the calendar type either set in the configuration or calculated from
544
+ * the locale.
545
+ * @returns {string} the combined pattern with datetime and timezone
546
+ * @private
547
+ * @ui5-restricted sap.ui.core.format.DateFormat
548
+ * @since 1.101
549
+ */
550
+ getCombinedDateTimeWithTimezonePattern: function (sDateStyle, sTimeStyle, sCalendarType) {
551
+ return this.applyTimezonePattern(this.getCombinedDateTimePattern(sDateStyle, sTimeStyle, sCalendarType));
552
+ },
553
+ /**
554
+ * Applies the timezone to the pattern
555
+ *
556
+ * @param {string} sPattern pattern, e.g. <code>y</code>
557
+ * @returns {string} applied timezone, e.g. <code>y VV</code>
558
+ * @private
559
+ * @ui5-restricted sap.ui.core.format.DateFormat
560
+ * @since 1.101
561
+ */
562
+ applyTimezonePattern: function (sPattern) {
563
+ var aPatterns = [sPattern];
564
+ var aMissingTokens = [{
565
+ group: "Timezone",
566
+ length: 2,
567
+ field: "zone",
568
+ symbol: "V"
569
+ }];
570
+ this._appendItems(aPatterns, aMissingTokens);
571
+ return aPatterns[0];
572
+ },
573
+ /**
574
+ * Retrieves all timezone translations.
575
+ *
576
+ * E.g. for locale "en"
577
+ * <pre>
578
+ * {
579
+ * "America/New_York": "Americas, New York"
580
+ * ...
581
+ * }
582
+ * </pre>
583
+ *
584
+ * @return {Object<string, string>} the mapping, with 'key' being the IANA timezone ID, and
585
+ * 'value' being the translation.
586
+ * @ui5-restricted sap.ui.core.format.DateFormat, sap.ui.export, sap.ushell
587
+ * @private
588
+ */
589
+ getTimezoneTranslations: function () {
590
+ var sLocale = this.oLocale.toString();
591
+ var mTranslations = LocaleData._mTimezoneTranslations[sLocale];
592
+ if (!mTranslations) {
593
+ LocaleData._mTimezoneTranslations[sLocale] = mTranslations = _resolveTimezoneTranslationStructure(this._get("timezoneNames"));
594
+ }
595
+
596
+ // retrieve a copy such that the original object won't be modified.
597
+ return Object.assign({}, mTranslations);
598
+ },
599
+ /**
600
+ * Get custom datetime pattern for a given skeleton format.
601
+ *
602
+ * The format string does contain pattern symbols (e.g. "yMMMd" or "Hms") and will be converted into the pattern in the used
603
+ * locale, which matches the wanted symbols best. The symbols must be in canonical order, that is:
604
+ * Era (G), Year (y/Y), Quarter (q/Q), Month (M/L), Week (w/W), Day-Of-Week (E/e/c), Day (d/D),
605
+ * Hour (h/H/k/K/), Minute (m), Second (s), Timezone (z/Z/v/V/O/X/x)
606
+ *
607
+ * See https://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems
608
+ *
609
+ * @param {string} sSkeleton the wanted skeleton format for the datetime pattern
610
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
611
+ * @returns {string} the best matching datetime pattern
612
+ * @since 1.34
613
+ * @public
614
+ */
615
+ getCustomDateTimePattern: function (sSkeleton, sCalendarType) {
616
+ var oAvailableFormats = this._get(getCLDRCalendarName(sCalendarType), "dateTimeFormats", "availableFormats");
617
+ return this._getFormatPattern(sSkeleton, oAvailableFormats, sCalendarType);
618
+ },
619
+ /**
620
+ * Returns the interval format with the given Id (see CLDR documentation for valid Ids)
621
+ * or the fallback format if no interval format with that Id is known.
622
+ *
623
+ * The empty Id ("") might be used to retrieve the interval format fallback.
624
+ *
625
+ * @param {string} sId Id of the interval format, e.g. "d-d"
626
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
627
+ * @returns {string} interval format string with placeholders {0} and {1}
628
+ * @public
629
+ * @since 1.17.0
630
+ */
631
+ getIntervalPattern: function (sId, sCalendarType) {
632
+ var oIntervalFormats = this._get(getCLDRCalendarName(sCalendarType), "dateTimeFormats", "intervalFormats"),
633
+ aIdParts,
634
+ sIntervalId,
635
+ sDifference,
636
+ oInterval,
637
+ sPattern;
638
+ if (sId) {
639
+ aIdParts = sId.split("-");
640
+ sIntervalId = aIdParts[0];
641
+ sDifference = aIdParts[1];
642
+ oInterval = oIntervalFormats[sIntervalId];
643
+ if (oInterval) {
644
+ sPattern = oInterval[sDifference];
645
+ if (sPattern) {
646
+ return sPattern;
647
+ }
648
+ }
649
+ }
650
+ return oIntervalFormats.intervalFormatFallback;
651
+ },
652
+ /**
653
+ * Get combined interval pattern using a given pattern and the fallback interval pattern.
654
+ *
655
+ * If a skeleton based pattern is not available or not wanted, this method can be used to create an interval
656
+ * pattern based on a given pattern, using the fallback interval pattern.
657
+ *
658
+ * @param {string} sPattern the single date pattern to use within the interval pattern
659
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
660
+ * @returns {string} the calculated interval pattern
661
+ * @since 1.46
662
+ * @public
663
+ */
664
+ getCombinedIntervalPattern: function (sPattern, sCalendarType) {
665
+ const oIntervalFormats = this._get(getCLDRCalendarName(sCalendarType), "dateTimeFormats", "intervalFormats");
666
+ const [/*sAll*/, sTextBefore, sTextBetween, sTextAfter] = rFallbackPatternTextParts.exec(oIntervalFormats.intervalFormatFallback);
667
+
668
+ // text part of intervalFormatFallback is not escaped
669
+ return LocaleData._escapeIfNeeded(sTextBefore) + sPattern + LocaleData._escapeIfNeeded(sTextBetween) + sPattern + LocaleData._escapeIfNeeded(sTextAfter);
670
+ },
671
+ /**
672
+ * Get interval pattern for a given skeleton format.
673
+ *
674
+ * The format string does contain pattern symbols (e.g. "yMMMd" or "Hms") and will be converted into the pattern in the used
675
+ * locale, which matches the wanted symbols best. The symbols must be in canonical order, that is:
676
+ * Era (G), Year (y/Y), Quarter (q/Q), Month (M/L), Week (w/W), Day-Of-Week (E/e/c), Day (d/D),
677
+ * Hour (h/H/k/K/), Minute (m), Second (s), Timezone (z/Z/v/V/O/X/x)
678
+ *
679
+ * See https://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems
680
+ *
681
+ * @param {string} sSkeleton the wanted skeleton format for the datetime pattern
682
+ * @param {object|string} vGreatestDiff is either a string which represents the symbol matching the greatest difference in the two dates to format or an object which contains key-value pairs.
683
+ * The value is always true. The key is one of the date field symbol groups whose value are different between the two dates. The key can only be set with 'Year', 'Quarter', 'Month', 'Week',
684
+ * 'Day', 'DayPeriod', 'Hour', 'Minute', or 'Second'.
685
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar. If it's not set, it falls back to the calendar type either set in configuration or calculated from locale.
686
+ * @returns {string|string[]} the best matching interval pattern if interval difference is given otherwise an array with all possible interval patterns which match the given skeleton format
687
+ * @since 1.46
688
+ * @public
689
+ */
690
+ getCustomIntervalPattern: function (sSkeleton, vGreatestDiff, sCalendarType) {
691
+ var oAvailableFormats = this._get(getCLDRCalendarName(sCalendarType), "dateTimeFormats", "intervalFormats");
692
+ return this._getFormatPattern(sSkeleton, oAvailableFormats, sCalendarType, vGreatestDiff);
693
+ },
694
+ /* Helper functions for skeleton pattern processing */
695
+ _getFormatPattern: function (sSkeleton, oAvailableFormats, sCalendarType, vDiff) {
696
+ var vPattern, aPatterns, oIntervalFormats;
697
+ if (!vDiff) {
698
+ // the call is from getCustomDateTimePattern
699
+ vPattern = oAvailableFormats[sSkeleton];
700
+ } else if (typeof vDiff === "string") {
701
+ // vDiff is given as a symbol
702
+ if (vDiff == "j" || vDiff == "J") {
703
+ vDiff = this.getPreferredHourSymbol();
704
+ }
705
+ oIntervalFormats = oAvailableFormats[sSkeleton];
706
+ vPattern = oIntervalFormats && oIntervalFormats[vDiff];
707
+ }
708
+ if (vPattern) {
709
+ if (typeof vPattern === "object") {
710
+ aPatterns = Object.keys(vPattern).map(function (sKey) {
711
+ return vPattern[sKey];
576
712
  });
577
- return mCustomCurrencyCodes;
578
- },
579
- getCurrencyDigits: function (sCurrency) {
580
- var mCustomCurrencies = this._get('currency');
581
- if (mCustomCurrencies) {
582
- if (mCustomCurrencies[sCurrency] && mCustomCurrencies[sCurrency].hasOwnProperty('digits')) {
583
- return mCustomCurrencies[sCurrency].digits;
584
- } else if (mCustomCurrencies['DEFAULT'] && mCustomCurrencies['DEFAULT'].hasOwnProperty('digits')) {
585
- return mCustomCurrencies['DEFAULT'].digits;
586
- }
587
- }
588
- var iDigits = this._get('currencyDigits', sCurrency);
589
- if (iDigits == null) {
590
- iDigits = this._get('currencyDigits', 'DEFAULT');
591
- if (iDigits == null) {
592
- iDigits = 2;
593
- }
594
- }
595
- return iDigits;
596
- },
597
- getCurrencySymbol: function (sCurrency) {
598
- var oCurrencySymbols = this.getCurrencySymbols();
599
- return oCurrencySymbols && oCurrencySymbols[sCurrency] || sCurrency;
600
- },
601
- getCurrencyCodeBySymbol: function (sCurrencySymbol) {
602
- var oCurrencySymbols = this._get('currencySymbols'), sCurrencyCode;
603
- for (sCurrencyCode in oCurrencySymbols) {
604
- if (oCurrencySymbols[sCurrencyCode] === sCurrencySymbol) {
605
- return sCurrencyCode;
606
- }
607
- }
608
- return sCurrencySymbol;
609
- },
610
- getCurrencySymbols: function () {
611
- var mCustomCurrencies = this._get('currency'), mCustomCurrencySymbols = {}, sIsoCode;
612
- for (var sCurrencyKey in mCustomCurrencies) {
613
- sIsoCode = mCustomCurrencies[sCurrencyKey].isoCode;
614
- if (mCustomCurrencies[sCurrencyKey].symbol) {
615
- mCustomCurrencySymbols[sCurrencyKey] = mCustomCurrencies[sCurrencyKey].symbol;
616
- } else if (sIsoCode) {
617
- mCustomCurrencySymbols[sCurrencyKey] = this._get('currencySymbols')[sIsoCode];
618
- }
619
- }
620
- return Object.assign({}, this._get('currencySymbols'), mCustomCurrencySymbols);
621
- },
622
- getUnitDisplayName: function (sUnit) {
623
- var mUnitFormat = this.getUnitFormat(sUnit);
624
- return mUnitFormat && mUnitFormat['displayName'] || '';
625
- },
626
- getRelativePatterns: function (aScales, sStyle) {
627
- if (sStyle === undefined) {
628
- sStyle = 'wide';
629
- }
630
- assert(sStyle === 'wide' || sStyle === 'short' || sStyle === 'narrow', 'sStyle is only allowed to be set with \'wide\', \'short\' or \'narrow\'');
631
- var aPatterns = [], aPluralCategories = this.getPluralCategories(), oScale, oTimeEntry, iValue, iSign;
632
- if (!aScales) {
633
- aScales = [
634
- 'year',
635
- 'month',
636
- 'week',
637
- 'day',
638
- 'hour',
639
- 'minute',
640
- 'second'
641
- ];
642
- }
643
- aScales.forEach(function (sScale) {
644
- oScale = this._get('dateFields', sScale + '-' + sStyle);
645
- for (var sEntry in oScale) {
646
- if (sEntry.indexOf('relative-type-') === 0) {
647
- iValue = parseInt(sEntry.substr(14));
648
- aPatterns.push({
649
- scale: sScale,
650
- value: iValue,
651
- pattern: oScale[sEntry]
652
- });
653
- } else if (sEntry.indexOf('relativeTime-type-') == 0) {
654
- oTimeEntry = oScale[sEntry];
655
- iSign = sEntry.substr(18) === 'past' ? -1 : 1;
656
- aPluralCategories.forEach(function (sKey) {
657
- var sPattern = oTimeEntry['relativeTimePattern-count-' + sKey];
658
- if (sPattern) {
659
- aPatterns.push({
660
- scale: sScale,
661
- sign: iSign,
662
- pattern: sPattern
663
- });
664
- }
665
- });
666
- }
667
- }
668
- }.bind(this));
669
- return aPatterns;
670
- },
671
- getRelativePattern: function (sScale, iDiff, bFuture, sStyle) {
672
- var sPattern, oTypes, sKey, sPluralCategory;
673
- if (typeof bFuture === 'string') {
674
- sStyle = bFuture;
675
- bFuture = undefined;
676
- }
677
- if (bFuture === undefined) {
678
- bFuture = iDiff > 0;
679
- }
680
- if (sStyle === undefined) {
681
- sStyle = 'wide';
682
- }
683
- assert(sStyle === 'wide' || sStyle === 'short' || sStyle === 'narrow', 'sStyle is only allowed to be set with \'wide\', \'short\' or \'narrow\'');
684
- sKey = sScale + '-' + sStyle;
685
- if (iDiff === 0 || iDiff === -2 || iDiff === 2) {
686
- sPattern = this._get('dateFields', sKey, 'relative-type-' + iDiff);
687
- }
688
- if (!sPattern) {
689
- oTypes = this._get('dateFields', sKey, 'relativeTime-type-' + (bFuture ? 'future' : 'past'));
690
- sPluralCategory = this.getPluralCategory(Math.abs(iDiff).toString());
691
- sPattern = oTypes['relativeTimePattern-count-' + sPluralCategory];
692
- }
693
- return sPattern;
694
- },
695
- getRelativeSecond: function (iDiff, sStyle) {
696
- return this.getRelativePattern('second', iDiff, sStyle);
697
- },
698
- getRelativeMinute: function (iDiff, sStyle) {
699
- if (iDiff == 0) {
700
- return null;
701
- }
702
- return this.getRelativePattern('minute', iDiff, sStyle);
703
- },
704
- getRelativeHour: function (iDiff, sStyle) {
705
- if (iDiff == 0) {
706
- return null;
707
- }
708
- return this.getRelativePattern('hour', iDiff, sStyle);
709
- },
710
- getRelativeDay: function (iDiff, sStyle) {
711
- return this.getRelativePattern('day', iDiff, sStyle);
712
- },
713
- getRelativeWeek: function (iDiff, sStyle) {
714
- return this.getRelativePattern('week', iDiff, sStyle);
715
- },
716
- getRelativeMonth: function (iDiff, sStyle) {
717
- return this.getRelativePattern('month', iDiff, sStyle);
718
- },
719
- getDisplayName: function (sType, sStyle) {
720
- assert(sType == 'second' || sType == 'minute' || sType == 'hour' || sType == 'zone' || sType == 'day' || sType == 'weekday' || sType == 'week' || sType == 'month' || sType == 'quarter' || sType == 'year' || sType == 'era', 'sType must be second, minute, hour, zone, day, weekday, week, month, quarter, year, era');
721
- if (sStyle === undefined) {
722
- sStyle = 'wide';
723
- }
724
- assert(sStyle === 'wide' || sStyle === 'short' || sStyle === 'narrow', 'sStyle is only allowed to be set with \'wide\', \'short\' or \'narrow\'');
725
- var aSingleFormFields = [
726
- 'era',
727
- 'weekday',
728
- 'zone'
729
- ], sKey = aSingleFormFields.indexOf(sType) === -1 ? sType + '-' + sStyle : sType;
730
- return this._get('dateFields', sKey, 'displayName');
731
- },
732
- getRelativeYear: function (iDiff, sStyle) {
733
- return this.getRelativePattern('year', iDiff, sStyle);
734
- },
735
- getDecimalFormat: function (sStyle, sNumber, sPlural) {
736
- var sFormat;
737
- var oFormats;
738
- switch (sStyle) {
739
- case 'long':
740
- oFormats = this._get('decimalFormat-long');
713
+ } else {
714
+ return vPattern;
715
+ }
716
+ }
717
+ if (!aPatterns) {
718
+ aPatterns = this._createFormatPattern(sSkeleton, oAvailableFormats, sCalendarType, vDiff);
719
+ }
720
+ if (aPatterns && aPatterns.length === 1) {
721
+ return aPatterns[0];
722
+ }
723
+ return aPatterns;
724
+ },
725
+ _createFormatPattern: function (sSkeleton, oAvailableFormats, sCalendarType, vDiff) {
726
+ var aTokens = this._parseSkeletonFormat(sSkeleton),
727
+ aPatterns,
728
+ oBestMatch = this._findBestMatch(aTokens, sSkeleton, oAvailableFormats),
729
+ oToken,
730
+ oAvailableDateTimeFormats,
731
+ oSymbol,
732
+ oGroup,
733
+ sPattern,
734
+ sSinglePattern,
735
+ sDiffSymbol,
736
+ sDiffGroup,
737
+ rMixedSkeleton = /^([GyYqQMLwWEecdD]+)([hHkKjJmszZvVOXx]+)$/,
738
+ bSingleDate,
739
+ i;
740
+ if (vDiff) {
741
+ if (typeof vDiff === "string") {
742
+ sDiffGroup = mCLDRSymbols[vDiff] ? mCLDRSymbols[vDiff].group : "";
743
+ if (sDiffGroup) {
744
+ // if the index of interval diff is greater than the index of the last field
745
+ // in the sSkeleton, which means the diff unit is smaller than all units in
746
+ // the skeleton, return a single date pattern which is generated using the
747
+ // given skeleton
748
+ bSingleDate = mCLDRSymbolGroups[sDiffGroup].index > aTokens[aTokens.length - 1].index;
749
+ }
750
+ sDiffSymbol = vDiff;
751
+ } else {
752
+ bSingleDate = true;
753
+ // Special handling of "y" (Year) in case patterns contains also "G" (Era)
754
+ if (aTokens[0].symbol === "y" && oBestMatch && oBestMatch.pattern.G) {
755
+ oSymbol = mCLDRSymbols["G"];
756
+ oGroup = mCLDRSymbolGroups[oSymbol.group];
757
+ aTokens.splice(0, 0, {
758
+ symbol: "G",
759
+ group: oSymbol.group,
760
+ match: oSymbol.match,
761
+ index: oGroup.index,
762
+ field: oGroup.field,
763
+ length: 1
764
+ });
765
+ }
766
+
767
+ // Check if at least one token's group appears in the interval diff
768
+ // If not, a single date pattern is returned
769
+ for (i = aTokens.length - 1; i >= 0; i--) {
770
+ oToken = aTokens[i];
771
+ if (vDiff[oToken.group]) {
772
+ bSingleDate = false;
741
773
  break;
742
- default:
743
- oFormats = this._get('decimalFormat-short');
774
+ }
775
+ }
776
+
777
+ // select the greatest diff symbol
778
+ for (i = 0; i < aTokens.length; i++) {
779
+ oToken = aTokens[i];
780
+ if (vDiff[oToken.group]) {
781
+ sDiffSymbol = oToken.symbol;
744
782
  break;
783
+ }
784
+ }
785
+ // Special handling of "a" (Dayperiod)
786
+ // Find out whether dayperiod is different between the dates
787
+ // If yes, set the diff symbol with 'a' Dayperiod symbol
788
+ if ((sDiffSymbol == "h" || sDiffSymbol == "K") && vDiff.DayPeriod) {
789
+ sDiffSymbol = "a";
790
+ }
791
+ }
792
+ if (bSingleDate) {
793
+ return [this.getCustomDateTimePattern(sSkeleton, sCalendarType)];
794
+ }
795
+
796
+ // Only use best match, if there are no missing tokens, as there is no possibility
797
+ // to append items on interval formats
798
+ if (oBestMatch && oBestMatch.missingTokens.length === 0) {
799
+ sPattern = oBestMatch.pattern[sDiffSymbol];
800
+ // if there is no exact match, we need to do further processing
801
+ if (sPattern && oBestMatch.distance > 0) {
802
+ sPattern = this._expandFields(sPattern, oBestMatch.patternTokens, aTokens);
803
+ }
804
+ }
805
+ // If no pattern could be found, get the best availableFormat for the skeleton
806
+ // and use the fallbackIntervalFormat to create the pattern
807
+ if (!sPattern) {
808
+ oAvailableDateTimeFormats = this._get(getCLDRCalendarName(sCalendarType), "dateTimeFormats", "availableFormats");
809
+ // If it is a mixed skeleton and the greatest interval on time, create a mixed pattern
810
+ if (rMixedSkeleton.test(sSkeleton) && "ahHkKjJms".indexOf(sDiffSymbol) >= 0) {
811
+ sPattern = this._getMixedFormatPattern(sSkeleton, oAvailableDateTimeFormats, sCalendarType, vDiff);
812
+ } else {
813
+ sSinglePattern = this._getFormatPattern(sSkeleton, oAvailableDateTimeFormats, sCalendarType);
814
+ sPattern = this.getCombinedIntervalPattern(sSinglePattern, sCalendarType);
815
+ }
816
+ }
817
+ aPatterns = [sPattern];
818
+ } else if (!oBestMatch) {
819
+ sPattern = sSkeleton;
820
+ aPatterns = [sPattern];
821
+ } else {
822
+ if (typeof oBestMatch.pattern === "string") {
823
+ aPatterns = [oBestMatch.pattern];
824
+ } else if (typeof oBestMatch.pattern === "object") {
825
+ aPatterns = [];
826
+ for (var sKey in oBestMatch.pattern) {
827
+ sPattern = oBestMatch.pattern[sKey];
828
+ aPatterns.push(sPattern);
829
+ }
830
+ }
831
+ // if there is no exact match, we need to do further processing
832
+ if (oBestMatch.distance > 0) {
833
+ if (oBestMatch.missingTokens.length > 0) {
834
+ // if tokens are missing create a pattern containing all, otherwise just adjust pattern
835
+ if (rMixedSkeleton.test(sSkeleton)) {
836
+ aPatterns = [this._getMixedFormatPattern(sSkeleton, oAvailableFormats, sCalendarType)];
837
+ } else {
838
+ aPatterns = this._expandFields(aPatterns, oBestMatch.patternTokens, aTokens);
839
+ aPatterns = this._appendItems(aPatterns, oBestMatch.missingTokens, sCalendarType);
840
+ }
841
+ } else {
842
+ aPatterns = this._expandFields(aPatterns, oBestMatch.patternTokens, aTokens);
745
843
  }
746
- if (oFormats) {
747
- var sName = sNumber + '-' + sPlural;
748
- sFormat = oFormats[sName];
749
- if (!sFormat) {
750
- sName = sNumber + '-other';
751
- sFormat = oFormats[sName];
752
- }
753
- }
754
- return sFormat;
755
- },
756
- getCurrencyFormat: function (sStyle, sNumber, sPlural) {
757
- var sFormat;
758
- var oFormats = this._get('currencyFormat-' + sStyle);
759
- if (!oFormats) {
760
- if (sStyle === 'sap-short') {
761
- throw new Error('Failed to get CLDR data for property "currencyFormat-sap-short"');
762
- }
763
- oFormats = this._get('currencyFormat-short');
764
- }
765
- if (oFormats) {
766
- var sName = sNumber + '-' + sPlural;
767
- sFormat = oFormats[sName];
768
- if (!sFormat) {
769
- sName = sNumber + '-other';
770
- sFormat = oFormats[sName];
771
- }
772
- }
773
- return sFormat;
774
- },
775
- getListFormat: function (sType, sStyle) {
776
- var oFormats = this._get('listPattern-' + (sType || 'standard') + '-' + (sStyle || 'wide'));
777
- if (oFormats) {
778
- return oFormats;
779
- }
780
- return {};
781
- },
782
- getResolvedUnitFormat: function (sUnit) {
783
- sUnit = this.getUnitFromMapping(sUnit) || sUnit;
784
- return this.getUnitFormat(sUnit);
785
- },
786
- getUnitFormat: function (sUnit) {
787
- var oResult = this._get('units', 'short', sUnit);
788
- if (!oResult && mLegacyUnit2CurrentUnit[sUnit]) {
789
- oResult = this._get('units', 'short', mLegacyUnit2CurrentUnit[sUnit]);
790
- }
791
- return oResult;
792
- },
793
- getUnitFormats: function () {
794
- return this._getMerged('units', 'short');
795
- },
796
- getUnitFromMapping: function (sMapping) {
797
- return this._get('unitMappings', sMapping);
798
- },
799
- getEras: function (sWidth, sCalendarType) {
800
- assert(sWidth == 'wide' || sWidth == 'abbreviated' || sWidth == 'narrow', 'sWidth must be wide, abbreviate or narrow');
801
- var oEras = this._get(getCLDRCalendarName(sCalendarType), 'era-' + sWidth), aEras = [];
802
- for (var i in oEras) {
803
- aEras[parseInt(i)] = oEras[i];
804
- }
805
- return aEras;
806
- },
807
- getEraDates: function (sCalendarType) {
808
- var oEraDates = this._get('eras-' + sCalendarType.toLowerCase()), aEraDates = [];
809
- for (var i in oEraDates) {
810
- aEraDates[parseInt(i)] = oEraDates[i];
811
- }
812
- return aEraDates;
813
- },
814
- getCalendarWeek: function (sStyle, iWeekNumber) {
815
- assert(sStyle == 'wide' || sStyle == 'narrow', 'sStyle must be wide or narrow');
816
- var oMessageBundle = Core.getLibraryResourceBundle('sap.ui.core', this.oLocale.toString()), sKey = 'date.week.calendarweek.' + sStyle;
817
- return oMessageBundle.getText(sKey, iWeekNumber);
818
- },
819
- firstDayStartsFirstWeek: function () {
820
- return this.oLocale.getLanguage() === 'en' && this.oLocale.getRegion() === 'US';
821
- },
822
- getPreferredCalendarType: function () {
823
- var sCalendarName, sType, i, aCalendars = this._get('calendarPreference') || [];
824
- for (i = 0; i < aCalendars.length; i++) {
825
- sCalendarName = aCalendars[i].split('-')[0];
826
- for (sType in CalendarType) {
827
- if (sCalendarName === sType.toLowerCase()) {
828
- return sType;
829
- }
830
- }
831
- }
832
- return CalendarType.Gregorian;
833
- },
834
- getPreferredHourSymbol: function () {
835
- return this._get('timeData', '_preferred');
836
- },
837
- getPluralCategories: function () {
838
- var oPlurals = this._get('plurals'), aCategories = Object.keys(oPlurals);
839
- aCategories.push('other');
840
- return aCategories;
841
- },
842
- getPluralCategory: function (vNumber) {
843
- var sNumber = typeof vNumber === 'number' ? vNumber.toString() : vNumber, oPlurals = this._get('plurals');
844
- if (!this._pluralTest) {
845
- this._pluralTest = {};
846
- }
847
- for (var sCategory in oPlurals) {
848
- var fnTest = this._pluralTest[sCategory];
849
- if (!fnTest) {
850
- fnTest = this._parsePluralRule(oPlurals[sCategory]);
851
- this._pluralTest[sCategory] = fnTest;
852
- }
853
- if (fnTest(sNumber).bMatch) {
854
- return sCategory;
855
- }
856
- }
857
- return 'other';
858
- },
859
- _parsePluralRule: function (sRule) {
860
- var OP_OR = 'or', OP_AND = 'and', OP_MOD = '%', OP_EQ = '=', OP_NEQ = '!=', OPD_N = 'n', OPD_I = 'i', OPD_F = 'f', OPD_T = 't', OPD_V = 'v', OPD_W = 'w', OPD_C = 'c', OPD_E = 'e', RANGE = '..', SEP = ',';
861
- var i = 0, aTokens;
862
- aTokens = sRule.split(' ');
863
- function accept(sToken) {
864
- if (aTokens[i] === sToken) {
865
- i++;
866
- return true;
867
- }
868
- return false;
869
- }
870
- function consume() {
871
- var sToken = aTokens[i];
872
- i++;
873
- return sToken;
874
- }
875
- function or_condition() {
876
- var fnAnd, fnOr;
877
- fnAnd = and_condition();
878
- if (accept(OP_OR)) {
879
- fnOr = or_condition();
880
- return function (o) {
881
- return fnAnd(o) || fnOr(o);
882
- };
844
+ }
845
+ }
846
+
847
+ // If special input token "J" was used, remove dayperiod from pattern
848
+ if (sSkeleton.indexOf("J") >= 0) {
849
+ aPatterns.forEach(function (sPattern, iIndex) {
850
+ aPatterns[iIndex] = sPattern.replace(/ ?[abB](?=([^']*'[^']*')*[^']*)$/g, "");
851
+ });
852
+ }
853
+ return aPatterns;
854
+ },
855
+ _parseSkeletonFormat: function (sSkeleton) {
856
+ var aTokens = [],
857
+ oToken = {
858
+ index: -1
859
+ },
860
+ sSymbol,
861
+ oSymbol,
862
+ oGroup;
863
+ for (var i = 0; i < sSkeleton.length; i++) {
864
+ sSymbol = sSkeleton.charAt(i);
865
+ // Handle special input symbols
866
+ if (sSymbol == "j" || sSymbol == "J") {
867
+ sSymbol = this.getPreferredHourSymbol();
868
+ }
869
+ // if the symbol is the same as current token, increase the length
870
+ if (sSymbol == oToken.symbol) {
871
+ oToken.length++;
872
+ continue;
873
+ }
874
+ // get symbol group
875
+ oSymbol = mCLDRSymbols[sSymbol];
876
+ oGroup = mCLDRSymbolGroups[oSymbol.group];
877
+ // if group is other, the symbol is not allowed in skeleton tokens
878
+ if (oSymbol.group == "Other" || oGroup.diffOnly) {
879
+ throw new Error("Symbol '" + sSymbol + "' is not allowed in skeleton format '" + sSkeleton + "'");
880
+ }
881
+ // if group index the same or lower, format is invalid
882
+ if (oGroup.index <= oToken.index) {
883
+ throw new Error("Symbol '" + sSymbol + "' at wrong position or duplicate in skeleton format '" + sSkeleton + "'");
884
+ }
885
+ // create token and add it the token array
886
+ oToken = {
887
+ symbol: sSymbol,
888
+ group: oSymbol.group,
889
+ match: oSymbol.match,
890
+ index: oGroup.index,
891
+ field: oGroup.field,
892
+ length: 1
893
+ };
894
+ aTokens.push(oToken);
895
+ }
896
+ return aTokens;
897
+ },
898
+ _findBestMatch: function (aTokens, sSkeleton, oAvailableFormats) {
899
+ var aTestTokens,
900
+ aMissingTokens,
901
+ oToken,
902
+ oTestToken,
903
+ iTest,
904
+ iDistance,
905
+ bMatch,
906
+ iFirstDiffPos,
907
+ oTokenSymbol,
908
+ oTestTokenSymbol,
909
+ oBestMatch = {
910
+ distance: 10000,
911
+ firstDiffPos: -1
912
+ };
913
+ // Loop through all available tokens, find matches and calculate distance
914
+ for (var sTestSkeleton in oAvailableFormats) {
915
+ // Skip patterns with symbol "B" (which is introduced from CLDR v32.0.0) which isn't supported in DateFormat yet
916
+ if (sTestSkeleton === "intervalFormatFallback" || sTestSkeleton.indexOf("B") > -1) {
917
+ continue;
918
+ }
919
+ aTestTokens = this._parseSkeletonFormat(sTestSkeleton);
920
+ iDistance = 0;
921
+ aMissingTokens = [];
922
+ bMatch = true;
923
+ // if test format contains more tokens, it cannot be a best match
924
+ if (aTokens.length < aTestTokens.length) {
925
+ continue;
926
+ }
927
+ iTest = 0;
928
+ iFirstDiffPos = aTokens.length;
929
+ for (var i = 0; i < aTokens.length; i++) {
930
+ oToken = aTokens[i];
931
+ oTestToken = aTestTokens[iTest];
932
+ if (iFirstDiffPos === aTokens.length) {
933
+ iFirstDiffPos = i;
934
+ }
935
+ if (oTestToken) {
936
+ oTokenSymbol = mCLDRSymbols[oToken.symbol];
937
+ oTestTokenSymbol = mCLDRSymbols[oTestToken.symbol];
938
+ // if the symbol matches, just add the length difference to the distance
939
+ if (oToken.symbol === oTestToken.symbol) {
940
+ if (oToken.length === oTestToken.length) {
941
+ // both symbol and length match, check the next token
942
+ // clear the first difference position
943
+ if (iFirstDiffPos === i) {
944
+ iFirstDiffPos = aTokens.length;
945
+ }
946
+ } else {
947
+ if (oToken.length < oTokenSymbol.numericCeiling ? oTestToken.length < oTestTokenSymbol.numericCeiling : oTestToken.length >= oTestTokenSymbol.numericCeiling) {
948
+ // if the symbols are in the same category (either numeric or text representation), add the length diff
949
+ iDistance += Math.abs(oToken.length - oTestToken.length);
950
+ } else {
951
+ // otherwise add 5 which is bigger than any length difference
952
+ iDistance += 5;
953
+ }
883
954
  }
884
- return fnAnd;
885
- }
886
- function and_condition() {
887
- var fnRelation, fnAnd;
888
- fnRelation = relation();
889
- if (accept(OP_AND)) {
890
- fnAnd = and_condition();
891
- return function (o) {
892
- return fnRelation(o) && fnAnd(o);
893
- };
955
+ iTest++;
956
+ continue;
957
+ } else {
958
+ // if only the group matches, add some more distance in addition to length difference
959
+ if (oToken.match == oTestToken.match) {
960
+ iDistance += Math.abs(oToken.length - oTestToken.length) + 10;
961
+ iTest++;
962
+ continue;
894
963
  }
895
- return fnRelation;
896
- }
897
- function relation() {
898
- var fnExpr, fnRangeList, bEq;
899
- fnExpr = expr();
900
- if (accept(OP_EQ)) {
901
- bEq = true;
902
- } else if (accept(OP_NEQ)) {
903
- bEq = false;
904
- } else {
905
- throw new Error('Expected \'=\' or \'!=\'');
964
+ }
965
+ }
966
+ // if neither symbol nor group matched, add it to the missing tokens and add distance
967
+ aMissingTokens.push(oToken);
968
+ iDistance += 50 - i;
969
+ }
970
+
971
+ // if not all test tokens have been found, the format does not match
972
+ if (iTest < aTestTokens.length) {
973
+ bMatch = false;
974
+ }
975
+
976
+ // The current pattern is saved as the best pattern when there is a match and
977
+ // 1. the distance is smaller than the best distance or
978
+ // 2. the distance equals the best distance and the position of the token in the given skeleton which
979
+ // isn't the same between the given skeleton and the available skeleton is bigger than the best one's.
980
+ if (bMatch && (iDistance < oBestMatch.distance || iDistance === oBestMatch.distance && iFirstDiffPos > oBestMatch.firstDiffPos)) {
981
+ oBestMatch.distance = iDistance;
982
+ oBestMatch.firstDiffPos = iFirstDiffPos;
983
+ oBestMatch.missingTokens = aMissingTokens;
984
+ oBestMatch.pattern = oAvailableFormats[sTestSkeleton];
985
+ oBestMatch.patternTokens = aTestTokens;
986
+ }
987
+ }
988
+ if (oBestMatch.pattern) {
989
+ return oBestMatch;
990
+ }
991
+ },
992
+ _expandFields: function (vPattern, aPatternTokens, aTokens) {
993
+ var bSinglePattern = typeof vPattern === "string";
994
+ var aPatterns;
995
+ if (bSinglePattern) {
996
+ aPatterns = [vPattern];
997
+ } else {
998
+ aPatterns = vPattern;
999
+ }
1000
+ var aResult = aPatterns.map(function (sPattern) {
1001
+ var mGroups = {},
1002
+ mPatternGroups = {},
1003
+ sResultPatterm = "",
1004
+ bQuoted = false,
1005
+ i = 0,
1006
+ iSkeletonLength,
1007
+ iPatternLength,
1008
+ iBestLength,
1009
+ iNewLength,
1010
+ oSkeletonToken,
1011
+ oBestToken,
1012
+ oSymbol,
1013
+ sChar;
1014
+
1015
+ // Create a map of group names to token
1016
+ aTokens.forEach(function (oToken) {
1017
+ mGroups[oToken.group] = oToken;
1018
+ });
1019
+ // Create a map of group names to token in best pattern
1020
+ aPatternTokens.forEach(function (oToken) {
1021
+ mPatternGroups[oToken.group] = oToken;
1022
+ });
1023
+ // Loop through pattern and adjust symbol length
1024
+ while (i < sPattern.length) {
1025
+ sChar = sPattern.charAt(i);
1026
+ if (bQuoted) {
1027
+ sResultPatterm += sChar;
1028
+ if (sChar == "'") {
1029
+ bQuoted = false;
1030
+ }
1031
+ } else {
1032
+ oSymbol = mCLDRSymbols[sChar];
1033
+ // If symbol is a CLDR symbol and is contained in the group, expand length
1034
+ if (oSymbol && mGroups[oSymbol.group] && mPatternGroups[oSymbol.group]) {
1035
+ oSkeletonToken = mGroups[oSymbol.group];
1036
+ oBestToken = mPatternGroups[oSymbol.group];
1037
+ iSkeletonLength = oSkeletonToken.length;
1038
+ iBestLength = oBestToken.length;
1039
+ iPatternLength = 1;
1040
+ while (sPattern.charAt(i + 1) == sChar) {
1041
+ i++;
1042
+ iPatternLength++;
906
1043
  }
907
- fnRangeList = range_list();
908
- if (bEq) {
909
- return function (o) {
910
- return fnRangeList(o).indexOf(fnExpr(o)) >= 0;
911
- };
1044
+
1045
+ // Prevent expanding the length of the field when:
1046
+ // 1. The length in the best matching skeleton (iBestLength) matches the length of the application provided skeleton (iSkeletonLength) or
1047
+ // 2. The length of the provided skeleton (iSkeletonLength) and the length of the result pattern (iPatternLength) are not in the same category (numeric or text)
1048
+ // because switching between numeric to text representation is wrong in all cases
1049
+ if (iSkeletonLength === iBestLength || (iSkeletonLength < oSymbol.numericCeiling ? iPatternLength >= oSymbol.numericCeiling : iPatternLength < oSymbol.numericCeiling)) {
1050
+ iNewLength = iPatternLength;
912
1051
  } else {
913
- return function (o) {
914
- return fnRangeList(o).indexOf(fnExpr(o)) === -1;
915
- };
1052
+ iNewLength = Math.max(iPatternLength, iSkeletonLength);
916
1053
  }
917
- }
918
- function expr() {
919
- var fnOperand;
920
- fnOperand = operand();
921
- if (accept(OP_MOD)) {
922
- var iDivisor = parseInt(consume());
923
- return function (o) {
924
- return fnOperand(o) % iDivisor;
925
- };
1054
+ for (var j = 0; j < iNewLength; j++) {
1055
+ sResultPatterm += sChar;
926
1056
  }
927
- return fnOperand;
928
- }
929
- function operand() {
930
- if (accept(OPD_N)) {
931
- return function (o) {
932
- return o.n;
933
- };
934
- } else if (accept(OPD_I)) {
935
- return function (o) {
936
- return o.i;
937
- };
938
- } else if (accept(OPD_F)) {
939
- return function (o) {
940
- return o.f;
941
- };
942
- } else if (accept(OPD_T)) {
943
- return function (o) {
944
- return o.t;
945
- };
946
- } else if (accept(OPD_V)) {
947
- return function (o) {
948
- return o.v;
949
- };
950
- } else if (accept(OPD_W)) {
951
- return function (o) {
952
- return o.w;
953
- };
954
- } else if (accept(OPD_C)) {
955
- return function (o) {
956
- return o.c;
957
- };
958
- } else if (accept(OPD_E)) {
959
- return function (o) {
960
- return o.c;
961
- };
962
- } else {
963
- throw new Error('Unknown operand: ' + consume());
1057
+ } else {
1058
+ sResultPatterm += sChar;
1059
+ if (sChar == "'") {
1060
+ bQuoted = true;
964
1061
  }
1062
+ }
965
1063
  }
966
- function range_list() {
967
- var aValues = [], sRangeList = consume(), aParts = sRangeList.split(SEP), aRange, iFrom, iTo;
968
- aParts.forEach(function (sPart) {
969
- aRange = sPart.split(RANGE);
970
- if (aRange.length === 1) {
971
- aValues.push(parseInt(sPart));
972
- } else {
973
- iFrom = parseInt(aRange[0]);
974
- iTo = parseInt(aRange[1]);
975
- for (var i = iFrom; i <= iTo; i++) {
976
- aValues.push(i);
977
- }
978
- }
979
- });
980
- return function (o) {
981
- return aValues;
982
- };
983
- }
984
- var fnOr = or_condition();
985
- if (i != aTokens.length) {
986
- throw new Error('Not completely parsed');
987
- }
988
- return function (sValue) {
989
- var iDotPos, iExponent, iExponentPos, sFraction, sFractionNoZeros, sInteger, o;
990
- sValue = sValue.replace(rCIgnoreCase, 'e');
991
- iExponentPos = sValue.search(rEIgnoreCase);
992
- iExponent = iExponentPos < 0 ? 0 : parseInt(sValue.slice(iExponentPos + 1));
993
- sValue = LocaleData.convertToDecimal(sValue);
994
- iDotPos = sValue.indexOf('.');
995
- if (iDotPos === -1) {
996
- sInteger = sValue;
997
- sFraction = '';
998
- sFractionNoZeros = '';
999
- } else {
1000
- sInteger = sValue.slice(0, iDotPos);
1001
- sFraction = sValue.slice(iDotPos + 1);
1002
- sFractionNoZeros = sFraction.replace(rTrailingZeroes, '');
1064
+ i++;
1065
+ }
1066
+ return sResultPatterm;
1067
+ });
1068
+ return bSinglePattern ? aResult[0] : aResult;
1069
+ },
1070
+ _appendItems: function (aPatterns, aMissingTokens, sCalendarType) {
1071
+ var oAppendItems = this._get(getCLDRCalendarName(sCalendarType), "dateTimeFormats", "appendItems");
1072
+ aPatterns.forEach(function (sPattern, iIndex) {
1073
+ var sDisplayName, sAppendPattern, sAppendField;
1074
+ aMissingTokens.forEach(function (oToken) {
1075
+ sAppendPattern = oAppendItems[oToken.group];
1076
+ sDisplayName = "'" + this.getDisplayName(oToken.field) + "'";
1077
+ sAppendField = "";
1078
+ for (var i = 0; i < oToken.length; i++) {
1079
+ sAppendField += oToken.symbol;
1080
+ }
1081
+ aPatterns[iIndex] = sAppendPattern.replace(/\{0\}/, sPattern).replace(/\{1\}/, sAppendField).replace(/\{2\}/, sDisplayName);
1082
+ }.bind(this));
1083
+ }.bind(this));
1084
+ return aPatterns;
1085
+ },
1086
+ _getMixedFormatPattern: function (sSkeleton, oAvailableFormats, sCalendarType, vDiff) {
1087
+ var rMixedSkeleton = /^([GyYqQMLwWEecdD]+)([hHkKjJmszZvVOXx]+)$/,
1088
+ rWideMonth = /MMMM|LLLL/,
1089
+ rAbbrevMonth = /MMM|LLL/,
1090
+ rWeekDay = /E|e|c/,
1091
+ oResult,
1092
+ sDateSkeleton,
1093
+ sTimeSkeleton,
1094
+ sStyle,
1095
+ sDatePattern,
1096
+ sTimePattern,
1097
+ sDateTimePattern,
1098
+ sResultPattern;
1099
+
1100
+ // Split skeleton into date and time part
1101
+ oResult = rMixedSkeleton.exec(sSkeleton);
1102
+ sDateSkeleton = oResult[1];
1103
+ sTimeSkeleton = oResult[2];
1104
+ // Get patterns for date and time separately
1105
+ sDatePattern = this._getFormatPattern(sDateSkeleton, oAvailableFormats, sCalendarType);
1106
+ if (vDiff) {
1107
+ sTimePattern = this.getCustomIntervalPattern(sTimeSkeleton, vDiff, sCalendarType);
1108
+ } else {
1109
+ sTimePattern = this._getFormatPattern(sTimeSkeleton, oAvailableFormats, sCalendarType);
1110
+ }
1111
+ // Combine patterns with datetime pattern, dependent on month and weekday
1112
+ if (rWideMonth.test(sDateSkeleton)) {
1113
+ sStyle = rWeekDay.test(sDateSkeleton) ? "full" : "long";
1114
+ } else if (rAbbrevMonth.test(sDateSkeleton)) {
1115
+ sStyle = "medium";
1116
+ } else {
1117
+ sStyle = "short";
1118
+ }
1119
+ sDateTimePattern = this.getDateTimePattern(sStyle, sCalendarType);
1120
+ sResultPattern = sDateTimePattern.replace(/\{1\}/, sDatePattern).replace(/\{0\}/, sTimePattern);
1121
+ return sResultPattern;
1122
+ },
1123
+ /**
1124
+ * Get number symbol "decimal", "group", "plusSign", "minusSign", "percentSign".
1125
+ *
1126
+ * @param {string} sType the required type of symbol
1127
+ * @returns {string} the selected number symbol
1128
+ * @public
1129
+ */
1130
+ getNumberSymbol: function (sType) {
1131
+ assert(sType == "decimal" || sType == "group" || sType == "plusSign" || sType == "minusSign" || sType == "percentSign", "sType must be decimal, group, plusSign, minusSign or percentSign");
1132
+ return this._get("symbols-latn-" + sType);
1133
+ },
1134
+ /**
1135
+ * Get lenient number symbols for "plusSign" or "minusSign".
1136
+ *
1137
+ * @param {string} sType the required type of symbol
1138
+ * @returns {string} the selected lenient number symbols, e.g. "-‒⁻₋−➖﹣"
1139
+ * @public
1140
+ */
1141
+ getLenientNumberSymbols: function (sType) {
1142
+ assert(sType == "plusSign" || sType == "minusSign", "sType must be plusSign or minusSign");
1143
+ return this._get("lenient-scope-number")[sType];
1144
+ },
1145
+ /**
1146
+ * Get decimal format pattern.
1147
+ *
1148
+ * @returns {string} The pattern
1149
+ * @public
1150
+ */
1151
+ getDecimalPattern: function () {
1152
+ return this._get("decimalFormat").standard;
1153
+ },
1154
+ /**
1155
+ * Get currency format pattern.
1156
+ *
1157
+ * CLDR format pattern:
1158
+ *
1159
+ * @example standard with currency symbol in front of the number
1160
+ * ¤#,##0.00
1161
+ * $100,000.00
1162
+ * $-100,000.00
1163
+ *
1164
+ * @example accounting with negative number pattern after the semicolon
1165
+ * ¤#,##0.00;(¤#,##0.00)
1166
+ * $100,000.00
1167
+ * ($100,000.00)
1168
+ *
1169
+ * @see https://cldr.unicode.org/translation/numbers-currency/number-patterns
1170
+ *
1171
+ * @param {string} sContext the context of the currency pattern (standard or accounting)
1172
+ * @returns {string} The pattern
1173
+ * @public
1174
+ */
1175
+ getCurrencyPattern: function (sContext) {
1176
+ // Undocumented contexts for NumberFormat internal use: "sap-standard" and "sap-accounting"
1177
+ return this._get("currencyFormat")[sContext] || this._get("currencyFormat").standard;
1178
+ },
1179
+ getCurrencySpacing: function (sPosition) {
1180
+ return this._get("currencyFormat", "currencySpacing", sPosition === "after" ? "afterCurrency" : "beforeCurrency");
1181
+ },
1182
+ /**
1183
+ * Get percent format pattern.
1184
+ *
1185
+ * @returns {string} The pattern
1186
+ * @public
1187
+ */
1188
+ getPercentPattern: function () {
1189
+ return this._get("percentFormat").standard;
1190
+ },
1191
+ /**
1192
+ * Get miscellaneous pattern.
1193
+ *
1194
+ * @param {string} sName the name of the misc pattern, can be "approximately", "atLeast", "atMost" or "range"
1195
+ * @returns {string} The pattern
1196
+ * @public
1197
+ */
1198
+ getMiscPattern: function (sName) {
1199
+ assert(sName == "approximately" || sName == "atLeast" || sName == "atMost" || sName == "range", "sName must be approximately, atLeast, atMost or range");
1200
+ return this._get("miscPattern")[sName];
1201
+ },
1202
+ /**
1203
+ * Returns the required minimal number of days for the first week of a year.
1204
+ *
1205
+ * This is the minimal number of days of the week which must be contained in the new year
1206
+ * for the week to become the first week of the year. Depending on the country, this
1207
+ * is just a single day (in the US) or at least 4 days (in most of Europe).
1208
+ *
1209
+ * All week data information in the CLDR is provided for territories (countries).
1210
+ * If the locale of this LocaleData doesn't contain country information (e.g. if it
1211
+ * contains only a language), then the "likelySubtag" information of the CLDR
1212
+ * is taken into account to guess the "most likely" territory for the locale.
1213
+ *
1214
+ * @returns {int} minimal number of days
1215
+ * @public
1216
+ */
1217
+ getMinimalDaysInFirstWeek: function () {
1218
+ return this._get("weekData-minDays");
1219
+ },
1220
+ /**
1221
+ * Returns the day that usually is regarded as the first day
1222
+ * of a week in the current locale.
1223
+ *
1224
+ * Days are encoded as integer where Sunday=0, Monday=1 etc.
1225
+ *
1226
+ * All week data information in the CLDR is provided for territories (countries).
1227
+ * If the locale of this LocaleData doesn't contain country information (e.g. if it
1228
+ * contains only a language), then the "likelySubtag" information of the CLDR
1229
+ * is taken into account to guess the "most likely" territory for the locale.
1230
+ *
1231
+ * @returns {int} first day of week
1232
+ * @public
1233
+ */
1234
+ getFirstDayOfWeek: function () {
1235
+ return this._get("weekData-firstDay");
1236
+ },
1237
+ /**
1238
+ * Returns the first day of a weekend for the given locale.
1239
+ *
1240
+ * Days are encoded in the same way as for {@link #getFirstDayOfWeek}.
1241
+ *
1242
+ * All week data information in the CLDR is provided for territories (countries).
1243
+ * If the locale of this LocaleData doesn't contain country information (e.g. if it
1244
+ * contains only a language), then the "likelySubtag" information of the CLDR
1245
+ * is taken into account to guess the "most likely" territory for the locale.
1246
+ *
1247
+ * @returns {int} first day of weekend
1248
+ * @public
1249
+ */
1250
+ getWeekendStart: function () {
1251
+ return this._get("weekData-weekendStart");
1252
+ },
1253
+ /**
1254
+ * Returns the last day of a weekend for the given locale.
1255
+ *
1256
+ * Days are encoded in the same way as for {@link #getFirstDayOfWeek}.
1257
+ *
1258
+ * All week data information in the CLDR is provided for territories (countries).
1259
+ * If the locale of this LocaleData doesn't contain country information (e.g. if it
1260
+ * contains only a language), then the "likelySubtag" information of the CLDR
1261
+ * is taken into account to guess the "most likely" territory for the locale.
1262
+ *
1263
+ * @returns {int} last day of weekend
1264
+ * @public
1265
+ */
1266
+ getWeekendEnd: function () {
1267
+ return this._get("weekData-weekendEnd");
1268
+ },
1269
+ /**
1270
+ * Returns a map of custom currency codes, defined via global configuration.
1271
+ * @returns {object} map of custom currency codes, e.g.
1272
+ * {
1273
+ * "AUD": "AUD",
1274
+ * "BRL": "BRL",
1275
+ * "EUR": "EUR",
1276
+ * "GBP": "GBP",
1277
+ * }
1278
+ * @private
1279
+ * @ui5-restricted sap.ui.core.format.NumberFormat
1280
+ * @since 1.63
1281
+ */
1282
+ getCustomCurrencyCodes: function () {
1283
+ var mCustomCurrencies = this._get("currency") || {},
1284
+ mCustomCurrencyCodes = {};
1285
+ Object.keys(mCustomCurrencies).forEach(function (sCurrencyKey) {
1286
+ mCustomCurrencyCodes[sCurrencyKey] = sCurrencyKey;
1287
+ });
1288
+ return mCustomCurrencyCodes;
1289
+ },
1290
+ /**
1291
+ * Returns the number of digits of the specified currency.
1292
+ *
1293
+ * @param {string} sCurrency ISO 4217 currency code
1294
+ * @returns {int} digits of the currency
1295
+ * @public
1296
+ * @since 1.21.1
1297
+ */
1298
+ getCurrencyDigits: function (sCurrency) {
1299
+ // try to lookup currency digits from custom currencies
1300
+ var mCustomCurrencies = this._get("currency");
1301
+ if (mCustomCurrencies) {
1302
+ if (mCustomCurrencies[sCurrency] && mCustomCurrencies[sCurrency].hasOwnProperty("digits")) {
1303
+ return mCustomCurrencies[sCurrency].digits;
1304
+ } else if (mCustomCurrencies["DEFAULT"] && mCustomCurrencies["DEFAULT"].hasOwnProperty("digits")) {
1305
+ return mCustomCurrencies["DEFAULT"].digits;
1306
+ }
1307
+ }
1308
+ var iDigits = this._get("currencyDigits", sCurrency);
1309
+ if (iDigits == null) {
1310
+ iDigits = this._get("currencyDigits", "DEFAULT");
1311
+ if (iDigits == null) {
1312
+ iDigits = 2; // default
1313
+ }
1314
+ }
1315
+ return iDigits;
1316
+ },
1317
+ /**
1318
+ * Returns the currency symbol for the specified currency, if no symbol is found the ISO 4217 currency code is returned.
1319
+ *
1320
+ * @param {string} sCurrency ISO 4217 currency code
1321
+ * @returns {string} the currency symbol
1322
+ * @public
1323
+ * @since 1.21.1
1324
+ */
1325
+ getCurrencySymbol: function (sCurrency) {
1326
+ var oCurrencySymbols = this.getCurrencySymbols();
1327
+ return oCurrencySymbols && oCurrencySymbols[sCurrency] || sCurrency;
1328
+ },
1329
+ /**
1330
+ * Returns the currency code which is corresponded with the given currency symbol.
1331
+ *
1332
+ * @param {string} sCurrencySymbol The currency symbol which needs to be converted to currency code
1333
+ * @return {string} The corresponded currency code defined for the given currency symbol. The given currency symbol is returned if no currency code can be found by using the given currency symbol.
1334
+ * @public
1335
+ * @since 1.27.0
1336
+ */
1337
+ getCurrencyCodeBySymbol: function (sCurrencySymbol) {
1338
+ var oCurrencySymbols = this._get("currencySymbols"),
1339
+ sCurrencyCode;
1340
+ for (sCurrencyCode in oCurrencySymbols) {
1341
+ if (oCurrencySymbols[sCurrencyCode] === sCurrencySymbol) {
1342
+ return sCurrencyCode;
1343
+ }
1344
+ }
1345
+ return sCurrencySymbol;
1346
+ },
1347
+ /**
1348
+ * Returns the currency symbols available for this locale.
1349
+ * Currency symbols get accumulated by custom currency symbols.
1350
+ *
1351
+ * @returns {Object<string, string>} the map of all currency symbols available in this locale, e.g.
1352
+ * {
1353
+ * "AUD": "A$",
1354
+ * "BRL": "R$",
1355
+ * "EUR": "€",
1356
+ * "GBP": "£",
1357
+ * }
1358
+ * @public
1359
+ * @since 1.60
1360
+ */
1361
+ getCurrencySymbols: function () {
1362
+ // Lookup into global Config
1363
+ var mCustomCurrencies = this._get("currency"),
1364
+ mCustomCurrencySymbols = {},
1365
+ sIsoCode;
1366
+ for (var sCurrencyKey in mCustomCurrencies) {
1367
+ sIsoCode = mCustomCurrencies[sCurrencyKey].isoCode;
1368
+ if (mCustomCurrencies[sCurrencyKey].symbol) {
1369
+ mCustomCurrencySymbols[sCurrencyKey] = mCustomCurrencies[sCurrencyKey].symbol;
1370
+ } else if (sIsoCode) {
1371
+ mCustomCurrencySymbols[sCurrencyKey] = this._get("currencySymbols")[sIsoCode];
1372
+ }
1373
+ }
1374
+ return Object.assign({}, this._get("currencySymbols"), mCustomCurrencySymbols);
1375
+ },
1376
+ /**
1377
+ * Retrieves the localized display name of a unit by sUnit, e.g. "duration-hour".
1378
+ * @param {string} sUnit the unit key, e.g. "duration-hour"
1379
+ * @return {string} The localized display name for the requested unit, e.g. <code>"Hour"</code>. Return empty string <code>""</code> if not found
1380
+ * @public
1381
+ * @since 1.54
1382
+ */
1383
+ getUnitDisplayName: function (sUnit) {
1384
+ var mUnitFormat = this.getUnitFormat(sUnit);
1385
+ return mUnitFormat && mUnitFormat["displayName"] || "";
1386
+ },
1387
+ /**
1388
+ * Returns relative time patterns for the given scales as an array of objects containing scale, value and pattern.
1389
+ *
1390
+ * The array may contain the following values: "year", "month", "week", "day", "hour", "minute" and "second". If
1391
+ * no scales are given, patterns for all available scales will be returned.
1392
+ *
1393
+ * The return array will contain objects looking like:
1394
+ * <pre>
1395
+ * {
1396
+ * scale: "minute",
1397
+ * sign: 1,
1398
+ * pattern: "in {0} minutes"
1399
+ * }
1400
+ * </pre>
1401
+ *
1402
+ * @param {string[]} aScales The scales for which the available patterns should be returned
1403
+ * @param {string} [sStyle="wide"] @since 1.32.10, 1.34.4 The style of the scale patterns. The valid values are "wide", "short" and "narrow".
1404
+ * @returns {object[]} An array of all relative time patterns
1405
+ * @public
1406
+ * @since 1.34
1407
+ */
1408
+ getRelativePatterns: function (aScales, sStyle) {
1409
+ if (sStyle === undefined) {
1410
+ sStyle = "wide";
1411
+ }
1412
+ assert(sStyle === "wide" || sStyle === "short" || sStyle === "narrow", "sStyle is only allowed to be set with 'wide', 'short' or 'narrow'");
1413
+ var aPatterns = [],
1414
+ aPluralCategories = this.getPluralCategories(),
1415
+ oScale,
1416
+ oTimeEntry,
1417
+ iValue,
1418
+ iSign;
1419
+ if (!aScales) {
1420
+ aScales = ["year", "month", "week", "day", "hour", "minute", "second"];
1421
+ }
1422
+ aScales.forEach(function (sScale) {
1423
+ oScale = this._get("dateFields", sScale + "-" + sStyle);
1424
+ for (var sEntry in oScale) {
1425
+ if (sEntry.indexOf("relative-type-") === 0) {
1426
+ iValue = parseInt(sEntry.substr(14));
1427
+ aPatterns.push({
1428
+ scale: sScale,
1429
+ value: iValue,
1430
+ pattern: oScale[sEntry]
1431
+ });
1432
+ } else if (sEntry.indexOf("relativeTime-type-") == 0) {
1433
+ oTimeEntry = oScale[sEntry];
1434
+ iSign = sEntry.substr(18) === "past" ? -1 : 1;
1435
+ aPluralCategories.forEach(function (sKey) {
1436
+ // eslint-disable-line no-loop-func
1437
+ var sPattern = oTimeEntry["relativeTimePattern-count-" + sKey];
1438
+ if (sPattern) {
1439
+ aPatterns.push({
1440
+ scale: sScale,
1441
+ sign: iSign,
1442
+ pattern: sPattern
1443
+ });
1003
1444
  }
1004
- o = {
1005
- n: parseFloat(sValue),
1006
- i: parseInt(sInteger),
1007
- v: sFraction.length,
1008
- w: sFractionNoZeros.length,
1009
- f: sFraction === '' ? 0 : parseInt(sFraction),
1010
- t: sFractionNoZeros === '' ? 0 : parseInt(sFractionNoZeros),
1011
- c: iExponent
1012
- };
1013
- return {
1014
- bMatch: fnOr(o),
1015
- oOperands: o
1016
- };
1445
+ });
1446
+ }
1447
+ }
1448
+ }.bind(this));
1449
+ return aPatterns;
1450
+ },
1451
+ /**
1452
+ * Returns the relative format pattern with given scale (year, month, week, ...) and difference value.
1453
+ *
1454
+ * @param {string} sScale the scale the relative pattern is needed for
1455
+ * @param {int} iDiff the difference in the given scale unit
1456
+ * @param {boolean} [bFuture] whether a future or past pattern should be used
1457
+ * @param {string} [sStyle="wide"] @since 1.32.10, 1.34.4 the style of the pattern. The valid values are "wide", "short" and "narrow"
1458
+ * @returns {string} the relative format pattern
1459
+ * @public
1460
+ * @since 1.34
1461
+ */
1462
+ getRelativePattern: function (sScale, iDiff, bFuture, sStyle) {
1463
+ var sPattern, oTypes, sKey, sPluralCategory;
1464
+ if (typeof bFuture === "string") {
1465
+ sStyle = bFuture;
1466
+ bFuture = undefined;
1467
+ }
1468
+ if (bFuture === undefined) {
1469
+ bFuture = iDiff > 0;
1470
+ }
1471
+ if (sStyle === undefined) {
1472
+ sStyle = "wide";
1473
+ }
1474
+ assert(sStyle === "wide" || sStyle === "short" || sStyle === "narrow", "sStyle is only allowed to be set with 'wide', 'short' or 'narrow'");
1475
+ sKey = sScale + "-" + sStyle;
1476
+ if (iDiff === 0 || iDiff === -2 || iDiff === 2) {
1477
+ sPattern = this._get("dateFields", sKey, "relative-type-" + iDiff);
1478
+ }
1479
+ if (!sPattern) {
1480
+ oTypes = this._get("dateFields", sKey, "relativeTime-type-" + (bFuture ? "future" : "past"));
1481
+ sPluralCategory = this.getPluralCategory(Math.abs(iDiff).toString());
1482
+ sPattern = oTypes["relativeTimePattern-count-" + sPluralCategory];
1483
+ }
1484
+ return sPattern;
1485
+ },
1486
+ /**
1487
+ * Returns the relative resource pattern with unit 'second' (like now, "in {0} seconds", "{0} seconds ago" under locale 'en') based on the given
1488
+ * difference value (0 means now, positive value means in the future and negative value means in the past).
1489
+ *
1490
+ * @param {int} iDiff the difference in seconds
1491
+ * @param {string} [sStyle="wide"] @since 1.32.10, 1.34.4 the style of the pattern. The valid values are "wide", "short" and "narrow"
1492
+ * @returns {string} the relative resource pattern in unit 'second'
1493
+ * @public
1494
+ * @since 1.31.0
1495
+ */
1496
+ getRelativeSecond: function (iDiff, sStyle) {
1497
+ return this.getRelativePattern("second", iDiff, sStyle);
1498
+ },
1499
+ /**
1500
+ * Returns the relative resource pattern with unit 'minute' (like "in {0} minute(s)", "{0} minute(s) ago" under locale 'en') based on the given
1501
+ * difference value (positive value means in the future and negative value means in the past).
1502
+ *
1503
+ * There's no pattern defined for 0 difference and the function returns null if 0 is given. In the 0 difference case, you can use the getRelativeSecond
1504
+ * function to format the difference using unit 'second'.
1505
+ *
1506
+ * @param {int} iDiff the difference in minutes
1507
+ * @param {string} [sStyle="wide"] @since 1.32.10, 1.34.4 the style of the pattern. The valid values are "wide", "short" and "narrow"
1508
+ * @returns {string|null} the relative resource pattern in unit 'minute'. The method returns null if 0 is given as parameter.
1509
+ * @public
1510
+ * @since 1.31.0
1511
+ */
1512
+ getRelativeMinute: function (iDiff, sStyle) {
1513
+ if (iDiff == 0) {
1514
+ return null;
1515
+ }
1516
+ return this.getRelativePattern("minute", iDiff, sStyle);
1517
+ },
1518
+ /**
1519
+ * Returns the relative resource pattern with unit 'hour' (like "in {0} hour(s)", "{0} hour(s) ago" under locale 'en') based on the given
1520
+ * difference value (positive value means in the future and negative value means in the past).
1521
+ *
1522
+ * There's no pattern defined for 0 difference and the function returns null if 0 is given. In the 0 difference case, you can use the getRelativeMinute or getRelativeSecond
1523
+ * function to format the difference using unit 'minute' or 'second'.
1524
+ *
1525
+ * @param {int} iDiff the difference in hours
1526
+ * @param {string} [sStyle="wide"] @since 1.32.10, 1.34.4 the style of the pattern. The valid values are "wide", "short" and "narrow"
1527
+ * @returns {string|null} the relative resource pattern in unit 'hour'. The method returns null if 0 is given as parameter.
1528
+ * @public
1529
+ * @since 1.31.0
1530
+ */
1531
+ getRelativeHour: function (iDiff, sStyle) {
1532
+ if (iDiff == 0) {
1533
+ return null;
1534
+ }
1535
+ return this.getRelativePattern("hour", iDiff, sStyle);
1536
+ },
1537
+ /**
1538
+ * Returns the relative day resource pattern (like "Today", "Yesterday", "{0} days ago") based on the given
1539
+ * difference of days (0 means today, 1 means tomorrow, -1 means yesterday, ...).
1540
+ *
1541
+ * @param {int} iDiff the difference in days
1542
+ * @param {string} [sStyle="wide"] @since 1.32.10, 1.34.4 the style of the pattern. The valid values are "wide", "short" and "narrow"
1543
+ * @returns {string} the relative day resource pattern
1544
+ * @public
1545
+ * @since 1.25.0
1546
+ */
1547
+ getRelativeDay: function (iDiff, sStyle) {
1548
+ return this.getRelativePattern("day", iDiff, sStyle);
1549
+ },
1550
+ /**
1551
+ * Returns the relative week resource pattern (like "This week", "Last week", "{0} weeks ago") based on the given
1552
+ * difference of weeks (0 means this week, 1 means next week, -1 means last week, ...).
1553
+ *
1554
+ * @param {int} iDiff the difference in weeks
1555
+ * @param {string} [sStyle="wide"] @since 1.32.10, 1.34.4 the style of the pattern. The valid values are "wide", "short" and "narrow"
1556
+ * @returns {string} the relative week resource pattern
1557
+ * @public
1558
+ * @since 1.31.0
1559
+ */
1560
+ getRelativeWeek: function (iDiff, sStyle) {
1561
+ return this.getRelativePattern("week", iDiff, sStyle);
1562
+ },
1563
+ /**
1564
+ * Returns the relative month resource pattern (like "This month", "Last month", "{0} months ago") based on the given
1565
+ * difference of months (0 means this month, 1 means next month, -1 means last month, ...).
1566
+ *
1567
+ * @param {int} iDiff the difference in months
1568
+ * @param {string} [sStyle="wide"] @since 1.32.10, 1.34.4 the style of the pattern. The valid values are "wide", "short" and "narrow"
1569
+ * @returns {string} the relative month resource pattern
1570
+ * @public
1571
+ * @since 1.25.0
1572
+ */
1573
+ getRelativeMonth: function (iDiff, sStyle) {
1574
+ return this.getRelativePattern("month", iDiff, sStyle);
1575
+ },
1576
+ /**
1577
+ * Returns the display name for a time unit (second, minute, hour, day, week, month, year).
1578
+ *
1579
+ * @param {string} sType Type (second, minute, hour, day, week, month, year)
1580
+ * @param {string} [sStyle="wide"] @since 1.32.10, 1.34.4 the style of the pattern. The valid values are "wide", "short" and "narrow"
1581
+ * returns {string} display name
1582
+ * @public
1583
+ * @since 1.34.0
1584
+ */
1585
+ getDisplayName: function (sType, sStyle) {
1586
+ assert(sType == "second" || sType == "minute" || sType == "hour" || sType == "zone" || sType == "day" || sType == "weekday" || sType == "week" || sType == "month" || sType == "quarter" || sType == "year" || sType == "era", "sType must be second, minute, hour, zone, day, weekday, week, month, quarter, year, era");
1587
+ if (sStyle === undefined) {
1588
+ sStyle = "wide";
1589
+ }
1590
+ assert(sStyle === "wide" || sStyle === "short" || sStyle === "narrow", "sStyle is only allowed to be set with 'wide', 'short' or 'narrow'");
1591
+ var aSingleFormFields = ["era", "weekday", "zone"],
1592
+ sKey = aSingleFormFields.indexOf(sType) === -1 ? sType + "-" + sStyle : sType;
1593
+ return this._get("dateFields", sKey, "displayName");
1594
+ },
1595
+ /**
1596
+ * Returns the relative year resource pattern (like "This year", "Last year", "{0} year ago") based on the given
1597
+ * difference of years (0 means this year, 1 means next year, -1 means last year, ...).
1598
+ *
1599
+ * @param {int} iDiff the difference in years
1600
+ * @param {string} [sStyle="wide"] @since 1.32.10, 1.34.4 the style of the pattern. The valid values are "wide", "short" and "narrow"
1601
+ * @returns {string} the relative year resource pattern
1602
+ * @public
1603
+ * @since 1.25.0
1604
+ */
1605
+ getRelativeYear: function (iDiff, sStyle) {
1606
+ return this.getRelativePattern("year", iDiff, sStyle);
1607
+ },
1608
+ /**
1609
+ * Returns the short decimal formats (like 1K, 1M....).
1610
+ *
1611
+ * @param {string} sStyle short or long
1612
+ * @param {string} sNumber 1000, 10000 ...
1613
+ * @param {string} sPlural one or other (if not exists other is used)
1614
+ * @returns {string} decimal format
1615
+ * @public
1616
+ * @since 1.25.0
1617
+ */
1618
+ getDecimalFormat: function (sStyle, sNumber, sPlural) {
1619
+ var sFormat;
1620
+ var oFormats;
1621
+ switch (sStyle) {
1622
+ case "long":
1623
+ oFormats = this._get("decimalFormat-long");
1624
+ break;
1625
+ default:
1626
+ //short
1627
+ oFormats = this._get("decimalFormat-short");
1628
+ break;
1629
+ }
1630
+ if (oFormats) {
1631
+ var sName = sNumber + "-" + sPlural;
1632
+ sFormat = oFormats[sName];
1633
+ if (!sFormat) {
1634
+ sName = sNumber + "-other";
1635
+ sFormat = oFormats[sName];
1636
+ }
1637
+ }
1638
+ return sFormat;
1639
+ },
1640
+ /**
1641
+ * Returns the short currency formats (like 1K USD, 1M USD....).
1642
+ *
1643
+ * @param {string} sStyle short
1644
+ * @param {string} sNumber 1000, 10000 ...
1645
+ * @param {string} sPlural one or other (if not exists other is used)
1646
+ * @returns {string} decimal format
1647
+ * @public
1648
+ * @since 1.51.0
1649
+ */
1650
+ getCurrencyFormat: function (sStyle, sNumber, sPlural) {
1651
+ var sFormat;
1652
+ var oFormats = this._get("currencyFormat-" + sStyle);
1653
+
1654
+ // Defaults to "short" if not found
1655
+ if (!oFormats) {
1656
+ if (sStyle === "sap-short") {
1657
+ throw new Error("Failed to get CLDR data for property \"currencyFormat-sap-short\"");
1658
+ }
1659
+ oFormats = this._get("currencyFormat-short");
1660
+ }
1661
+ if (oFormats) {
1662
+ var sName = sNumber + "-" + sPlural;
1663
+ sFormat = oFormats[sName];
1664
+ if (!sFormat) {
1665
+ sName = sNumber + "-other";
1666
+ sFormat = oFormats[sName];
1667
+ }
1668
+ }
1669
+ return sFormat;
1670
+ },
1671
+ /**
1672
+ * Returns a map containing patterns for formatting lists
1673
+ *
1674
+ *@param {string} [sType='standard'] The type of the list pattern. It can be 'standard' or 'or'.
1675
+ *@param {string} [sStyle='wide'] The style of the list pattern. It can be 'wide' or 'short'.
1676
+ * @return {object} Map with list patterns
1677
+ */
1678
+ getListFormat: function (sType, sStyle) {
1679
+ var oFormats = this._get("listPattern-" + (sType || "standard") + "-" + (sStyle || "wide"));
1680
+ if (oFormats) {
1681
+ return oFormats;
1682
+ }
1683
+ return {};
1684
+ },
1685
+ /**
1686
+ * Retrieves the unit format pattern for a specific unit name considering the unit mappings.
1687
+ * @param {string} sUnit unit name, e.g. "duration-hour" or "my"
1688
+ * @return {object} The unit format configuration for the given unit name
1689
+ * @public
1690
+ * @since 1.54
1691
+ * @see sap.ui.core.LocaleData#getUnitFromMapping
1692
+ */
1693
+ getResolvedUnitFormat: function (sUnit) {
1694
+ sUnit = this.getUnitFromMapping(sUnit) || sUnit;
1695
+ return this.getUnitFormat(sUnit);
1696
+ },
1697
+ /**
1698
+ * Retrieves the unit format pattern for a specific unit name.
1699
+ *
1700
+ * Note: Does not take unit mapping into consideration.
1701
+ * @param {string} sUnit unit name, e.g. "duration-hour"
1702
+ * @return {object} The unit format configuration for the given unit name
1703
+ * @public
1704
+ * @since 1.54
1705
+ */
1706
+ getUnitFormat: function (sUnit) {
1707
+ var oResult = this._get("units", "short", sUnit);
1708
+ if (!oResult && mLegacyUnit2CurrentUnit[sUnit]) {
1709
+ oResult = this._get("units", "short", mLegacyUnit2CurrentUnit[sUnit]);
1710
+ }
1711
+ return oResult;
1712
+ },
1713
+ /**
1714
+ * Retrieves all unit format patterns merged.
1715
+ *
1716
+ * Note: Does not take unit mapping into consideration.
1717
+ * @return {object} The unit format patterns
1718
+ * @public
1719
+ * @since 1.54
1720
+ */
1721
+ getUnitFormats: function () {
1722
+ return this._getMerged("units", "short");
1723
+ },
1724
+ /**
1725
+ * Looks up the unit from defined unit mapping.
1726
+ * E.g. for defined unit mapping
1727
+ * <code>
1728
+ * {
1729
+ * "my": "my-custom-unit",
1730
+ * "cm": "length-centimeter"
1731
+ * }
1732
+ * </code>
1733
+ *
1734
+ * Call:
1735
+ * <code>getUnitFromMapping("my")</code> would result in <code>"my-custom-unit"</code>
1736
+ * @param {string} sMapping mapping identifier
1737
+ * @return {string} unit from the mapping
1738
+ * @public
1739
+ * @since 1.54
1740
+ */
1741
+ getUnitFromMapping: function (sMapping) {
1742
+ return this._get("unitMappings", sMapping);
1743
+ },
1744
+ /**
1745
+ * Returns array of eras.
1746
+ *
1747
+ * @param {string} sWidth the style of the era name. It can be 'wide', 'abbreviated' or 'narrow'
1748
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar
1749
+ * @return {array} the array of eras
1750
+ * @public
1751
+ * @since 1.32.0
1752
+ */
1753
+ getEras: function (sWidth, sCalendarType) {
1754
+ assert(sWidth == "wide" || sWidth == "abbreviated" || sWidth == "narrow", "sWidth must be wide, abbreviate or narrow");
1755
+
1756
+ //TODO Adapt generation so that eras are an array instead of object
1757
+ var oEras = this._get(getCLDRCalendarName(sCalendarType), "era-" + sWidth),
1758
+ aEras = [];
1759
+ for (var i in oEras) {
1760
+ aEras[parseInt(i)] = oEras[i];
1761
+ }
1762
+ return aEras;
1763
+ },
1764
+ /**
1765
+ * Returns the map of era IDs to era dates.
1766
+ *
1767
+ * @param {sap.ui.core.CalendarType} [sCalendarType] the type of calendar
1768
+ * @return {array} the array of eras containing objects with either an _end or _start property with a date
1769
+ * @public
1770
+ * @since 1.32.0
1771
+ */
1772
+ getEraDates: function (sCalendarType) {
1773
+ //TODO Adapt generation so that eradates are an array instead of object
1774
+ var oEraDates = this._get("eras-" + sCalendarType.toLowerCase()),
1775
+ aEraDates = [];
1776
+ for (var i in oEraDates) {
1777
+ aEraDates[parseInt(i)] = oEraDates[i];
1778
+ }
1779
+ return aEraDates;
1780
+ },
1781
+ /**
1782
+ * Returns the defined pattern for representing the calendar week number.
1783
+ *
1784
+ * @param {string} sStyle the style of the pattern. It can only be either "wide" or "narrow".
1785
+ * @param {int} iWeekNumber the week number
1786
+ * @return {string} the week number string
1787
+ *
1788
+ * @public
1789
+ * @since 1.32.0
1790
+ */
1791
+ getCalendarWeek: function (sStyle, iWeekNumber) {
1792
+ assert(sStyle == "wide" || sStyle == "narrow", "sStyle must be wide or narrow");
1793
+ var oMessageBundle = Core.getLibraryResourceBundle("sap.ui.core", this.oLocale.toString()),
1794
+ sKey = "date.week.calendarweek." + sStyle;
1795
+ return oMessageBundle.getText(sKey, iWeekNumber ? [iWeekNumber] : undefined);
1796
+ },
1797
+ /**
1798
+ * Whether 1 January is the first day of the first calendar week.
1799
+ * This is the definition of the calendar week in the US.
1800
+ *
1801
+ * @return {boolean} true if the first week of the year starts with 1 January.
1802
+ * @public
1803
+ * @since 1.92.0
1804
+ */
1805
+ firstDayStartsFirstWeek: function () {
1806
+ return this.oLocale.getLanguage() === "en" && this.oLocale.getRegion() === "US";
1807
+ },
1808
+ /**
1809
+ * Returns the preferred calendar type for the current locale which exists in {@link sap.ui.core.CalendarType}
1810
+ *
1811
+ * @returns {sap.ui.core.CalendarType} the preferred calendar type
1812
+ * @public
1813
+ * @since 1.28.6
1814
+ */
1815
+ getPreferredCalendarType: function () {
1816
+ var sCalendarName,
1817
+ sType,
1818
+ i,
1819
+ aCalendars = this._get("calendarPreference") || [];
1820
+ for (i = 0; i < aCalendars.length; i++) {
1821
+ // No support for calendar subtypes (islamic) yet, so ignore part after -
1822
+ sCalendarName = aCalendars[i].split("-")[0];
1823
+ for (sType in CalendarType) {
1824
+ if (sCalendarName === sType.toLowerCase()) {
1825
+ return sType;
1826
+ }
1827
+ }
1828
+ }
1829
+ return CalendarType.Gregorian;
1830
+ },
1831
+ /**
1832
+ * Returns the preferred hour pattern symbol (h for 12, H for 24 hours) for the current locale.
1833
+ *
1834
+ * @returns {string} the preferred hour symbol
1835
+ * @public
1836
+ * @since 1.34
1837
+ */
1838
+ getPreferredHourSymbol: function () {
1839
+ return this._get("timeData", "_preferred");
1840
+ },
1841
+ /**
1842
+ * Returns an array of all plural categories available in this language.
1843
+ *
1844
+ * @returns {array} The array of plural categories
1845
+ * @public
1846
+ * @since 1.50
1847
+ */
1848
+ getPluralCategories: function () {
1849
+ var oPlurals = this._get("plurals"),
1850
+ aCategories = Object.keys(oPlurals);
1851
+ aCategories.push("other");
1852
+ return aCategories;
1853
+ },
1854
+ /**
1855
+ * Returns the plural category (zero, one, two, few, many or other) for the given number value.
1856
+ * The number must be passed as an unformatted number string with dot as decimal
1857
+ * separator (for example "12345.67"). To determine the correct plural category, it
1858
+ * is also necessary to keep the same number of decimal digits as given in the formatted
1859
+ * output string. For example "1" and "1.0" could be in different plural categories as
1860
+ * the number of decimal digits is different.
1861
+ *
1862
+ * Compact numbers (for example in "short" format) must be provided in the
1863
+ * locale-independent CLDR compact notation. This notation uses the plural rule operand "c"
1864
+ * for the compact decimal exponent, for example "1.2c3" for "1.2K" (1200) or "4c6" for
1865
+ * "4M" (4000000).
1866
+ *
1867
+ * Note that the operand "e" is deprecated, but is a synonym corresponding to the CLDR
1868
+ * specification for "c" and may be redefined in the future.
1869
+ *
1870
+ * @param {string|number} vNumber The number to find the plural category for
1871
+ * @returns {string} The plural category
1872
+ * @public
1873
+ * @since 1.50
1874
+ */
1875
+ getPluralCategory: function (vNumber) {
1876
+ var sNumber = typeof vNumber === "number" ? vNumber.toString() : vNumber,
1877
+ oPlurals = this._get("plurals");
1878
+ if (!this._pluralTest) {
1879
+ this._pluralTest = {};
1880
+ }
1881
+ for (var sCategory in oPlurals) {
1882
+ var fnTest = this._pluralTest[sCategory];
1883
+ if (!fnTest) {
1884
+ fnTest = this._parsePluralRule(oPlurals[sCategory]);
1885
+ this._pluralTest[sCategory] = fnTest;
1886
+ }
1887
+ if (fnTest(sNumber).bMatch) {
1888
+ return sCategory;
1889
+ }
1890
+ }
1891
+ return "other";
1892
+ },
1893
+ /**
1894
+ * Parses a language plural rule as specified in
1895
+ * https://unicode.org/reports/tr35/tr35-numbers.html#table-plural-operand-meanings
1896
+ *
1897
+ * @param {string} sRule The plural rule as a string
1898
+ * @returns {function(string)} A function to determine for a number given as string parameter if it matches the
1899
+ * plural rule.
1900
+ *
1901
+ * @private
1902
+ */
1903
+ _parsePluralRule: function (sRule) {
1904
+ var OP_OR = "or",
1905
+ OP_AND = "and",
1906
+ OP_MOD = "%",
1907
+ OP_EQ = "=",
1908
+ OP_NEQ = "!=",
1909
+ OPD_N = "n",
1910
+ OPD_I = "i",
1911
+ OPD_F = "f",
1912
+ OPD_T = "t",
1913
+ OPD_V = "v",
1914
+ OPD_W = "w",
1915
+ OPD_C = "c",
1916
+ OPD_E = "e",
1917
+ RANGE = "..",
1918
+ SEP = ",";
1919
+ var i = 0,
1920
+ aTokens;
1921
+ aTokens = sRule.split(" ");
1922
+ function accept(sToken) {
1923
+ if (aTokens[i] === sToken) {
1924
+ i++;
1925
+ return true;
1926
+ }
1927
+ return false;
1928
+ }
1929
+ function consume() {
1930
+ var sToken = aTokens[i];
1931
+ i++;
1932
+ return sToken;
1933
+ }
1934
+ function or_condition() {
1935
+ var fnAnd, fnOr;
1936
+ fnAnd = and_condition();
1937
+ if (accept(OP_OR)) {
1938
+ fnOr = or_condition();
1939
+ return function (o) {
1940
+ return fnAnd(o) || fnOr(o);
1017
1941
  };
1942
+ }
1943
+ return fnAnd;
1018
1944
  }
1019
- });
1020
- LocaleData.convertToDecimal = function (vValue) {
1021
- var iIntegerLength, iExponent, iFractionLength, bNegative, iNewIntegerLength, aResult, sValue = String(vValue);
1022
- if (!sValue.includes('e') && !sValue.includes('E')) {
1023
- return sValue;
1024
- }
1025
- aResult = sValue.match(rNumberInScientificNotation);
1026
- bNegative = aResult[1] === '-';
1027
- sValue = aResult[2].replace('.', '');
1028
- iIntegerLength = aResult[3] ? aResult[3].length : 0;
1029
- iFractionLength = aResult[4] ? aResult[4].length : 0;
1030
- iExponent = parseInt(aResult[5]);
1031
- iNewIntegerLength = iIntegerLength + iExponent;
1032
- if (iExponent > 0) {
1033
- sValue = iExponent < iFractionLength ? sValue.slice(0, iNewIntegerLength) + '.' + sValue.slice(iNewIntegerLength) : sValue = sValue.padEnd(iNewIntegerLength, '0');
1034
- } else {
1035
- sValue = -iExponent < iIntegerLength ? sValue = sValue.slice(0, iNewIntegerLength) + '.' + sValue.slice(iNewIntegerLength) : sValue = '0.' + sValue.padStart(iFractionLength - iExponent, '0');
1945
+ function and_condition() {
1946
+ var fnRelation, fnAnd;
1947
+ fnRelation = relation();
1948
+ if (accept(OP_AND)) {
1949
+ fnAnd = and_condition();
1950
+ return function (o) {
1951
+ return fnRelation(o) && fnAnd(o);
1952
+ };
1953
+ }
1954
+ return fnRelation;
1036
1955
  }
1037
- if (bNegative) {
1038
- sValue = '-' + sValue;
1956
+ function relation() {
1957
+ var fnExpr, fnRangeList, bEq;
1958
+ fnExpr = expr();
1959
+ if (accept(OP_EQ)) {
1960
+ bEq = true;
1961
+ } else if (accept(OP_NEQ)) {
1962
+ bEq = false;
1963
+ } else {
1964
+ throw new Error("Expected '=' or '!='");
1965
+ }
1966
+ fnRangeList = range_list();
1967
+ if (bEq) {
1968
+ return function (o) {
1969
+ return fnRangeList(o).indexOf(fnExpr(o)) >= 0;
1970
+ };
1971
+ } else {
1972
+ return function (o) {
1973
+ return fnRangeList(o).indexOf(fnExpr(o)) === -1;
1974
+ };
1975
+ }
1039
1976
  }
1977
+ function expr() {
1978
+ var fnOperand;
1979
+ fnOperand = operand();
1980
+ if (accept(OP_MOD)) {
1981
+ var iDivisor = parseInt(consume());
1982
+ return function (o) {
1983
+ return fnOperand(o) % iDivisor;
1984
+ };
1985
+ }
1986
+ return fnOperand;
1987
+ }
1988
+ function operand() {
1989
+ if (accept(OPD_N)) {
1990
+ return function (o) {
1991
+ return o.n;
1992
+ };
1993
+ } else if (accept(OPD_I)) {
1994
+ return function (o) {
1995
+ return o.i;
1996
+ };
1997
+ } else if (accept(OPD_F)) {
1998
+ return function (o) {
1999
+ return o.f;
2000
+ };
2001
+ } else if (accept(OPD_T)) {
2002
+ return function (o) {
2003
+ return o.t;
2004
+ };
2005
+ } else if (accept(OPD_V)) {
2006
+ return function (o) {
2007
+ return o.v;
2008
+ };
2009
+ } else if (accept(OPD_W)) {
2010
+ return function (o) {
2011
+ return o.w;
2012
+ };
2013
+ } else if (accept(OPD_C)) {
2014
+ return function (o) {
2015
+ return o.c;
2016
+ };
2017
+ } else if (accept(OPD_E)) {
2018
+ return function (o) {
2019
+ return o.c; // c is an alias for e
2020
+ };
2021
+ } else {
2022
+ throw new Error("Unknown operand: " + consume());
2023
+ }
2024
+ }
2025
+ function range_list() {
2026
+ var aValues = [],
2027
+ sRangeList = consume(),
2028
+ aParts = sRangeList.split(SEP),
2029
+ aRange,
2030
+ iFrom,
2031
+ iTo;
2032
+ aParts.forEach(function (sPart) {
2033
+ aRange = sPart.split(RANGE);
2034
+ if (aRange.length === 1) {
2035
+ aValues.push(parseInt(sPart));
2036
+ } else {
2037
+ iFrom = parseInt(aRange[0]);
2038
+ iTo = parseInt(aRange[1]);
2039
+ for (var i = iFrom; i <= iTo; i++) {
2040
+ aValues.push(i);
2041
+ }
2042
+ }
2043
+ });
2044
+ return function (o) {
2045
+ return aValues;
2046
+ };
2047
+ }
2048
+ var fnOr = or_condition();
2049
+ if (i != aTokens.length) {
2050
+ throw new Error("Not completely parsed");
2051
+ }
2052
+ return function (sValue) {
2053
+ var iDotPos, iExponent, iExponentPos, sFraction, sFractionNoZeros, sInteger, o;
2054
+
2055
+ // replace compact operand "c" to scientific "e" to be convertible in LocaleData.convertToDecimal
2056
+ sValue = sValue.replace(rCIgnoreCase, "e");
2057
+ iExponentPos = sValue.search(rEIgnoreCase);
2058
+ iExponent = iExponentPos < 0 ? 0 : parseInt(sValue.slice(iExponentPos + 1));
2059
+ sValue = LocaleData.convertToDecimal(sValue);
2060
+ iDotPos = sValue.indexOf(".");
2061
+ if (iDotPos === -1) {
2062
+ sInteger = sValue;
2063
+ sFraction = "";
2064
+ sFractionNoZeros = "";
2065
+ } else {
2066
+ sInteger = sValue.slice(0, iDotPos);
2067
+ sFraction = sValue.slice(iDotPos + 1);
2068
+ sFractionNoZeros = sFraction.replace(rTrailingZeroes, "");
2069
+ }
2070
+ o = {
2071
+ n: parseFloat(sValue),
2072
+ i: parseInt(sInteger),
2073
+ v: sFraction.length,
2074
+ w: sFractionNoZeros.length,
2075
+ f: sFraction === "" ? 0 : parseInt(sFraction),
2076
+ t: sFractionNoZeros === "" ? 0 : parseInt(sFractionNoZeros),
2077
+ c: iExponent
2078
+ };
2079
+ return {
2080
+ bMatch: fnOr(o),
2081
+ oOperands: o
2082
+ };
2083
+ };
2084
+ }
2085
+ });
2086
+
2087
+ /**
2088
+ * Returns the non-scientific (=decimal) notation of the given numeric value which does not contain an exponent
2089
+ * value.
2090
+ * For numbers with a magnitude (ignoring sign) greater than or equal to 1e+21 or less than 1e-6, a conversion is
2091
+ * required, as Number#toString formats these in scientific notation.
2092
+ *
2093
+ * @param {float|string} vValue
2094
+ * A number such as 10.1 or a string containing a number based on radix 10
2095
+ * @return {string} The number in decimal notation
2096
+ *
2097
+ * @private
2098
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString#description
2099
+ */
2100
+ LocaleData.convertToDecimal = function (vValue) {
2101
+ var iIntegerLength,
2102
+ iExponent,
2103
+ iFractionLength,
2104
+ bNegative,
2105
+ iNewIntegerLength,
2106
+ aResult,
2107
+ sValue = String(vValue);
2108
+ if (!sValue.includes("e") && !sValue.includes("E")) {
1040
2109
  return sValue;
2110
+ }
2111
+ aResult = sValue.match(rNumberInScientificNotation);
2112
+ bNegative = aResult[1] === "-";
2113
+ sValue = aResult[2].replace(".", "");
2114
+ iIntegerLength = aResult[3] ? aResult[3].length : 0;
2115
+ iFractionLength = aResult[4] ? aResult[4].length : 0;
2116
+ iExponent = parseInt(aResult[5]);
2117
+ iNewIntegerLength = iIntegerLength + iExponent;
2118
+ if (iExponent > 0) {
2119
+ sValue = iExponent < iFractionLength ? sValue.slice(0, iNewIntegerLength) + "." + sValue.slice(iNewIntegerLength) : sValue = sValue.padEnd(iNewIntegerLength, "0");
2120
+ } else {
2121
+ sValue = -iExponent < iIntegerLength ? sValue = sValue.slice(0, iNewIntegerLength) + "." + sValue.slice(iNewIntegerLength) : sValue = "0." + sValue.padStart(iFractionLength - iExponent, "0");
2122
+ }
2123
+ if (bNegative) {
2124
+ sValue = "-" + sValue;
2125
+ }
2126
+ return sValue;
1041
2127
  };
1042
2128
  var mCLDRSymbolGroups = {
1043
- 'Era': {
1044
- field: 'era',
1045
- index: 0
1046
- },
1047
- 'Year': {
1048
- field: 'year',
1049
- index: 1
1050
- },
1051
- 'Quarter': {
1052
- field: 'quarter',
1053
- index: 2
1054
- },
1055
- 'Month': {
1056
- field: 'month',
1057
- index: 3
1058
- },
1059
- 'Week': {
1060
- field: 'week',
1061
- index: 4
1062
- },
1063
- 'Day-Of-Week': {
1064
- field: 'weekday',
1065
- index: 5
1066
- },
1067
- 'Day': {
1068
- field: 'day',
1069
- index: 6
1070
- },
1071
- 'DayPeriod': {
1072
- field: 'hour',
1073
- index: 7,
1074
- diffOnly: true
1075
- },
1076
- 'Hour': {
1077
- field: 'hour',
1078
- index: 8
1079
- },
1080
- 'Minute': {
1081
- field: 'minute',
1082
- index: 9
1083
- },
1084
- 'Second': {
1085
- field: 'second',
1086
- index: 10
1087
- },
1088
- 'Timezone': {
1089
- field: 'zone',
1090
- index: 11
1091
- }
2129
+ "Era": {
2130
+ field: "era",
2131
+ index: 0
2132
+ },
2133
+ "Year": {
2134
+ field: "year",
2135
+ index: 1
2136
+ },
2137
+ "Quarter": {
2138
+ field: "quarter",
2139
+ index: 2
2140
+ },
2141
+ "Month": {
2142
+ field: "month",
2143
+ index: 3
2144
+ },
2145
+ "Week": {
2146
+ field: "week",
2147
+ index: 4
2148
+ },
2149
+ "Day-Of-Week": {
2150
+ field: "weekday",
2151
+ index: 5
2152
+ },
2153
+ "Day": {
2154
+ field: "day",
2155
+ index: 6
2156
+ },
2157
+ "DayPeriod": {
2158
+ field: "hour",
2159
+ index: 7,
2160
+ diffOnly: true
2161
+ },
2162
+ "Hour": {
2163
+ field: "hour",
2164
+ index: 8
2165
+ },
2166
+ "Minute": {
2167
+ field: "minute",
2168
+ index: 9
2169
+ },
2170
+ "Second": {
2171
+ field: "second",
2172
+ index: 10
2173
+ },
2174
+ "Timezone": {
2175
+ field: "zone",
2176
+ index: 11
2177
+ }
1092
2178
  };
1093
2179
  var mCLDRSymbols = {
1094
- 'G': {
1095
- group: 'Era',
1096
- match: 'Era',
1097
- numericCeiling: 1
1098
- },
1099
- 'y': {
1100
- group: 'Year',
1101
- match: 'Year',
1102
- numericCeiling: 100
1103
- },
1104
- 'Y': {
1105
- group: 'Year',
1106
- match: 'Year',
1107
- numericCeiling: 100
1108
- },
1109
- 'Q': {
1110
- group: 'Quarter',
1111
- match: 'Quarter',
1112
- numericCeiling: 3
1113
- },
1114
- 'q': {
1115
- group: 'Quarter',
1116
- match: 'Quarter',
1117
- numericCeiling: 3
1118
- },
1119
- 'M': {
1120
- group: 'Month',
1121
- match: 'Month',
1122
- numericCeiling: 3
1123
- },
1124
- 'L': {
1125
- group: 'Month',
1126
- match: 'Month',
1127
- numericCeiling: 3
1128
- },
1129
- 'w': {
1130
- group: 'Week',
1131
- match: 'Week',
1132
- numericCeiling: 100
1133
- },
1134
- 'W': {
1135
- group: 'Week',
1136
- match: 'Week',
1137
- numericCeiling: 100
1138
- },
1139
- 'd': {
1140
- group: 'Day',
1141
- match: 'Day',
1142
- numericCeiling: 100
1143
- },
1144
- 'D': {
1145
- group: 'Day',
1146
- match: 'Day',
1147
- numericCeiling: 100
1148
- },
1149
- 'E': {
1150
- group: 'Day-Of-Week',
1151
- match: 'Day-Of-Week',
1152
- numericCeiling: 1
1153
- },
1154
- 'e': {
1155
- group: 'Day-Of-Week',
1156
- match: 'Day-Of-Week',
1157
- numericCeiling: 3
1158
- },
1159
- 'c': {
1160
- group: 'Day-Of-Week',
1161
- match: 'Day-Of-Week',
1162
- numericCeiling: 2
1163
- },
1164
- 'h': {
1165
- group: 'Hour',
1166
- match: 'Hour12',
1167
- numericCeiling: 100
1168
- },
1169
- 'H': {
1170
- group: 'Hour',
1171
- match: 'Hour24',
1172
- numericCeiling: 100
1173
- },
1174
- 'k': {
1175
- group: 'Hour',
1176
- match: 'Hour24',
1177
- numericCeiling: 100
1178
- },
1179
- 'K': {
1180
- group: 'Hour',
1181
- match: 'Hour12',
1182
- numericCeiling: 100
1183
- },
1184
- 'm': {
1185
- group: 'Minute',
1186
- match: 'Minute',
1187
- numericCeiling: 100
1188
- },
1189
- 's': {
1190
- group: 'Second',
1191
- match: 'Second',
1192
- numericCeiling: 100
1193
- },
1194
- 'z': {
1195
- group: 'Timezone',
1196
- match: 'Timezone',
1197
- numericCeiling: 1
1198
- },
1199
- 'Z': {
1200
- group: 'Timezone',
1201
- match: 'Timezone',
1202
- numericCeiling: 1
1203
- },
1204
- 'O': {
1205
- group: 'Timezone',
1206
- match: 'Timezone',
1207
- numericCeiling: 1
1208
- },
1209
- 'v': {
1210
- group: 'Timezone',
1211
- match: 'Timezone',
1212
- numericCeiling: 1
1213
- },
1214
- 'V': {
1215
- group: 'Timezone',
1216
- match: 'Timezone',
1217
- numericCeiling: 1
1218
- },
1219
- 'X': {
1220
- group: 'Timezone',
1221
- match: 'Timezone',
1222
- numericCeiling: 1
1223
- },
1224
- 'x': {
1225
- group: 'Timezone',
1226
- match: 'Timezone',
1227
- numericCeiling: 1
1228
- },
1229
- 'S': {
1230
- group: 'Other',
1231
- numericCeiling: 100
1232
- },
1233
- 'u': {
1234
- group: 'Other',
1235
- numericCeiling: 100
1236
- },
1237
- 'U': {
1238
- group: 'Other',
1239
- numericCeiling: 1
1240
- },
1241
- 'r': {
1242
- group: 'Other',
1243
- numericCeiling: 100
1244
- },
1245
- 'F': {
1246
- group: 'Other',
1247
- numericCeiling: 100
1248
- },
1249
- 'g': {
1250
- group: 'Other',
1251
- numericCeiling: 100
1252
- },
1253
- 'a': {
1254
- group: 'DayPeriod',
1255
- numericCeiling: 1
1256
- },
1257
- 'b': {
1258
- group: 'Other',
1259
- numericCeiling: 1
1260
- },
1261
- 'B': {
1262
- group: 'Other',
1263
- numericCeiling: 1
1264
- },
1265
- 'A': {
1266
- group: 'Other',
1267
- numericCeiling: 100
1268
- }
2180
+ "G": {
2181
+ group: "Era",
2182
+ match: "Era",
2183
+ numericCeiling: 1
2184
+ },
2185
+ "y": {
2186
+ group: "Year",
2187
+ match: "Year",
2188
+ numericCeiling: 100
2189
+ },
2190
+ "Y": {
2191
+ group: "Year",
2192
+ match: "Year",
2193
+ numericCeiling: 100
2194
+ },
2195
+ "Q": {
2196
+ group: "Quarter",
2197
+ match: "Quarter",
2198
+ numericCeiling: 3
2199
+ },
2200
+ "q": {
2201
+ group: "Quarter",
2202
+ match: "Quarter",
2203
+ numericCeiling: 3
2204
+ },
2205
+ "M": {
2206
+ group: "Month",
2207
+ match: "Month",
2208
+ numericCeiling: 3
2209
+ },
2210
+ "L": {
2211
+ group: "Month",
2212
+ match: "Month",
2213
+ numericCeiling: 3
2214
+ },
2215
+ "w": {
2216
+ group: "Week",
2217
+ match: "Week",
2218
+ numericCeiling: 100
2219
+ },
2220
+ "W": {
2221
+ group: "Week",
2222
+ match: "Week",
2223
+ numericCeiling: 100
2224
+ },
2225
+ "d": {
2226
+ group: "Day",
2227
+ match: "Day",
2228
+ numericCeiling: 100
2229
+ },
2230
+ "D": {
2231
+ group: "Day",
2232
+ match: "Day",
2233
+ numericCeiling: 100
2234
+ },
2235
+ "E": {
2236
+ group: "Day-Of-Week",
2237
+ match: "Day-Of-Week",
2238
+ numericCeiling: 1
2239
+ },
2240
+ "e": {
2241
+ group: "Day-Of-Week",
2242
+ match: "Day-Of-Week",
2243
+ numericCeiling: 3
2244
+ },
2245
+ "c": {
2246
+ group: "Day-Of-Week",
2247
+ match: "Day-Of-Week",
2248
+ numericCeiling: 2
2249
+ },
2250
+ "h": {
2251
+ group: "Hour",
2252
+ match: "Hour12",
2253
+ numericCeiling: 100
2254
+ },
2255
+ "H": {
2256
+ group: "Hour",
2257
+ match: "Hour24",
2258
+ numericCeiling: 100
2259
+ },
2260
+ "k": {
2261
+ group: "Hour",
2262
+ match: "Hour24",
2263
+ numericCeiling: 100
2264
+ },
2265
+ "K": {
2266
+ group: "Hour",
2267
+ match: "Hour12",
2268
+ numericCeiling: 100
2269
+ },
2270
+ "m": {
2271
+ group: "Minute",
2272
+ match: "Minute",
2273
+ numericCeiling: 100
2274
+ },
2275
+ "s": {
2276
+ group: "Second",
2277
+ match: "Second",
2278
+ numericCeiling: 100
2279
+ },
2280
+ "z": {
2281
+ group: "Timezone",
2282
+ match: "Timezone",
2283
+ numericCeiling: 1
2284
+ },
2285
+ "Z": {
2286
+ group: "Timezone",
2287
+ match: "Timezone",
2288
+ numericCeiling: 1
2289
+ },
2290
+ "O": {
2291
+ group: "Timezone",
2292
+ match: "Timezone",
2293
+ numericCeiling: 1
2294
+ },
2295
+ "v": {
2296
+ group: "Timezone",
2297
+ match: "Timezone",
2298
+ numericCeiling: 1
2299
+ },
2300
+ "V": {
2301
+ group: "Timezone",
2302
+ match: "Timezone",
2303
+ numericCeiling: 1
2304
+ },
2305
+ "X": {
2306
+ group: "Timezone",
2307
+ match: "Timezone",
2308
+ numericCeiling: 1
2309
+ },
2310
+ "x": {
2311
+ group: "Timezone",
2312
+ match: "Timezone",
2313
+ numericCeiling: 1
2314
+ },
2315
+ "S": {
2316
+ group: "Other",
2317
+ numericCeiling: 100
2318
+ },
2319
+ "u": {
2320
+ group: "Other",
2321
+ numericCeiling: 100
2322
+ },
2323
+ "U": {
2324
+ group: "Other",
2325
+ numericCeiling: 1
2326
+ },
2327
+ "r": {
2328
+ group: "Other",
2329
+ numericCeiling: 100
2330
+ },
2331
+ "F": {
2332
+ group: "Other",
2333
+ numericCeiling: 100
2334
+ },
2335
+ "g": {
2336
+ group: "Other",
2337
+ numericCeiling: 100
2338
+ },
2339
+ "a": {
2340
+ group: "DayPeriod",
2341
+ numericCeiling: 1
2342
+ },
2343
+ "b": {
2344
+ group: "Other",
2345
+ numericCeiling: 1
2346
+ },
2347
+ "B": {
2348
+ group: "Other",
2349
+ numericCeiling: 1
2350
+ },
2351
+ "A": {
2352
+ group: "Other",
2353
+ numericCeiling: 100
2354
+ }
1269
2355
  };
2356
+
2357
+ /**
2358
+ * Helper to analyze and parse designtime (aka buildtime) variables
2359
+ *
2360
+ * At buildtime, the build can detect a pattern like $some-variable-name:some-value$
2361
+ * and replace 'some-value' with a value determined at buildtime (here: the actual list of locales).
2362
+ *
2363
+ * At runtime, this method removes the surrounding pattern ('$some-variable-name:' and '$') and leaves only the 'some-value'.
2364
+ * Additionally, this value is parsed as a comma-separated list (because this is the only use case here).
2365
+ *
2366
+ * The mimic of the comments is borrowed from the CVS (Concurrent Versions System),
2367
+ * see http://web.mit.edu/gnu/doc/html/cvs_17.html.
2368
+ *
2369
+ * If no valid <code>sValue</code> is given, <code>null</code> is returned
2370
+ *
2371
+ * @param {string} sValue The raw designtime property e.g. $cldr-rtl-locales:ar,fa,he$
2372
+ * @returns {string[]|null} The designtime property e.g. ['ar', 'fa', 'he']
2373
+ * @private
2374
+ */
1270
2375
  function getDesigntimePropertyAsArray(sValue) {
1271
- var m = /\$([-a-z0-9A-Z._]+)(?::([^$]*))?\$/.exec(sValue);
1272
- return m && m[2] ? m[2].split(/,/) : null;
2376
+ var m = /\$([-a-z0-9A-Z._]+)(?::([^$]*))?\$/.exec(sValue);
2377
+ return m && m[2] ? m[2].split(/,/) : null;
1273
2378
  }
1274
- var _cldrLocales = getDesigntimePropertyAsArray('$cldr-locales:ar,ar_EG,ar_SA,bg,ca,cy,cs,da,de,de_AT,de_CH,el,el_CY,en,en_AU,en_GB,en_HK,en_IE,en_IN,en_NZ,en_PG,en_SG,en_ZA,es,es_AR,es_BO,es_CL,es_CO,es_MX,es_PE,es_UY,es_VE,et,fa,fi,fr,fr_BE,fr_CA,fr_CH,fr_LU,he,hi,hr,hu,id,it,it_CH,ja,kk,ko,lt,lv,ms,nb,nl,nl_BE,pl,pt,pt_PT,ro,ru,ru_UA,sk,sl,sr,sr_Latn,sv,th,tr,uk,vi,zh_CN,zh_HK,zh_SG,zh_TW$');
2379
+
2380
+ /**
2381
+ * A list of locales for which CLDR data is bundled with the UI5 runtime.
2382
+ * @private
2383
+ */
2384
+ var _cldrLocales = getDesigntimePropertyAsArray("$cldr-locales:ar,ar_EG,ar_SA,bg,ca,cy,cs,da,de,de_AT,de_CH,el,el_CY,en,en_AU,en_GB,en_HK,en_IE,en_IN,en_NZ,en_PG,en_SG,en_ZA,es,es_AR,es_BO,es_CL,es_CO,es_MX,es_PE,es_UY,es_VE,et,fa,fi,fr,fr_BE,fr_CA,fr_CH,fr_LU,he,hi,hr,hu,id,it,it_CH,ja,kk,ko,lt,lv,ms,nb,nl,nl_BE,pl,pt,pt_PT,ro,ru,ru_UA,sk,sl,sr,sr_Latn,sv,th,tr,uk,vi,zh_CN,zh_HK,zh_SG,zh_TW$");
2385
+
2386
+ /**
2387
+ * A set of locales for which the UI5 runtime contains a CLDR JSON file.
2388
+ *
2389
+ * Helps to avoid unsatisfiable backend calls.
2390
+ *
2391
+ * @private
2392
+ */
1275
2393
  var M_SUPPORTED_LOCALES = function () {
1276
- var LOCALES = _cldrLocales, result = {}, i;
1277
- if (LOCALES) {
1278
- for (i = 0; i < LOCALES.length; i++) {
1279
- result[LOCALES[i]] = true;
1280
- }
2394
+ var LOCALES = _cldrLocales,
2395
+ result = {},
2396
+ i;
2397
+ if (LOCALES) {
2398
+ for (i = 0; i < LOCALES.length; i++) {
2399
+ result[LOCALES[i]] = true;
1281
2400
  }
1282
- return result;
2401
+ }
2402
+ return result;
1283
2403
  }();
2404
+
2405
+ /**
2406
+ * Locale data cache.
2407
+ *
2408
+ * @private
2409
+ */
1284
2410
  var mLocaleDatas = {};
2411
+
2412
+ /**
2413
+ * Creates a flat map from an object structure which contains a link to the parent ("_parent").
2414
+ * The values should contain the parent(s) and the element joined by <code>", "</code>.
2415
+ * The keys are the keys of the object structure joined by "/" excluding "_parent".
2416
+ *
2417
+ * E.g. input
2418
+ * <code>
2419
+ * {
2420
+ * a: {
2421
+ * a1: {
2422
+ * a11: "A11",
2423
+ * _parent: "A1"
2424
+ * },
2425
+ * _parent: "A"
2426
+ * }
2427
+ * }
2428
+ * </code>
2429
+ *
2430
+ * output:
2431
+ * <code>
2432
+ * {
2433
+ * "a/a1/a11": "A, A1, A11"
2434
+ * }
2435
+ * </code>
2436
+ *
2437
+ * @param {object} oNode the node which will be processed
2438
+ * @param {string} [sKey=""] the key inside the node which should be processed
2439
+ * @param {object} [oResult={}] the result which is passed through the recursion
2440
+ * @param {string[]} [aParentTranslations=[]] the list of parent translations, e.g. ["A", "A1"]
2441
+ * @returns {Object<string, string>} object map with key being the keys joined by "/" and the values joined by ", ".
2442
+ * @private
2443
+ */
1285
2444
  function _resolveTimezoneTranslationStructure(oNode, sKey, oResult, aParentTranslations) {
1286
- aParentTranslations = aParentTranslations ? aParentTranslations.slice() : [];
1287
- oResult = oResult || {};
1288
- sKey = sKey || '';
1289
- Object.keys(oNode).forEach(function (sChildKey) {
1290
- var vChildNode = oNode[sChildKey];
1291
- if (typeof vChildNode === 'object') {
1292
- var aParentTranslationForChild = aParentTranslations.slice();
1293
- var sParent = vChildNode['_parent'];
1294
- if (sParent) {
1295
- aParentTranslationForChild.push(sParent);
1296
- }
1297
- _resolveTimezoneTranslationStructure(vChildNode, sKey + sChildKey + '/', oResult, aParentTranslationForChild);
1298
- } else if (typeof vChildNode === 'string' && sChildKey !== '_parent') {
1299
- var sParents = aParentTranslations.length ? aParentTranslations.join(', ') + ', ' : '';
1300
- oResult[sKey + sChildKey] = sParents + vChildNode;
1301
- }
1302
- });
1303
- return oResult;
2445
+ aParentTranslations = aParentTranslations ? aParentTranslations.slice() : [];
2446
+ oResult = oResult || {};
2447
+ sKey = sKey || "";
2448
+ Object.keys(oNode).forEach(function (sChildKey) {
2449
+ var vChildNode = oNode[sChildKey];
2450
+ if (typeof vChildNode === "object") {
2451
+ var aParentTranslationForChild = aParentTranslations.slice();
2452
+ var sParent = vChildNode["_parent"];
2453
+ if (sParent) {
2454
+ aParentTranslationForChild.push(sParent);
2455
+ }
2456
+ _resolveTimezoneTranslationStructure(vChildNode, sKey + sChildKey + "/", oResult, aParentTranslationForChild);
2457
+ } else if (typeof vChildNode === "string" && sChildKey !== "_parent") {
2458
+ var sParents = aParentTranslations.length ? aParentTranslations.join(", ") + ", " : "";
2459
+ oResult[sKey + sChildKey] = sParents + vChildNode;
2460
+ }
2461
+ });
2462
+ return oResult;
1304
2463
  }
2464
+
2465
+ /**
2466
+ * Returns the corresponding calendar name in CLDR of the given calendar type, or the calendar type
2467
+ * from the configuration, in case sCalendarType is undefined.
2468
+ *
2469
+ * @param {sap.ui.core.CalendarType} sCalendarType the type defined in {@link sap.ui.core.CalendarType}.
2470
+ * @returns {string} calendar name
2471
+ * @private
2472
+ */
1305
2473
  function getCLDRCalendarName(sCalendarType) {
1306
- if (!sCalendarType) {
1307
- sCalendarType = Configuration.getCalendarType();
1308
- }
1309
- return 'ca-' + sCalendarType.toLowerCase();
2474
+ if (!sCalendarType) {
2475
+ sCalendarType = Configuration.getCalendarType();
2476
+ }
2477
+ return "ca-" + sCalendarType.toLowerCase();
1310
2478
  }
2479
+
2480
+ /**
2481
+ * Load LocaleData data from the CLDR generated files.
2482
+ */
1311
2483
  function getData(oLocale) {
1312
- var sLanguage = oLocale.getLanguage() || '', sScript = oLocale.getScript() || '', sRegion = oLocale.getRegion() || '', mData;
1313
- function merge(obj, fallbackObj) {
1314
- var name, value, fallbackValue;
1315
- if (!fallbackObj) {
1316
- return;
1317
- }
1318
- for (name in fallbackObj) {
1319
- if (fallbackObj.hasOwnProperty(name)) {
1320
- value = obj[name];
1321
- fallbackValue = fallbackObj[name];
1322
- if (value === undefined) {
1323
- obj[name] = fallbackValue;
1324
- } else if (value === null) {
1325
- delete obj[name];
1326
- } else if (typeof value === 'object' && typeof fallbackValue === 'object' && !Array.isArray(value)) {
1327
- merge(value, fallbackValue);
1328
- }
1329
- }
1330
- }
1331
- }
1332
- function getOrLoad(sId) {
1333
- if (!mLocaleDatas[sId] && (!M_SUPPORTED_LOCALES || M_SUPPORTED_LOCALES[sId] === true)) {
1334
- var data = mLocaleDatas[sId] = LoaderExtensions.loadResource('sap/ui/core/cldr/' + sId + '.json', {
1335
- dataType: 'json',
1336
- failOnError: false
1337
- });
1338
- if (data && data.__fallbackLocale) {
1339
- merge(data, getOrLoad(data.__fallbackLocale));
1340
- delete data.__fallbackLocale;
1341
- }
1342
- }
1343
- return mLocaleDatas[sId];
2484
+ var sLanguage = oLocale.getLanguage() || "",
2485
+ sScript = oLocale.getScript() || "",
2486
+ sRegion = oLocale.getRegion() || "",
2487
+ mData;
2488
+
2489
+ /*
2490
+ * Merge a CLDR delta file and a CLDR fallback file.
2491
+ *
2492
+ * Note: this function can't be replaced by sap/base/util/extend or sap/base/util/merge
2493
+ * as its contract for null values differs from those modules.
2494
+ */
2495
+ function merge(obj, fallbackObj) {
2496
+ var name, value, fallbackValue;
2497
+ if (!fallbackObj) {
2498
+ return;
1344
2499
  }
1345
- sLanguage = sLanguage && Localization.getModernLanguage(sLanguage) || sLanguage;
1346
- if (sLanguage === 'no') {
1347
- sLanguage = 'nb';
2500
+ for (name in fallbackObj) {
2501
+ if (fallbackObj.hasOwnProperty(name)) {
2502
+ value = obj[name];
2503
+ fallbackValue = fallbackObj[name];
2504
+ if (value === undefined) {
2505
+ // 'undefined': value doesn't exist in delta, so take it from the fallback object
2506
+ // Note: undefined is not a valid value in JSON, so we can't misunderstand an existing undefined
2507
+ obj[name] = fallbackValue;
2508
+ } else if (value === null) {
2509
+ // 'null' is used by the delta tooling as a marker that a value must not be taken form the fallback
2510
+ delete obj[name];
2511
+ } else if (typeof value === 'object' && typeof fallbackValue === 'object' && !Array.isArray(value)) {
2512
+ // both values are objects, merge them recursively
2513
+ merge(value, fallbackValue);
2514
+ }
2515
+ }
1348
2516
  }
1349
- if (sLanguage === 'zh' && !sRegion) {
1350
- if (sScript === 'Hans') {
1351
- sRegion = 'CN';
1352
- } else if (sScript === 'Hant') {
1353
- sRegion = 'TW';
1354
- }
2517
+ }
2518
+ function getOrLoad(sId) {
2519
+ if (!mLocaleDatas[sId] && (!M_SUPPORTED_LOCALES || M_SUPPORTED_LOCALES[sId] === true)) {
2520
+ var data = mLocaleDatas[sId] = LoaderExtensions.loadResource("sap/ui/core/cldr/" + sId + ".json", {
2521
+ dataType: "json",
2522
+ failOnError: false
2523
+ });
2524
+
2525
+ // check if the data is a minified delta file.
2526
+ // If so, load the corresponding fallback data as well, merge it and remove the fallback marker
2527
+ if (data && data.__fallbackLocale) {
2528
+ merge(data, getOrLoad(data.__fallbackLocale));
2529
+ delete data.__fallbackLocale;
2530
+ }
2531
+
2532
+ // if load fails, null is returned
2533
+ // -> caller will process the fallback chain, in the end a result is identified and stored in mDatas under the originally requested ID
1355
2534
  }
1356
- if (sLanguage === 'sh' || sLanguage === 'sr' && sScript === 'Latn') {
1357
- sLanguage = 'sr_Latn';
2535
+ return mLocaleDatas[sId];
2536
+ }
2537
+
2538
+ // normalize language and handle special cases
2539
+ sLanguage = sLanguage && Localization.getModernLanguage(sLanguage) || sLanguage;
2540
+ // Special case 1: in an SAP context, the inclusive language code "no" always means Norwegian Bokmal ("nb")
2541
+ if (sLanguage === "no") {
2542
+ sLanguage = "nb";
2543
+ }
2544
+ // Special case 2: for Chinese, derive a default region from the script (this behavior is inherited from Java)
2545
+ if (sLanguage === "zh" && !sRegion) {
2546
+ if (sScript === "Hans") {
2547
+ sRegion = "CN";
2548
+ } else if (sScript === "Hant") {
2549
+ sRegion = "TW";
1358
2550
  }
1359
- var sId = sLanguage + '_' + sRegion;
1360
- var sCLDRLocaleId = sId;
1361
- if (sLanguage && sRegion) {
1362
- mData = getOrLoad(sId);
2551
+ }
2552
+
2553
+ // Special case 3: for Serbian, there is script cyrillic and latin, "sh" and "sr-latn" map to "latin", "sr" maps to cyrillic
2554
+ // CLDR files: sr.json (cyrillic) and sr_Latn.json (latin)
2555
+ if (sLanguage === "sh" || sLanguage === "sr" && sScript === "Latn") {
2556
+ sLanguage = "sr_Latn";
2557
+ }
2558
+
2559
+ // sId is the originally requested locale.
2560
+ // this is the key under which the result (even a fallback one) will be stored in the end
2561
+ var sId = sLanguage + "_" + sRegion;
2562
+
2563
+ // the locale of the loaded json file
2564
+ var sCLDRLocaleId = sId;
2565
+
2566
+ // first try: load CLDR data for specific language / region combination
2567
+ if (sLanguage && sRegion) {
2568
+ mData = getOrLoad(sId);
2569
+ }
2570
+ // second try: load data for language only
2571
+ if (!mData && sLanguage) {
2572
+ mData = getOrLoad(sLanguage);
2573
+ sCLDRLocaleId = sLanguage;
2574
+ }
2575
+ // last try: load data for default language "en" (english)
2576
+ if (!mData) {
2577
+ mData = getOrLoad("en");
2578
+ sCLDRLocaleId = "en";
2579
+ }
2580
+
2581
+ // store in cache
2582
+ mLocaleDatas[sId] = mData;
2583
+ sCLDRLocaleId = sCLDRLocaleId.replace(/_/g, "-");
2584
+ return {
2585
+ mData: mData,
2586
+ sCLDRLocaleId: sCLDRLocaleId
2587
+ };
2588
+ }
2589
+
2590
+ /**
2591
+ * @classdesc A specialized subclass of LocaleData that merges custom settings.
2592
+ * @extends sap.ui.core.LocaleData
2593
+ * @alias sap.ui.core.CustomLocaleData
2594
+ * @private
2595
+ */
2596
+ var CustomLocaleData = LocaleData.extend("sap.ui.core.CustomLocaleData", {
2597
+ constructor: function (oLocale) {
2598
+ LocaleData.apply(this, arguments);
2599
+ this.mCustomData = Configuration.getFormatSettings().getCustomLocaleData();
2600
+ },
2601
+ /**
2602
+ * Retrieves the value for the given arguments by checking first <code>mCustomData</code> and if not
2603
+ * found <code>mData</code>
2604
+ * @returns {*} value
2605
+ * @private
2606
+ */
2607
+ _get: function () {
2608
+ var aArguments = Array.prototype.slice.call(arguments),
2609
+ sCalendar,
2610
+ sKey;
2611
+ // Calendar data needs special handling, as CustomLocaleData does have one version of calendar data only
2612
+ if (aArguments[0].indexOf("ca-") == 0) {
2613
+ sCalendar = aArguments[0];
2614
+ if (sCalendar == getCLDRCalendarName()) {
2615
+ aArguments = aArguments.slice(1);
2616
+ }
1363
2617
  }
1364
- if (!mData && sLanguage) {
1365
- mData = getOrLoad(sLanguage);
1366
- sCLDRLocaleId = sLanguage;
2618
+ sKey = aArguments.join("-");
2619
+ // first try customdata with special formatted key
2620
+ // afterwards try customdata lookup
2621
+ // afterwards try mData lookup
2622
+ var vValue = this.mCustomData[sKey];
2623
+ if (vValue == null) {
2624
+ vValue = this._getDeep(this.mCustomData, arguments);
2625
+ if (vValue == null) {
2626
+ vValue = this._getDeep(this.mData, arguments);
2627
+ }
1367
2628
  }
1368
- if (!mData) {
1369
- mData = getOrLoad('en');
1370
- sCLDRLocaleId = 'en';
2629
+ return vValue;
2630
+ },
2631
+ /**
2632
+ * Retrieves merged object from <code>mData</code> extended with <code>mCustomData</code>.
2633
+ * This function merges the content of <code>mData</code> and <code>mCustomData</code> instead of returning one or the other like <code>_get()</code> does.
2634
+ *
2635
+ * Note: Properties defined in <code>mCustomData</code> overwrite the ones from <code>mData</code>.
2636
+ * @private
2637
+ * @return {object} merged object
2638
+ */
2639
+ _getMerged: function () {
2640
+ var mData = this._getDeep(this.mData, arguments);
2641
+ var mCustomData = this._getDeep(this.mCustomData, arguments);
2642
+ return extend({}, mData, mCustomData);
2643
+ },
2644
+ /**
2645
+ * Returns the first day of the week defined by the calendar week numbering algorithm
2646
+ * set in the configuration, see {@link sap.ui.core.Configuration#setCalendarWeekNumbering}.
2647
+ * If no specific calendar week numbering algorithm is configured the value set by
2648
+ * {@link sap.ui.core.Configuration#setFirstDayOfWeek} is returned. Otherwise the first day
2649
+ * of the week is determined by the current locale, see {@link sap.ui.core.LocaleData#getFirstDayOfWeek}.
2650
+ *
2651
+ * Days are encoded as integer where Sunday=0, Monday=1 etc.
2652
+ *
2653
+ * @returns {int} The first day of week
2654
+ * @override sap.ui.core.LocalData#getFirstDayOfWeek
2655
+ * @since 1.113.0
2656
+ */
2657
+ getFirstDayOfWeek: function () {
2658
+ var sCalendarWeekNumbering = Configuration.getCalendarWeekNumbering();
2659
+ if (sCalendarWeekNumbering === CalendarWeekNumbering.Default) {
2660
+ return LocaleData.prototype.getFirstDayOfWeek.call(this);
1371
2661
  }
1372
- mLocaleDatas[sId] = mData;
1373
- sCLDRLocaleId = sCLDRLocaleId.replace(/_/g, '-');
1374
- return {
1375
- mData: mData,
1376
- sCLDRLocaleId: sCLDRLocaleId
1377
- };
1378
- }
1379
- var CustomLocaleData = LocaleData.extend('sap.ui.core.CustomLocaleData', {
1380
- constructor: function (oLocale) {
1381
- LocaleData.apply(this, arguments);
1382
- this.mCustomData = Configuration.getFormatSettings().getCustomLocaleData();
1383
- },
1384
- _get: function () {
1385
- var aArguments = Array.prototype.slice.call(arguments), sCalendar, sKey;
1386
- if (aArguments[0].indexOf('ca-') == 0) {
1387
- sCalendar = aArguments[0];
1388
- if (sCalendar == getCLDRCalendarName()) {
1389
- aArguments = aArguments.slice(1);
1390
- }
1391
- }
1392
- sKey = aArguments.join('-');
1393
- var vValue = this.mCustomData[sKey];
1394
- if (vValue == null) {
1395
- vValue = this._getDeep(this.mCustomData, arguments);
1396
- if (vValue == null) {
1397
- vValue = this._getDeep(this.mData, arguments);
1398
- }
1399
- }
1400
- return vValue;
1401
- },
1402
- _getMerged: function () {
1403
- var mData = this._getDeep(this.mData, arguments);
1404
- var mCustomData = this._getDeep(this.mCustomData, arguments);
1405
- return extend({}, mData, mCustomData);
1406
- },
1407
- getFirstDayOfWeek: function () {
1408
- var sCalendarWeekNumbering = Configuration.getCalendarWeekNumbering();
1409
- if (sCalendarWeekNumbering === CalendarWeekNumbering.Default) {
1410
- return LocaleData.prototype.getFirstDayOfWeek.call(this);
1411
- }
1412
- return CalendarWeekNumbering.getWeekConfigurationValues(sCalendarWeekNumbering).firstDayOfWeek;
1413
- },
1414
- getMinimalDaysInFirstWeek: function () {
1415
- var sCalendarWeekNumbering = Configuration.getCalendarWeekNumbering();
1416
- if (sCalendarWeekNumbering === CalendarWeekNumbering.Default) {
1417
- return LocaleData.prototype.getMinimalDaysInFirstWeek.call(this);
1418
- }
1419
- return CalendarWeekNumbering.getWeekConfigurationValues(sCalendarWeekNumbering).minimalDaysInFirstWeek;
2662
+ return CalendarWeekNumbering.getWeekConfigurationValues(sCalendarWeekNumbering).firstDayOfWeek;
2663
+ },
2664
+ /**
2665
+ * Returns the required minimal number of days for the first week of a year defined by the
2666
+ * calendar week numbering algorithm set in the configuration,
2667
+ * see {@link sap.ui.core.Configuration#setCalendarWeekNumbering}.
2668
+ * If no specific calendar week numbering algorithm is configured the required minimal number
2669
+ * of days for the first week of a year is determined by the current locale,
2670
+ * see {@link sap.ui.core.LocaleData#getMinimalDaysInFirstWeek}.
2671
+ *
2672
+ * @returns {int} The required minimal number of days for the first week of a year
2673
+ * @override sap.ui.core.LocalData#getMinimalDaysInFirstWeek
2674
+ * @since 1.113.0
2675
+ */
2676
+ getMinimalDaysInFirstWeek: function () {
2677
+ var sCalendarWeekNumbering = Configuration.getCalendarWeekNumbering();
2678
+ if (sCalendarWeekNumbering === CalendarWeekNumbering.Default) {
2679
+ return LocaleData.prototype.getMinimalDaysInFirstWeek.call(this);
1420
2680
  }
2681
+ return CalendarWeekNumbering.getWeekConfigurationValues(sCalendarWeekNumbering).minimalDaysInFirstWeek;
2682
+ }
1421
2683
  });
2684
+
2685
+ /**
2686
+ *
2687
+ */
1422
2688
  LocaleData.getInstance = function (oLocale) {
1423
- oLocale = Locale._getCoreLocale(oLocale);
1424
- return oLocale.hasPrivateUseSubtag('sapufmt') ? new CustomLocaleData(oLocale) : new LocaleData(oLocale);
2689
+ oLocale = Locale._getCoreLocale(oLocale);
2690
+ return oLocale.hasPrivateUseSubtag("sapufmt") ? new CustomLocaleData(oLocale) : new LocaleData(oLocale);
1425
2691
  };
1426
2692
  LocaleData._cldrLocales = _cldrLocales;
2693
+ // maps a locale to a map of time zone translations, which maps an IANA time zone ID to the translated time zone
2694
+ // name
2695
+ LocaleData._mTimezoneTranslations = {};
2696
+ const rContainsSymbol = new RegExp("[" + Object.keys(mCLDRSymbols).join("") + "]");
2697
+ const rTextWithOptionalSpacesAtStartAndEnd = /^(\s)?(.*?)(\s)?$/;
2698
+
2699
+ /**
2700
+ * Returns the escaped value if the given value contains CLDR symbols.
2701
+ *
2702
+ * @param {string} [sValue=""]
2703
+ * The value to be checked and escaped if needed; the value must not contain '
2704
+ * @returns {string}
2705
+ * The escaped value; only the string between one optional space at the beginning and at the
2706
+ * end is escaped
2707
+ */
2708
+ LocaleData._escapeIfNeeded = function (sValue) {
2709
+ if (sValue === undefined) {
2710
+ return "";
2711
+ }
2712
+ if (rContainsSymbol.test(sValue)) {
2713
+ return sValue.replace(rTextWithOptionalSpacesAtStartAndEnd, "$1'$2'$3");
2714
+ }
2715
+ return sValue;
2716
+ };
1427
2717
  export default LocaleData;