68 lines
2.5 KiB
TypeScript
68 lines
2.5 KiB
TypeScript
/**
|
|
* Build the demo's `I18nInstance`.
|
|
*
|
|
* The instance is consumed by `<ReactUiProvider>` and any
|
|
* `@suaveplan/react-ui` primitive that calls `useTranslation()` (e.g.
|
|
* `<Button>` for icon-only-button fallback, `<Input>` for placeholder
|
|
* resolution).
|
|
*
|
|
* Locale strategy: the URL carries the language subtag only (`/en/home`,
|
|
* `/zh/home`, etc.). The chassis bundles in `@suaveplan/react-ui` are
|
|
* keyed by full BCP47 — `en-GB`, `zh-CN`, `ar-AE`, `cy-GB`, `ru-RU`. We
|
|
* therefore canonicalise each demo base locale to its closest BCP47
|
|
* variant and use THAT as the i18n locale. The demo's typed `Messages`
|
|
* catalog continues to be consumed via `useLocale()` keyed by base, so
|
|
* the demo never depends on react-i18n's `t(key)` for its own copy.
|
|
*
|
|
* The chassis bundles themselves are auto-registered by
|
|
* `<ReactUiProvider>` (its internal `ReactUiBundleLoader` effect imports
|
|
* the matching JSON and merges it into the catalog on mount / language
|
|
* change), so this module deliberately does NOT preload them.
|
|
*/
|
|
import { createI18n, type I18nInstance } from "@suaveplan/i18n/plugin";
|
|
import type { BaseLocale } from "./locales.js";
|
|
|
|
export type DemoBcp47 = "en-GB" | "zh-CN" | "ar-AE" | "cy-GB" | "ru-RU";
|
|
|
|
/** Map URL base locale -> canonical BCP47 variant fed to the i18n core. */
|
|
export const BASE_TO_BCP47: Readonly<Record<BaseLocale, DemoBcp47>> = {
|
|
en: "en-GB",
|
|
zh: "zh-CN",
|
|
ar: "ar-AE",
|
|
cy: "cy-GB",
|
|
ru: "ru-RU",
|
|
};
|
|
|
|
/**
|
|
* Singleton i18n instance for the demo. Created lazily so the i18n core
|
|
* (which is module-side-effect free) does not run during static module
|
|
* graph evaluation in tests or SSR snapshots.
|
|
*/
|
|
let cached: I18nInstance | undefined;
|
|
|
|
export function getDemoI18n(): I18nInstance {
|
|
if (cached !== undefined) return cached;
|
|
// Use the default `string` generic so the cached singleton matches
|
|
// `<ReactUiProvider>`'s `i18n: I18nInstance` (without the
|
|
// narrowed locale generic).
|
|
const instance: I18nInstance = createI18n({
|
|
defaultLocale: BASE_TO_BCP47.en as string,
|
|
fallbackLocale: BASE_TO_BCP47.en as string,
|
|
});
|
|
cached = instance;
|
|
return instance;
|
|
}
|
|
|
|
/**
|
|
* Drive the i18n instance to the BCP47 variant matching the URL base.
|
|
* Safe to call from a `useEffect` — `changeLanguage(...)` short-circuits
|
|
* when the locale already matches.
|
|
*/
|
|
export async function syncDemoLocale(base: BaseLocale): Promise<void> {
|
|
const i18n = getDemoI18n();
|
|
const target = BASE_TO_BCP47[base];
|
|
if (i18n.locale !== target) {
|
|
await i18n.changeLanguage(target);
|
|
}
|
|
}
|