From 1ab8d260a2ad7d14d2b89f7d493f9e3e90379606 Mon Sep 17 00:00:00 2001 From: Biki Kalita <86558912+Biki-dev@users.noreply.github.com> Date: Tue, 30 Dec 2025 17:10:33 +0530 Subject: [PATCH] fix: restore locale redirection using Next.js middleware (#462) * fix: restore locale redirection using Next.js middleware * fix: use proxy.ts instead of middleware.ts for Next.js 16 --------- Co-authored-by: Dayuan Jiang --- proxy.ts | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 proxy.ts diff --git a/proxy.ts b/proxy.ts new file mode 100644 index 0000000..1db77c6 --- /dev/null +++ b/proxy.ts @@ -0,0 +1,63 @@ +import { match as matchLocale } from "@formatjs/intl-localematcher" +import Negotiator from "negotiator" +import type { NextRequest } from "next/server" +import { NextResponse } from "next/server" +import { i18n } from "./lib/i18n/config" + +function getLocale(request: NextRequest): string | undefined { + // Negotiator expects plain object so we need to transform headers + const negotiatorHeaders: Record = {} + request.headers.forEach((value, key) => { + negotiatorHeaders[key] = value + }) + + // @ts-expect-error locales are readonly + const locales: string[] = i18n.locales + + // Use negotiator and intl-localematcher to get best locale + const languages = new Negotiator({ headers: negotiatorHeaders }).languages( + locales, + ) + + const locale = matchLocale(languages, locales, i18n.defaultLocale) + + return locale +} + +export function proxy(request: NextRequest) { + const pathname = request.nextUrl.pathname + + // Skip API routes, static files, and Next.js internals + if ( + pathname.startsWith("/api/") || + pathname.startsWith("/_next/") || + pathname.includes("/favicon") || + /\.(.*)$/.test(pathname) + ) { + return + } + + // Check if there is any supported locale in the pathname + const pathnameIsMissingLocale = i18n.locales.every( + (locale) => + !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`, + ) + + // Redirect if there is no locale + if (pathnameIsMissingLocale) { + const locale = getLocale(request) + + // Redirect to localized path + return NextResponse.redirect( + new URL( + `/${locale}${pathname.startsWith("/") ? "" : "/"}${pathname}`, + request.url, + ), + ) + } +} + +export const config = { + // Matcher ignoring `/_next/` and `/api/` + matcher: ["/((?!api|_next/static|_next/image|favicon.ico).*)"], +}