@object-ui/i18n 17.7.0 → 18.0.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 +1088 -0
- package/README.md +64 -1
- package/dist/LocalizationContext.d.ts +32 -9
- package/dist/LocalizationContext.js +32 -10
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -0
- package/dist/locales/ar.d.ts +591 -108
- package/dist/locales/ar.js +704 -208
- package/dist/locales/de.d.ts +475 -88
- package/dist/locales/de.js +589 -183
- package/dist/locales/en.d.ts +562 -175
- package/dist/locales/en.js +745 -208
- package/dist/locales/es.d.ts +504 -93
- package/dist/locales/es.js +617 -186
- package/dist/locales/fr.d.ts +504 -93
- package/dist/locales/fr.js +617 -187
- package/dist/locales/index.d.ts +5178 -1092
- package/dist/locales/ja.d.ts +475 -88
- package/dist/locales/ja.js +588 -182
- package/dist/locales/ko.d.ts +475 -88
- package/dist/locales/ko.js +588 -182
- package/dist/locales/pt.d.ts +504 -93
- package/dist/locales/pt.js +617 -186
- package/dist/locales/ru.d.ts +533 -98
- package/dist/locales/ru.js +646 -197
- package/dist/locales/zh.d.ts +563 -176
- package/dist/locales/zh.js +589 -197
- package/dist/useObjectLabel.d.ts +109 -88
- package/dist/useObjectLabel.js +86 -71
- package/dist/utils/first-day-of-week.d.ts +71 -0
- package/dist/utils/first-day-of-week.js +61 -0
- package/dist/utils/formatting.d.ts +7 -1
- package/dist/utils/formatting.js +11 -2
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -196,7 +196,70 @@ A date-only string such as `'2026-09-01'` names a calendar day: every date
|
|
|
196
196
|
helper reads it as that day in every viewer's time zone (`formatDateTime` shows
|
|
197
197
|
its midnight, and `formatRelativeTime` counts to the start of it). A string
|
|
198
198
|
with a time part is an instant, read in the viewer's zone. `formatDateSpec`
|
|
199
|
-
applies its `timeZone` to an instant only.
|
|
199
|
+
applies its `timeZone` to an instant only. These helpers do not read the
|
|
200
|
+
display zone below; the field cells and measures format through
|
|
201
|
+
`@object-ui/core`'s date faces, which do.
|
|
202
|
+
|
|
203
|
+
### Regional defaults (`LocalizationProvider`)
|
|
204
|
+
|
|
205
|
+
`LocalizationProvider` carries the workspace's resolved regional defaults to
|
|
206
|
+
every renderer below it, and `useLocalization()` reads them (`{}` outside a
|
|
207
|
+
provider). The console fills it from `GET /api/v1/auth/me/localization`.
|
|
208
|
+
|
|
209
|
+
```tsx
|
|
210
|
+
import type { ReactNode } from 'react';
|
|
211
|
+
import { LocalizationProvider, useLocalization } from '@object-ui/i18n';
|
|
212
|
+
|
|
213
|
+
export function Regional({ children }: { children: ReactNode }) {
|
|
214
|
+
return (
|
|
215
|
+
<LocalizationProvider value={{ currency: 'EUR', locale: 'de-DE', timezone: 'Europe/Berlin' }}>
|
|
216
|
+
{children}
|
|
217
|
+
</LocalizationProvider>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function ZoneLabel() {
|
|
222
|
+
const { timezone } = useLocalization();
|
|
223
|
+
return <span>{timezone ?? 'viewer zone'}</span>;
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
- `currency` (ISO 4217) is the default a currency field without its own code
|
|
228
|
+
renders in.
|
|
229
|
+
- `locale` (BCP-47) outranks the UI language for number and date formatting;
|
|
230
|
+
read the effective tag with `useDisplayLocale()`.
|
|
231
|
+
- `timezone` (IANA) is the zone instants render in. The provider hands it to
|
|
232
|
+
`setDisplayTimeZone` in `@object-ui/core`, so every date and datetime face
|
|
233
|
+
takes it without any renderer passing a zone, and `useLocalization().timezone`
|
|
234
|
+
reads back the zone those faces use (`undefined` for a name the runtime does
|
|
235
|
+
not know). Without one, instants render in the viewer's zone. There is one
|
|
236
|
+
display zone per page, and unmounting the provider clears it.
|
|
237
|
+
|
|
238
|
+
#### The first day of the week
|
|
239
|
+
|
|
240
|
+
`firstDayOfWeek(locale)` answers the first day of the week for a BCP-47 tag,
|
|
241
|
+
numbered as `Date.prototype.getDay` numbers weekdays (0 is Sunday), which is
|
|
242
|
+
also what react-day-picker's `weekStartsOn` takes. It reads the engine's
|
|
243
|
+
`Intl.Locale` week info, and CLDR's region table where the engine has none, so
|
|
244
|
+
a week grid or a "this week" bound starts where the user's locale says rather
|
|
245
|
+
than on a fixed day. There is no separate week-start setting: the tag is the
|
|
246
|
+
one the caller already formats its dates with, such as `useDisplayLocale()`.
|
|
247
|
+
|
|
248
|
+
```tsx
|
|
249
|
+
import { firstDayOfWeek, useDisplayLocale } from '@object-ui/i18n';
|
|
250
|
+
|
|
251
|
+
firstDayOfWeek('en-US'); // 0, Sunday
|
|
252
|
+
firstDayOfWeek('en-GB'); // 1, Monday
|
|
253
|
+
firstDayOfWeek('zh-CN'); // 1, Monday
|
|
254
|
+
|
|
255
|
+
function WeekHeader() {
|
|
256
|
+
const weekStart = firstDayOfWeek(useDisplayLocale());
|
|
257
|
+
// ...lay the week out from `weekStart`
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
A tag `Intl` refuses (`en_US`) throws the same `RangeError` that formatting a
|
|
262
|
+
date with it would.
|
|
200
263
|
|
|
201
264
|
### Built-in locales — one is resident, nine are fetched on demand
|
|
202
265
|
|
|
@@ -7,18 +7,20 @@
|
|
|
7
7
|
*/
|
|
8
8
|
/**
|
|
9
9
|
* LocalizationContext — the tenant's resolved REGIONAL defaults (currency,
|
|
10
|
-
* locale) for the current request, surfaced to every renderer.
|
|
10
|
+
* locale, time zone) for the current request, surfaced to every renderer.
|
|
11
11
|
*
|
|
12
12
|
* This is the client half of ADR-0053: the framework resolves a workspace
|
|
13
|
-
* `localization.currency` / `locale` onto each request's
|
|
14
|
-
* exposes them at `GET /api/v1/auth/me/localization`. A
|
|
15
|
-
* app-shell) loads them once and feeds this PURE context,
|
|
16
|
-
* measure renderers can resolve a currency code down to
|
|
17
|
-
* instead of hard-coding `$`/`¥`/`USD` or degrading to a
|
|
18
|
-
* any of them depending on app-shell or making their own
|
|
13
|
+
* `localization.currency` / `locale` / `timezone` onto each request's
|
|
14
|
+
* ExecutionContext and exposes them at `GET /api/v1/auth/me/localization`. A
|
|
15
|
+
* fetching wrapper (in app-shell) loads them once and feeds this PURE context,
|
|
16
|
+
* so low-level field / measure renderers can resolve a currency code down to
|
|
17
|
+
* the org default — instead of hard-coding `$`/`¥`/`USD` or degrading to a
|
|
18
|
+
* bare number — without any of them depending on app-shell or making their own
|
|
19
|
+
* fetch.
|
|
19
20
|
*
|
|
20
21
|
* Undefined values mean "no tenant default known" → consumers render a plain
|
|
21
|
-
* number (the existing safe behavior)
|
|
22
|
+
* number (the existing safe behavior), and instants render in the viewer's
|
|
23
|
+
* own zone.
|
|
22
24
|
*/
|
|
23
25
|
import * as React from 'react';
|
|
24
26
|
export interface LocalizationValue {
|
|
@@ -26,8 +28,29 @@ export interface LocalizationValue {
|
|
|
26
28
|
currency?: string;
|
|
27
29
|
/** Tenant/display locale (BCP-47) for Intl formatting, or undefined. */
|
|
28
30
|
locale?: string;
|
|
31
|
+
/**
|
|
32
|
+
* The zone instants render in (an IANA name), or undefined for the viewer's
|
|
33
|
+
* own (objectui#11693). The provider hands it to the central date faces in
|
|
34
|
+
* `@object-ui/core`; read back from {@link useLocalization}, it is the zone
|
|
35
|
+
* those faces render in, so a name the runtime does not know reads back
|
|
36
|
+
* `undefined`.
|
|
37
|
+
*/
|
|
38
|
+
timezone?: string;
|
|
29
39
|
}
|
|
30
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* Pure provider — the fetching/loading concern lives in the app shell.
|
|
42
|
+
*
|
|
43
|
+
* It is also the ONE place the display zone enters the date faces
|
|
44
|
+
* (objectui#11693): `value.timezone` is handed to `setDisplayTimeZone` in
|
|
45
|
+
* `@object-ui/core`, which every date and datetime face reads, so no renderer
|
|
46
|
+
* threads a zone of its own. The hand-off runs in a layout effect, and the
|
|
47
|
+
* zone the context carries is read back from core through
|
|
48
|
+
* `useSyncExternalStore`, so the context changes only AFTER the faces have the
|
|
49
|
+
* new zone: every consumer then re-renders in it, before the browser paints.
|
|
50
|
+
*
|
|
51
|
+
* The display zone is one per page, as the date faces are: a second provider
|
|
52
|
+
* with a different zone would race this one for it, and unmounting clears it.
|
|
53
|
+
*/
|
|
31
54
|
export declare function LocalizationProvider({ value, children, }: {
|
|
32
55
|
value: LocalizationValue;
|
|
33
56
|
children: React.ReactNode;
|
|
@@ -8,25 +8,47 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
10
|
* LocalizationContext — the tenant's resolved REGIONAL defaults (currency,
|
|
11
|
-
* locale) for the current request, surfaced to every renderer.
|
|
11
|
+
* locale, time zone) for the current request, surfaced to every renderer.
|
|
12
12
|
*
|
|
13
13
|
* This is the client half of ADR-0053: the framework resolves a workspace
|
|
14
|
-
* `localization.currency` / `locale` onto each request's
|
|
15
|
-
* exposes them at `GET /api/v1/auth/me/localization`. A
|
|
16
|
-
* app-shell) loads them once and feeds this PURE context,
|
|
17
|
-
* measure renderers can resolve a currency code down to
|
|
18
|
-
* instead of hard-coding `$`/`¥`/`USD` or degrading to a
|
|
19
|
-
* any of them depending on app-shell or making their own
|
|
14
|
+
* `localization.currency` / `locale` / `timezone` onto each request's
|
|
15
|
+
* ExecutionContext and exposes them at `GET /api/v1/auth/me/localization`. A
|
|
16
|
+
* fetching wrapper (in app-shell) loads them once and feeds this PURE context,
|
|
17
|
+
* so low-level field / measure renderers can resolve a currency code down to
|
|
18
|
+
* the org default — instead of hard-coding `$`/`¥`/`USD` or degrading to a
|
|
19
|
+
* bare number — without any of them depending on app-shell or making their own
|
|
20
|
+
* fetch.
|
|
20
21
|
*
|
|
21
22
|
* Undefined values mean "no tenant default known" → consumers render a plain
|
|
22
|
-
* number (the existing safe behavior)
|
|
23
|
+
* number (the existing safe behavior), and instants render in the viewer's
|
|
24
|
+
* own zone.
|
|
23
25
|
*/
|
|
24
26
|
import * as React from 'react';
|
|
27
|
+
import { getDisplayTimeZone, setDisplayTimeZone, subscribeDisplayTimeZone } from '@object-ui/core';
|
|
25
28
|
const LocalizationCtx = React.createContext({});
|
|
26
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Pure provider — the fetching/loading concern lives in the app shell.
|
|
31
|
+
*
|
|
32
|
+
* It is also the ONE place the display zone enters the date faces
|
|
33
|
+
* (objectui#11693): `value.timezone` is handed to `setDisplayTimeZone` in
|
|
34
|
+
* `@object-ui/core`, which every date and datetime face reads, so no renderer
|
|
35
|
+
* threads a zone of its own. The hand-off runs in a layout effect, and the
|
|
36
|
+
* zone the context carries is read back from core through
|
|
37
|
+
* `useSyncExternalStore`, so the context changes only AFTER the faces have the
|
|
38
|
+
* new zone: every consumer then re-renders in it, before the browser paints.
|
|
39
|
+
*
|
|
40
|
+
* The display zone is one per page, as the date faces are: a second provider
|
|
41
|
+
* with a different zone would race this one for it, and unmounting clears it.
|
|
42
|
+
*/
|
|
27
43
|
export function LocalizationProvider({ value, children, }) {
|
|
44
|
+
const { timezone } = value;
|
|
45
|
+
React.useLayoutEffect(() => {
|
|
46
|
+
setDisplayTimeZone(timezone);
|
|
47
|
+
return () => setDisplayTimeZone(undefined);
|
|
48
|
+
}, [timezone]);
|
|
49
|
+
const appliedZone = React.useSyncExternalStore(subscribeDisplayTimeZone, getDisplayTimeZone, getDisplayTimeZone);
|
|
28
50
|
// Stable identity unless the resolved values actually change.
|
|
29
|
-
const memo = React.useMemo(() => ({ currency: value.currency, locale: value.locale }), [value.currency, value.locale]);
|
|
51
|
+
const memo = React.useMemo(() => ({ currency: value.currency, locale: value.locale, timezone: appliedZone }), [value.currency, value.locale, appliedZone]);
|
|
30
52
|
return _jsx(LocalizationCtx.Provider, { value: memo, children: children });
|
|
31
53
|
}
|
|
32
54
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -47,3 +47,4 @@ export { LocalizationProvider, useLocalization, type LocalizationValue } from '.
|
|
|
47
47
|
export { resolveFieldCurrency } from './currency.js';
|
|
48
48
|
export { useDisplayLocale } from './useDisplayLocale.js';
|
|
49
49
|
export { formatDisplayNumber, shouldGroupDisplayNumber, type DisplayNumberFormatOptions, } from './utils/index.js';
|
|
50
|
+
export { firstDayOfWeek, type WeekdayIndex } from './utils/index.js';
|
package/dist/index.js
CHANGED
|
@@ -98,3 +98,7 @@ export { resolveFieldCurrency } from './currency.js';
|
|
|
98
98
|
// see `utils/number-display.ts` for the grouping policy and its interim status.
|
|
99
99
|
export { useDisplayLocale } from './useDisplayLocale.js';
|
|
100
100
|
export { formatDisplayNumber, shouldGroupDisplayNumber, } from './utils/index.js';
|
|
101
|
+
// objectui#11675 — the first day of the week for a locale tag. The calendar's
|
|
102
|
+
// grids and the timeline's week buckets read it from the tag they format with,
|
|
103
|
+
// so the week starts where the locale says and never on a hard-coded day.
|
|
104
|
+
export { firstDayOfWeek } from './utils/index.js';
|