@object-ui/i18n 17.3.0 → 17.5.0
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.
- package/CHANGELOG.md +1295 -1
- package/README.md +0 -13
- package/dist/index.d.ts +3 -1
- package/dist/index.js +11 -1
- package/dist/locales/ar.d.ts +466 -107
- package/dist/locales/ar.js +559 -153
- package/dist/locales/de.d.ts +466 -107
- package/dist/locales/de.js +574 -175
- package/dist/locales/en.d.ts +502 -143
- package/dist/locales/en.js +678 -145
- package/dist/locales/es.d.ts +466 -107
- package/dist/locales/es.js +553 -155
- package/dist/locales/fr.d.ts +466 -107
- package/dist/locales/fr.js +553 -152
- package/dist/locales/index.d.ts +4734 -1144
- package/dist/locales/ja.d.ts +466 -107
- package/dist/locales/ja.js +545 -146
- package/dist/locales/ko.d.ts +466 -107
- package/dist/locales/ko.js +551 -153
- package/dist/locales/pt.d.ts +466 -107
- package/dist/locales/pt.js +552 -154
- package/dist/locales/ru.d.ts +466 -107
- package/dist/locales/ru.js +563 -153
- package/dist/locales/zh.d.ts +501 -142
- package/dist/locales/zh.js +542 -142
- package/dist/pickLocalized.d.ts +21 -0
- package/dist/pickLocalized.js +40 -7
- package/dist/provider.d.ts +83 -1
- package/dist/provider.js +303 -29
- package/dist/useDisplayLocale.d.ts +49 -0
- package/dist/useDisplayLocale.js +55 -0
- package/dist/useObjectLabel.d.ts +8 -2
- package/dist/useObjectLabel.js +28 -8
- package/dist/useSafeTranslation.js +50 -2
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/number-display.d.ts +32 -0
- package/dist/utils/number-display.js +32 -0
- package/dist/utils/spec-formatters.d.ts +39 -13
- package/dist/utils/spec-formatters.js +3 -3
- package/package.json +4 -3
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
import { useLocalization } from './LocalizationContext';
|
|
9
|
+
import { useObjectTranslation } from './provider';
|
|
10
|
+
/**
|
|
11
|
+
* `useDisplayLocale` — the BCP-47 tag that field / cell / metric renderers
|
|
12
|
+
* format numbers and other `Intl` values with.
|
|
13
|
+
*
|
|
14
|
+
* This composes the two locale channels this repo already has; it does not add
|
|
15
|
+
* a third. The precedence, highest first:
|
|
16
|
+
*
|
|
17
|
+
* 1. **`useLocalization().locale`** — the tenant's resolved regional default
|
|
18
|
+
* (ADR-0053, served by `GET /api/v1/auth/me/localization`). An org that has
|
|
19
|
+
* explicitly configured a display locale means it, so it outranks the UI
|
|
20
|
+
* language. Frequently `undefined`: the endpoint is
|
|
21
|
+
* cosmetic and non-blocking, so an unconfigured or still-loading tenant
|
|
22
|
+
* simply has no answer here (the state objectui#4033 was measured in — a
|
|
23
|
+
* fresh database, console running `zh-CN`).
|
|
24
|
+
*
|
|
25
|
+
* 2. **`useObjectTranslation().language`** — the ACTIVE UI language, i.e. what
|
|
26
|
+
* the user picked in the language switcher. This is the channel that makes
|
|
27
|
+
* grouping and decimal marks follow the user's language when the tenant has
|
|
28
|
+
* stated no regional preference.
|
|
29
|
+
*
|
|
30
|
+
* 3. **`'en'`** — a concrete last resort rather than `undefined`. `undefined`
|
|
31
|
+
* would hand `Intl` the *machine's* locale, which is invisible in review and
|
|
32
|
+
* non-deterministic in CI; `'en'` at least fails the same way everywhere.
|
|
33
|
+
* Note this is `'en'`, not `'en-US'`: the point of objectui#4033 is that
|
|
34
|
+
* `en-US` is not the world's default. In practice step 2 already answers,
|
|
35
|
+
* since `useObjectTranslation` falls back to the react-i18next global
|
|
36
|
+
* instance and ultimately reports `'en'` itself.
|
|
37
|
+
*
|
|
38
|
+
* Provider-safe at every step: `useLocalization` returns `{}` outside its
|
|
39
|
+
* provider and `useObjectTranslation` reads an optional context, so a renderer
|
|
40
|
+
* mounted standalone (tests, docs demos) degrades instead of throwing.
|
|
41
|
+
*
|
|
42
|
+
* **This composition is also the whole `'zh'` ↔ BCP-47 story** (objectui#4468).
|
|
43
|
+
* There is no mapping table anywhere and none is needed: the UI language codes
|
|
44
|
+
* this renderer ships (`'zh'`, `'ja'`, `'de'`, …) are already well-formed
|
|
45
|
+
* BCP-47 language subtags, so `Intl` accepts them verbatim. The one thing a
|
|
46
|
+
* caller must not do is reach past this hook for the raw tenant locale and hand
|
|
47
|
+
* `Intl` the `undefined` it gets on an unconfigured workspace — `undefined`
|
|
48
|
+
* means "the MACHINE's locale", which is neither channel. Every date, number
|
|
49
|
+
* and currency renderer goes through here for exactly that reason.
|
|
50
|
+
*/
|
|
51
|
+
export function useDisplayLocale() {
|
|
52
|
+
const { locale } = useLocalization();
|
|
53
|
+
const { language } = useObjectTranslation();
|
|
54
|
+
return locale || language || 'en';
|
|
55
|
+
}
|
package/dist/useObjectLabel.d.ts
CHANGED
|
@@ -151,7 +151,10 @@ export declare function useObjectLabel(): {
|
|
|
151
151
|
}) => string;
|
|
152
152
|
/**
|
|
153
153
|
* Resolve translated list-view label.
|
|
154
|
-
* Convention (per @objectstack/spec): `{ns}.objects.{objectName}._views.{viewName}.label
|
|
154
|
+
* Convention (per @objectstack/spec): `{ns}.objects.{objectName}._views.{viewName}.label`,
|
|
155
|
+
* where `{viewName}` is the **bare** view name — pass either the bare name or
|
|
156
|
+
* the qualified runtime id, the object prefix is stripped either way. A key
|
|
157
|
+
* that spells the prefix out does not resolve (see `viewSuffixes`).
|
|
155
158
|
*/
|
|
156
159
|
viewLabel: (objectName: string, viewName: string, fallback: string) => string;
|
|
157
160
|
/**
|
|
@@ -371,7 +374,10 @@ export declare function useSafeFieldLabel(): {
|
|
|
371
374
|
}) => string;
|
|
372
375
|
/**
|
|
373
376
|
* Resolve translated list-view label.
|
|
374
|
-
* Convention (per @objectstack/spec): `{ns}.objects.{objectName}._views.{viewName}.label
|
|
377
|
+
* Convention (per @objectstack/spec): `{ns}.objects.{objectName}._views.{viewName}.label`,
|
|
378
|
+
* where `{viewName}` is the **bare** view name — pass either the bare name or
|
|
379
|
+
* the qualified runtime id, the object prefix is stripped either way. A key
|
|
380
|
+
* that spells the prefix out does not resolve (see `viewSuffixes`).
|
|
375
381
|
*/
|
|
376
382
|
viewLabel: (objectName: string, viewName: string, fallback: string) => string;
|
|
377
383
|
/**
|
package/dist/useObjectLabel.js
CHANGED
|
@@ -188,19 +188,36 @@ export function useObjectLabel() {
|
|
|
188
188
|
/**
|
|
189
189
|
* Build suffix candidates for a list-view scoped key.
|
|
190
190
|
*
|
|
191
|
-
* The runtime uses qualified view ids (`<objectName>.<viewName>`) in URLs
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
191
|
+
* The runtime uses qualified view ids (`<objectName>.<viewName>`) in URLs and
|
|
192
|
+
* metadata records, while translation bundles are keyed by the **bare** view
|
|
193
|
+
* name under `_views` — the runtime view identity's own name, stripped of the
|
|
194
|
+
* object prefix. That single spelling is canonical per the objectstack#5164
|
|
195
|
+
* ruling A (2026-08-06): the i18n extractor asks the view composer for the key
|
|
196
|
+
* (objectstack#6124) and `packages/lint` enforces exactly that spelling
|
|
197
|
+
* (objectstack#6038), so this resolver accepts exactly what those produce.
|
|
198
|
+
*
|
|
199
|
+
* Deliberately NOT a second candidate: the prefixed full name
|
|
200
|
+
* (`_views.<objectName>.<viewName>`). Accepting it made this client more
|
|
201
|
+
* lenient than the server-side resolver, which only ever reads the one key
|
|
202
|
+
* (objectstack#5165) — a bundle authored against the prefixed spelling showed
|
|
203
|
+
* translated labels in the Console while every consumer that does not run a
|
|
204
|
+
* second resolution pass (REST boundary, mobile, plain HTTP, SDUI) still got
|
|
205
|
+
* English. A prefixed key now simply misses, and the label falls back to the
|
|
206
|
+
* metadata default on every surface alike, so the authoring mistake is visible
|
|
207
|
+
* instead of half-hidden. It is caught at authoring time by `os lint`'s
|
|
208
|
+
* `translation-target-unknown`, not papered over here.
|
|
209
|
+
*
|
|
210
|
+
* The object-name candidates (`objects.<ns__obj>` then `objects.<obj>`) are a
|
|
211
|
+
* separate axis and stay: they let bundles written against short object names
|
|
212
|
+
* resolve when the runtime presents fully-qualified ones.
|
|
195
213
|
*/
|
|
196
214
|
const viewSuffixes = (objectName, viewName, tail) => {
|
|
197
215
|
const objectNames = [objectName, stripNamespace(objectName)];
|
|
198
216
|
const matchedPrefix = objectNames
|
|
199
217
|
.map((name) => `${name}.`)
|
|
200
218
|
.find((prefix) => viewName.startsWith(prefix));
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
return viewNames.flatMap((name) => objectSuffixes(objectName, `_views.${name}.${tail}`));
|
|
219
|
+
const bareViewName = matchedPrefix ? viewName.slice(matchedPrefix.length) : viewName;
|
|
220
|
+
return objectSuffixes(objectName, `_views.${bareViewName}.${tail}`);
|
|
204
221
|
};
|
|
205
222
|
return {
|
|
206
223
|
/**
|
|
@@ -309,7 +326,10 @@ export function useObjectLabel() {
|
|
|
309
326
|
reportLabel: (reportDef) => resolve(reportSuffixes(reportDef.name, 'label'), reportDef.label ?? reportDef.name),
|
|
310
327
|
/**
|
|
311
328
|
* Resolve translated list-view label.
|
|
312
|
-
* Convention (per @objectstack/spec): `{ns}.objects.{objectName}._views.{viewName}.label
|
|
329
|
+
* Convention (per @objectstack/spec): `{ns}.objects.{objectName}._views.{viewName}.label`,
|
|
330
|
+
* where `{viewName}` is the **bare** view name — pass either the bare name or
|
|
331
|
+
* the qualified runtime id, the object prefix is stripped either way. A key
|
|
332
|
+
* that spells the prefix out does not resolve (see `viewSuffixes`).
|
|
313
333
|
*/
|
|
314
334
|
viewLabel: (objectName, viewName, fallback) => resolve(viewSuffixes(objectName, viewName, 'label'), fallback),
|
|
315
335
|
/**
|
|
@@ -3,20 +3,68 @@
|
|
|
3
3
|
*
|
|
4
4
|
* When no I18nProvider is available (e.g., in tests or standalone usage),
|
|
5
5
|
* this hook falls back to the provided default translations instead of
|
|
6
|
-
* returning raw i18n keys
|
|
6
|
+
* returning raw i18n keys — and, for a key the `defaults` map does not carry,
|
|
7
|
+
* to the call site's own inline `t(key, { defaultValue })` (objectui#3865).
|
|
8
|
+
* The lookup order is i18next's, so a provider-less host and a provider-mounted
|
|
9
|
+
* one render the same string: `defaults[key]` (the pack value's stand-in here)
|
|
10
|
+
* -> `defaultValue` -> the key.
|
|
7
11
|
*
|
|
8
12
|
* @param defaults - Fallback English translations keyed by i18n key
|
|
9
13
|
* @param testKey - A key to test if i18n is properly configured (must be in defaults)
|
|
10
14
|
*/
|
|
11
15
|
import { useObjectTranslation } from './provider';
|
|
16
|
+
/**
|
|
17
|
+
* The i18next option that names the string to use when the lookup misses.
|
|
18
|
+
*
|
|
19
|
+
* It is a LOOKUP CONTROL, not interpolation data (objectui#3865): it chooses
|
|
20
|
+
* which string is rendered, so it must never also be spliced into a
|
|
21
|
+
* `{{defaultValue}}` hole in the string it chose — or in any other.
|
|
22
|
+
*/
|
|
23
|
+
const DEFAULT_VALUE_OPTION = 'defaultValue';
|
|
12
24
|
export function createSafeTranslation(defaults, testKey) {
|
|
13
25
|
// Factory-level fallback: one stable reference per defaults map, so
|
|
14
26
|
// downstream useMemo/useCallback deps don't invalidate every render in
|
|
15
27
|
// the no-translations case.
|
|
16
28
|
const fallbackT = (key, options) => {
|
|
17
|
-
|
|
29
|
+
// Lookup order: defaults table -> inline `defaultValue` -> the key itself
|
|
30
|
+
// (objectui#3865). The table is the pack value's stand-in on this path, so
|
|
31
|
+
// it takes the pack's position in i18next's own order — verified against a
|
|
32
|
+
// real i18next 26.3.6 instance configured the way `createI18n` configures
|
|
33
|
+
// it: `t('anchor', { defaultValue: 'INLINE' })` is the pack's `'Anchor
|
|
34
|
+
// value'`, `t('missing', { defaultValue: 'INLINE' })` is `'INLINE'`, and
|
|
35
|
+
// `t('missing')` is `'missing'`.
|
|
36
|
+
//
|
|
37
|
+
// Before this, the inline default was DEAD on both paths for every
|
|
38
|
+
// component behind this factory: the provider path never reaches it
|
|
39
|
+
// (the pack value always wins), and this path did not read it at all —
|
|
40
|
+
// it rendered the raw key and then treated `defaultValue` as one more
|
|
41
|
+
// interpolation variable. A census over all 26 `createSafeTranslation`
|
|
42
|
+
// hooks measured 27 keys whose table lacks them, 21 of those carrying an
|
|
43
|
+
// inline default that used to be dropped (objectui#3865; the fact is
|
|
44
|
+
// recorded on objectui#3810, whose option C rests on it).
|
|
45
|
+
//
|
|
46
|
+
// Non-strings are ignored rather than coerced — this function returns a
|
|
47
|
+
// `string`, and i18next itself declines a `null` default. `||` (not `??`)
|
|
48
|
+
// keeps the whole chain consistent with the pre-existing `defaults[key] ||`
|
|
49
|
+
// step: an empty string at any position falls through to the next.
|
|
50
|
+
const inlineDefault = options?.[DEFAULT_VALUE_OPTION];
|
|
51
|
+
let value = defaults[key] || (typeof inlineDefault === 'string' ? inlineDefault : '') || key;
|
|
18
52
|
if (options) {
|
|
19
53
|
for (const [k, v] of Object.entries(options)) {
|
|
54
|
+
// Reserved: see DEFAULT_VALUE_OPTION. Skipped whatever its type, so an
|
|
55
|
+
// ignored non-string default cannot re-enter through this loop.
|
|
56
|
+
//
|
|
57
|
+
// This is the one deliberate divergence from i18next on this path, and
|
|
58
|
+
// it is unreachable with today's strings: i18next passes the whole
|
|
59
|
+
// options object to its interpolator, so it WOULD render
|
|
60
|
+
// `'Fallback: {{defaultValue}}'` as `'Fallback: INLINE'` (measured on
|
|
61
|
+
// 26.3.6) — but no value in this repo spells that hole (zero hits for
|
|
62
|
+
// `{{defaultValue` across packages/apps/examples), and splicing a
|
|
63
|
+
// fallback string into a hole named after itself has no sensible
|
|
64
|
+
// reading. The alternative — letting a call site's fallback text leak
|
|
65
|
+
// into an unrelated table value — is the worse of the two.
|
|
66
|
+
if (k === DEFAULT_VALUE_OPTION)
|
|
67
|
+
continue;
|
|
20
68
|
// `split(needle).join(value)` — deliberately not `replace`, and not
|
|
21
69
|
// `replaceAll` either (objectui#3418). This path must agree with
|
|
22
70
|
// i18next, which serves the *provider* path; any divergence is a
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { formatDate, formatDateTime, formatRelativeTime, formatCurrency, formatNumber, type DateFormatOptions, type CurrencyFormatOptions, type NumberFormatOptions, } from './formatting';
|
|
2
2
|
export { resolvePlural, formatDateSpec, formatNumberSpec, applyLocaleConfig, type SpecPluralRule, type SpecDateFormat, type SpecNumberFormat, type SpecLocaleConfig, } from './spec-formatters';
|
|
3
3
|
export { isSpecTranslationData, transformSpecTranslations, type SpecTranslationData, } from './spec-translations';
|
|
4
|
+
export { formatDisplayNumber, shouldGroupDisplayNumber, type DisplayNumberFormatOptions, } from './number-display';
|
package/dist/utils/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { formatDate, formatDateTime, formatRelativeTime, formatCurrency, formatNumber, } from './formatting';
|
|
2
2
|
export { resolvePlural, formatDateSpec, formatNumberSpec, applyLocaleConfig, } from './spec-formatters';
|
|
3
3
|
export { isSpecTranslationData, transformSpecTranslations, } from './spec-translations';
|
|
4
|
+
export { formatDisplayNumber, shouldGroupDisplayNumber, } from './number-display';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* RE-EXPORT ONLY — the implementation moved to `@object-ui/core`
|
|
10
|
+
* (`utils/number-display.ts`) in objectui#4576. Read it there; nothing is
|
|
11
|
+
* redeclared here, so there is no second copy to drift.
|
|
12
|
+
*
|
|
13
|
+
* Why it moved: `@object-ui/core`'s `dataset-format.ts` needs this exact
|
|
14
|
+
* policy, and it could not import it while it lived here — `core` is the
|
|
15
|
+
* React-free engine and this package depends on `i18next`/`react-i18next` and
|
|
16
|
+
* peer-depends on React. So `formatMeasure` kept a parallel `Intl`
|
|
17
|
+
* implementation, and the two drifted apart in the one place `Intl` and a
|
|
18
|
+
* hand-built string disagree: a German session read `1.234,5 %` from a list
|
|
19
|
+
* cell beside `1.234,5%` from a dashboard measure (objectui#4576). The function
|
|
20
|
+
* is pure, so the boundary was never a property of the code — only of where the
|
|
21
|
+
* code sat. Moving it DOWN removed the obstacle; this package gained a
|
|
22
|
+
* dependency on `@object-ui/core` (no cycle: `core` imports nothing from here).
|
|
23
|
+
*
|
|
24
|
+
* This file survives as a re-export rather than being deleted so that BOTH
|
|
25
|
+
* historical import paths keep working byte-compatibly — the package entry
|
|
26
|
+
* (`@object-ui/i18n`, used by `fields`, `components` and `plugin-dashboard`)
|
|
27
|
+
* and the relative `../utils/number-display` this package's own suite uses.
|
|
28
|
+
* `number-display.reexport-identity.test.ts` pins that the two paths resolve to
|
|
29
|
+
* the SAME function object and the same type, so a future edit cannot quietly
|
|
30
|
+
* reintroduce a copy.
|
|
31
|
+
*/
|
|
32
|
+
export { formatDisplayNumber, shouldGroupDisplayNumber, type DisplayNumberFormatOptions, } from '@object-ui/core';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* RE-EXPORT ONLY — the implementation moved to `@object-ui/core`
|
|
10
|
+
* (`utils/number-display.ts`) in objectui#4576. Read it there; nothing is
|
|
11
|
+
* redeclared here, so there is no second copy to drift.
|
|
12
|
+
*
|
|
13
|
+
* Why it moved: `@object-ui/core`'s `dataset-format.ts` needs this exact
|
|
14
|
+
* policy, and it could not import it while it lived here — `core` is the
|
|
15
|
+
* React-free engine and this package depends on `i18next`/`react-i18next` and
|
|
16
|
+
* peer-depends on React. So `formatMeasure` kept a parallel `Intl`
|
|
17
|
+
* implementation, and the two drifted apart in the one place `Intl` and a
|
|
18
|
+
* hand-built string disagree: a German session read `1.234,5 %` from a list
|
|
19
|
+
* cell beside `1.234,5%` from a dashboard measure (objectui#4576). The function
|
|
20
|
+
* is pure, so the boundary was never a property of the code — only of where the
|
|
21
|
+
* code sat. Moving it DOWN removed the obstacle; this package gained a
|
|
22
|
+
* dependency on `@object-ui/core` (no cycle: `core` imports nothing from here).
|
|
23
|
+
*
|
|
24
|
+
* This file survives as a re-export rather than being deleted so that BOTH
|
|
25
|
+
* historical import paths keep working byte-compatibly — the package entry
|
|
26
|
+
* (`@object-ui/i18n`, used by `fields`, `components` and `plugin-dashboard`)
|
|
27
|
+
* and the relative `../utils/number-display` this package's own suite uses.
|
|
28
|
+
* `number-display.reexport-identity.test.ts` pins that the two paths resolve to
|
|
29
|
+
* the SAME function object and the same type, so a future edit cannot quietly
|
|
30
|
+
* reintroduce a copy.
|
|
31
|
+
*/
|
|
32
|
+
export { formatDisplayNumber, shouldGroupDisplayNumber, } from '@object-ui/core';
|
|
@@ -6,18 +6,33 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
|
-
* @object-ui/i18n -
|
|
9
|
+
* @object-ui/i18n - locale formatting helpers
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* -
|
|
11
|
+
* ## Provenance of the four shapes below (objectui#4597)
|
|
12
|
+
*
|
|
13
|
+
* They were authored against `@objectstack/spec/ui`, which exported
|
|
14
|
+
* `PluralRuleSchema`, `DateFormatSchema`, `NumberFormatSchema` and
|
|
15
|
+
* `LocaleConfigSchema` up to and including 17.0.0-rc.5. The pinned
|
|
16
|
+
* 17.0.0-rc.6 removed all four under ADR-0049 enforce-or-remove
|
|
17
|
+
* (objectstack#5055, maintainer ruling 2026-08-06): they carried no key on any
|
|
18
|
+
* authorable shape and nothing ever parsed them, so the vocabulary was retired
|
|
19
|
+
* rather than given a door. The key sets here were faithful to the retired
|
|
20
|
+
* schemas — this is a retirement, not a drift.
|
|
21
|
+
*
|
|
22
|
+
* Nothing in the pinned protocol models locale formatting today, so the
|
|
23
|
+
* interfaces below are declarations this package owns outright, not a view onto
|
|
24
|
+
* a protocol type. The retirement note records that localisation returns as
|
|
25
|
+
* authorable metadata through a new ADR — "the formatter that reads a
|
|
26
|
+
* LocaleConfig first, the vocabulary second" — so re-derive these at that point
|
|
27
|
+
* instead of assuming they still track anything upstream.
|
|
16
28
|
*
|
|
17
29
|
* @module spec-formatters
|
|
18
30
|
*/
|
|
19
31
|
/**
|
|
20
|
-
*
|
|
32
|
+
* Plural forms for a single translation key, in CLDR categories.
|
|
33
|
+
*
|
|
34
|
+
* Local shape — authored against the protocol's `PluralRuleSchema`, retired in
|
|
35
|
+
* 17.0.0-rc.6 (see the module doc), so there is nothing upstream to derive from.
|
|
21
36
|
*/
|
|
22
37
|
export interface SpecPluralRule {
|
|
23
38
|
/** Translation key */
|
|
@@ -54,7 +69,10 @@ export interface SpecPluralRule {
|
|
|
54
69
|
*/
|
|
55
70
|
export declare function resolvePlural(rule: SpecPluralRule, count: number, locale?: string): string;
|
|
56
71
|
/**
|
|
57
|
-
*
|
|
72
|
+
* Date/time formatting options passed through to `Intl.DateTimeFormat`.
|
|
73
|
+
*
|
|
74
|
+
* Local shape — authored against the protocol's `DateFormatSchema`, retired in
|
|
75
|
+
* 17.0.0-rc.6 (see the module doc), so there is nothing upstream to derive from.
|
|
58
76
|
*/
|
|
59
77
|
export interface SpecDateFormat {
|
|
60
78
|
dateStyle?: 'full' | 'long' | 'medium' | 'short';
|
|
@@ -63,7 +81,7 @@ export interface SpecDateFormat {
|
|
|
63
81
|
hour12?: boolean;
|
|
64
82
|
}
|
|
65
83
|
/**
|
|
66
|
-
* Format a date using @
|
|
84
|
+
* Format a date using a {@link SpecDateFormat} configuration.
|
|
67
85
|
*
|
|
68
86
|
* @example
|
|
69
87
|
* ```ts
|
|
@@ -76,7 +94,11 @@ export interface SpecDateFormat {
|
|
|
76
94
|
*/
|
|
77
95
|
export declare function formatDateSpec(date: Date | string | number, format: SpecDateFormat, locale?: string): string;
|
|
78
96
|
/**
|
|
79
|
-
*
|
|
97
|
+
* Number formatting options passed through to `Intl.NumberFormat`.
|
|
98
|
+
*
|
|
99
|
+
* Local shape — authored against the protocol's `NumberFormatSchema`, retired
|
|
100
|
+
* in 17.0.0-rc.6 (see the module doc), so there is nothing upstream to derive
|
|
101
|
+
* from.
|
|
80
102
|
*/
|
|
81
103
|
export interface SpecNumberFormat {
|
|
82
104
|
style?: 'currency' | 'percent' | 'decimal' | 'unit';
|
|
@@ -87,7 +109,7 @@ export interface SpecNumberFormat {
|
|
|
87
109
|
useGrouping?: boolean;
|
|
88
110
|
}
|
|
89
111
|
/**
|
|
90
|
-
* Format a number using @
|
|
112
|
+
* Format a number using a {@link SpecNumberFormat} configuration.
|
|
91
113
|
*
|
|
92
114
|
* @example
|
|
93
115
|
* ```ts
|
|
@@ -100,7 +122,11 @@ export interface SpecNumberFormat {
|
|
|
100
122
|
*/
|
|
101
123
|
export declare function formatNumberSpec(value: number, format: SpecNumberFormat, locale?: string): string;
|
|
102
124
|
/**
|
|
103
|
-
*
|
|
125
|
+
* One locale's formatting defaults, resolved by `applyLocaleConfig()`.
|
|
126
|
+
*
|
|
127
|
+
* Local shape — authored against the protocol's `LocaleConfigSchema`, retired
|
|
128
|
+
* in 17.0.0-rc.6 (see the module doc), so there is nothing upstream to derive
|
|
129
|
+
* from.
|
|
104
130
|
*/
|
|
105
131
|
export interface SpecLocaleConfig {
|
|
106
132
|
/** BCP 47 language code (e.g., 'en-US', 'zh-CN') */
|
|
@@ -115,7 +141,7 @@ export interface SpecLocaleConfig {
|
|
|
115
141
|
dateFormat?: SpecDateFormat;
|
|
116
142
|
}
|
|
117
143
|
/**
|
|
118
|
-
* Apply a
|
|
144
|
+
* Apply a {@link SpecLocaleConfig} to configure i18n formatting defaults.
|
|
119
145
|
* Returns resolved formatting functions bound to the locale config.
|
|
120
146
|
*
|
|
121
147
|
* @example
|
|
@@ -36,7 +36,7 @@ export function resolvePlural(rule, count, locale = 'en') {
|
|
|
36
36
|
return template.replace(/\{count\}/g, String(count));
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
|
-
* Format a date using @
|
|
39
|
+
* Format a date using a {@link SpecDateFormat} configuration.
|
|
40
40
|
*
|
|
41
41
|
* @example
|
|
42
42
|
* ```ts
|
|
@@ -63,7 +63,7 @@ export function formatDateSpec(date, format, locale = 'en') {
|
|
|
63
63
|
return new Intl.DateTimeFormat(locale, options).format(d);
|
|
64
64
|
}
|
|
65
65
|
/**
|
|
66
|
-
* Format a number using @
|
|
66
|
+
* Format a number using a {@link SpecNumberFormat} configuration.
|
|
67
67
|
*
|
|
68
68
|
* @example
|
|
69
69
|
* ```ts
|
|
@@ -91,7 +91,7 @@ export function formatNumberSpec(value, format, locale = 'en') {
|
|
|
91
91
|
return new Intl.NumberFormat(locale, options).format(value);
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
|
-
* Apply a
|
|
94
|
+
* Apply a {@link SpecLocaleConfig} to configure i18n formatting defaults.
|
|
95
95
|
* Returns resolved formatting functions bound to the locale config.
|
|
96
96
|
*
|
|
97
97
|
* @example
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/i18n",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"i18next": "^26.3.6",
|
|
34
|
-
"react-i18next": "^17.0.11"
|
|
34
|
+
"react-i18next": "^17.0.11",
|
|
35
|
+
"@object-ui/core": "17.5.0"
|
|
35
36
|
},
|
|
36
37
|
"peerDependencies": {
|
|
37
38
|
"react": "^18.0.0 || ^19.0.0"
|
|
@@ -68,7 +69,7 @@
|
|
|
68
69
|
"scripts": {
|
|
69
70
|
"build": "tsc",
|
|
70
71
|
"test": "vitest run",
|
|
71
|
-
"type-check": "tsc --noEmit",
|
|
72
|
+
"type-check": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
72
73
|
"lint": "eslint ."
|
|
73
74
|
}
|
|
74
75
|
}
|