Files
skills/docs/localization/i18n/react-i18n/src/provider/provider-context.md
2026-05-29 08:20:56 +01:00

3.6 KiB

provider-context.ts

Purpose

Defines the React context that carries the active I18nInstance from @suaveplan/i18n to every descendant of <TranslationProvider>. The context is the single coupling point between the Provider and every hook in @suaveplan/react-i18n — hooks read the instance through this context, which means they all see the same instance even when the Provider is mounted under a portal, a nested tree, or a Storybook decorator.

The default value is intentionally null so the consuming hooks (which land in sub-wave 1c) can detect a missing Provider ancestor and route to either the dev-mode loud-failure throw (ReactI18nError(REACT_I18N.NO_PROVIDER)) or the production-mode soft-fail identity translator. A null default — rather than a factory-default no-op instance — keeps the failure path explicit and prevents silent fall-through to identity behaviour in development.

Features

  • React-native createContext so descendants get the standard context-update behaviour (re-render on value-reference change) for free.
  • displayName set so React DevTools shows SuaveplanTranslationContext instead of the anonymous Context.Provider default.
  • Exports the context object (not a hook) so subpath consumers can useContext(TranslationContext) directly when they need raw access outside the canonical hook surface.

Usage: Basic Example

import { useContext } from "react";
import { TranslationContext } from "@suaveplan/react-i18n/provider";

export function PreviewBadge() {
    const i18n = useContext(TranslationContext);
    if (!i18n) return null;
    return <span>{i18n.catalog.defaultLocale}</span>;
}

Usage: Advanced Example

import { useContext } from "react";
import { TranslationContext } from "@suaveplan/react-i18n/provider";
import {
    REACT_I18N_CODES,
    ReactI18nError,
} from "@suaveplan/react-i18n/errors";
import { isProductionEnv } from "@suaveplan/react-i18n";

export function useI18n() {
    const i18n = useContext(TranslationContext);
    if (i18n) return i18n;
    if (isProductionEnv()) {
        return null;
    }
    throw new ReactI18nError(
        REACT_I18N_CODES.NO_PROVIDER,
        "react-i18n.no_provider",
        { context: { hook: "useI18n" } }
    );
}

API Reference

TranslationContext: React.Context<I18nInstance | null>

The context whose value is the active I18nInstance (when a <TranslationProvider> is mounted) or null (when no Provider is present).

  • Default value: null.
  • displayName: "SuaveplanTranslationContext".

Implementation Notes

  • The default of null is deliberate. A "no-op identity instance" default would silently pass renders through in development and mask the missing-Provider misconfiguration the dev-mode loud-failure path exists to surface.
  • The context is exported (rather than wrapped behind a useI18n() hook) because the hook lives in a separate sub-wave (1c) and consumers in 1b — primarily test fixtures, Storybook decorators, and the Provider itself — need raw access. Exporting both the context AND the eventual hook is the long-standing React pattern proven across react-router, react-query, and dozens of other ecosystem libraries.
  • The display name is stamped at module load. React DevTools picks it up automatically; production bundlers strip the assignment under the standard production mode flag set by Webpack/Vite.
  • The context value type is I18nInstance | null. The null arm forces every reader to handle the no-Provider case explicitly, which catches misconfigurations at type-check time rather than at runtime.