import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { match } from '@formatjs/intl-localematcher'; import Negotiator from 'negotiator'; import { i18n } from '@/i18n-config'; import { getPathnameLocale } from '@/src/utils/getLocale'; /** Pick the best locale from the Accept-Language header */ function getLocale(request: NextRequest): string { // Negotiator wants a plain JS object, not a Headers instance const negotiatorHeaders: Record = {}; request.headers.forEach((value, key) => { negotiatorHeaders[key] = value; }); try { const languages = new Negotiator({ headers: negotiatorHeaders }).languages(); // Filter out invalid locale values that would cause Intl.getCanonicalLocales to fail const validLanguages = languages.filter((lang) => { try { Intl.getCanonicalLocales(lang); return true; } catch { return false; } }); if (validLanguages.length === 0) { return i18n.defaultLocale; } return match(validLanguages, i18n.locales, i18n.defaultLocale); } catch (error) { // Fallback to default locale if locale negotiation fails console.error('Locale negotiation error:', error); return i18n.defaultLocale; } } export function middleware(request: NextRequest) { const { pathname } = request.nextUrl; /* ------------------------------------------------------------------ */ /* Locale handling: redirect /dashboard → /en-US/dashboard */ /* ------------------------------------------------------------------ */ const hasLocale = Boolean(getPathnameLocale(pathname)); if (!hasLocale) { const locale = getLocale(request); const url = request.nextUrl.clone(); url.pathname = `/${locale}${pathname}`; return NextResponse.redirect(url); } // Auth is handled client-side by swissoid-front return NextResponse.next(); } /** * Run the middleware on every request except: * • /_next/static & /_next/image * • any file that looks like a static asset (has a file extension) * • images folder */ export const config = { matcher: [ '/((?!_next/static|_next/image|images/.*|favicon.ico|robots.txt|sitemap.xml|.*\\.(?:jpg|jpeg|gif|png|svg|ico|webp|avif)).*)', ], };