在Next.js中读取Accept-language头,适配Strapi多语言API内容
解决方案:Next.js结合Strapi基于Accept-Language返回多语言内容
一、你的中间件问题修正
你的中间件逻辑方向是对的,但有两个小问题:
match函数返回的是单个匹配的locale字符串,不是数组,变量名改成req.preferredLocale更准确- Next.js的Pages Router和App Router中间件语法不同,需对应调整
Pages Router 修正后的中间件
import { match } from '@formatjs/intl-localematcher'; import Negotiator from 'negotiator'; export default function middleware(req, res, next) { const acceptLangHeader = req.headers['accept-language'] || 'en-US,en;q=0.5'; const negotiator = new Negotiator({ headers: { 'accept-language': acceptLangHeader } }); const userLangs = negotiator.languages(); const supportedLocales = ['en-US', 'nl-NL', 'nl']; const defaultLocale = 'en-US'; // 匹配到单个最优locale req.preferredLocale = match(userLangs, supportedLocales, defaultLocale); next(); }
App Router 中间件写法(适用Next.js 13+)
App Router的中间件不能直接修改req,需通过请求头传递偏好语言:
import { match } from '@formatjs/intl-localematcher'; import Negotiator from 'negotiator'; import { NextResponse } from 'next/server'; export function middleware(request) { const acceptLangHeader = request.headers.get('accept-language') || 'en-US,en;q=0.5'; const negotiator = new Negotiator({ headers: { 'accept-language': acceptLangHeader } }); const userLangs = negotiator.languages(); const supportedLocales = ['en-US', 'nl-NL', 'nl']; const defaultLocale = 'en-US'; const preferredLocale = match(userLangs, supportedLocales, defaultLocale); // 将偏好语言通过请求头传递给后续路由/组件 const response = NextResponse.next(); response.headers.set('x-preferred-locale', preferredLocale); return response; }
二、结合Strapi API获取对应语言内容
Strapi启用国际化插件后,所有内容API都支持通过locale查询参数指定返回语言,比如GET /api/posts?locale=nl-NL。
Pages Router 示例(在getServerSideProps中使用)
export async function getServerSideProps(context) { // 从中间件设置的req.preferredLocale拿值 const preferredLocale = context.req.preferredLocale; // 调用Strapi API时带上locale参数 const res = await fetch(`${process.env.NEXT_PUBLIC_STRAPI_URL}/api/posts?locale=${preferredLocale}`); const data = await res.json(); return { props: { posts: data.data, locale: preferredLocale } }; }
App Router 示例(Server Component中获取)
import { headers } from 'next/headers'; export default async function PostsPage() { // 从中间件设置的请求头拿偏好语言 const headersList = headers(); const preferredLocale = headersList.get('x-preferred-locale') || 'en-US'; const res = await fetch(`${process.env.NEXT_PUBLIC_STRAPI_URL}/api/posts?locale=${preferredLocale}`, { next: { revalidate: 60 } // 可选:添加缓存策略 }); const data = await res.json(); return ( <div> <h1>Posts in {preferredLocale}</h1> {data.data.map(post => ( <div key={post.id}>{post.attributes.title}</div> ))} </div> ); }
三、更轻量的替代方案(无需中间件)
如果不想依赖第三方包,可直接在数据获取逻辑里解析Accept-Language头:
function getPreferredLocale(acceptLangHeader, supportedLocales, defaultLocale) { if (!acceptLangHeader) return defaultLocale; // 解析头信息并按权重排序 const langEntries = acceptLangHeader.split(',').map(entry => { const [lang, weight] = entry.trim().split(';q='); return { lang: lang.toLowerCase(), weight: weight ? parseFloat(weight) : 1.0 }; }).sort((a, b) => b.weight - a.weight); // 匹配支持的locale for (const { lang } of langEntries) { const match = supportedLocales.find(locale => locale.toLowerCase().startsWith(lang)); if (match) return match; } return defaultLocale; } // 在Server Component中使用 export default async function PostsPage() { const headersList = headers(); const acceptLang = headersList.get('accept-language'); const supportedLocales = ['en-US', 'nl-NL', 'nl']; const preferredLocale = getPreferredLocale(acceptLang, supportedLocales, 'en-US'); const res = await fetch(`${process.env.NEXT_PUBLIC_STRAPI_URL}/api/posts?locale=${preferredLocale}`); const data = await res.json(); return <div>{/* 渲染内容 */}</div>; }
内容的提问来源于stack exchange,提问作者Samuel
相关产品推荐
相关产品推荐

