+11
-3
@@ -1,9 +1,17 @@
|
|||||||
import { defineRouting } from "next-intl/routing";
|
import { defineRouting } from "next-intl/routing";
|
||||||
|
|
||||||
export const routing = defineRouting({
|
export const appLocales = ["de", "en", "ar"] as const;
|
||||||
locales: ["de", "en", "ar"],
|
|
||||||
defaultLocale: "de",
|
export type RoutingLocale = (typeof appLocales)[number];
|
||||||
|
|
||||||
|
export function createI18nRouting(defaultLocale: RoutingLocale = "de") {
|
||||||
|
return defineRouting({
|
||||||
|
locales: appLocales,
|
||||||
|
defaultLocale,
|
||||||
localePrefix: "as-needed",
|
localePrefix: "as-needed",
|
||||||
localeCookie: false,
|
localeCookie: false,
|
||||||
localeDetection: 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 { NextResponse } from "next/server";
|
||||||
import type { NextRequest } from "next/server";
|
import type { NextRequest } from "next/server";
|
||||||
|
|
||||||
import { routing } from "./i18n/routing";
|
import { appLocales, createI18nRouting, routing } from "./i18n/routing";
|
||||||
import {
|
import {
|
||||||
fromDevelopmentAdminPath,
|
fromDevelopmentAdminPath,
|
||||||
getAdminBaseUrl,
|
getAdminBaseUrl,
|
||||||
@@ -16,19 +16,18 @@ import {
|
|||||||
} from "./lib/admin-routing";
|
} from "./lib/admin-routing";
|
||||||
import { getLocalizedPathWithDefault, stripLocalePrefix } from "./lib/locale";
|
import { getLocalizedPathWithDefault, stripLocalePrefix } from "./lib/locale";
|
||||||
|
|
||||||
const intlMiddleware = createMiddleware(routing);
|
|
||||||
const ADMIN_SESSION_COOKIE = "moh_admin_session";
|
const ADMIN_SESSION_COOKIE = "moh_admin_session";
|
||||||
|
|
||||||
type SiteRuntimeState = {
|
type SiteRuntimeState = {
|
||||||
defaultLocale: (typeof routing.locales)[number];
|
defaultLocale: (typeof appLocales)[number];
|
||||||
maintenanceEnabled: boolean;
|
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";
|
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];
|
const locale = pathname.split("/")[1];
|
||||||
|
|
||||||
return isSupportedLocale(locale) ? locale : fallbackLocale;
|
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 {
|
function getAdminBasicAuthUser(): string {
|
||||||
return process.env.ADMIN_BASIC_AUTH_USER ?? "";
|
return process.env.ADMIN_BASIC_AUTH_USER ?? "";
|
||||||
}
|
}
|
||||||
@@ -173,6 +168,7 @@ export default async function middleware(request: NextRequest) {
|
|||||||
|
|
||||||
const siteRuntimeState = await getSiteRuntimeState(request);
|
const siteRuntimeState = await getSiteRuntimeState(request);
|
||||||
const configuredDefaultLocale = siteRuntimeState.defaultLocale;
|
const configuredDefaultLocale = siteRuntimeState.defaultLocale;
|
||||||
|
const intlMiddleware = createMiddleware(createI18nRouting(configuredDefaultLocale));
|
||||||
|
|
||||||
if (
|
if (
|
||||||
siteRuntimeState.maintenanceEnabled &&
|
siteRuntimeState.maintenanceEnabled &&
|
||||||
@@ -185,36 +181,6 @@ export default async function middleware(request: NextRequest) {
|
|||||||
return NextResponse.redirect(redirectUrl, 307);
|
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);
|
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