I'm building a project using next.js and next-intl
plugin for internationalization.
I want to extend next-intl
locale detection logic by forcing the use of our own cookies (that were used before on this project).
The problem is when I chain my custom middleware in front of next-intl
middleware it does not seem to work. Looks like they are getting overwritten by a middleware in chain
my middleware - handleLocaleRedirect.ts:
export default async function handler(request: NextRequest) {
...
const newUrl = new URL(newPathname)
return NextResponse.redirect(newUrl)
}
handleI18NRouting.ts:
import { routing } from '../i18n/routing'
import createMiddleware from 'next-intl/middleware'
const handleI18nRouting = createMiddleware(routing)
export default async function handler(request: NextRequest) {
const response = handleI18nRouting(request)
// Remove excessive alternate links
const link = LinkHeader.parse(response.headers.get('link') || '')
link.refs = link.refs.filter((entry) =>
STANDARD_LOCALES.includes(entry.hreflang)
)
response.headers.set('link', link.toString())
return response
}
middleware.ts:
import { pagesWhiteListMiddleware } from './middlewares/pagesWhiteList'
import { chain } from '@nimpl/middleware-chain'
import handleI18nRouting from './middlewares/handleI18nRouting'
import handleLocaleRedirect from './middlewares/handleLocaleRedirect'
export default chain([
handleLocaleRedirect,
handleI18nRouting, // <-- here the page is getting redirected again, forcing next-intl logic
pagesWhiteListMiddleware,
])
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|next-assets|favicon.ico|sw.js|site.webmanifest).*)',
],
}
How to force my redirect?
The solution became clear after I stated the question like that ^
The final request is only returned to the client after the whole chain is complete.
This means that interim NextResponse.redirect
won't work in case there are more redirects afterwards.
The solution was to place the redirect logic inside next-intl
middleware configuration and remove it from the middlewares chain:
handleI18NRouting.ts:
const handleI18nRouting = createMiddleware(routing)
export default async function handler(request: NextRequest) {
const newUrl = await handleLocaleRedirect(request)
if (newUrl) {
const resp = NextResponse.redirect(newUrl)
resp.cookies.set(LANGUAGE_MODAL_COOKIE, 'true')
return resp
}
const response = handleI18nRouting(request)
// Remove excessive alternate links
const link = LinkHeader.parse(response.headers.get('link') || '')
link.refs = link.refs.filter((entry) =>
STANDARD_LOCALES.includes(entry.hreflang)
)
response.headers.set('link', link.toString())
return response
}
UPDATE:
Also since I was using the @nimpl/middleware-chain
it's really important to return FinalNextResponse
in case you want to redirect before hitting the rest of the middlewares:
middleware.ts:
import { pagesWhiteListMiddleware } from './middlewares/pagesWhiteList'
import { chain, FinalNextResponse } from '@nimpl/middleware-chain'
import handleI18nRouting from './middlewares/handleI18nRouting'
import { NextResponse } from 'next/server'
export default chain([
handleI18nRouting,
function (req) {
if (req.summary.type === 'redirect') return FinalNextResponse.next() // <-- this will break the chain and return the actual response from the previous chain middleware
return NextResponse.next()
},
pagesWhiteListMiddleware,
])
export const config = {
matcher: [
'/((?!api|_next/static|_next/image|next-assets|favicon.ico|sw.js|site.webmanifest).*)',
],
}