niuma-ui 2.0.0 → 2.0.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 (98) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.en.md +1 -1
  3. package/README.md +1 -1
  4. package/dist/brand-icons.css +40 -0
  5. package/dist/components/_shared/src/resolve-radius.js +1 -1
  6. package/dist/components/button/src/RsButton.impl.js +1 -1
  7. package/dist/components/cascader/src/RsCascader.css +20 -20
  8. package/dist/components/cascader/src/RsCascader.js +1 -1
  9. package/dist/components/code-block/src/RsCodeBlock.d.ts +1 -1
  10. package/dist/components/code-editor/src/code-editor-utils.js +2 -2
  11. package/dist/components/code-editor/src/code-mirror-lang.js +1 -1
  12. package/dist/components/config-provider/src/RsConfigProvider.css +2 -2
  13. package/dist/components/config-provider/src/RsConfigProvider.d.ts +6 -3
  14. package/dist/components/config-provider/src/RsConfigProvider.impl.js +47 -7
  15. package/dist/components/config-provider/src/RsConfigProvider.js +1 -1
  16. package/dist/components/context-menu/src/RsContextMenu.css +2 -2
  17. package/dist/components/date-picker/src/RsDatePicker.css +17 -17
  18. package/dist/components/date-picker/src/RsDatePicker.impl.js +1 -1
  19. package/dist/components/date-picker/src/RsDatePicker.js +1 -1
  20. package/dist/components/dialog/src/RsDialog.css +1 -2
  21. package/dist/components/divider/src/RsDivider.css +13 -13
  22. package/dist/components/divider/src/RsDivider.js +1 -1
  23. package/dist/components/drawer/src/RsDrawer.css +2 -4
  24. package/dist/components/dropdown/src/RsDropdown.css +2 -2
  25. package/dist/components/dropdown/src/RsDropdownItemView.impl.js +1 -1
  26. package/dist/components/icon/src/RsIcon.css +4 -4
  27. package/dist/components/icon/src/RsIcon.impl.js +6 -1
  28. package/dist/components/icon/src/RsIcon.js +1 -1
  29. package/dist/components/input/src/RsInput.css +86 -86
  30. package/dist/components/input/src/RsInput.js +1 -1
  31. package/dist/components/input-number/src/RsInputNumber.css +32 -32
  32. package/dist/components/input-number/src/RsInputNumber.js +1 -1
  33. package/dist/components/label/src/RsLabel.css +7 -7
  34. package/dist/components/label/src/RsLabel.js +1 -1
  35. package/dist/components/loading-bar/src/RsLoadingBar.css +4 -5
  36. package/dist/components/loading-bar/src/RsLoadingBar.js +1 -1
  37. package/dist/components/log/src/RsLog.css +39 -39
  38. package/dist/components/log/src/RsLog.d.ts +1 -1
  39. package/dist/components/log/src/RsLog.impl.js +1 -1
  40. package/dist/components/log/src/RsLog.js +1 -1
  41. package/dist/components/markdown/src/RsMarkdown.css +9 -7
  42. package/dist/components/menu/src/RsMenu.css +5 -5
  43. package/dist/components/pagination/src/RsPagination.css +18 -18
  44. package/dist/components/pagination/src/RsPagination.impl.js +1 -1
  45. package/dist/components/pagination/src/RsPagination.js +1 -1
  46. package/dist/components/select/src/RsSelect.css +42 -42
  47. package/dist/components/select/src/RsSelect.impl.js +1 -1
  48. package/dist/components/select/src/RsSelect.js +1 -1
  49. package/dist/components/steps/src/RsSteps.css +18 -18
  50. package/dist/components/steps/src/RsSteps.js +1 -1
  51. package/dist/components/switch/src/RsSwitch.css +4 -6
  52. package/dist/components/table/style/rs-table.css +15 -15
  53. package/dist/components/terminal/src/RsTerminal.css +24 -24
  54. package/dist/components/terminal/src/RsTerminal.js +1 -1
  55. package/dist/components/textarea/src/RsTextarea.css +26 -26
  56. package/dist/components/textarea/src/RsTextarea.js +1 -1
  57. package/dist/components/time-picker/src/RsTimePicker.css +20 -20
  58. package/dist/components/time-picker/src/RsTimePicker.impl.js +1 -1
  59. package/dist/components/time-picker/src/RsTimePicker.js +1 -1
  60. package/dist/components/toaster/src/RsToaster.css +6 -6
  61. package/dist/components/toaster/src/RsToaster.impl.js +3 -6
  62. package/dist/components/tree/src/RsTree.css +72 -73
  63. package/dist/components/tree/src/RsTree.js +1 -1
  64. package/dist/components/tree-select/src/RsTreeSelect.css +11 -11
  65. package/dist/components/tree-select/src/RsTreeSelect.js +1 -1
  66. package/dist/components/virtual-list/src/RsVirtualList.css +7 -8
  67. package/dist/components/virtual-list/src/RsVirtualList.js +1 -1
  68. package/dist/composables/createRsDialog.js +4 -3
  69. package/dist/composables/useRsConfig.d.ts +11 -3
  70. package/dist/composables/useRsConfig.js +17 -5
  71. package/dist/composables/useRsI18n.js +2 -2
  72. package/dist/icons/brand.d.ts +6 -0
  73. package/dist/icons/brand.js +26 -0
  74. package/dist/icons/registry.d.ts +2 -0
  75. package/dist/icons/registry.js +2 -1
  76. package/dist/index.d.ts +7 -4
  77. package/dist/index.js +16 -0
  78. package/dist/locale/apply.d.ts +8 -0
  79. package/dist/locale/apply.js +20 -0
  80. package/dist/locale/interpolate.d.ts +4 -3
  81. package/dist/locale/interpolate.js +96 -5
  82. package/dist/locale/messages.d.ts +0 -4
  83. package/dist/locale/messages.js +5 -9
  84. package/dist/locale/registry-public.d.ts +2 -0
  85. package/dist/locale/registry.d.ts +19 -0
  86. package/dist/locale/registry.js +50 -0
  87. package/dist/locale/types.d.ts +11 -2
  88. package/dist/locale/types.js +4 -1
  89. package/dist/styles.css +245 -250
  90. package/dist/theme/apply.d.ts +15 -3
  91. package/dist/theme/apply.js +41 -4
  92. package/dist/theme/brand.example.css +5 -1
  93. package/dist/theme/presets.d.ts +6 -5
  94. package/dist/theme/presets.js +4 -3
  95. package/dist/theme/types.d.ts +15 -7
  96. package/dist/theme/types.js +4 -1
  97. package/dist/vite-plugins/niuma-ui-host.js +7 -0
  98. package/package.json +2 -1
@@ -1,4 +1,5 @@
1
1
  import { LUCIDE_ATTRIBUTION, LUCIDE_LICENSE, isRsIconName, lucideIconCount, resolveLucideIcon } from "./lucide.js";
2
+ import { isRsBrandIconName, rsBrandIconAccentVar, rsBrandIconNames } from "./brand.js";
2
3
  //#region src/icons/registry.ts
3
4
  /** Playground / 文档常用图标(Lucide 全库约 1600+;kebab-case,如 `house`、`trash-2`) */
4
5
  var rsCommonIconNames = [
@@ -28,4 +29,4 @@ var rsCommonIconNames = [
28
29
  "shield-check"
29
30
  ];
30
31
  //#endregion
31
- export { LUCIDE_ATTRIBUTION, LUCIDE_LICENSE, isRsIconName, lucideIconCount, resolveLucideIcon, rsCommonIconNames };
32
+ export { LUCIDE_ATTRIBUTION, LUCIDE_LICENSE, isRsBrandIconName, isRsIconName, lucideIconCount, resolveLucideIcon, rsBrandIconAccentVar, rsBrandIconNames, rsCommonIconNames };
package/dist/index.d.ts CHANGED
@@ -214,13 +214,16 @@ export { useRsI18n, createTranslator } from './composables/useRsI18n';
214
214
  export type { RsTranslateFn } from './composables/useRsI18n';
215
215
  export { useRsToast } from './composables/useRsToast';
216
216
  export type { RsToastInput } from './composables/useRsToast';
217
- export { rsCommonIconNames, LUCIDE_ATTRIBUTION, LUCIDE_LICENSE, lucideIconCount, isRsIconName, } from './icons/registry';
218
- export type { RsThemeMode, RsThemeTokens, RsComponentSize, RsRadius, RsFontSize, RsFontWeight, } from './theme/types';
217
+ export { rsCommonIconNames, rsBrandIconNames, rsBrandIconAccentVar, LUCIDE_ATTRIBUTION, LUCIDE_LICENSE, lucideIconCount, isRsIconName, isRsBrandIconName, } from './icons/registry';
218
+ export type { RsBrandIconName } from './icons/registry';
219
+ export type { RsThemeMode, RsResolvedTheme, RsThemeTokens, RsComponentSize, RsRadius, RsFontSize, RsFontWeight, } from './theme/types';
219
220
  export { RS_COMPONENT_SIZES, RS_COMPONENT_SIZE_ICON_PX, RS_RADII, RS_RADIUS_CSS, RS_FONT_SIZES, RS_FONT_SIZE_CSS, RS_FONT_WEIGHTS, RS_FONT_WEIGHT_CSS, } from './theme/types';
220
- export type { RsLocale } from './locale/types';
221
+ export type { RsBuiltinLocale, RsDirMode, RsLocale, RsLocaleMessages, RsTextDirection, } from './locale/types';
222
+ export { defaultLocale, fallbackLocale } from './locale/types';
223
+ export { applyLocale, inferRsLocaleDir, isRsLocaleRegistered, listRsLocales, registerRsLocale, resolveRsLocaleDir, resolveRsMessage, } from './locale/registry-public';
221
224
  export { useRsConfig, useRsConfigOptional, createRsConfigState } from './composables/useRsConfig';
222
225
  export { useResolvedRsComponentSize, resolveRsComponentSize } from './components/_shared';
223
226
  export { useResolvedRsRadius, rsRadiusCss } from './components/_shared';
224
227
  export { themePresets } from './theme/presets';
225
- export { applyTheme } from './theme/apply';
228
+ export { applyTheme, prefersColorSchemeDark, readResolvedTheme, resolveThemeMode, subscribePreferredColorScheme, } from './theme/apply';
226
229
  export { parseCssLengthToPx, readCodeFontFamily, readCodeFontSizePx, readCssLengthPx, readCssVar, readRootFontSizePx, readTerminalFontFamily, readTerminalFontSizePx, readTerminalFontWeight, readTerminalFontWeightBold, } from './theme/css-token';
package/dist/index.js CHANGED
@@ -129,6 +129,7 @@ export { default as RsVirtualList } from './components/virtual-list/src/RsVirtua
129
129
  export { TIME_HOUR_OPTIONS } from './components/time-picker/src/time-picker-utils.js'
130
130
  export { TIME_SECOND_OPTIONS } from './components/time-picker/src/time-picker-utils.js'
131
131
  export { aggregateColumnSummary } from './components/table/src/utils/table-summary-utils.js'
132
+ export { applyLocale } from './locale/apply.js'
132
133
  export { applyMonacoDebugDecorations } from './monaco/debug-decorations2.js'
133
134
  export { applySplitResize } from './components/split-pane/src/split-pane-utils.js'
134
135
  export { applyTheme } from './theme/apply.js'
@@ -182,11 +183,13 @@ export { createRsTableViewContext } from './components/table/src/context/rs-tabl
182
183
  export { createToolbarTableFeature } from './components/table/src/features/table-features.js'
183
184
  export { createTranslator } from './composables/useRsI18n.js'
184
185
  export { createUploadFileFromContent } from './components/upload/src/upload-utils.js'
186
+ export { defaultLocale } from './locale/types.js'
185
187
  export { defaultTreeFilterNode } from './components/tree/src/tree-utils.js'
186
188
  export { downloadUploadFile } from './components/upload/src/upload-utils.js'
187
189
  export { ensureMongodbShellLanguage } from './monaco/languages/mongodb-shell.js'
188
190
  export { escapeHtml } from './components/markdown/src/markdown-utils.js'
189
191
  export { expandSplitPane } from './components/split-pane/src/split-pane-utils.js'
192
+ export { fallbackLocale } from './locale/types.js'
190
193
  export { filterLogLines } from './components/log/src/log-utils.js'
191
194
  export { filterTableRows } from './components/table/src/utils/table-utils.js'
192
195
  export { filterTableTreeRows } from './components/table/src/utils/table-utils.js'
@@ -239,6 +242,7 @@ export { hasTableTreeChildren } from './components/table/src/utils/table-utils.j
239
242
  export { hasTreeChildren } from './components/tree/src/tree-utils.js'
240
243
  export { hrefToAnchorId } from './components/anchor/src/anchor-utils.js'
241
244
  export { inferLogLevel } from './components/log/src/log-utils.js'
245
+ export { inferRsLocaleDir } from './locale/registry.js'
242
246
  export { injectExpandRows } from './components/table/src/utils/table-utils.js'
243
247
  export { inputRuleMessageKeys } from './components/input/src/input-rules.js'
244
248
  export { isCodeMirrorLightTheme } from './components/code-editor/src/code-mirror-lang.js'
@@ -250,10 +254,12 @@ export { isIndexSegment } from './components/form/src/form-path.js'
250
254
  export { isNearScrollBottom } from './components/table/src/utils/table-utils.js'
251
255
  export { isNullDraft } from './components/table/src/utils/table-edit-utils.js'
252
256
  export { isNumberInputInterim } from './components/input-number/src/input-number-utils.js'
257
+ export { isRsBrandIconName } from './icons/brand.js'
253
258
  export { isRsButtonFilledVariant } from './components/button/src/button-utils.js'
254
259
  export { isRsDialogWidthPreset } from './components/dialog/src/dialog-utils.js'
255
260
  export { isRsFormItemBoundControl } from './components/form/src/form-utils.js'
256
261
  export { isRsIconName } from './icons/lucide.js'
262
+ export { isRsLocaleRegistered } from './locale/registry.js'
257
263
  export { isRsLogLevel } from './components/log/src/log-utils.js'
258
264
  export { isRsSplitPaneAutoSize } from './components/split-pane/src/split-pane-utils.js'
259
265
  export { isRsTableApi } from './components/table/src/rs-table-api.js'
@@ -273,6 +279,7 @@ export { isTreeAncestorKey } from './components/tree/src/tree-utils.js'
273
279
  export { joinLogLines } from './components/log/src/log-utils.js'
274
280
  export { listBatchColumnTargets } from './components/table/src/utils/table-edit-utils.js'
275
281
  export { listEditableCells } from './components/table/src/utils/table-edit-utils.js'
282
+ export { listRsLocales } from './locale/registry.js'
276
283
  export { looksLikeIsoDateTimeWithTz } from './utils/iso-local-datetime.js'
277
284
  export { lucideIconCount } from './icons/lucide.js'
278
285
  export { mapRsTableSeriesToEChartsOption } from './components/table/src/utils/rs-table-echarts-adapter.js'
@@ -305,6 +312,7 @@ export { parseRsLogLevel } from './components/log/src/log-utils.js'
305
312
  export { parseTimeValue } from './components/time-picker/src/time-picker-utils.js'
306
313
  export { pickActiveAnchorHref } from './components/anchor/src/anchor-utils.js'
307
314
  export { placeAnchoredPopup } from './components/_shared/src/overlay-utils.js'
315
+ export { prefersColorSchemeDark } from './theme/apply.js'
308
316
  export { prefetchClipboardText } from './utils/rs-clipboard.js'
309
317
  export { prewarmCodeMirrorEditor } from './components/code-editor/src/code-mirror-lang.js'
310
318
  export { provideRsFormItemContext } from './components/form/src/form-utils.js'
@@ -316,12 +324,14 @@ export { readCodeFontSizePx } from './theme/css-token.js'
316
324
  export { readCssLengthPx } from './theme/css-token.js'
317
325
  export { readCssVar } from './theme/css-token.js'
318
326
  export { readDocumentTheme } from './components/code-editor/src/code-editor-utils.js'
327
+ export { readResolvedTheme } from './theme/apply.js'
319
328
  export { readRootFontSizePx } from './theme/css-token.js'
320
329
  export { readTerminalFontFamily } from './theme/css-token.js'
321
330
  export { readTerminalFontSizePx } from './theme/css-token.js'
322
331
  export { readTerminalFontWeight } from './theme/css-token.js'
323
332
  export { readTerminalFontWeightBold } from './theme/css-token.js'
324
333
  export { readTerminalThemeFromCss } from './components/terminal/src/terminal-utils.js'
334
+ export { registerRsLocale } from './locale/registry.js'
325
335
  export { removeUploadFileAt } from './components/upload/src/upload-utils.js'
326
336
  export { renderMarkdown } from './components/markdown/src/markdown-utils.js'
327
337
  export { renderMarkdownInline } from './components/markdown/src/markdown-utils.js'
@@ -358,6 +368,8 @@ export { resolveRsDialogWidthPx } from './components/dialog/src/dialog-utils.js'
358
368
  export { resolveRsDrawerDimensionCss } from './components/drawer/src/drawer-utils.js'
359
369
  export { resolveRsDrawerSizeCss } from './components/drawer/src/drawer-utils.js'
360
370
  export { resolveRsDrawerSizePx } from './components/drawer/src/drawer-utils.js'
371
+ export { resolveRsLocaleDir } from './locale/registry.js'
372
+ export { resolveRsMessage } from './locale/registry.js'
361
373
  export { resolveRuleMessage } from './components/form/src/form-rules.js'
362
374
  export { resolveSelectAllState } from './components/table/src/utils/table-utils.js'
363
375
  export { resolveSelectableRowKeys } from './components/table/src/utils/table-utils.js'
@@ -371,6 +383,7 @@ export { resolveTableTreeRowKey } from './components/table/src/utils/table-utils
371
383
  export { resolveTableVirtualEnabled } from './components/table/src/utils/table-utils.js'
372
384
  export { resolveTabsToClose } from './components/tabs/src/tabs-utils.js'
373
385
  export { resolveTerminalTheme } from './components/terminal/src/terminal-utils.js'
386
+ export { resolveThemeMode } from './theme/apply.js'
374
387
  export { resolveTreeCheckState } from './components/tree/src/tree-utils.js'
375
388
  export { resolveTreeFieldNames } from './components/tree/src/tree-utils.js'
376
389
  export { resolveTreeFocusKey } from './components/tree/src/tree-utils.js'
@@ -382,6 +395,8 @@ export { resolveVirtualListHeight } from './components/virtual-list/src/virtual-
382
395
  export { resolveVisibleTabValues } from './components/tabs/src/tabs-utils.js'
383
396
  export { restoreSelectValue } from './components/select/src/select-utils.js'
384
397
  export { roundToPrecision } from './components/input-number/src/input-number-utils.js'
398
+ export { rsBrandIconAccentVar } from './icons/brand.js'
399
+ export { rsBrandIconNames } from './icons/brand.js'
385
400
  export { rsCommonIconNames } from './icons/registry.js'
386
401
  export { rsConfirm } from './composables/createRsDialog.js'
387
402
  export { rsFeedbackIconClass } from './components/_shared/src/overlay-utils.js'
@@ -411,6 +426,7 @@ export { splitSizesEqual } from './components/split-pane/src/split-pane-utils.js
411
426
  export { splitTreeLabelHighlight } from './components/tree/src/tree-utils.js'
412
427
  export { stepEnabledIndex } from './components/_shared/src/overlay-utils.js'
413
428
  export { stepNumberValue } from './components/input-number/src/input-number-utils.js'
429
+ export { subscribePreferredColorScheme } from './theme/apply.js'
414
430
  export { supportsRsButtonTone } from './components/button/src/button-utils.js'
415
431
  export { syslogSeverityOf } from './components/log/src/log-utils.js'
416
432
  export { terminalShortcutLabel } from './components/terminal/src/terminal-utils.js'
@@ -0,0 +1,8 @@
1
+ import { type RsDirMode, type RsLocale, type RsTextDirection } from './types';
2
+ export declare function resolveDirMode(mode: RsDirMode, locale: RsLocale): RsTextDirection;
3
+ /**
4
+ * 写入语言与书写方向。色值不在这里。
5
+ * `dir` 同时写元素的 HTML `dir` 与 `data-rs-dir`,Portal 跟 document 时才能翻。
6
+ */
7
+ export declare function applyLocale(locale: RsLocale, dir?: RsDirMode, el?: HTMLElement): void;
8
+ export declare function readDocumentLocale(el?: HTMLElement | null): RsLocale;
@@ -0,0 +1,20 @@
1
+ import { dirAttribute, localeAttribute } from "./types.js";
2
+ import { resolveRsLocaleDir } from "./registry.js";
3
+ //#region src/locale/apply.ts
4
+ function resolveDirMode(mode, locale) {
5
+ if (mode === "ltr" || mode === "rtl") return mode;
6
+ return resolveRsLocaleDir(locale);
7
+ }
8
+ /**
9
+ * 写入语言与书写方向。色值不在这里。
10
+ * `dir` 同时写元素的 HTML `dir` 与 `data-rs-dir`,Portal 跟 document 时才能翻。
11
+ */
12
+ function applyLocale(locale, dir = "auto", el = document.documentElement) {
13
+ const resolvedDir = resolveDirMode(dir, locale);
14
+ el.setAttribute(localeAttribute, locale);
15
+ el.setAttribute("lang", locale);
16
+ el.setAttribute("dir", resolvedDir);
17
+ el.setAttribute(dirAttribute, resolvedDir);
18
+ }
19
+ //#endregion
20
+ export { applyLocale, resolveDirMode };
@@ -1,10 +1,11 @@
1
1
  export type RsI18nVars = Record<string, string | number>;
2
2
  export type RsTranslateFn = (key: string, fallbackOrVars?: string | RsI18nVars, vars?: RsI18nVars) => string;
3
3
  /**
4
- * 将文案中的 `{name}` 替换为 vars。
5
- * 对标 Ant Design / vue-i18n 的命名插值。
4
+ * 插值:`{name}` 换成 vars。
5
+ * 复数(ICU 子集):`{count, plural, one {# item} other {# items}}`,
6
+ * 可用 `=0` / `=1`。`#` 换成数字。类别由 `Intl.PluralRules(locale)` 决定。
6
7
  */
7
- export declare function interpolateRsMessage(template: string, vars?: RsI18nVars): string;
8
+ export declare function interpolateRsMessage(template: string, vars?: RsI18nVars, locale?: string): string;
8
9
  /**
9
10
  * 解析 t() 的第 2、3 参:既兼容 `t(key, fallback)`,也支持 `t(key, vars)`。
10
11
  */
@@ -1,15 +1,106 @@
1
1
  //#region src/locale/interpolate.ts
2
+ var PLURAL_HEAD = /^\{(\w+),\s*plural\s*,/;
2
3
  /**
3
- * 将文案中的 `{name}` 替换为 vars。
4
- * 对标 Ant Design / vue-i18n 的命名插值。
4
+ * 插值:`{name}` 换成 vars。
5
+ * 复数(ICU 子集):`{count, plural, one {# item} other {# items}}`,
6
+ * 可用 `=0` / `=1`。`#` 换成数字。类别由 `Intl.PluralRules(locale)` 决定。
5
7
  */
6
- function interpolateRsMessage(template, vars) {
7
- if (!vars) return template;
8
- return template.replace(/\{(\w+)\}/g, (matched, key) => {
8
+ function interpolateRsMessage(template, vars, locale = "en-US") {
9
+ const withPlural = expandPluralBlocks(template, vars, locale);
10
+ if (!vars) return withPlural;
11
+ return withPlural.replace(/\{(\w+)\}/g, (matched, key) => {
9
12
  const value = vars[key];
10
13
  return value == null ? matched : String(value);
11
14
  });
12
15
  }
16
+ function expandPluralBlocks(template, vars, locale) {
17
+ let i = 0;
18
+ let out = "";
19
+ while (i < template.length) {
20
+ if (template[i] !== "{") {
21
+ out += template[i];
22
+ i += 1;
23
+ continue;
24
+ }
25
+ const parsed = parsePluralBlock(template, i);
26
+ if (!parsed) {
27
+ const end = template.indexOf("}", i);
28
+ if (end === -1) {
29
+ out += template.slice(i);
30
+ break;
31
+ }
32
+ out += template.slice(i, end + 1);
33
+ i = end + 1;
34
+ continue;
35
+ }
36
+ const raw = vars?.[parsed.name];
37
+ const n = typeof raw === "number" ? raw : Number(raw);
38
+ const clause = pickPluralClause(locale, n, parsed.clauses);
39
+ const numeral = Number.isFinite(n) ? String(n) : raw == null ? "" : String(raw);
40
+ out += clause.replace(/#/g, numeral);
41
+ i = parsed.end;
42
+ }
43
+ return out;
44
+ }
45
+ function parsePluralBlock(source, start) {
46
+ const head = PLURAL_HEAD.exec(source.slice(start));
47
+ if (!head) return null;
48
+ let i = start + head[0].length;
49
+ const clauses = /* @__PURE__ */ new Map();
50
+ while (i < source.length) {
51
+ while (source[i] === " " || source[i] === "\n" || source[i] === " ") i += 1;
52
+ if (source[i] === "}") return {
53
+ name: head[1],
54
+ clauses,
55
+ end: i + 1
56
+ };
57
+ let selector = "";
58
+ if (source[i] === "=") {
59
+ let j = i + 1;
60
+ while (j < source.length && source[j] >= "0" && source[j] <= "9") j += 1;
61
+ selector = source.slice(i, j);
62
+ i = j;
63
+ } else {
64
+ let j = i;
65
+ while (j < source.length && source[j] >= "a" && source[j] <= "z") j += 1;
66
+ selector = source.slice(i, j);
67
+ i = j;
68
+ }
69
+ if (!selector) return null;
70
+ while (source[i] === " " || source[i] === " ") i += 1;
71
+ if (source[i] !== "{") return null;
72
+ const inner = readBalanced(source, i);
73
+ if (!inner) return null;
74
+ clauses.set(selector, inner.text);
75
+ i = inner.end;
76
+ }
77
+ return null;
78
+ }
79
+ function readBalanced(source, open) {
80
+ if (source[open] !== "{") return null;
81
+ let depth = 0;
82
+ for (let i = open; i < source.length; i += 1) if (source[i] === "{") depth += 1;
83
+ else if (source[i] === "}") {
84
+ depth -= 1;
85
+ if (depth === 0) return {
86
+ text: source.slice(open + 1, i),
87
+ end: i + 1
88
+ };
89
+ }
90
+ return null;
91
+ }
92
+ function pickPluralClause(locale, n, clauses) {
93
+ if (Number.isFinite(n)) {
94
+ const exact = clauses.get(`=${n}`);
95
+ if (exact != null) return exact;
96
+ try {
97
+ const category = new Intl.PluralRules(locale).select(n);
98
+ const matched = clauses.get(category);
99
+ if (matched != null) return matched;
100
+ } catch {}
101
+ }
102
+ return clauses.get("other") ?? "";
103
+ }
13
104
  /**
14
105
  * 解析 t() 的第 2、3 参:既兼容 `t(key, fallback)`,也支持 `t(key, vars)`。
15
106
  */
@@ -1,7 +1,3 @@
1
1
  import type { RsLocaleMessages } from './types';
2
2
  export declare const zhCN: RsLocaleMessages;
3
3
  export declare const enUS: RsLocaleMessages;
4
- export declare const localeMap: {
5
- readonly 'zh-CN': RsLocaleMessages;
6
- readonly 'en-US': RsLocaleMessages;
7
- };
@@ -70,7 +70,7 @@ var zhCN = {
70
70
  "pagination.prev": "上一页",
71
71
  "pagination.next": "下一页",
72
72
  "pagination.page": "页",
73
- "pagination.summary": "共 {total} 条",
73
+ "pagination.summary": "{total, plural, other {共 # 条}}",
74
74
  "pagination.jumpTo": "跳至",
75
75
  "pagination.jumpPageSuffix": "页",
76
76
  "pagination.jumpConfirm": "确定",
@@ -167,7 +167,7 @@ var zhCN = {
167
167
  "log.copied": "已复制",
168
168
  "log.copyFailed": "复制失败,请用 HTTPS 或手动选择正文",
169
169
  "log.filter": "按级别过滤",
170
- "log.newLines": "新增 {count} 行",
170
+ "log.newLines": "{count, plural, other {新增 # 行}}",
171
171
  "log.lineNo": "第 {n} 行",
172
172
  "log.level.trace": "跟踪",
173
173
  "log.level.debug": "调试",
@@ -303,7 +303,7 @@ var enUS = {
303
303
  "pagination.prev": "Previous",
304
304
  "pagination.next": "Next",
305
305
  "pagination.page": "page",
306
- "pagination.summary": "Total {total} items",
306
+ "pagination.summary": "{total, plural, one {# item} other {# items}}",
307
307
  "pagination.jumpTo": "Go to",
308
308
  "pagination.jumpPageSuffix": "page",
309
309
  "pagination.jumpConfirm": "Go",
@@ -400,7 +400,7 @@ var enUS = {
400
400
  "log.copied": "Copied",
401
401
  "log.copyFailed": "Copy failed. Use HTTPS or select the log text.",
402
402
  "log.filter": "Filter levels",
403
- "log.newLines": "{count} new lines",
403
+ "log.newLines": "{count, plural, one {# new line} other {# new lines}}",
404
404
  "log.lineNo": "Line {n}",
405
405
  "log.level.trace": "Trace",
406
406
  "log.level.debug": "Debug",
@@ -465,9 +465,5 @@ var enUS = {
465
465
  "markdown.placeholder": "Markdown supported (headings, lists, links, code…)",
466
466
  "markdown.empty": "Nothing to preview"
467
467
  };
468
- var localeMap = {
469
- "zh-CN": zhCN,
470
- "en-US": enUS
471
- };
472
468
  //#endregion
473
- export { enUS, localeMap, zhCN };
469
+ export { enUS, zhCN };
@@ -0,0 +1,2 @@
1
+ export { applyLocale, readDocumentLocale, resolveDirMode } from './apply';
2
+ export { inferRsLocaleDir, isRsLocaleRegistered, listRsLocales, registerRsLocale, resolveRsLocaleDir, resolveRsLocalePack, resolveRsMessage, } from './registry';
@@ -0,0 +1,19 @@
1
+ import { type RsLocale, type RsLocaleMessages, type RsTextDirection } from './types';
2
+ export interface RsLocalePack {
3
+ messages: RsLocaleMessages;
4
+ dir: RsTextDirection;
5
+ }
6
+ export declare function inferRsLocaleDir(code: string): RsTextDirection;
7
+ /**
8
+ * 登记或合并一种语言。第二次调用同码会覆盖已给的 key,并保留未改的 dir(除非这次传了 dir)。
9
+ * 内置 `zh-CN` / `en-US` 启动时已登记;第三方只调这一次即可被 `RsConfigProvider.locale` 使用。
10
+ */
11
+ export declare function registerRsLocale(code: RsLocale, messages: RsLocaleMessages, options?: {
12
+ dir?: RsTextDirection;
13
+ }): void;
14
+ export declare function isRsLocaleRegistered(code: string): boolean;
15
+ export declare function listRsLocales(): string[];
16
+ export declare function resolveRsLocalePack(code: string): RsLocalePack;
17
+ export declare function resolveRsLocaleDir(code: string): RsTextDirection;
18
+ /** 缺 key:当前语言 → en-US → zh-CN。 */
19
+ export declare function resolveRsMessage(code: string, key: string): string | undefined;
@@ -0,0 +1,50 @@
1
+ import { enUS, zhCN } from "./messages.js";
2
+ import "./types.js";
3
+ //#region src/locale/registry.ts
4
+ var packs = /* @__PURE__ */ new Map();
5
+ var RTL_LANG = /* @__PURE__ */ new Set([
6
+ "ar",
7
+ "he",
8
+ "fa",
9
+ "ur",
10
+ "ps",
11
+ "sd",
12
+ "yi"
13
+ ]);
14
+ function inferRsLocaleDir(code) {
15
+ const base = code.trim().split(/[-_]/)[0]?.toLowerCase() ?? "";
16
+ return RTL_LANG.has(base) ? "rtl" : "ltr";
17
+ }
18
+ /**
19
+ * 登记或合并一种语言。第二次调用同码会覆盖已给的 key,并保留未改的 dir(除非这次传了 dir)。
20
+ * 内置 `zh-CN` / `en-US` 启动时已登记;第三方只调这一次即可被 `RsConfigProvider.locale` 使用。
21
+ */
22
+ function registerRsLocale(code, messages, options) {
23
+ const id = code.trim();
24
+ if (!id) throw new Error("registerRsLocale: code is required");
25
+ const prev = packs.get(id);
26
+ packs.set(id, {
27
+ messages: prev ? {
28
+ ...prev.messages,
29
+ ...messages
30
+ } : { ...messages },
31
+ dir: options?.dir ?? prev?.dir ?? inferRsLocaleDir(id)
32
+ });
33
+ }
34
+ function isRsLocaleRegistered(code) {
35
+ return packs.has(code);
36
+ }
37
+ function listRsLocales() {
38
+ return [...packs.keys()];
39
+ }
40
+ function resolveRsLocaleDir(code) {
41
+ return packs.get(code)?.dir ?? inferRsLocaleDir(code);
42
+ }
43
+ /** 缺 key:当前语言 → en-US → zh-CN。 */
44
+ function resolveRsMessage(code, key) {
45
+ return packs.get(code)?.messages[key] ?? packs.get("en-US")?.messages[key] ?? packs.get("zh-CN")?.messages[key];
46
+ }
47
+ registerRsLocale("zh-CN", zhCN, { dir: "ltr" });
48
+ registerRsLocale("en-US", enUS, { dir: "ltr" });
49
+ //#endregion
50
+ export { inferRsLocaleDir, isRsLocaleRegistered, listRsLocales, registerRsLocale, resolveRsLocaleDir, resolveRsMessage };
@@ -1,3 +1,12 @@
1
- export type RsLocale = 'zh-CN' | 'en-US';
1
+ /** 内置语言。第三方用 `registerRsLocale` 加 BCP-47 码。 */
2
+ export type RsBuiltinLocale = 'zh-CN' | 'en-US';
3
+ /** BCP-47。内置码可自动补全;注册后的任意码也合法。 */
4
+ export type RsLocale = RsBuiltinLocale | (string & {});
2
5
  export type RsLocaleMessages = Record<string, string>;
3
- export declare const defaultLocale: RsLocale;
6
+ export type RsTextDirection = 'ltr' | 'rtl';
7
+ /** 书写方向:auto 跟当前 locale 的 dir。 */
8
+ export type RsDirMode = RsTextDirection | 'auto';
9
+ export declare const defaultLocale: RsBuiltinLocale;
10
+ export declare const fallbackLocale: RsBuiltinLocale;
11
+ export declare const localeAttribute = "data-rs-locale";
12
+ export declare const dirAttribute = "data-rs-dir";
@@ -1,4 +1,7 @@
1
1
  //#region src/locale/types.ts
2
2
  var defaultLocale = "zh-CN";
3
+ var fallbackLocale = "en-US";
4
+ var localeAttribute = "data-rs-locale";
5
+ var dirAttribute = "data-rs-dir";
3
6
  //#endregion
4
- export { defaultLocale };
7
+ export { defaultLocale, dirAttribute, fallbackLocale, localeAttribute };