import { NextRequest, NextResponse } from 'next/server'; import { locales, defaultLocale, isLocale, LOCALE_COOKIE, type Locale } from '@/i18n/config'; // Host-based separation between the marketing landing site and the // authenticated panel. Configured at runtime (server-side) so the same // frontend image can serve both hosts. When PANEL_HOST is unset (local dev), // host routing is disabled and everything is served from a single origin. const PANEL_HOST = process.env.PANEL_HOST?.trim().toLowerCase(); const LANDING_HOST = process.env.LANDING_HOST?.trim().toLowerCase(); // Locale-stripped path prefixes that belong to the authenticated panel. const PANEL_PATH_PREFIXES = ['/dashboard', '/login', '/register']; function stripLocale(pathname: string): string { for (const l of locales) { if (pathname === `/${l}`) return '/'; if (pathname.startsWith(`/${l}/`)) return pathname.slice(l.length + 1); } return pathname; } function isPanelPath(pathname: string): boolean { const p = stripLocale(pathname); return PANEL_PATH_PREFIXES.some((pre) => p === pre || p.startsWith(`${pre}/`)); } function hostOf(request: NextRequest): string { return (request.headers.get('host') || '').split(':')[0].toLowerCase(); } function detectLocale(request: NextRequest): Locale { // Honour the user's last explicit choice, persisted in a cookie by the // language switcher. On the very first visit (no cookie) we always serve the // default locale (fa-IR) rather than guessing from Accept-Language, so the // browser's language preference never overrides the default. From then on, // the user's last selection is what determines the language. const cookieLocale = request.cookies.get(LOCALE_COOKIE)?.value; if (isLocale(cookieLocale)) return cookieLocale; return defaultLocale; } export function middleware(request: NextRequest) { const { pathname, search } = request.nextUrl; // 1. Ensure a locale prefix (e.g. /login -> /fa-IR/login). On the redirect // the host is preserved, so host routing (below) runs on the next request. const pathnameHasLocale = locales.some( (locale) => pathname === `/${locale}` || pathname.startsWith(`/${locale}/`), ); if (!pathnameHasLocale) { const locale = detectLocale(request); request.nextUrl.pathname = `/${locale}${pathname === '/' ? '' : pathname}`; const response = NextResponse.redirect(request.nextUrl); response.cookies.set(LOCALE_COOKIE, locale, { path: '/', maxAge: 60 * 60 * 24 * 365 }); return response; } // 2. Host-based separation between the landing site and the panel. // Disabled entirely unless PANEL_HOST is configured (local dev). if (PANEL_HOST) { const host = hostOf(request); const panelPath = isPanelPath(pathname); // Authenticated routes requested on the landing host -> move to the panel. if (LANDING_HOST && host === LANDING_HOST && panelPath) { return NextResponse.redirect(`https://${PANEL_HOST}${pathname}${search}`, 308); } // Marketing pages requested on the panel host -> send to the dashboard. if (host === PANEL_HOST && !panelPath) { const locale = pathname.split('/')[1]; // path is already locale-prefixed const target = request.nextUrl.clone(); target.pathname = `/${locale}/dashboard`; return NextResponse.redirect(target); } } return; } export const config = { // Skip Next internals, the API, and any path containing a dot (static files). matcher: ['/((?!_next|api|.*\\..*).*)'], };