@sphinxjs/detect-locale
v0.0.1
Published
Server-side locale detection from an HTTP `Accept-Language` header using `@formatjs/intl-localematcher` and `negotiator`.
Readme
@sphinxjs/detect-locale
Server-side locale detection from an HTTP Accept-Language header using @formatjs/intl-localematcher and negotiator.
Install
pnpm add @sphinxjs/detect-localeAPI
detectLocale({ locales, defaultLocale, acceptLanguage })
Returns the best-matching locale string for a given Accept-Language header value.
import { detectLocale } from "@sphinxjs/detect-locale";
const locale = detectLocale({
locales: ["en", "fr", "de"],
defaultLocale: "en",
acceptLanguage: request.headers.get("accept-language") ?? "",
});
// → "fr" (when the browser prefers French)Usage by framework
Next.js
Add a middleware.ts at the project root. On every request, detect the preferred locale and redirect to the locale-prefixed path if the URL doesn't already have one.
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
import { detectLocale } from "@sphinxjs/detect-locale";
const locales = ["en", "fr", "de"];
const defaultLocale = "en";
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Skip if already locale-prefixed or is a static asset
const hasLocale = locales.some(
(locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`,
);
if (hasLocale) return;
const locale = detectLocale({
locales,
defaultLocale,
acceptLanguage: request.headers.get("accept-language") ?? "",
});
request.nextUrl.pathname = `/${locale}${pathname}`;
return NextResponse.redirect(request.nextUrl);
}
export const config = {
matcher: ["/((?!_next|favicon.ico).*)"],
};Pair with i18n routing in next.config.ts or the App Router's locale segment (app/[locale]/).
Astro
Use Astro middleware (src/middleware.ts) to detect locale and store it in locals for use in pages and layouts.
// src/middleware.ts
import type { MiddlewareHandler } from "astro";
import { defineMiddleware } from "astro/middleware";
import { detectLocale } from "@sphinxjs/detect-locale";
const locales = ["en", "fr", "de"];
const defaultLocale = "en";
export const onRequest: MiddlewareHandler = defineMiddleware((context, next) => {
const locale = detectLocale({
locales,
defaultLocale,
acceptLanguage: context.request.headers.get("accept-language") ?? "",
});
context.locals.locale = locale;
return next();
});// src/env.d.ts (extend Astro's Locals type)
declare namespace App {
interface Locals {
locale: string;
}
}Then read Astro.locals.locale in any .astro page or layout.
React Router (v7 / framework mode)
Use a loader in root.tsx or a dedicated locale route to detect locale server-side and expose it to the client.
// app/root.tsx
import type { LoaderFunctionArgs } from "react-router";
import { detectLocale } from "@sphinxjs/detect-locale";
const locales = ["en", "fr", "de"];
const defaultLocale = "en";
export async function loader({ request }: LoaderFunctionArgs) {
const locale = detectLocale({
locales,
defaultLocale,
acceptLanguage: request.headers.get("accept-language") ?? "",
});
return { locale };
}For locale-prefixed URLs, add a catch-all route app/routes/$locale.tsx and validate the locale param against your supported list, falling back to detectLocale when the URL has no prefix.
