first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
# `useLocaleAdapter`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`useLocaleAdapter<TLocale>(id)` resolves a registered `LocaleAdapterPlugin<TLocale>` against the active locale and returns its library-specific output. The canonical use case is `react-day-picker`'s `<Calendar>`, which wants a date-fns `Locale` object — the component calls `useLocaleAdapter<Locale>("date-fns")` and the consumer registers an adapter that maps the active BCP-47 locale to the corresponding date-fns reference. The package stays library-agnostic; the consumer wires the date / time library they already use.
## Features
- Strict resolution — throws `REACT_I18N.LOCALE_ADAPTER_NOT_REGISTERED` for an unknown id.
- Memoized on `(registry, id, locale)` so a no-op re-render does not re-invoke `plugin.resolve`.
- Built-in `"intl"` identity adapter is auto-registered by `<RegistryProvider>` so any consumer that just needs the locale string back gets it without registering a plugin.
## Usage: Basic Example
```tsx
import { useLocaleAdapter } from "@suaveplan/react-i18n";
function HtmlLang(): JSX.Element {
const lang = useLocaleAdapter<string>("intl");
return <meta name="content-language" content={lang} />;
}
```
## Usage: Advanced Example
A `<Calendar>` component asks for the date-fns adapter:
```tsx
import { useLocaleAdapter } from "@suaveplan/react-i18n";
import { DayPicker } from "react-day-picker";
import type { Locale as DateFnsLocale } from "date-fns";
function Calendar(props: CalendarProps): JSX.Element {
const dateFnsLocale = useLocaleAdapter<DateFnsLocale>("date-fns");
return <DayPicker {...props} locale={dateFnsLocale} />;
}
```
The consumer wires the adapter once in `<RegistryProvider>`:
```tsx
import { createDateFnsLocaleAdapter, RegistryProvider } from "@suaveplan/react-i18n";
import { enGB, frFR, zhCN } from "date-fns/locale";
const dateFnsAdapter = createDateFnsLocaleAdapter({
locales: { enGB, frFR, zhCN },
});
<RegistryProvider plugins={[{ kind: "locale-adapter", plugin: dateFnsAdapter }]}>
{/* … Calendar resolves "date-fns" to the active locale's Locale object */}
</RegistryProvider>;
```
Without registering the adapter, `<Calendar>` throws `REACT_I18N.LOCALE_ADAPTER_NOT_REGISTERED` on first render. This is intentional — silent fallback to a hardcoded English locale would be surprising in an RTL locale.
## API Reference
### `useLocaleAdapter<TLocale>(id: string): TLocale`
- `id`: the registered plugin's id. The built-in `"intl"` is auto-registered; other ids (`"date-fns"`, `"luxon"`, `"temporal"`) are consumer-registered.
Throws `ReactI18nError(REACT_I18N.LOCALE_ADAPTER_NOT_REGISTERED)` for an unknown id, `REACT_I18N.REGISTRY_NOT_PROVIDED` outside a `<RegistryProvider>`.
## Implementation Notes
- The hook is memoized on `(registry, id, resolvedLocale)`. Adapter implementations must be pure — calling `resolve(locale)` twice with the same locale must return referentially-equal output for the memo to be useful.
- Adapters typically hold their locale map at construction time (see `createDateFnsLocaleAdapter`); this means the adapter object identity is stable across renders, which keeps the memoization key stable.
- A consumer registering multiple adapters under different ids (e.g. `"date-fns"` AND `"luxon"`) gets two independent resolution paths. Components decide which library they need by passing the matching id.