+11
-3
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user