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,85 @@
# `stringify-children`
## Purpose
Helpers that translate a `<Trans>` `children` block into a canonical
ICU message body string so the message parser renders a missing-key
fallback identically to a catalog entry. The module exists as a sibling
of `<Trans>` (rather than inline) so the trans component file stays
within the per-file size budget and so the structurally-invalid-child
branch can be unit-tested directly without going through React's JSX
surface (which validates and rejects invalid children before they
reach our `Children.forEach` callback).
## Features
- `childrenToMessageString` — entry point that walks `Children.forEach`
and concatenates each child's stringified form
- `stringifyChild` — single-child stringifier, exported for direct unit
testing of the defensive `TRANS_INVALID_CHILD` throw
- Nested children are recursed; tag-wrapped children render as
`<tagName>...</tagName>` with the same component-map semantics
- Boolean, `null`, and `undefined` children render as the empty string
(matches React's own rendering rules)
- Defensive throw of `ReactI18nError(REACT_I18N.TRANS_INVALID_CHILD)`
for any structurally-invalid value (functions, custom objects)
## Usage: Basic Example
```ts
import { childrenToMessageString } from "@suaveplan/react-i18n/components/trans/stringify-children";
const body = childrenToMessageString(
<>Hello <strong>{"{name}"}</strong>!</>,
"absent.key"
);
// body === "Hello <strong>{name}</strong>!"
```
## Usage: Advanced Example
The helpers operate purely on React children, so consumers can use
them outside `<Trans>` for snapshot / logging surfaces where a
React-children tree needs a stable string serialisation:
```ts
import { stringifyChild } from "@suaveplan/react-i18n/components/trans/stringify-children";
function snapshotChild(node: React.ReactNode): string {
try {
return stringifyChild(node, "snapshot");
} catch (err) {
return `[invalid: ${(err as Error).message}]`;
}
}
```
## API Reference
### `childrenToMessageString(children: ReactNode, key: string): string`
Walks `React.Children.forEach` over `children` and concatenates each
result of `stringifyChild`. Returns the literal `key` string when
`children` is `null` or `undefined`.
### `stringifyChild(child: ReactNode, key: string): string`
Stringifies one React child. Recurses into element children via
`childrenToMessageString` for the tag body. Throws
`ReactI18nError(REACT_I18N.TRANS_INVALID_CHILD)` with `context: { key }`
for structurally-invalid input.
## Implementation Notes
- The module is intentionally side-effect-free; both helpers are pure
string returners with the single exception of the defensive throw.
- Element children with no `props.children` produce `<tagName></tagName>`
rather than `<tagName>key</tagName>` — the nested-children helper
reads the children prop with a fall-through to the empty string so
the recursion does not mistakenly inject the outer key into a
childless tag body.
- The defensive throw exists for the edge case where TypeScript's
`ReactNode` typing is bypassed by a caller who hand-constructs a
child via `React.createElement`. In typical JSX usage React's own
pre-render validation rejects invalid values before our callback
runs.