65 lines
2.3 KiB
TypeScript
65 lines
2.3 KiB
TypeScript
import { NextResponse } from 'next/server'
|
|
import type { NextRequest } from 'next/server'
|
|
|
|
const SHARED_LANGUAGE_COOKIE = 'rentaldrivego-language'
|
|
const MARKETPLACE_LANGUAGE_COOKIE = 'marketplace-language'
|
|
|
|
|
|
function rejectInternalSubrequest(request: NextRequest): NextResponse | null {
|
|
if (!request.headers.has('x-middleware-subrequest')) return null
|
|
return new NextResponse('Unsupported internal request header', { status: 400 })
|
|
}
|
|
|
|
function isValidLanguage(val: string | null | undefined): val is 'en' | 'fr' | 'ar' {
|
|
return val === 'en' || val === 'fr' || val === 'ar'
|
|
}
|
|
|
|
function detectFromAcceptLanguage(header: string | null): 'en' | 'fr' | 'ar' {
|
|
if (!header) return 'en'
|
|
for (const entry of header.split(',')) {
|
|
const code = entry.split(';')[0].trim().split('-')[0].toLowerCase()
|
|
if (code === 'ar' || code === 'fr' || code === 'en') return code as 'en' | 'fr' | 'ar'
|
|
}
|
|
return 'en'
|
|
}
|
|
|
|
export function middleware(request: NextRequest) {
|
|
const rejected = rejectInternalSubrequest(request)
|
|
if (rejected) return rejected
|
|
|
|
const sharedLang = request.cookies.get(SHARED_LANGUAGE_COOKIE)?.value
|
|
|
|
// Already has the canonical language cookie — no action needed
|
|
if (isValidLanguage(sharedLang)) return NextResponse.next()
|
|
|
|
const legacyLang = request.cookies.get(MARKETPLACE_LANGUAGE_COOKIE)?.value
|
|
const resolved: 'en' | 'fr' | 'ar' = isValidLanguage(legacyLang)
|
|
? legacyLang
|
|
: detectFromAcceptLanguage(request.headers.get('accept-language'))
|
|
|
|
// Inject the resolved language into the request cookie header so that
|
|
// getMarketplaceLanguage() (which calls cookies()) sees the correct value
|
|
// even on this very first render — before the browser has stored the cookie.
|
|
const requestHeaders = new Headers(request.headers)
|
|
const existing = request.headers.get('cookie') ?? ''
|
|
const injected = `${SHARED_LANGUAGE_COOKIE}=${resolved}`
|
|
requestHeaders.set('cookie', existing ? `${existing}; ${injected}` : injected)
|
|
|
|
const response = NextResponse.next({ request: { headers: requestHeaders } })
|
|
|
|
// Persist in the browser for future requests
|
|
response.cookies.set(SHARED_LANGUAGE_COOKIE, resolved, {
|
|
maxAge: 365 * 24 * 60 * 60,
|
|
path: '/',
|
|
sameSite: 'lax',
|
|
})
|
|
|
|
return response
|
|
}
|
|
|
|
export const config = {
|
|
matcher: [
|
|
'/((?!_next/static|_next/image|favicon\\.ico|.*\\.(?:png|ico|jpg|jpeg|svg|webp)$).*)',
|
|
],
|
|
}
|