Owns the locale axis of an application. One locale set derives the URL segment, negotiation, the params schema, and the static paths; each message is a function that reads the locale where it is called, so the same line renders on the server and in the browser, and only the messages a page names reach its bundle.
Every word from the header to the footer comes from @k8ordo/i18n's message. The greeting below is a message that takes an argument.
Hello.
detectingThe argument of greeting(name) is typed by the function written for ja. An en written with different parameters does not compile.
Define the locale set, register it, write each message with message, and call it. That is all.
defineLocales(['ja', 'en']) is written once. The default, membership, negotiation, the URL segment, and the [locale] schema all come from it, so there is nowhere to copy the list to.localize / delocalize put the segment on and take it off, and paramsSchema makes /fr/… a real 404. The rest of the pathname belongs to @k8ordo/router.negotiate(navigator.languages) and negotiate(parseAcceptLanguage(header)) are the same function: each requested tag in order, exact match, then the same language, then the default.message({ ja, en }) is one message. It does not type-check until every locale is there, and its arguments are typed by the function you wrote. No key list, no dictionary object.[locale] is the locale of that render; in the browser the URL is. nav.home() renders the same on both.The guide ships inside the npm package. An AI coding assistant reads the exact installed version out of node_modules/@k8ordo/i18n/docs/.
// i18n.ts — 一覧はここにしか書かない
export const locales = defineLocales(['ja', 'en']);
declare module '@k8ordo/i18n' {
interface Register { locale: LocaleOf<typeof locales> }
}
// messages/nav.ts — 文言は 1 つずつ関数。全ロケールが揃わないと通らない
export const home = message({ ja: 'ホーム', en: 'Home' });
export const greeting = message({
ja: (name: string) => `こんにちは、${name}さん`,
en: (name) => `Hello, ${name}`, // 引数の型は ja から流れる
});
// routes/[locale]/layout.tsx — 受理したロケールがこの描画のロケールになる
export const paramsSchema = locales.paramsSchema; // /fr/… は 404
// Server Component でも Client Component でも、同じ 1 行
<h1>{nav.home()}</h1>
<p>{nav.greeting(name)}</p>