/** * Helper for spinning up a real `@suaveplan/i18n` `I18nInstance` plus * its bundled translations under a fresh `I18nInstance` per test. No * mocks — every consumer of an i18n instance in the test suite uses * this helper so the wiring matches production exactly. * * The bundled `react-ui` JSON files ship FLAT keys * (`"react-ui.button.iconOnly.fallback": "Action"`). The catalog's `t()` * walks dot-separated paths, so we nest the flat bag into a deep * record (`{ react-ui: { button: { iconOnly: { fallback: "Action" } } } }`) * before merging into the catalog. This mirrors the chassis * `ReactUiProvider`'s `nestFlatKeys` step exactly so production and * tests resolve keys via the same pathway. */ import { createI18n, type I18nInstance } from "@suaveplan/i18n/plugin"; import { reactUiBundles } from "../../src/locales/index.js"; export interface CreateTestI18nOptions { readonly locale?: "en-GB" | "zh-CN" | "ar-AE" | "cy-GB" | "ru-RU"; } type NestedTranslationRecord = { [key: string]: string | NestedTranslationRecord; }; function nestFlatKeys(bag: Record): NestedTranslationRecord { const out: NestedTranslationRecord = {}; for (const [flatKey, value] of Object.entries(bag)) { const parts = flatKey.split("."); let cursor: NestedTranslationRecord = out; for (let i = 0; i < parts.length - 1; i += 1) { const seg = parts[i] as string; const existing = cursor[seg]; if ( typeof existing !== "object" || existing === null || Array.isArray(existing) ) { cursor[seg] = {}; } cursor = cursor[seg] as NestedTranslationRecord; } cursor[parts[parts.length - 1] as string] = value; } return out; } /** * Build an `I18nInstance` seeded with the chassis locale bundles. * Useful for tests that need a Provider but want deterministic * translations. */ export async function createTestI18n( options: CreateTestI18nOptions = {} ): Promise { const locale = options.locale ?? "en-GB"; const i18n = createI18n({ defaultLocale: locale, fallbackLocale: "en-GB", }); for (const code of ["en-GB", "zh-CN", "ar-AE", "cy-GB", "ru-RU"] as const) { const bundle = await reactUiBundles[code](); const nested = nestFlatKeys(bundle as Record); i18n.catalog.mergeMessages(code, nested as Record); } return i18n; }