Localization (i18n)
@bext-stack/framework/i18n gives PRISM apps translation the Laravel way:
per-language message catalogs, t(key, params) with {placeholder}
interpolation, pluralization, a fallback locale, and locale detection from the
request. It's the shared replacement for the i18n.ts copies each site was
hand-rolling, and the app-developer counterpart to the Rust
I18n capability.
Setup#
import { createI18n } from "@bext-stack/framework/i18n";
const i18n = createI18n({
default: "en",
fallback: "en", // consulted when a key is missing in the active locale
locales: {
en: {
greeting: "Hello, {name}!",
cart: "Your cart is empty | 1 item | {count} items", // zero | one | other
},
fr: {
greeting: "Bonjour, {name} !",
cart: "Panier vide | 1 article | {count} articles",
},
},
});
Translating#
export async function loader({ request }) {
const t = i18n.for(i18n.detect(request)); // a Translator for the request's locale
return {
hi: t.t("greeting", { name: "Ada" }), // → "Hello, Ada!" (interpolation)
cart: t.n("cart", count), // → "3 items" (pluralization)
};
}
| Member | Does |
|---|---|
i18n.for(locale) |
a Translator bound to a locale (unknown → default) |
i18n.detect(request) |
resolve the request's locale (see below) |
t.t(key, params?) |
translate + interpolate {placeholder} |
t.n(key, count, params?) |
pluralize (one|other or zero|one|other), {count} interpolated |
t.has(key) |
is the key present (incl. fallback)? |
Missing keys fall back to the fallback locale, then to the key itself — so a partial translation degrades gracefully instead of throwing.
Locale detection#
detect(request) resolves in this order, first hit wins:
- Path prefix —
/fr/dashboard→fr. - Cookie — a
localecookie (name configurable). Accept-Language— respectsqweights and matches the base language (fr-CA→fr).- Default.
For site-wide prefixed routing (/en/…, /fr/…) you can also configure
[i18n] in bext.config.toml (the Rust capability). This module is the
in-code path for translating strings and for custom/page-scoped detection.
Try It#
The live i18n demo switches across
en/fr/es/ja with live interpolation and pluralization. Source in
sites/demo/src/app/examples/i18n/page.tsx.
See Also#
- I18n — the Rust capability +
bext.config.tomlrouting. - Validation — localise validation messages via the
{ required, invalid }options. - Application Toolkit — the rest of the TypeScript app layer.