Locale runtime
Create and bind your locale runtime using createLocaleRuntime. Access isomorphic locale status, url helpers, and state detection utilities.
defineLocaleConfig alone does not run at request time — you need a runtime object your app imports everywhere. This guide explains how to export locale from src/locale.ts, create an isomorphic helper for safe SSR and client reads, and use it in loaders to determine the active locale.
Prerequisites
- Configuration —
locale-config.ts - URL prefix modes — prefix mode affects URL helpers
Bind the runtime
Create src/locale.ts:
import { createLocaleRuntime } from "@wadiou/tanstack-i18n";
import { config } from "./locale-config";
export const locale = createLocaleRuntime(config);
export { config };Bind-time validation runs here (empty persist+infer, never without cookie, etc.) — errors listed in Configuration — API reference.
Import locale in server entry and providers. For reading the active locale on both client and server, use the isomorphic helper in the next step.
Create the locale helper (SSR only)
To read the active locale correctly during server-side rendering (SSR) and client-side transitions in full-stack frameworks like TanStack Start, wrap the runtime calls in isomorphic helper functions. These resolve request headers and cookies on the server while falling back to the client-side router context in the browser.
We can generate these helpers using createStartLocaleHelpers from @wadiou/tanstack-i18n/react-start (for React) or @wadiou/tanstack-i18n/solid-start (for Solid).
Update src/locale.ts to export these helper functions:
import { createLocaleRuntime } from "@wadiou/tanstack-i18n";
import { createStartLocaleHelpers } from "@wadiou/tanstack-i18n/react-start"; // or /solid-start
import { config } from "./locale-config";
export const locale = createLocaleRuntime(config);
export const { getLocale, getDetectedLocale } =
createStartLocaleHelpers(locale, config);[!NOTE]
If you are building a Single Page Application (SPA), you don't needcreateStartLocaleHelpers. Calllocale.client.getLocale()directly in your loaders — no extra exports needed.
Read the active locale in a loader
Marketing site about page needs en or ar for layout and message loading.
For Full-stack (SSR):
Import the isomorphic getLocale helper:
// routes/{-$locale}/about.tsx loader
import { getLocale } from "../../locale";
export const Route = createFileRoute("/{-$locale}/about")({
loader: async () => {
const active = await getLocale();
return { activeLocale: active };
},
});For Single Page Applications (SPA):
Call locale.client.getLocale() directly:
// routes/{-$locale}/about.tsx loader
import { locale } from "../../locale";
export const Route = createFileRoute("/{-$locale}/about")({
loader: () => {
const active = locale.client.getLocale();
return { activeLocale: active };
},
});Resolution order: valid URL segment → persist adapters → defaultLocale. Infer is not in this chain — Behavior contract.
How it works
LocaleRuntime is the app-facing API. Config is frozen; methods close over it.
| Method | Role |
|---|---|
config | Validated LocaleConfig |
server.getLocale({ request }) | Active locale for SSR rendering (requires request) |
client.getLocale() | Active locale for client-side rendering |
localizeUrl / deLocalizeUrl | Prefix-aware URL building |
server.createServerEntry(handler) | Start middleware — TanStack Start |
[!NOTE] The root-level
locale.getLocale()andlocale.createServerEntry()methods still work for backward compatibility but are deprecated. Prefer thelocale.server.*andlocale.client.*namespaces.
User-initiated switching: Change locale — setLocale from createLocaleProvider, not the runtime directly.
Complete example
For Full-stack (SSR):
// src/locale.ts
import { createLocaleRuntime } from "@wadiou/tanstack-i18n";
import { createStartLocaleHelpers } from "@wadiou/tanstack-i18n/react-start"; // or /solid-start
import { config } from "./locale-config";
export const locale = createLocaleRuntime(config);
export const { getLocale, getDetectedLocale } =
createStartLocaleHelpers(locale, config);For Single Page Applications (SPA):
// src/locale.ts
import { createLocaleRuntime } from "@wadiou/tanstack-i18n";
import { config } from "./locale-config";
export const locale = createLocaleRuntime(config);
// Use locale.client.getLocale() directly in loaders — no extra exports neededURL localization helpers
The runtime exposes prefix-aware helper methods to format and parse pathnames programmatically. These methods are available on the root locale object, as well as on locale.server and locale.client.
localizeUrl(url, locale?)
Prefixes a URL object with a locale prefix segment based on the configured prefix mode.
If locale is omitted, the method resolves the locale from the incoming URL segment, falling back to defaultLocale (no cookie/persist storage read is performed).
import { locale } from "./locale";
const url = new URL("https://example.com/about");
// Prefix with a specific locale
const localizedAr = locale.localizeUrl(url, "ar");
console.log(localizedAr.pathname); // "/ar/about"
// Resolves locale from URL, falling back to defaultLocale
const localizedDefault = locale.localizeUrl(url);
console.log(localizedDefault.pathname); // "/about" (if default is "en" and prefix is "as-needed")deLocalizeUrl(url)
Strips the locale prefix segment from a URL object if a prefix exists.
import { locale } from "./locale";
const url = new URL("https://example.com/ar/about");
const deLocalized = locale.deLocalizeUrl(url);
console.log(deLocalized.pathname); // "/about"API reference
LocaleRuntime members
See table in How it works. Server entry outcomes (pass, redirect, …) are documented in Behavior contract and walked through in TanStack Start — not duplicated here.
What's next
Deepen how cookie and infer participate in requests: Adapters.
URL prefix modes
Manage URL language routing prefixes. Configure always, as-needed, or custom prefix paths, and define ignored routes and URL segments.
Adapters
Configure locale persistence and inference adapters. Learn how to use cookies, custom server/client callbacks, and Accept-Language headers in TanStack i18n.