first commit
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# `to-i18n-instance-options.ts`
|
||||
|
||||
## Purpose
|
||||
|
||||
Translates a Zod-parsed `I18nConfig` (the React-tier shape) into the
|
||||
universal-core `I18nInstanceOptions` accepted by `createI18n(...)` from
|
||||
`@suaveplan/i18n`. This is the bridge between the React Provider's
|
||||
config surface (where field names favour SSR semantics, e.g.
|
||||
`initialMessages`) and the universal core's option bag (where field
|
||||
names favour catalog semantics, e.g. `messages`).
|
||||
|
||||
The function is pure and stable across calls so the Provider can wrap it
|
||||
in `useMemo` without churning the universal core's instance lifecycle on
|
||||
every render.
|
||||
|
||||
## Features
|
||||
|
||||
- Single-pass field mapping with explicit conditional forwarding so
|
||||
`exactOptionalPropertyTypes` (the tsconfig setting) does not
|
||||
require sentinel `undefined`s on the output.
|
||||
- Renames `initialMessages` → `messages` so the React-tier name
|
||||
("initial" matches the SSR-hydration story) and the core-tier name
|
||||
("messages" matches the catalog story) can each be ergonomic in their
|
||||
own context.
|
||||
- Forwards every other field as-is (`fallbackLocale`, `backend`,
|
||||
`backends`, `saveMissing`, `plugins`).
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
createI18nConfig,
|
||||
toI18nInstanceOptions,
|
||||
} from "@suaveplan/react-i18n/config";
|
||||
import { createI18n } from "@suaveplan/i18n";
|
||||
|
||||
const cfg = createI18nConfig({
|
||||
defaultLocale: "en-GB",
|
||||
initialMessages: { "en-GB": { hello: "Hi" } },
|
||||
});
|
||||
const i18n = createI18n(toI18nInstanceOptions(cfg));
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```ts
|
||||
import { useMemo } from "react";
|
||||
import { createI18n, type I18nInstance } from "@suaveplan/i18n";
|
||||
import {
|
||||
type I18nConfig,
|
||||
toI18nInstanceOptions,
|
||||
} from "@suaveplan/react-i18n/config";
|
||||
|
||||
function useStableInstance(config: I18nConfig): I18nInstance {
|
||||
return useMemo(
|
||||
() => createI18n(toI18nInstanceOptions(config)),
|
||||
[config]
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `toI18nInstanceOptions(config: I18nConfig): I18nInstanceOptions`
|
||||
|
||||
Pure mapping. Returns a new `I18nInstanceOptions` object on every call;
|
||||
fields not present on the input config are omitted from the output (so
|
||||
the universal-core defaults take over).
|
||||
|
||||
| Input field | Output field | Notes |
|
||||
| --- | --- | --- |
|
||||
| `defaultLocale` | `defaultLocale` | Always present (required). |
|
||||
| `fallbackLocale` | `fallbackLocale` | Forwarded when defined. |
|
||||
| `initialMessages` | `messages` | Renamed; structurally identical. |
|
||||
| `backend` | `backend` | Forwarded as-is (structural). |
|
||||
| `backends` | `backends` | Forwarded as-is (structural). |
|
||||
| `saveMissing` | `saveMissing` | Forwarded when defined. |
|
||||
| `plugins` | `plugins` | Forwarded as-is (structural). |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Field forwarding uses explicit `if (value !== undefined)` guards
|
||||
rather than spread because the tsconfig sets
|
||||
`exactOptionalPropertyTypes: true` — explicit guards keep the output
|
||||
shape free of sentinel `undefined` properties that would otherwise
|
||||
conflict with optional fields on `I18nInstanceOptions`.
|
||||
- `Backend` and `I18nPlugin` casts at the conversion boundary are
|
||||
unavoidable: the React-tier Zod schema validates only the structural
|
||||
fields (`name`, `capabilities`) of these types because their full
|
||||
surface includes function fields Zod cannot meaningfully validate.
|
||||
The Provider's runtime guard is the universal core itself, which
|
||||
exercises the function fields when it boots the instance.
|
||||
- The function is pure — calling it twice with the same input yields
|
||||
equivalent options (deep-equal but not necessarily reference-equal).
|
||||
- The function does NOT call `createI18n`. The Provider does that
|
||||
separately so config building and instance construction can be wired
|
||||
to different React lifecycles (`useMemo` on the config,
|
||||
`useState`/`useRef` on the instance).
|
||||
Reference in New Issue
Block a user