目前,Next.js 仅从根目录重定向到用户的语言,因此“/”变为“/fr-FR”。但是如果用户访问例如“/profile”路由,它不会将他重定向到“/fr-FR/profile”。
有没有办法强制 Next 做这些类型的重定向?
对我来说,关键是按照以下方式设置我的
_middleware.ts
:
const PUBLIC_FILE = /\.(.*)$/ // anything having a file extension.
const getIsInternalRoute = (url: string) => {
if (url.startsWith('/_next')) return true // next internal routes
if (url.includes('/api/')) return true // nextjs api routes
return PUBLIC_FILE.test(url) // static files
}
const handleLocaleRedirects = (req: NextRequest) => {
const { pathname } = req.nextUrl
const isPreloadRequest = req.method === 'HEAD'
/*
Due to several bugs with prefetching/middleware/i18n combination
https://github.com/vercel/next.js/issues/35648
https://github.com/vercel/next.js/issues/36100
https://github.com/vercel/next.js/issues/40678
we cannot redirect any prefetch requests. They get cached with the current locale which then causes
infinite loop redirect when we click a link to change the locale.
Possibly might be fixed in later NextJs versions (>=13), but I'd be really careful & skeptical here.
*/
if (isPreloadRequest || getIsInternalRoute(pathname)) return
const locale = req.cookies.NEXT_LOCALE || req.nextUrl.defaultLocale // locale you're supposed to have
if (locale && req.nextUrl.locale !== locale) {
req.nextUrl.locale = locale
return NextResponse.redirect(req.nextUrl)
}
}
export function middleware(req: NextRequest) {
const maybeRedirectResponse = handleLocaleRedirects(req)
if (maybeRedirectResponse) return maybeRedirectResponse
const response = NextResponse.next()
// perhaps other middleware logic here...
return response
}
并设置切换器链接以在重定向到新路由之前设置 cookie,因此中间件已经具有新的 NEXT_LOCALE 值。
function LocaleSwitcher({ locale, children, ...props }) {
const router = useRouter()
const { pathname, asPath, query } = router
const handleClick = e => {
e.preventDefault()
/*
The locale cookie needs to be set before the page redirect, so the nextjs middleware already knows which locale is correct.
*/
setCookie({}, 'NEXT_LOCALE', locale, {
maxAge: 100 * 365 * 24 * 60 * 60, // 100 yrs
})
// change just the locale and maintain all other route information including href's query
router.push({ pathname, query }, asPath, { locale })
}
return (
<Link {...props} locale={locale} to={asPath} onClick={handleClick}>
{children}
</Link>
)
}
此设置从每条路线上的 cookie 中检查用户的语言环境,并将他们重定向到站点的正确语言环境版本。
您可以使用 middleware 和 NEXT_LOCALE cookie,当您更改语言时,您应该设置这个 cookie
document.cookie = `NEXT_LOCALE=${langugage};path=/`;
中间件.js
import { NextResponse } from "next/server";
export function middleware(request) {
const localeCookie = request.cookies.get("NEXT_LOCALE");
if (localeCookie !== undefined && request.nextUrl.locale !== localeCookie) {
return NextResponse.redirect(new URL(`/${localeCookie}${request.nextUrl.pathname}`, request.url));
}
}
export const config = {
matcher: ["/", "/about"], // paths on which middleware will work
};
https://nextjs.org/docs/advanced-features/i18n-routing#leveraging-the-next_locale-cookie
https://nextjs.org/docs/advanced-features/i18n-routing#prefixing-the-default-locale
https://nextjs.org/docs/advanced-features/middleware
Sub-path Routing
Sub-path Routing puts the locale in the url path.
With the above configuration en-US, fr, and nl-NL will be available to be routed to, and en-US is the default locale. If you have a pages/blog.js the following urls would be available:
//next.config.js
module.exports = {
i18n: {
locales: ['en-US', 'fr', 'nl-NL'],
defaultLocale: 'en-US',
},
}
/blog
/fr/blog
/nl-nl/blog
The default locale does not have a prefix.
from Nextjs docs