// proxy.ts (was middleware.ts) import { NextRequest, NextResponse } from "next/server"; import { defaultLocale, isValidLocale } from "@/lib/dictionaries"; // RENAMED: middleware → proxy (Next.js 16 convention) export function proxy(request: NextRequest) { const { pathname } = request.nextUrl; // Skip static files, API routes, Next.js internals if ( pathname.startsWith("/_next") || pathname.startsWith("/api") || pathname.startsWith("/favicon") || pathname.includes(".") ) { return NextResponse.next(); } // Check if path already has a valid locale prefix const pathLocale = pathname.split("/")[1]; if (isValidLocale(pathLocale)) { // Serve directly — NEVER redirect locale-prefixed URLs. // Forward the URL locale as a request header so server components // without params access (e.g. not-found.tsx) can read it. const requestHeaders = new Headers(request.headers); requestHeaders.set("x-locale", pathLocale); requestHeaders.set("x-preferred-locale", detectPreferredLocale(request)); return NextResponse.next({ request: { headers: requestHeaders } }); } // No locale prefix — redirect to default (or cookie preference) const cookieLocale = request.cookies.get("NEXT_LOCALE")?.value; const targetLocale = cookieLocale && isValidLocale(cookieLocale) ? cookieLocale : defaultLocale; const url = request.nextUrl.clone(); url.pathname = `/${targetLocale}${pathname}`; return NextResponse.redirect(url, 307); } function detectPreferredLocale(request: NextRequest): string { const acceptLang = request.headers.get("accept-language") || ""; const segments = acceptLang .split(",") .map((part) => { const [lang, q] = part.trim().split(";q="); return { lang: lang.toLowerCase().trim(), quality: q ? parseFloat(q) : 1.0, }; }) .sort((a, b) => b.quality - a.quality); for (const { lang } of segments) { const base = lang.split("-")[0]; if (["sr", "bs", "hr"].includes(base)) return "sr"; if (base === "en") return "en"; } return defaultLocale; } export const config = { matcher: ["/((?!_next|api|favicon\\.ico|.*\\..*).*)"], };