Internationalization (i18n)
createI18n handles per-language catalogs with {placeholder} interpolation, pluralization, a fallback locale, and request detection (path prefix → cookie → Accept-Language). Every render is a fresh server pick — no flash of the wrong language.
Tip
Detection order: path prefix (/fr/…) → 'locale' cookie → Accept-Language (q-weighted) → default. A missing key falls back to the fallback locale, then the key. For site-wide /en/… routing, configure [i18n] in bext.config.toml.
Hello
Welcome to the shop, Ada!
🛒 3 items in your cart
Pick another locale:
Active locale: en · Detected from request: en
import { createI18n } from "@bext-stack/framework/i18n";
const i18n = createI18n({
default: "en", fallback: "en",
locales: {
en: { greeting: "Welcome, {name}!", cart: "empty | 1 item | {count} items" },
fr: { greeting: "Bienvenue, {name} !", cart: "vide | 1 article | {count} articles" },
},
});
export async function loader({ request }) {
// detection: path prefix → 'locale' cookie → Accept-Language → default
const t = i18n.for(i18n.detect(request));
return {
greeting: t.t("greeting", { name: "Ada" }), // interpolation
cart: t.n("cart", count), // pluralization (empty|one|other)
};
}