@nanahoshi/mona-ui 0.23.3 → 0.24.1

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 (110) hide show
  1. package/README.md +1 -0
  2. package/fesm2022/nanahoshi-mona-ui-auto-complete.mjs +2 -0
  3. package/fesm2022/nanahoshi-mona-ui-breadcrumb.mjs +2 -0
  4. package/fesm2022/nanahoshi-mona-ui-button-group.mjs +2 -0
  5. package/fesm2022/nanahoshi-mona-ui-calendar.mjs +13 -11
  6. package/fesm2022/nanahoshi-mona-ui-card.mjs +2 -0
  7. package/fesm2022/nanahoshi-mona-ui-chart.mjs +4 -2
  8. package/fesm2022/nanahoshi-mona-ui-chip.mjs +2 -0
  9. package/fesm2022/nanahoshi-mona-ui-color-gradient.mjs +5 -3
  10. package/fesm2022/nanahoshi-mona-ui-color-palette.mjs +2 -0
  11. package/fesm2022/nanahoshi-mona-ui-color-picker.mjs +2 -0
  12. package/fesm2022/nanahoshi-mona-ui-combo-box.mjs +2 -0
  13. package/fesm2022/nanahoshi-mona-ui-common.mjs +265 -159
  14. package/fesm2022/nanahoshi-mona-ui-date-picker.mjs +2 -0
  15. package/fesm2022/nanahoshi-mona-ui-datetime-picker.mjs +2 -0
  16. package/fesm2022/nanahoshi-mona-ui-dialog.mjs +2 -0
  17. package/fesm2022/nanahoshi-mona-ui-dropdown-list.mjs +2 -0
  18. package/fesm2022/nanahoshi-mona-ui-dropdowns.mjs +5 -3
  19. package/fesm2022/nanahoshi-mona-ui-editor.mjs +5 -3
  20. package/fesm2022/nanahoshi-mona-ui-filter.mjs +3 -1
  21. package/fesm2022/{nanahoshi-mona-ui-grid-grid-footer-row.component-BSVlcB9_.mjs → nanahoshi-mona-ui-grid-grid-footer-row.component-CnPhVIr4.mjs} +2 -2
  22. package/fesm2022/{nanahoshi-mona-ui-grid-grid-list.component-B2pBOuLa.mjs → nanahoshi-mona-ui-grid-grid-list.component-DxY6bfTX.mjs} +4 -4
  23. package/fesm2022/{nanahoshi-mona-ui-grid-grid-row.component-Buf4evf5.mjs → nanahoshi-mona-ui-grid-grid-row.component-CaO5Lae6.mjs} +3 -3
  24. package/fesm2022/{nanahoshi-mona-ui-grid-grid-virtual-list.component-1RdqLEa9.mjs → nanahoshi-mona-ui-grid-grid-virtual-list.component-jNYtqg5B.mjs} +4 -4
  25. package/fesm2022/{nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-DeRc_QcP.mjs → nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-9FtfCutf.mjs} +12 -10
  26. package/fesm2022/nanahoshi-mona-ui-grid.mjs +1 -1
  27. package/fesm2022/nanahoshi-mona-ui-i18n-icu.mjs +888 -0
  28. package/fesm2022/nanahoshi-mona-ui-i18n.mjs +337 -104
  29. package/fesm2022/nanahoshi-mona-ui-internal-list.mjs +2 -0
  30. package/fesm2022/nanahoshi-mona-ui-internal-tree.mjs +2 -0
  31. package/fesm2022/nanahoshi-mona-ui-list-box.mjs +2 -0
  32. package/fesm2022/nanahoshi-mona-ui-locales-ar-sa.mjs +401 -0
  33. package/fesm2022/nanahoshi-mona-ui-locales-de-de.mjs +399 -0
  34. package/fesm2022/nanahoshi-mona-ui-locales-es-es.mjs +399 -0
  35. package/fesm2022/nanahoshi-mona-ui-locales-fr-fr.mjs +399 -0
  36. package/fesm2022/nanahoshi-mona-ui-locales-id-id.mjs +397 -0
  37. package/fesm2022/nanahoshi-mona-ui-locales-it-it.mjs +399 -0
  38. package/fesm2022/nanahoshi-mona-ui-locales-ja-jp.mjs +397 -0
  39. package/fesm2022/nanahoshi-mona-ui-locales-ko-kr.mjs +397 -0
  40. package/fesm2022/nanahoshi-mona-ui-locales-pt-br.mjs +399 -0
  41. package/fesm2022/nanahoshi-mona-ui-locales-ru-ru.mjs +401 -0
  42. package/fesm2022/nanahoshi-mona-ui-locales-tr-tr.mjs +397 -0
  43. package/fesm2022/nanahoshi-mona-ui-locales-zh-cn.mjs +397 -0
  44. package/fesm2022/nanahoshi-mona-ui-locales-zh-tw.mjs +397 -0
  45. package/fesm2022/nanahoshi-mona-ui-locales.mjs +76 -5060
  46. package/fesm2022/nanahoshi-mona-ui-multi-select.mjs +5 -3
  47. package/fesm2022/nanahoshi-mona-ui-notification.mjs +2 -0
  48. package/fesm2022/nanahoshi-mona-ui-numeric-text-box.mjs +299 -167
  49. package/fesm2022/nanahoshi-mona-ui-otp-input.mjs +2 -0
  50. package/fesm2022/nanahoshi-mona-ui-pager.mjs +5 -3
  51. package/fesm2022/nanahoshi-mona-ui-rating.mjs +4 -2
  52. package/fesm2022/nanahoshi-mona-ui-scroll-view.mjs +5 -3
  53. package/fesm2022/nanahoshi-mona-ui-sheet.mjs +2 -0
  54. package/fesm2022/nanahoshi-mona-ui-slider.mjs +2 -0
  55. package/fesm2022/nanahoshi-mona-ui-spinner.mjs +2 -0
  56. package/fesm2022/nanahoshi-mona-ui-split-button.mjs +2 -0
  57. package/fesm2022/nanahoshi-mona-ui-splitter.mjs +2 -0
  58. package/fesm2022/nanahoshi-mona-ui-stepper.mjs +2 -0
  59. package/fesm2022/nanahoshi-mona-ui-tabs.mjs +2 -0
  60. package/fesm2022/nanahoshi-mona-ui-text-box.mjs +2 -0
  61. package/fesm2022/nanahoshi-mona-ui-time-picker.mjs +2 -0
  62. package/fesm2022/nanahoshi-mona-ui-time-selector.mjs +2 -0
  63. package/fesm2022/nanahoshi-mona-ui-window.mjs +2 -0
  64. package/i18n/catalogs/en-US.messages.json +373 -0
  65. package/i18n/icu/package.json +4 -0
  66. package/locales/ar-sa/ar-sa.messages.json +373 -0
  67. package/locales/ar-sa/package.json +4 -0
  68. package/locales/de-de/de-de.messages.json +373 -0
  69. package/locales/de-de/package.json +4 -0
  70. package/locales/es-es/es-es.messages.json +373 -0
  71. package/locales/es-es/package.json +4 -0
  72. package/locales/fr-fr/fr-fr.messages.json +373 -0
  73. package/locales/fr-fr/package.json +4 -0
  74. package/locales/id-id/id-id.messages.json +373 -0
  75. package/locales/id-id/package.json +4 -0
  76. package/locales/it-it/it-it.messages.json +373 -0
  77. package/locales/it-it/package.json +4 -0
  78. package/locales/ja-jp/ja-jp.messages.json +373 -0
  79. package/locales/ja-jp/package.json +4 -0
  80. package/locales/ko-kr/ko-kr.messages.json +373 -0
  81. package/locales/ko-kr/package.json +4 -0
  82. package/locales/pt-br/package.json +4 -0
  83. package/locales/pt-br/pt-br.messages.json +373 -0
  84. package/locales/ru-ru/package.json +4 -0
  85. package/locales/ru-ru/ru-ru.messages.json +373 -0
  86. package/locales/tr-tr/package.json +4 -0
  87. package/locales/tr-tr/tr-tr.messages.json +373 -0
  88. package/locales/zh-cn/package.json +4 -0
  89. package/locales/zh-cn/zh-cn.messages.json +373 -0
  90. package/locales/zh-tw/package.json +4 -0
  91. package/locales/zh-tw/zh-tw.messages.json +373 -0
  92. package/package.json +111 -53
  93. package/types/nanahoshi-mona-ui-common.d.ts +116 -73
  94. package/types/nanahoshi-mona-ui-i18n-icu.d.ts +74 -0
  95. package/types/nanahoshi-mona-ui-i18n.d.ts +108 -6
  96. package/types/nanahoshi-mona-ui-locales-ar-sa.d.ts +379 -0
  97. package/types/nanahoshi-mona-ui-locales-de-de.d.ts +379 -0
  98. package/types/nanahoshi-mona-ui-locales-es-es.d.ts +379 -0
  99. package/types/nanahoshi-mona-ui-locales-fr-fr.d.ts +379 -0
  100. package/types/nanahoshi-mona-ui-locales-id-id.d.ts +379 -0
  101. package/types/nanahoshi-mona-ui-locales-it-it.d.ts +379 -0
  102. package/types/nanahoshi-mona-ui-locales-ja-jp.d.ts +379 -0
  103. package/types/nanahoshi-mona-ui-locales-ko-kr.d.ts +379 -0
  104. package/types/nanahoshi-mona-ui-locales-pt-br.d.ts +379 -0
  105. package/types/nanahoshi-mona-ui-locales-ru-ru.d.ts +379 -0
  106. package/types/nanahoshi-mona-ui-locales-tr-tr.d.ts +379 -0
  107. package/types/nanahoshi-mona-ui-locales-zh-cn.d.ts +379 -0
  108. package/types/nanahoshi-mona-ui-locales-zh-tw.d.ts +379 -0
  109. package/types/nanahoshi-mona-ui-locales.d.ts +30 -4915
  110. package/types/nanahoshi-mona-ui-numeric-text-box.d.ts +113 -37
@@ -0,0 +1,888 @@
1
+ import { isDevMode } from '@angular/core';
2
+ import { formatNumber, MONA_FALLBACK_LOCALE_ID, tryCanonicalizeLocaleId, canonicalizeLocaleId } from '@nanahoshi/mona-ui/i18n';
3
+
4
+ // Generated by scripts/generate-message-parameters.ts from i18n/message-types. Do not edit.
5
+ // Run `npm run generate:message-parameters` after changing a message type.
6
+ /**
7
+ * The parameters of every message, by namespace and key, in the order the message function takes them. A plain
8
+ * string message has `null`.
9
+ */
10
+ const MONA_MESSAGE_PARAMETERS = {
11
+ autoComplete: {
12
+ clear: null
13
+ },
14
+ breadcrumb: {
15
+ breadcrumb: null
16
+ },
17
+ buttonGroup: {
18
+ buttonGroup: null
19
+ },
20
+ calendar: {
21
+ calendarLabel: [{ name: "formattedMonthAndYear", type: "string" }],
22
+ decadeRange: [
23
+ { name: "start", type: "number" },
24
+ { name: "end", type: "number" }
25
+ ],
26
+ decadeViewLabel: [
27
+ { name: "start", type: "number" },
28
+ { name: "end", type: "number" }
29
+ ],
30
+ goToToday: [{ name: "formattedDate", type: "string" }],
31
+ nextDecade: null,
32
+ nextMonth: null,
33
+ nextYear: null,
34
+ previousDecade: null,
35
+ previousMonth: null,
36
+ previousYear: null,
37
+ switchToDecadeView: [{ name: "currentYear", type: "string" }],
38
+ switchToYearView: [{ name: "currentMonthAndYear", type: "string" }],
39
+ today: null,
40
+ yearCellLabel: [{ name: "year", type: "number" }],
41
+ yearViewLabel: [{ name: "year", type: "string" }]
42
+ },
43
+ card: {
44
+ actionsLabel: null
45
+ },
46
+ chart: {
47
+ change: null,
48
+ chart: null,
49
+ chartLegend: null,
50
+ close: null,
51
+ closeAbbreviation: null,
52
+ colorScale: null,
53
+ conversion: null,
54
+ divergingRangeDescription: [
55
+ { name: "title", type: "string" },
56
+ { name: "minimum", type: "string" },
57
+ { name: "midpoint", type: "string" },
58
+ { name: "maximum", type: "string" }
59
+ ],
60
+ dropOff: null,
61
+ falling: null,
62
+ high: null,
63
+ highAbbreviation: null,
64
+ labelValueSeparator: null,
65
+ low: null,
66
+ lowAbbreviation: null,
67
+ noData: null,
68
+ open: null,
69
+ openAbbreviation: null,
70
+ overall: null,
71
+ range: null,
72
+ rangeDescription: [
73
+ { name: "title", type: "string" },
74
+ { name: "minimum", type: "string" },
75
+ { name: "maximum", type: "string" }
76
+ ],
77
+ rising: null,
78
+ runningTotal: null,
79
+ size: null,
80
+ unchanged: null,
81
+ value: null,
82
+ visualIndicatorClamped: null
83
+ },
84
+ chip: {
85
+ removeLabel: [{ name: "label", optional: true, type: "string" }]
86
+ },
87
+ colorGradient: {
88
+ apply: null,
89
+ cancel: null,
90
+ clearColor: null,
91
+ copyAsHex: null,
92
+ copyAsRgb: null,
93
+ copyColor: null,
94
+ currentColor: null,
95
+ previousColor: null,
96
+ saturationAndValue: null,
97
+ saturationAndValueText: [
98
+ { name: "saturation", type: "number" },
99
+ { name: "value", type: "number" }
100
+ ],
101
+ switchColorMode: null
102
+ },
103
+ colorPalette: {
104
+ color: [{ name: "color", type: "string" }],
105
+ colorPalette: null
106
+ },
107
+ colorPicker: {
108
+ clearColor: null,
109
+ colorGradientPicker: null,
110
+ colorPalettePicker: null,
111
+ colorPicker: null
112
+ },
113
+ comboBox: {
114
+ clear: null
115
+ },
116
+ datePicker: {
117
+ datePicker: null,
118
+ openCalendar: null
119
+ },
120
+ dateTimePicker: {
121
+ calendar: null,
122
+ cancel: null,
123
+ date: null,
124
+ dateTimePicker: null,
125
+ openDateTimePicker: null,
126
+ set: null,
127
+ time: null,
128
+ timePicker: null
129
+ },
130
+ dialog: {
131
+ cancel: null,
132
+ closeDialog: null,
133
+ ok: null
134
+ },
135
+ dropdownList: {
136
+ clear: null
137
+ },
138
+ dropdowns: {
139
+ itemPosition: [
140
+ { name: "text", type: "string" },
141
+ { name: "position", type: "number" },
142
+ { name: "total", type: "number" }
143
+ ],
144
+ noResultsFound: null,
145
+ resultsAvailable: [{ name: "count", type: "number" }]
146
+ },
147
+ editor: {
148
+ addColumnAfter: null,
149
+ addColumnBefore: null,
150
+ addHorizontalLine: null,
151
+ addRowAfter: null,
152
+ addRowBefore: null,
153
+ alignCenter: null,
154
+ alignLeft: null,
155
+ alignRight: null,
156
+ altText: null,
157
+ backgroundColor: null,
158
+ bold: null,
159
+ cancel: null,
160
+ codeBlock: null,
161
+ color: null,
162
+ deleteColumn: null,
163
+ deleteRow: null,
164
+ deleteTable: null,
165
+ enterUrl: null,
166
+ fontSize: null,
167
+ format: null,
168
+ heading: [{ name: "level", type: "number" }],
169
+ heightPx: null,
170
+ imageUrl: null,
171
+ indent: null,
172
+ insert: null,
173
+ insertImage: null,
174
+ insertLink: null,
175
+ insertOrderedList: null,
176
+ insertTable: null,
177
+ insertTaskList: null,
178
+ insertUnorderedList: null,
179
+ italic: null,
180
+ justify: null,
181
+ mergeCells: null,
182
+ outdent: null,
183
+ paragraph: null,
184
+ quotation: null,
185
+ redo: null,
186
+ removeLink: null,
187
+ selectFontFamily: null,
188
+ selectFontSize: null,
189
+ splitCell: null,
190
+ strikethrough: null,
191
+ subscript: null,
192
+ superscript: null,
193
+ toggleHeaderRow: null,
194
+ underline: null,
195
+ undo: null,
196
+ widthPx: null
197
+ },
198
+ filter: {
199
+ and: null,
200
+ apply: null,
201
+ clear: null,
202
+ contains: null,
203
+ doesNotContain: null,
204
+ endsWith: null,
205
+ isAfter: null,
206
+ isAfterOrEqualTo: null,
207
+ isBefore: null,
208
+ isBeforeOrEqualTo: null,
209
+ isEmpty: null,
210
+ isEqualTo: null,
211
+ isFalse: null,
212
+ isGreaterThan: null,
213
+ isGreaterThanOrEqualTo: null,
214
+ isLessThan: null,
215
+ isLessThanOrEqualTo: null,
216
+ isNotEmpty: null,
217
+ isNotEqualTo: null,
218
+ isNotNull: null,
219
+ isNotNullOrEmpty: null,
220
+ isNull: null,
221
+ isNullOrEmpty: null,
222
+ isTrue: null,
223
+ or: null,
224
+ startsWith: null
225
+ },
226
+ grid: {
227
+ all: null,
228
+ apply: null,
229
+ cancel: null,
230
+ cancelRowEdit: null,
231
+ columns: null,
232
+ columnsSelected: [{ name: "count", type: "number" }],
233
+ delete: null,
234
+ deleteRowConfirmation: null,
235
+ deleteRowTitle: null,
236
+ dragColumnHeaderToGroup: null,
237
+ edit: null,
238
+ editRow: null,
239
+ fieldValidationError: null,
240
+ filterByColumn: [{ name: "column", type: "string" }],
241
+ filterPlaceholder: null,
242
+ modified: null,
243
+ moveAsNext: null,
244
+ moveAsPrevious: null,
245
+ moveRow: null,
246
+ noData: null,
247
+ remove: null,
248
+ removeRow: null,
249
+ reorderRow: [{ name: "rowNumber", type: "number" }],
250
+ resizeColumn: null,
251
+ rowReorder: null,
252
+ rowReorderDisabled: null,
253
+ rowReorderDisabledEditing: null,
254
+ rowReorderDisabledFiltered: null,
255
+ rowReorderDisabledGrouped: null,
256
+ rowReorderDisabledServerBinding: null,
257
+ rowReorderDisabledSingleRow: null,
258
+ rowReorderDisabledSorted: null,
259
+ rowReorderDisabledVirtualScroll: null,
260
+ rowReorderHandleAriaLabel: [
261
+ { name: "rowLabel", type: "string" },
262
+ { name: "keyboardHint", type: "string" },
263
+ { name: "disabledReason", optional: true, type: "string" }
264
+ ],
265
+ rowReorderKeyboardHint: null,
266
+ rowReorderMoved: [
267
+ { name: "fromRowNumber", type: "number" },
268
+ { name: "toPosition", type: "number" }
269
+ ],
270
+ rowValidationError: null,
271
+ save: null,
272
+ saveRow: null,
273
+ selectAllRows: null,
274
+ selectRow: [{ name: "rowNumber", type: "number" }]
275
+ },
276
+ list: {
277
+ filterList: null,
278
+ noData: null
279
+ },
280
+ listBox: {
281
+ clearSelection: null,
282
+ moveDown: null,
283
+ moveUp: null,
284
+ remove: null,
285
+ transferAllFrom: null,
286
+ transferAllTo: null,
287
+ transferFrom: null,
288
+ transferTo: null
289
+ },
290
+ multiSelect: {
291
+ clear: null,
292
+ itemsCount: [{ name: "count", type: "number" }]
293
+ },
294
+ notification: {
295
+ close: null,
296
+ error: null,
297
+ info: null,
298
+ success: null,
299
+ warning: null
300
+ },
301
+ numericTextBox: {
302
+ decrease: null,
303
+ increase: null
304
+ },
305
+ otpInput: {
306
+ verificationCode: null
307
+ },
308
+ pager: {
309
+ firstPageLabel: null,
310
+ jumpBackwardLabel: [{ name: "pages", type: "number" }],
311
+ jumpForwardLabel: [{ name: "pages", type: "number" }],
312
+ lastPageLabel: null,
313
+ nextPageLabel: null,
314
+ ofText: null,
315
+ pageLabel: [{ name: "page", type: "number" }],
316
+ pageSizeLabel: [{ name: "pageSize", type: "number" }],
317
+ pageStatus: [
318
+ { name: "page", type: "number" },
319
+ { name: "totalPages", type: "number" }
320
+ ],
321
+ pageText: null,
322
+ previousPageLabel: null,
323
+ rangeStatus: [
324
+ { name: "start", type: "number" },
325
+ { name: "end", type: "number" },
326
+ { name: "total", type: "number" }
327
+ ]
328
+ },
329
+ rating: {
330
+ notRated: null,
331
+ valueText: [
332
+ { name: "value", type: "number" },
333
+ { name: "max", type: "number" }
334
+ ]
335
+ },
336
+ scrollView: {
337
+ carousel: null,
338
+ nextPage: null,
339
+ page: [{ name: "current", type: "number" }],
340
+ pageOf: [
341
+ { name: "current", type: "number" },
342
+ { name: "total", type: "number" }
343
+ ],
344
+ previousPage: null,
345
+ scrollPagerNext: null,
346
+ scrollPagerPrevious: null,
347
+ slide: null
348
+ },
349
+ sheet: {
350
+ closeSheet: null
351
+ },
352
+ slider: {
353
+ maximumValue: null,
354
+ minimumValue: null,
355
+ sliderValue: null
356
+ },
357
+ spinner: {
358
+ cancel: null,
359
+ loading: null
360
+ },
361
+ splitButton: {
362
+ menuButtonAriaLabel: null,
363
+ splitButton: [{ name: "text", type: "string" }]
364
+ },
365
+ splitter: {
366
+ collapseDown: null,
367
+ collapseNext: null,
368
+ collapsePrevious: null,
369
+ collapseUp: null,
370
+ resizer: null
371
+ },
372
+ stepper: {
373
+ stepProgress: null,
374
+ stepper: null
375
+ },
376
+ tabs: {
377
+ closeTab: null,
378
+ scrollNext: null,
379
+ scrollPrevious: null
380
+ },
381
+ textBox: {
382
+ clear: null
383
+ },
384
+ timePicker: {
385
+ openTimePicker: null,
386
+ timePicker: null
387
+ },
388
+ timeSelector: {
389
+ am: null,
390
+ amPm: null,
391
+ headerHours: null,
392
+ headerMinutes: null,
393
+ headerSeconds: null,
394
+ hours: null,
395
+ minutes: null,
396
+ now: null,
397
+ pm: null,
398
+ seconds: null,
399
+ set: null,
400
+ timeSelector: null
401
+ },
402
+ treeView: {
403
+ collapse: null,
404
+ expand: null,
405
+ filter: null,
406
+ filterTree: null
407
+ },
408
+ window: {
409
+ close: null,
410
+ closeWindow: null,
411
+ maximize: null,
412
+ minimize: null,
413
+ moveWindow: null,
414
+ resizeBottom: null,
415
+ resizeBottomLeft: null,
416
+ resizeBottomRight: null,
417
+ resizeLeft: null,
418
+ resizeRight: null,
419
+ resizeTop: null,
420
+ resizeTopLeft: null,
421
+ resizeTopRight: null,
422
+ restore: null
423
+ }
424
+ };
425
+
426
+ /** The `select` key that an absent or empty argument selects, before falling back to `other`. */
427
+ const ICU_ABSENT_SELECT_KEY = "undefined";
428
+ const pluralRulesCache = new Map();
429
+ /**
430
+ * Formats a parsed message. Numbers go through `formatNumber`, so they use the locale's digits and grouping, the
431
+ * same as Mona's TypeScript catalogs.
432
+ *
433
+ * - An absent argument (`undefined`) formats as an empty string.
434
+ * - In `select`, an absent or empty argument picks the `undefined` option, then `other`; a present value never
435
+ * picks `undefined`.
436
+ * - In `plural`, an exact `=N` option wins over the value's plural category, which is taken after the offset.
437
+ */
438
+ function formatIcuMessage(elements, values, localeId) {
439
+ return formatElements(elements, values, localeId, null);
440
+ }
441
+ function formatElements(elements, values, localeId, pound) {
442
+ let result = "";
443
+ for (const element of elements) {
444
+ switch (element.kind) {
445
+ case "literal":
446
+ result += element.value;
447
+ break;
448
+ case "argument":
449
+ case "number": {
450
+ const value = values.get(element.name);
451
+ result +=
452
+ typeof value === "number"
453
+ ? formatNumber(value, localeId, element.kind === "number" ? element.options : undefined)
454
+ : (value ?? "");
455
+ break;
456
+ }
457
+ case "pound":
458
+ result += pound == null ? "#" : formatNumber(pound, localeId);
459
+ break;
460
+ case "plural": {
461
+ const value = Number(values.get(element.name));
462
+ const exact = [...element.options].find(([key]) => key.startsWith("=") && Number(key.slice(1)) === value);
463
+ const adjusted = value - element.offset;
464
+ const option = exact?.[1] ??
465
+ element.options.get(getPluralRules(localeId, element.ordinal).select(adjusted)) ??
466
+ element.options.get("other");
467
+ result += formatElements(option, values, localeId, adjusted);
468
+ break;
469
+ }
470
+ case "select": {
471
+ const option = selectOption(element.options, values.get(element.name)) ?? element.options.get("other");
472
+ result += formatElements(option, values, localeId, pound);
473
+ break;
474
+ }
475
+ }
476
+ }
477
+ return result;
478
+ }
479
+ function getPluralRules(localeId, ordinal) {
480
+ const cacheKey = `${ordinal ? "ordinal" : "cardinal"}:${localeId}`;
481
+ let rules = pluralRulesCache.get(cacheKey);
482
+ if (rules == null) {
483
+ rules = new Intl.PluralRules(localeId, { type: ordinal ? "ordinal" : "cardinal" });
484
+ pluralRulesCache.set(cacheKey, rules);
485
+ }
486
+ return rules;
487
+ }
488
+ function selectOption(options, value) {
489
+ if (value == null || value === "") {
490
+ return options.get(ICU_ABSENT_SELECT_KEY);
491
+ }
492
+ const key = String(value);
493
+ return key === ICU_ABSENT_SELECT_KEY ? undefined : options.get(key);
494
+ }
495
+
496
+ /**
497
+ * Parser for the subset of ICU MessageFormat that Mona supports:
498
+ *
499
+ * - `{name}` and `{name, number}`, with the `integer` and `percent` styles and the `::group-off`,
500
+ * `::percent` and `::precision-integer` skeletons
501
+ * - `{name, plural, ...}` and `{name, selectordinal, ...}`, with `=N` and CLDR category selectors, `offset:N`, and `#`
502
+ * - `{name, select, ...}`
503
+ * - apostrophe quoting: `''` is an apostrophe, and `'{'`, `'}'` and, inside a plural, `'#'` are literal
504
+ *
505
+ * Dates, times and other argument types are rejected, because no Mona message takes one.
506
+ */
507
+ class IcuSyntaxError extends Error {
508
+ constructor(message, offset, kind = "syntax") {
509
+ super(`${message} at position ${offset}`);
510
+ this.name = "IcuSyntaxError";
511
+ this.kind = kind;
512
+ this.offset = offset;
513
+ }
514
+ }
515
+ /** Arguments can nest this deep; deeper input is rejected rather than risking a stack overflow. */
516
+ const MAX_DEPTH = 16;
517
+ const PLURAL_CATEGORIES = new Set(["few", "many", "one", "other", "two", "zero"]);
518
+ const IDENTIFIER_REGEX = /[A-Za-z_][A-Za-z0-9_]*/y;
519
+ const KEYWORD_REGEX = /[\p{L}\p{N}_-]+/uy;
520
+ const EXACT_SELECTOR_REGEX = /=-?\d+(?:\.\d+)?/y;
521
+ const OFFSET_REGEX = /offset:\s*(\d+)/y;
522
+ const WHITESPACE_REGEX = /\s*/y;
523
+ const NUMBER_SKELETON_OPTIONS = {
524
+ "group-off": { useGrouping: false },
525
+ percent: { style: "percent" },
526
+ "precision-integer": { maximumFractionDigits: 0 }
527
+ };
528
+ /** Parses an ICU message. Throws an {@link IcuSyntaxError} for input outside the supported subset. */
529
+ function parseIcuMessage(source) {
530
+ const state = { pos: 0, source };
531
+ return parseMessage(state, 0, false, false);
532
+ }
533
+ function expect(state, char) {
534
+ if (state.source[state.pos] !== char) {
535
+ throw new IcuSyntaxError(state.pos >= state.source.length ? `Expected "${char}" but the message ended` : `Expected "${char}"`, state.pos);
536
+ }
537
+ state.pos++;
538
+ }
539
+ function match(state, regex) {
540
+ regex.lastIndex = state.pos;
541
+ const result = regex.exec(state.source);
542
+ if (result != null) {
543
+ state.pos = regex.lastIndex;
544
+ }
545
+ return result;
546
+ }
547
+ function parseArgument(state, depth, inPlural) {
548
+ const start = state.pos;
549
+ if (depth > MAX_DEPTH) {
550
+ throw new IcuSyntaxError(`Arguments are nested more than ${MAX_DEPTH} levels deep`, start);
551
+ }
552
+ expect(state, "{");
553
+ skipWhitespace(state);
554
+ const name = match(state, IDENTIFIER_REGEX)?.[0];
555
+ if (name == null) {
556
+ throw new IcuSyntaxError("Expected an argument name", state.pos);
557
+ }
558
+ skipWhitespace(state);
559
+ if (state.source[state.pos] === "}") {
560
+ state.pos++;
561
+ return { kind: "argument", name };
562
+ }
563
+ expect(state, ",");
564
+ skipWhitespace(state);
565
+ const typeStart = state.pos;
566
+ const type = match(state, IDENTIFIER_REGEX)?.[0];
567
+ skipWhitespace(state);
568
+ switch (type) {
569
+ case "number":
570
+ return parseNumberArgument(state, name);
571
+ case "plural":
572
+ case "selectordinal":
573
+ return parsePluralArgument(state, name, type === "selectordinal", depth, start);
574
+ case "select":
575
+ expect(state, ",");
576
+ return { kind: "select", name, options: parseOptions(state, depth, inPlural, false, start) };
577
+ default:
578
+ throw new IcuSyntaxError(type == null ? "Expected an argument type" : `Unsupported argument type "${type}"`, typeStart);
579
+ }
580
+ }
581
+ function parseMessage(state, depth, inPlural, nested) {
582
+ const { source } = state;
583
+ const elements = [];
584
+ let text = "";
585
+ const flush = () => {
586
+ if (text !== "") {
587
+ elements.push({ kind: "literal", value: text });
588
+ text = "";
589
+ }
590
+ };
591
+ while (state.pos < source.length) {
592
+ const char = source[state.pos];
593
+ if (char === "'") {
594
+ text += readApostrophe(state, inPlural);
595
+ }
596
+ else if (char === "{") {
597
+ flush();
598
+ elements.push(parseArgument(state, depth + 1, inPlural));
599
+ }
600
+ else if (char === "}") {
601
+ if (nested) {
602
+ break;
603
+ }
604
+ throw new IcuSyntaxError('Unexpected "}"', state.pos);
605
+ }
606
+ else if (char === "#" && inPlural) {
607
+ flush();
608
+ elements.push({ kind: "pound" });
609
+ state.pos++;
610
+ }
611
+ else {
612
+ text += char;
613
+ state.pos++;
614
+ }
615
+ }
616
+ flush();
617
+ return elements;
618
+ }
619
+ function parseNumberArgument(state, name) {
620
+ if (state.source[state.pos] === "}") {
621
+ state.pos++;
622
+ return { kind: "number", name };
623
+ }
624
+ expect(state, ",");
625
+ const styleStart = state.pos;
626
+ const end = state.source.indexOf("}", state.pos);
627
+ if (end < 0) {
628
+ throw new IcuSyntaxError('Expected "}" but the message ended', state.source.length);
629
+ }
630
+ const style = state.source.slice(state.pos, end).trim();
631
+ state.pos = end + 1;
632
+ if (style === "integer") {
633
+ return { kind: "number", name, options: NUMBER_SKELETON_OPTIONS["precision-integer"] };
634
+ }
635
+ if (style === "percent") {
636
+ return { kind: "number", name, options: NUMBER_SKELETON_OPTIONS["percent"] };
637
+ }
638
+ if (style.startsWith("::")) {
639
+ let options = {};
640
+ for (const token of style.slice(2).trim().split(/\s+/)) {
641
+ if (!Object.hasOwn(NUMBER_SKELETON_OPTIONS, token)) {
642
+ throw new IcuSyntaxError(`Unsupported number skeleton "${token}"`, styleStart);
643
+ }
644
+ options = { ...options, ...NUMBER_SKELETON_OPTIONS[token] };
645
+ }
646
+ return { kind: "number", name, options };
647
+ }
648
+ throw new IcuSyntaxError(`Unsupported number style "${style}"`, styleStart);
649
+ }
650
+ /**
651
+ * Parses the `selector {message}` pairs that follow the comma after the argument type (and offset), up to and including the argument's closing brace. Every plural and select must
652
+ * have an `other` option, which is used when no other selector matches.
653
+ */
654
+ function parseOptions(state, depth, inPlural, plural, argumentStart) {
655
+ skipWhitespace(state);
656
+ const options = new Map();
657
+ while (state.source[state.pos] !== "}") {
658
+ if (state.pos >= state.source.length) {
659
+ throw new IcuSyntaxError('Expected "}" but the message ended', state.pos);
660
+ }
661
+ const selectorStart = state.pos;
662
+ const selector = (plural ? match(state, EXACT_SELECTOR_REGEX)?.[0] : undefined) ?? match(state, KEYWORD_REGEX)?.[0];
663
+ if (selector == null) {
664
+ throw new IcuSyntaxError("Expected a selector", selectorStart);
665
+ }
666
+ if (plural && !selector.startsWith("=") && !PLURAL_CATEGORIES.has(selector)) {
667
+ throw new IcuSyntaxError(`Unknown plural category "${selector}"`, selectorStart);
668
+ }
669
+ if (options.has(selector)) {
670
+ throw new IcuSyntaxError(`Duplicate selector "${selector}"`, selectorStart);
671
+ }
672
+ skipWhitespace(state);
673
+ expect(state, "{");
674
+ options.set(selector, parseMessage(state, depth, inPlural || plural, true));
675
+ expect(state, "}");
676
+ skipWhitespace(state);
677
+ }
678
+ state.pos++;
679
+ if (!options.has("other")) {
680
+ throw new IcuSyntaxError('Missing the "other" option', argumentStart, "missing-other");
681
+ }
682
+ return options;
683
+ }
684
+ function parsePluralArgument(state, name, ordinal, depth, argumentStart) {
685
+ expect(state, ",");
686
+ skipWhitespace(state);
687
+ const offset = Number(match(state, OFFSET_REGEX)?.[1] ?? 0);
688
+ return { kind: "plural", name, offset, options: parseOptions(state, depth, true, true, argumentStart), ordinal };
689
+ }
690
+ /**
691
+ * Reads apostrophe quoting at the current position. `''` is one apostrophe. An apostrophe before `{`, `}`, or `#`
692
+ * inside a plural starts quoted text, which ends at the next single apostrophe. Any other apostrophe is literal.
693
+ */
694
+ function readApostrophe(state, inPlural) {
695
+ const { source } = state;
696
+ const next = source[state.pos + 1];
697
+ if (next === "'") {
698
+ state.pos += 2;
699
+ return "'";
700
+ }
701
+ if (next !== "{" && next !== "}" && !(next === "#" && inPlural)) {
702
+ state.pos++;
703
+ return "'";
704
+ }
705
+ state.pos++;
706
+ let text = "";
707
+ while (state.pos < source.length) {
708
+ if (source[state.pos] === "'") {
709
+ if (source[state.pos + 1] === "'") {
710
+ text += "'";
711
+ state.pos += 2;
712
+ continue;
713
+ }
714
+ state.pos++;
715
+ break;
716
+ }
717
+ text += source[state.pos];
718
+ state.pos++;
719
+ }
720
+ return text;
721
+ }
722
+ function skipWhitespace(state) {
723
+ match(state, WHITESPACE_REGEX);
724
+ }
725
+
726
+ /** Thrown by `compileMonaLocale` in strict mode when the data has issues. */
727
+ class MonaLocaleDataError extends Error {
728
+ constructor(issues) {
729
+ super(`[mona-ui] The locale data has ${issues.length} issue(s):\n` +
730
+ issues.map(issue => `- ${issue.path || "(root)"}: ${issue.message}`).join("\n"));
731
+ this.name = "MonaLocaleDataError";
732
+ this.issues = issues;
733
+ }
734
+ }
735
+ /**
736
+ * Compiles locale data, such as a JSON catalog from a translation-management system, into a `MonaLocale`. Messages
737
+ * with parameters become functions; plain messages become strings.
738
+ *
739
+ * By default, a message with an issue (an unknown key or parameter, or a syntax error) is skipped, so components
740
+ * show their English default for it, and a dev-mode warning lists the issues. With `{ strict: true }`, any issue
741
+ * throws a {@link MonaLocaleDataError} instead.
742
+ *
743
+ * ```ts
744
+ * provideMonaI18n({
745
+ * loadLocale: id => fetch(`/i18n/${id}.json`).then(r => r.json()).then(data => compileMonaLocale(data))
746
+ * });
747
+ * ```
748
+ */
749
+ function compileMonaLocale(data, options) {
750
+ const { issues, locale } = analyzeLocaleData(data);
751
+ if (issues.length > 0) {
752
+ if (options?.strict === true) {
753
+ throw new MonaLocaleDataError(issues);
754
+ }
755
+ if (isDevMode()) {
756
+ console.warn(`[mona-ui] compileMonaLocale skipped what it could not compile; those messages fall back to English.`, issues);
757
+ }
758
+ }
759
+ return locale;
760
+ }
761
+ /**
762
+ * Checks locale data without compiling it, for example in CI before a catalog exported from a
763
+ * translation-management system ships. Returns every issue; an empty array means the data compiles cleanly.
764
+ */
765
+ function validateMonaLocaleData(data) {
766
+ return analyzeLocaleData(data).issues;
767
+ }
768
+ function analyzeLocaleData(data) {
769
+ const issues = [];
770
+ const report = (code, path, message) => {
771
+ issues.push({ code, message, path });
772
+ };
773
+ if (!isRecord(data)) {
774
+ report("invalid-structure", "", "Locale data must be an object with id, direction and messages.");
775
+ return { issues, locale: { direction: "ltr", id: MONA_FALLBACK_LOCALE_ID, messages: {} } };
776
+ }
777
+ let id = MONA_FALLBACK_LOCALE_ID;
778
+ if (typeof data["id"] === "string" && tryCanonicalizeLocaleId(data["id"]) != null) {
779
+ id = data["id"];
780
+ }
781
+ else {
782
+ report("invalid-id", "id", "id must be a valid BCP 47 locale id, such as de-DE.");
783
+ }
784
+ let direction = "ltr";
785
+ if (data["direction"] === "ltr" || data["direction"] === "rtl") {
786
+ direction = data["direction"];
787
+ }
788
+ else {
789
+ report("invalid-direction", "direction", 'direction must be "ltr" or "rtl".');
790
+ }
791
+ const messages = {};
792
+ const localeId = canonicalizeLocaleId(id);
793
+ const dataMessages = data["messages"];
794
+ if (!isRecord(dataMessages)) {
795
+ report("invalid-structure", "messages", "messages must be an object of namespaces.");
796
+ return { issues, locale: { direction, id, messages: {} } };
797
+ }
798
+ for (const [namespace, namespaceMessages] of Object.entries(dataMessages)) {
799
+ const namespacePath = `messages.${namespace}`;
800
+ if (!Object.hasOwn(MONA_MESSAGE_PARAMETERS, namespace)) {
801
+ report("unknown-namespace", namespacePath, `"${namespace}" is not a message namespace.`);
802
+ continue;
803
+ }
804
+ if (!isRecord(namespaceMessages)) {
805
+ report("invalid-structure", namespacePath, "A namespace must be an object of messages.");
806
+ continue;
807
+ }
808
+ const namespaceParameters = MONA_MESSAGE_PARAMETERS[namespace];
809
+ const compiled = {};
810
+ for (const [key, source] of Object.entries(namespaceMessages)) {
811
+ const path = `${namespacePath}.${key}`;
812
+ if (!Object.hasOwn(namespaceParameters, key)) {
813
+ report("unknown-key", path, `"${key}" is not a message of the "${namespace}" namespace.`);
814
+ continue;
815
+ }
816
+ if (typeof source !== "string") {
817
+ report("not-a-string", path, "A message must be a string.");
818
+ continue;
819
+ }
820
+ const message = compileMessage(source, namespaceParameters[key], localeId, path, report);
821
+ if (message !== undefined) {
822
+ compiled[key] = message;
823
+ }
824
+ }
825
+ messages[namespace] = compiled;
826
+ }
827
+ return { issues, locale: { direction, id, messages: messages } };
828
+ }
829
+ function checkArguments(elements, parameters, path, report) {
830
+ let valid = true;
831
+ for (const element of elements) {
832
+ if (element.kind === "literal" || element.kind === "pound") {
833
+ continue;
834
+ }
835
+ const parameter = parameters.find(p => p.name === element.name);
836
+ if (parameter == null) {
837
+ const known = parameters.length === 0 ? "it takes none" : `it takes ${parameters.map(p => p.name).join(", ")}`;
838
+ report("unknown-parameter", path, `"${element.name}" is not a parameter of this message; ${known}.`);
839
+ valid = false;
840
+ continue;
841
+ }
842
+ if ((element.kind === "number" || element.kind === "plural") && parameter.type !== "number") {
843
+ report("parameter-type", path, `"${element.name}" is a ${parameter.type}, so it cannot be a ${element.kind}.`);
844
+ valid = false;
845
+ }
846
+ if (element.kind === "plural" || element.kind === "select") {
847
+ for (const option of element.options.values()) {
848
+ valid = checkArguments(option, parameters, path, report) && valid;
849
+ }
850
+ }
851
+ }
852
+ return valid;
853
+ }
854
+ /** Compiles one message to a string or a function, or reports its issues and returns `undefined`. */
855
+ function compileMessage(source, parameters, localeId, path, report) {
856
+ let elements;
857
+ try {
858
+ elements = parseIcuMessage(source);
859
+ }
860
+ catch (error) {
861
+ if (error instanceof IcuSyntaxError) {
862
+ report(error.kind, path, error.message);
863
+ return undefined;
864
+ }
865
+ throw error;
866
+ }
867
+ if (!checkArguments(elements, parameters ?? [], path, report)) {
868
+ return undefined;
869
+ }
870
+ if (parameters == null) {
871
+ return formatIcuMessage(elements, new Map(), localeId);
872
+ }
873
+ return (...args) => formatIcuMessage(elements, new Map(parameters.map((p, index) => [p.name, args[index]])), localeId);
874
+ }
875
+ function isRecord(value) {
876
+ return typeof value === "object" && value != null && !Array.isArray(value);
877
+ }
878
+
879
+ /*
880
+ * Public API Surface of @nanahoshi/mona-ui/i18n/icu
881
+ */
882
+
883
+ /**
884
+ * Generated bundle index. Do not edit.
885
+ */
886
+
887
+ export { MONA_MESSAGE_PARAMETERS, MonaLocaleDataError, compileMonaLocale, validateMonaLocaleData };
888
+ //# sourceMappingURL=nanahoshi-mona-ui-i18n-icu.mjs.map