first commit
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user