Files
skills/docs/localization/i18n/react-i18n/src/components/trans/stringify-children.md
2026-05-29 08:20:56 +01:00

3.2 KiB

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

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:

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.