Express & Fastify
On this page
@better-i18n/server/node provides two utilities for Node.js HTTP servers:
betterI18nMiddleware(i18n)— drop-in Express/Connect middlewarefromNodeHeaders(nodeHeaders)— convertsIncomingHttpHeadersto Web StandardsHeadersfor manual use with Fastify, Koa, or raw Node.js
Express #
Create the i18n singleton #
src/i18n.ts
import { createServerI18n } from "@better-i18n/server";
export const i18n = createServerI18n({
projectId: "my-org/api",
defaultLocale: "en",
});Register the middleware #
src/app.ts
import express from "express";
import { betterI18nMiddleware } from "@better-i18n/server/node"; // [!code highlight]
import { i18n } from "./i18n";
const app = express();
app.use(betterI18nMiddleware(i18n)); // [!code highlight]
app.get("/users/:id", async (req, res) => {
const user = await db.users.findById(req.params.id);
if (!user) {
return res.status(404).json({ error: req.t("errors.notFound") }); // [!code highlight]
}
res.json({ user, locale: req.locale }); // [!code highlight]
});
export default app;Add TypeScript types #
betterI18nMiddleware injects req.locale and req.t at runtime, but TypeScript doesn't know about them. Add a declaration file to augment the Express Request type:
src/types/express.d.ts
import type { Translator } from "@better-i18n/server";
declare global {
namespace Express {
interface Request {
locale: string; // [!code ++]
t: Translator; // [!code ++]
}
}
}Fastify #
Fastify doesn't use Express middleware, but fromNodeHeaders converts Fastify's req.headers (IncomingHttpHeaders) to a Web Standards Headers object that detectLocaleFromHeaders accepts:
src/plugins/i18n.ts
import fp from "fastify-plugin";
import { fromNodeHeaders } from "@better-i18n/server/node"; // [!code highlight]
import { i18n } from "../i18n";
export default fp(async (fastify) => {
fastify.decorateRequest("locale", "");
fastify.decorateRequest("t", null);
fastify.addHook("onRequest", async (request) => {
const headers = fromNodeHeaders(request.headers); // [!code highlight]
const locale = await i18n.detectLocaleFromHeaders(headers); // [!code highlight]
const t = await i18n.getTranslator(locale); // [!code highlight]
request.locale = locale;
request.t = t;
});
});Augment Fastify's request type:
src/types/fastify.d.ts
import type { Translator } from "@better-i18n/server";
declare module "fastify" {
interface FastifyRequest {
locale: string;
t: Translator;
}
}Related #
- Getting Started — Runtime-agnostic usage — workers, email senders, and scripts without middleware.
- Hono — Web Standards middleware for Hono, Cloudflare Workers, and Deno Deploy.
- API Reference — Full reference for
betterI18nMiddleware,fromNodeHeaders, andServerI18n.
Better I18N