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,105 @@
# Locales
Bundled translation strings shipped with `@suaveplan/react-forms`.
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
The package owns a small set of user-facing strings used by the recipes
(`Next`, `Back`, `Submit`, `Add`, `Remove`, `Loading…`, `Failed to
load`). The strings ship as flat-key JSON bundles in five locales
(`en-GB`, `zh-CN`, `ar-AE`, `cy-GB`, `ru-RU`) and are merged into the
consumer's `I18nInstance.catalog` at provider mount.
Consumers MAY override any key via `<TranslationProvider>`'s catalog
merging or via the recipe factory's per-recipe `labels` prop.
## Features
- Flat-key bundles addressable by `react-forms.<recipe>.<key>`
- Lazy loaders (one dynamic import per locale) so only the active
locale's JSON ships in the consumer's main bundle
- Type-narrowed via the generated `augmentation.d.ts` so misuse fails
at compile time
- Sorted key list (`REACT_FORMS_BUNDLE_KEYS`) for parity tests
- One source of truth (`en-GB.json`); other locales are kept parity-
complete by `scripts/check-locale-completeness.ts`
## Usage: Basic Example
```ts
import {
REACT_FORMS_BUNDLE_KEYS,
reactFormsBundles,
} from "@suaveplan/react-forms";
const en = await reactFormsBundles["en-GB"]();
console.log(Object.keys(en).length); // 7
console.log(REACT_FORMS_BUNDLE_KEYS[0]); // "react-forms.asyncSearch.error"
```
## Usage: Advanced Example
Wire the bundles into the active `I18nInstance` so recipe defaults
resolve correctly. The pattern mirrors `react-ui`'s `ReactUiProvider`
flat-to-nested merging step:
```ts
import { reactFormsBundles } from "@suaveplan/react-forms";
import type { I18nInstance } from "@suaveplan/i18n/plugin";
function nestFlat(bag: Record<string, string>): Record<string, unknown> {
const out: Record<string, unknown> = {};
for (const [k, v] of Object.entries(bag)) {
const parts = k.split(".");
let cur: Record<string, unknown> = out;
for (let i = 0; i < parts.length - 1; i += 1) {
const seg = parts[i] as string;
if (typeof cur[seg] !== "object" || cur[seg] === null) {
cur[seg] = {};
}
cur = cur[seg] as Record<string, unknown>;
}
cur[parts[parts.length - 1] as string] = v;
}
return out;
}
export async function registerReactFormsLocales(
i18n: I18nInstance
): Promise<void> {
for (const [locale, loader] of Object.entries(reactFormsBundles)) {
const bundle = await loader();
i18n.catalog.mergeMessages(
locale,
nestFlat(bundle as Record<string, string>)
);
}
}
```
## API Reference
- `SupportedFormsLocale` — `"en-GB" | "zh-CN" | "ar-AE" | "cy-GB" | "ru-RU"`. The five locales the package ships translations for.
- `reactFormsBundles` — `Readonly<Record<SupportedFormsLocale, () => Promise<FormsLocaleBundle>>>`. Frozen map of locale → async loader returning the flat key/value bag for that locale. Loaders are lazy so consumers only chunk the active locale.
- `FormsLocaleBundle` — `Readonly<Record<string, string>>`. Shape of a single locale's bundle.
- `REACT_FORMS_BUNDLE_KEYS` — `ReadonlyArray<string>`. Sorted list of every key in `en-GB.json` for parity tests.
## Implementation Notes
- The bundles are imported via dynamic JSON imports so the bundler can
tree-shake unused locales when consumers split per language route.
- The augmentation lives in two files (`augmentation.ts` + the
generated `augmentation.d.ts`) so a side-effect runtime import
carries the augmentation through the package barrel even when
declaration-only files are pruned by aggressive bundlers.
- `Object.freeze` plus `Readonly<...>` annotations prevent accidental
mutation by consumers — the bundles MUST be treated as immutable.
- Adding a key requires updating ALL FIVE locale bundles + re-running
the codegen (`bun packages/react/react-i18n/scripts/generate-translation-types.ts packages/react/react-forms --package-name @suaveplan/react-forms`)
- duplicating the entry into `augmentation.ts`. The
`check-locale-completeness.ts` CI gate fails the build if any locale
drifts.