ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Next.js Edge Middleware 实现 i18n 自动本地化重定向:edge-middleware/i18n 模板源码解析

Next.js Edge Middleware 实现 i18n 自动本地化重定向:edge-middleware/i18n 模板源码解析 Next.js Edge Middleware 实现 i18n 自动本地化重定向edge-middleware/i18n 模板源码解析【免费下载链接】examplesEnjoy our curated collection of examples and solutions. Use these patterns to build your own robust and scalable applications.项目地址: https://gitcode.com/GitHub_Trending/examples1/examples本文围绕当前仓库中的 edge-middleware/i18n 示例深入讲解如何在 Next.js 中利用 Edge Middleware 结合accept-language请求头与geolocation地理信息将首页请求自动重写到对应的本地化页面/[locale]/[country]。读完本文你将掌握基于 Edge Middleware 的 i18n 重定向完整实现思路、字典数据层设计以及它与静态生成SSG页面协同工作的实战方案。示例解决的问题当一个全球化的网站只有一个首页时不同语言、不同国家的用户访问到的应该是自己的版本。传统做法是在服务端渲染时读取请求头做条件渲染而在本示例中这一判断被前移到Edge Middleware边缘中间件它在请求到达页面之前执行直接改写 URL 路径让 Next.js 把请求路由到对应的本地化页面。从 middleware.ts 的注释可以看到该示例的设计目标是仅对首页路径/生效通过matcher: /精确匹配依据accept-language请求头解析用户首选语言locale依据 Vercel Edge Network 提供的geolocation请求头推断用户所在国家country将路径重写为/{locale}/{country}由静态页面承接渲染。其核心价值在于本地化路由的动态决策发生在边缘层页面本身可以是完全静态的兼顾了用户体验自动适配语言与性能静态页面全球 CDN 缓存。边缘中间件核心实现匹配规则与中间件入口edge-middleware/i18n/middleware.ts 首先通过export const config声明只匹配根路径import { geolocation } from vercel/functions import { type NextRequest, NextResponse } from next/server // only run middleware on home page export const config { matcher: /, }matcher: /意味着中间件仅在用户访问站点首页时触发其他路径直接放行避免对全站请求造成不必要的边缘执行开销。读取请求头并执行重写中间件默认导出函数的核心逻辑位于 middleware.tsexport default function middleware(req: NextRequest) { const country geolocation(req).country?.toLowerCase() || us const locale req.headers.get(accept-language)?.split(,)?.[0] || en-US // Rewrite the path (/) to the localized page (pages/[locale]/[country]) req.nextUrl.pathname /${locale}/${country} return NextResponse.rewrite(req.nextUrl) }两行关键代码的含义国家推断geolocation(req)来自vercel/functions包读取 Vercel 边缘网络注入的地理位置请求头如x-vercel-ip-country取country字段并转为小写若无法识别例如本地开发环境缺少相关请求头则回退为默认值us。语言推断req.headers.get(accept-language)取浏览器发送的语言协商请求头split(,)[0]拿到客户端优先级最高的语言标签如zh-CN、en-US、es-ES缺失时回退为en-US。随后通过NextResponse.rewrite(req.nextUrl)将 URL 路径原地改写为/{locale}/{country}。注意这里使用的是rewrite重写而非 redirect重定向浏览器地址栏仍显示/但内部请求被路由到本地化页面用户无感知也不产生额外的网络往返。本地化字典数据层中间件只负责路由决策实际的文案翻译由一套轻量的字典模块提供位于 lib 目录下由三个文件组成。类型定义lib/types.ts 定义了字典的 TypeScript 接口保证所有语言的文案结构一致export interface Dictionary { title: string subtitle: string link: string greet: string }四个字段分别对应页面上的标题、副标题、文档链接文案与问候语。字典常量lib/constants.ts 以Recordstring, Dictionary的形式维护了五套语言文案default兜底英语、en英语、es西班牙语、fr法语、cn简体中文export const DICTIONARIES: Recordstring, Dictionary { default: { title: i18n Example, greet: Hello!, we could not detect your locale so we defaulted to english., subtitle: Localized text based on geolocation headers, link: See headers documentation, }, // en / es / fr / cn ... }其中default键承担兜底职责当请求中的 locale 不在字典范围内时页面使用该套文案并明确提示用户未能检测到你的语言设置已回退到英语。从仓库实现看新增语言只需在DICTIONARIES中追加一个键值对无需改动路由逻辑。字典获取 APIlib/api.ts 封装了字典的获取接口屏蔽了数据来源细节const api { dictionaries: { fetch: async (locale): PromiseDictionary DICTIONARIES[locale] || DICTIONARIES[default], }, } export default apifetch在键不存在时回退到DICTIONARIES[default]与middleware.ts中的||兜底逻辑形成双保险中间件层兜底 locale 格式数据层兜底字典内容。本地化页面的静态渲染动态路由结构页面位于 pages/[locale]/[country].tsx采用 Next.js Pages Router 的两级动态路由。由于国家数量众多仓库 public/flags 目录下包含了 250 个国家的旗帜 SVG示例刻意不预生成所有路径而是使用fallback: blockingexport const getStaticPaths: GetStaticPaths async () { // We dont want to specify all possible countries as we get those from the headers return { paths: [], fallback: blocking, } }这表示任何/{locale}/{country}路径首次被访问时Next.js 会在服务端阻塞式生成该静态页面并缓存后续访问直接命中缓存——既覆盖了中间件可能产生的任意国家组合又避免了海量预构建。按语言取字典getStaticProps 中通过api.dictionaries.fetch(locale)按路由参数获取对应语言的字典并设置revalidate: false保持纯静态export const getStaticProps: GetStaticPropsunknown, Params async ({ params: { country, locale }, }) { // Get dictionary const dictionary await api.dictionaries.fetch(locale) return { props: { country, dictionary, locale, }, revalidate: false, } }页面内容渲染组件接收country、locale、dictionary三个 props渲染内容包括字典驱动的标题与副标题、/flags/${country.toLowerCase()}.svg动态加载的国家旗帜以及展示当前locale值的调试信息块便于验证中间件的语言推断结果。布局通过CountryPage.Layout Layout挂载vercel/examples-ui提供的页面外壳。在 pages/_app.tsx 中应用级布局会读取pageProps.dictionary动态设置页面标题与描述使浏览器标签页也随语言变化。目录结构与运行方式关键文件一览文件职责middleware.ts边缘层 i18n 决策解析 locale/country 并 rewrite 到本地化路径lib/constants.ts多语言字典常量含 default 兜底lib/types.ts字典类型定义lib/api.ts字典获取接口封装pages/[locale]/[country].tsx本地化落地页SSG blocking fallbackpages/_app.tsx全局布局与动态标题public/flags各国旗帜 SVG 资源package.json依赖与脚本next、vercel/functions等克隆与本地运行仓库 README 提供了两种使用方式其中本地开发推荐通过create-next-app以该模板为蓝本初始化项目pnpm create next-app --example https://github.com/vercel/examples/tree/main/edge-middleware/i18n i18n随后进入项目目录启动开发服务器pnpm dev需要说明的是geolocation依赖 Vercel Edge Network 注入的地理位置请求头本地开发时该请求头通常缺失因此中间件会回退到默认值usaccept-language则来自本机浏览器/请求设置可在本地直接验证语言切换效果。若需本地调试国家逻辑可在中间件中临时注入测试请求头观察重写结果。生产构建与启动命令定义在 package.json 中pnpm build # next build pnpm start # next start云端部署README 同时提供一键部署方式点击 Vercel Deploy 按钮即可将模板部署到云端。仓库根部的 vercel.json 声明了部署相关配置{ buildCommand: pnpm turbo build, ignoreCommand: pnpm dlx turbo-ignore }即云端构建使用 Turborepo 流水线对应 turbo.json 中的build/lintpipeline并通过turbo-ignore实现基于变更的构建跳过。部署到 Vercel 后geolocation请求头即真实生效不同地区的用户访问/会自动获得对应国家的本地化页面。扩展思路与注意事项中间件仅匹配首页matcher: /限定了本示例只对根路径做 i18n 决策。若要让全站 URL 都携带 locale 前缀如/es/about需要扩展 matcher 规则并在中间件中处理相对路径拼接避免破坏静态资源与 API 路由。locale 归一化示例直接使用accept-language的首个标签作为字典键而浏览器可能发送zh-CN、zh-Hans等复合标签生产环境通常需要做语言标签 → 支持语言的归一化映射如提取主语言码、配置别名表否则会频繁落入default兜底。改写 vs 重定向rewrite 对用户透明且无额外跳转利于 SEO 与体验若希望地址栏展示规范化的 locale 路径便于分享链接可改用NextResponse.redirect但要注意避免重定向循环。静态生成与边缘决策的分工本示例展示了边缘层做动态路由决策、页面层保持纯静态的经典组合fallback: blocking让任意国家组合都能按需生成并缓存是这类模式落地时值得复用的关键配置。总体而言edge-middleware/i18n 以不足 20 行的中间件代码完整演示了请求头驱动 边缘重写 静态页面承接的轻量 i18n 方案是理解 Edge Middleware 在真实业务场景中价值的优秀参考实现。【免费下载链接】examplesEnjoy our curated collection of examples and solutions. Use these patterns to build your own robust and scalable applications.项目地址: https://gitcode.com/GitHub_Trending/examples1/examples创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表