Unify dynamic locale routing
CI / quality (push) Waiting to run

This commit is contained in:
MOH
2026-03-15 05:12:33 +01:00
parent dfed5ec831
commit 27df4ad2fe
3 changed files with 42 additions and 46 deletions
+11 -3
View File
@@ -1,9 +1,17 @@
import { defineRouting } from "next-intl/routing";
export const routing = defineRouting({
locales: ["de", "en", "ar"],
defaultLocale: "de",
export const appLocales = ["de", "en", "ar"] as const;
export type RoutingLocale = (typeof appLocales)[number];
export function createI18nRouting(defaultLocale: RoutingLocale = "de") {
return defineRouting({
locales: appLocales,
defaultLocale,
localePrefix: "as-needed",
localeCookie: false,
localeDetection: false,
});
}
export const routing = createI18nRouting();
+5 -39
View File
@@ -2,7 +2,7 @@ import createMiddleware from "next-intl/middleware";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { routing } from "./i18n/routing";
import { appLocales, createI18nRouting, routing } from "./i18n/routing";
import {
fromDevelopmentAdminPath,
getAdminBaseUrl,
@@ -16,19 +16,18 @@ import {
} from "./lib/admin-routing";
import { getLocalizedPathWithDefault, stripLocalePrefix } from "./lib/locale";
const intlMiddleware = createMiddleware(routing);
const ADMIN_SESSION_COOKIE = "moh_admin_session";
type SiteRuntimeState = {
defaultLocale: (typeof routing.locales)[number];
defaultLocale: (typeof appLocales)[number];
maintenanceEnabled: boolean;
};
function isSupportedLocale(locale: string | undefined): locale is (typeof routing.locales)[number] {
function isSupportedLocale(locale: string | undefined): locale is (typeof appLocales)[number] {
return locale === "ar" || locale === "en" || locale === "de";
}
function getPathLocale(pathname: string, fallbackLocale: (typeof routing.locales)[number]) {
function getPathLocale(pathname: string, fallbackLocale: (typeof appLocales)[number]) {
const locale = pathname.split("/")[1];
return isSupportedLocale(locale) ? locale : fallbackLocale;
@@ -71,10 +70,6 @@ async function getSiteRuntimeState(request: NextRequest): Promise<SiteRuntimeSta
}
}
function hasLocalePrefix(pathname: string) {
return routing.locales.some((locale) => pathname === `/${locale}` || pathname.startsWith(`/${locale}/`));
}
function getAdminBasicAuthUser(): string {
return process.env.ADMIN_BASIC_AUTH_USER ?? "";
}
@@ -173,6 +168,7 @@ export default async function middleware(request: NextRequest) {
const siteRuntimeState = await getSiteRuntimeState(request);
const configuredDefaultLocale = siteRuntimeState.defaultLocale;
const intlMiddleware = createMiddleware(createI18nRouting(configuredDefaultLocale));
if (
siteRuntimeState.maintenanceEnabled &&
@@ -185,36 +181,6 @@ export default async function middleware(request: NextRequest) {
return NextResponse.redirect(redirectUrl, 307);
}
if (
configuredDefaultLocale !== routing.defaultLocale &&
(pathname === "/de" || pathname.startsWith("/de/"))
) {
return NextResponse.next();
}
if (
configuredDefaultLocale !== routing.defaultLocale &&
!hasLocalePrefix(pathname)
) {
const rewriteUrl = request.nextUrl.clone();
rewriteUrl.pathname = getLocalizedPathWithDefault(
configuredDefaultLocale,
pathname,
routing.defaultLocale,
);
return NextResponse.rewrite(rewriteUrl);
}
if (
configuredDefaultLocale === routing.defaultLocale &&
(pathname === "/de" || pathname.startsWith("/de/"))
) {
const redirectUrl = request.nextUrl.clone();
const nextPath = pathname.slice(3) || "/";
redirectUrl.pathname = nextPath;
return NextResponse.redirect(redirectUrl, 308);
}
return intlMiddleware(request);
}
+22
View File
@@ -0,0 +1,22 @@
import { describe, expect, it } from "vitest";
import { getLocalizedPathWithDefault } from "../lib/locale";
describe("locale path helpers", () => {
it("keeps the configured default locale on the bare domain", () => {
expect(getLocalizedPathWithDefault("ar", "/", "ar")).toBe("/");
expect(getLocalizedPathWithDefault("de", "/", "ar")).toBe("/de");
expect(getLocalizedPathWithDefault("en", "/", "ar")).toBe("/en");
});
it("builds nested paths against the configured default locale", () => {
expect(getLocalizedPathWithDefault("ar", "/coming-soon", "ar")).toBe("/coming-soon");
expect(getLocalizedPathWithDefault("de", "/coming-soon", "ar")).toBe("/de/coming-soon");
expect(getLocalizedPathWithDefault("en", "/portfolio", "de")).toBe("/en/portfolio");
});
it("strips old locale prefixes before rebuilding the target path", () => {
expect(getLocalizedPathWithDefault("en", "/ar/contact", "de")).toBe("/en/contact");
expect(getLocalizedPathWithDefault("ar", "/de/about", "ar")).toBe("/about");
});
});