1
+ import prependString from '@louffee/lib/prepend-string'
1
2
import { NextResponse , type NextRequest } from 'next/server'
2
3
3
4
import constants from './constants'
@@ -19,8 +20,9 @@ export interface DetectLanguageMiddlewareOptions extends MatchLanguageOptions {
19
20
}
20
21
21
22
/**
22
- * Detects the language from the request and redirects to the correct language
23
- * if the language is not set.
23
+ * The `detectLanguageMiddleware()` creates a function which detects the
24
+ * language from the request and redirects to the correct language if the
25
+ * language is not set.
24
26
*
25
27
* If the language is not set, it will redirect to the `default` language. The
26
28
* language is defined in the `NEXT_language` cookie and the user is redirected
@@ -55,27 +57,35 @@ function detectLanguageMiddleware({ defaultLanguage, languages, ignoredPaths }:
55
57
// of the object must be "accept-language" (case sensitive). For
56
58
// reference, see:
57
59
// https://github.com/jshttp/negotiator/blob/master/index.js#L62C1-L63C1
58
- request . headers . forEach ( ( value , key ) => {
59
- negotiatorHeaders [ key ] = value
60
- } )
60
+ for ( const [ key , value ] of request . headers ) {
61
+ if ( key . toLowerCase ( ) === 'accept-language' ) {
62
+ negotiatorHeaders [ key ] = value
63
+ }
64
+ }
61
65
62
66
const isPathnameMissingLocale = ! hasPathnameAnyLanguage ( pathname , languages )
63
67
64
68
if ( isPathnameMissingLocale ) {
65
69
const locale = matchLanguage ( negotiatorHeaders , { defaultLanguage, languages } )
66
70
67
- const slashAfterLocale = `${ pathname . startsWith ( '/' ) ? '' : '/' } `
68
71
const searchParams = request . nextUrl . searchParams ?. length ? `?${ request . nextUrl . searchParams } ` : ''
72
+ const pathnameWithSlash = prependString ( '/' , pathname )
69
73
70
- const redirectPath = `${ locale } ${ slashAfterLocale } ${ pathname } ${ searchParams } `
74
+ const redirectPath = `${ locale } ${ pathnameWithSlash } ${ searchParams } `
71
75
const redirectBase = request . url
72
76
73
77
const href = `${ redirectBase } ${ redirectPath } `
74
78
75
- const response = NextResponse . next ( )
79
+ // NOTE: We have to set the language cookie here because the `redirect()`.
80
+ // So we create the NextResponse from the redirect() static method,
81
+ // inject the LANGUAGE_COOKIE_NAME and return the response, which
82
+ // Next.js interprets as the end of the middleware chain. See the
83
+ // official documentation on how to use the `redirect()` method:
84
+ // https://nextjs.org/docs/app/api-reference/functions/next-response#redirect
85
+ const response = NextResponse . redirect ( href )
76
86
response . cookies . set ( constants . LANGUAGE_COOKIE_NAME , locale )
77
87
78
- return NextResponse . rewrite ( href , response )
88
+ return response
79
89
}
80
90
81
91
const response = NextResponse . next ( )
0 commit comments