# `identity-instance.ts` ## Purpose Provides the identity translator used as the production-mode fallback when a `useTranslation()` (or any sibling hook) is called outside a `` ancestor. The fallback exists so production bundles don't crash on a `null` destructure — instead they degrade to a visibly-broken-but-not-blocking state where every key renders as its literal key string, and the misconfiguration is logged once via the warn-once helper. The dev-mode counterpart is a thrown `ReactI18nError(NO_PROVIDER)`. The split is by environment, not by hook — every hook that can be called outside a Provider must use this fallback in production. ## Features - Stable reference identity: `getIdentityTranslator()` returns the same function reference on every call so memoisation in consumers does not churn. - `IDENTITY_TRANSLATION_RETURN` — a frozen singleton-shaped object matching `UseTranslationReturn` so destructuring works without allocating a fresh object per fallback render. - Honours `options.defaultValue` so `t("missing", { defaultValue: "x" })` still returns `"x"` even on the fallback path. This is the same contract the universal-core `t` honours, so consumers don't need to branch on `ready`. ## Usage: Basic Example ```ts import { getIdentityTranslator } from "@suaveplan/react-i18n/utils/identity-instance"; const t = getIdentityTranslator(); t("hello"); // "hello" t("hello", { defaultValue: "Hi" }); // "Hi" ``` ## Usage: Advanced Example ```ts import { useState } from "react"; import { IDENTITY_TRANSLATION_RETURN, type IdentityTranslationReturn, } from "@suaveplan/react-i18n/utils/identity-instance"; import type { UseTranslationReturn } from "@suaveplan/react-i18n"; function useFallbackOrLive( live: UseTranslationReturn | null ): UseTranslationReturn | IdentityTranslationReturn { return live ?? IDENTITY_TRANSLATION_RETURN; } ``` ## API Reference ### `getIdentityTranslator(): IdentityTranslator` Returns a stable reference to the identity translator function. Same reference on every call. ### `IDENTITY_TRANSLATION_RETURN: IdentityTranslationReturn` Frozen singleton-shaped object with `{ t, i18n: undefined, ready: false }`. Mirrors `UseTranslationReturn` on the failure branch so consumers can destructure safely. The `i18n` field is intentionally `undefined` (not `null`) so the runtime distinction with a real instance is trivial. ### `interface IdentityTranslator` ```ts (key: string, options?: IdentityTranslatorOptions) => string; ``` Returns `options.defaultValue` when provided, else the key string. ### `interface IdentityTranslatorOptions` Mirrors the ergonomic-options-bag the universal-core `t` accepts. Carries `defaultValue`, `count`, and an open record of additional fields so the fallback is signature-compatible with the live translator. ### `interface IdentityTranslationReturn` The exact return shape used by the production-mode fallback path of `useTranslation()`. The `i18n` field is `undefined` (not `null`) and `ready` is the literal `false` so a TypeScript narrow on `ready` lets consumers branch into the fallback's specific shape. ## Implementation Notes - The translator function is a module-level constant, not a per-call factory product. Returning the same function reference is critical because consumers downstream can `useMemo` on `t` to skip work; a fresh function reference per call would invalidate that memo. - The `IDENTITY_TRANSLATION_RETURN` object is constructed once at module load and shared. Consumers MUST NOT mutate it (the field types are `readonly` and the object is the singular shared instance). - The fallback honours `defaultValue` because doing otherwise would silently regress the production-mode behaviour of any string with a default — `t("greeting", { defaultValue: "Hi" })` becomes `"greeting"` instead of `"Hi"`, which is a worse failure mode than the known identity behaviour. - The fallback intentionally does NOT honour interpolation (`{{count}}`-style) because doing so would couple the React-tier fallback to the universal-core interpolation engine — the whole point of the identity path is to avoid the engine entirely. If a consumer wants interpolation in production-mode no-Provider rendering, they should write a Provider rather than rely on the fallback.