使用您最喜欢的AI助手总结文档,并引用此页面和AI提供商
此文档已过期,基础版本已在以下日期更新 2026年8月22日.
前往英文文档版本历史
- "更新 Solid useIntlayer API 用法以直接访问属性"v8.9.02026/5/4
- "添加 init 命令"v7.5.92025/12/30
- "初始化历史"v5.5.102025/6/29
此页面的内容已使用 AI 翻译。
查看英文原文的最新版本如果您有改善此文档的想法,请随时通过在GitHub上提交拉取请求来贡献。
文档的 GitHub 链接复制文档 Markdown 到剪贴板
使用 Intlayer 翻译您的 Next.js 15 网站 | 国际化 (i18n)
目录
为什么选择 Inlayer 而不是替代品?
与 next-intl 或 i18next 等主要解决方案相比,Intlayer 是一个提供了集成优化的解决方案,例如:
与“next-intl”或“i18next”等主要解决方案相比,Intlayer是一个具有集成优化的解决方案,例如:
不要将大量 JSON 文件加载到页面中,而只需加载必要的内容。 Intlayer 有助于将捆绑包和页面大小减少多达 50%。
确定应用程序内容的范围有利于大型应用程序的维护。您可以复制或删除单个功能文件夹,而无需承担检查整个内容代码库的精神负担。此外,Intlayer 具有完全类型化 (fully typed),以确保您的内容的准确性。
共置内容减少大型语言模型 (LLM) 所需的上下文。 Intlayer 还附带了一套工具,例如用于测试缺失翻译的 CLI、LSP、MCP 和 agent skills,使 AI 代理的开发者体验 (DX) 更加流畅。
使用您选择的法学硕士,通过自动化在 CI/CD 管道中进行翻译,而费用由您的 AI 提供商承担。 Intlayer 还提供了一个编译器来自动提取内容,以及一个网络平台来帮助在后台翻译。
将大量 JSON 文件连接到组件可能会导致性能和反应性问题。 Intlayer 可在构建时 (build time)优化您的内容加载。
在 Next.js 应用中设置 Intlayer 的分步指南
查看 GitHub 上的应用程序模板。
配置您的项目
Here is the final structure that we will make:
bash复制代码复制代码到剪贴板
If you don't want locale routing, intlayer can be used as a simple provider / hook. See this guide for more details.
创建一个配置文件以配置您应用程序的语言:
intlayer.config.ts复制代码复制代码到剪贴板
import { Locales, type IntlayerConfig } from "intlayer"; const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, // 你的其他语言环境 ], defaultLocale: Locales.ENGLISH, }, }; export default config;通过此配置文件,你可以设置本地化的 URL、中间件重定向、cookie 名称、内容声明的位置和扩展名,禁用控制台中的 Intlayer 日志等。有关可用参数的完整列表,请参阅配置文档。
在你的 Next.js 配置中集成 Intlayer
配置你的 Next.js 以使用 Intlayer:
next.config.ts复制代码复制代码到剪贴板
import type { NextConfig } from "next"; import { withIntlayer } from "next-intlayer/server"; const nextConfig: NextConfig = {/* 这里是配置选项 */}; export default withIntlayer(nextConfig);withIntlayer()Next.js 插件用于将 Intlayer 集成到 Next.js 中。它确保构建内容声明文件并在开发模式下监视这些文件。在 Webpack 或 Turbopack 环境中定义 Intlayer 环境变量。此外,它还提供别名以优化性能,并确保与服务器组件的兼容性。withIntlayer()函数是一个 promise 函数。它允许在构建启动前准备 intlayer 字典。如果你想将它与其他插件一起使用,可以对其进行 await。示例:tsx复制代码复制代码到剪贴板
如果你想同步使用它,可以使用
withIntlayerSync()函数。示例:tsx复制代码复制代码到剪贴板
定义动态本地化路由
清空
RootLayout中的所有内容,并替换为以下代码:src/app/layout.tsx复制代码复制代码到剪贴板
import type { PropsWithChildren, FC } from "react"; import "./globals.css"; const RootLayout: FC<PropsWithChildren> = ({ children }) => children; export default RootLayout;保持
RootLayout组件为空,可以设置<html>标签的lang和dir属性。为了实现动态路由,通过在
[locale]目录中添加新的布局来提供语言环境路径:src/app/[locale]/layout.tsx复制代码复制代码到剪贴板
import { type NextLayoutIntlayer } from "next-intlayer"; import { IntlayerProvider } from "next-intlayer/server"; import { Inter } from "next/font/google"; import { getHTMLTextDir } from "intlayer"; const inter = Inter({ subsets: ["latin"] }); const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => { const { locale } = await params; return ( <html lang={locale} dir={getHTMLTextDir(locale)}> <body className={inter.className}> <IntlayerProvider locale={locale}>{children}</IntlayerProvider> </body> </html> ); }; export default LocaleLayout;一个
IntlayerProvider覆盖树的两个部分:它为服务器 hooks 读取的请求作用域服务器上下文提供种子,并挂载客户端提供者,以便客户端组件接收相同的语言环境。src/app/[locale]/layout.tsx复制代码复制代码到剪贴板
import { type NextLayoutIntlayer, IntlayerClientProvider } from "next-intlayer"; import { Inter } from "next/font/google"; import { getHTMLTextDir } from "intlayer"; const inter = Inter({ subsets: ["latin"] }); const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => { const { locale } = await params; return ( <html lang={locale} dir={getHTMLTextDir(locale)}> <body className={inter.className}> <IntlayerClientProvider locale={locale}> {children} </IntlayerClientProvider> </body> </html> ); }; export default LocaleLayout;[locale]路径段用于定义语言环境。例如:/en-US/about将对应en-US,而/fr/about对应fr。在此阶段,您会遇到错误:
Error: Missing <html> and <body> tags in the root layout.。这是预期中的,因为/app/page.tsx文件不再使用,可以删除。取而代之的是,[locale]路径段将激活/app/[locale]/page.tsx页面。因此,页面将通过浏览器中的路径如/en、/fr、/es访问。要将默认语言环境设置为根页面,请参考第7步中的middleware配置。然后,在您的应用布局中实现
generateStaticParams函数。src/app/[locale]/layout.tsx复制代码复制代码到剪贴板
export { generateStaticParams } from "next-intlayer"; // 插入的代码行 const LocaleLayout: NextLayoutIntlayer = async ({ children, params }) => { /*... 代码的其余部分 */ }; export default LocaleLayout;generateStaticParams确保您的应用程序为所有语言环境预构建必要的页面,从而减少运行时计算并提升用户体验。更多详情,请参阅 Next.js 关于 generateStaticParams 的文档。Intlayer 与
export const dynamic = 'force-static';配合使用,以确保为所有语言预构建页面。声明您的内容
创建并管理您的内容声明以存储翻译:
src/app/[locale]/page.content.ts复制代码复制代码到剪贴板
import { t, type Dictionary } from "intlayer"; const pageContent = { key: "page", content: { getStarted: { main: t({ en: "Get started by editing", fr: "Commencez par éditer", es: "Comience por editar", }), pageLink: "src/app/page.tsx", }, }, } satisfies Dictionary; export default pageContent;您的内容声明可以在应用程序中的任何位置定义,只要它们被包含在
contentDir目录中(默认是./src)。并且文件扩展名需匹配内容声明文件扩展名(默认是.content.{json,ts,tsx,js,jsx,mjs,cjs,md,mdx,yaml,yml})。更多详情,请参考内容声明文档。
在代码中使用内容
在整个应用程序中访问您的内容字典:
src/app/[locale]/page.tsx复制代码复制代码到剪贴板
import type { FC } from "react"; import { ClientComponentExample } from "@components/ClientComponentExample"; import { ServerComponentExample } from "@components/ServerComponentExample"; import { type NextPageIntlayer, useIntlayer } from "next-intlayer"; const PageContent: FC = () => { const content = useIntlayer("page"); return ( <> <p>{content.getStarted.main}</p> <code>{content.getStarted.pageLink}</code> </> ); }; const Page: NextPageIntlayer = () => ( <> <PageContent /> <ServerComponentExample /> <ClientComponentExample /> </> ); export default Page;IntlayerProvider在本地语言布局中挂载一次。它向服务器和客户端组件提供本地语言,因此页面不再自行包装。- 服务器 hooks 按以下顺序解析本地语言:在调用点传递的本地语言,然后是由提供程序设置的服务器上下文,然后是请求中携带的本地语言(由 Intlayer 代理设置的
x-intlayer-localeheader,然后是本地语言 cookie)。最后一步是保持客户端导航正确的内容,该导航只重新渲染页面段,而布局——以及与之相关的提供程序——不会重新运行。
在整个应用程序中访问您的内容字典:
src/app/[locale]/page.tsx复制代码复制代码到剪贴板
import type { FC } from "react"; import { ClientComponentExample } from "@components/ClientComponentExample"; import { ServerComponentExample } from "@components/ServerComponentExample"; import { type NextPageIntlayer } from "next-intlayer"; import { IntlayerServerProvider, useIntlayer } from "next-intlayer/server"; const PageContent: FC = () => { const content = useIntlayer("page"); return ( <> <p>{content.getStarted.main}</p> {/* 显示“开始使用”部分的主要内容 */} <code>{content.getStarted.pageLink}</code>{" "} {/* 显示“开始使用”部分的页面链接 */} </> ); }; const Page: NextPageIntlayer = async ({ params }) => { const { locale } = await params; return ( <IntlayerServerProvider locale={locale}> <PageContent /> <ServerComponentExample /> <ClientComponentExample /> </IntlayerServerProvider> ); }; export default Page;IntlayerClientProvider用于向客户端组件提供语言环境。它可以放置在任何父组件中,包括布局组件中。然而,推荐将其放置在布局中,因为 Next.js 会在页面之间共享布局代码,这样更高效。通过在布局中使用IntlayerClientProvider,可以避免每个页面都重新初始化它,从而提升性能并保持整个应用中的本地化上下文一致性。IntlayerServerProvider用于向服务器端子组件提供语言环境。它不能设置在布局中。
布局和页面不能共享公共的服务器上下文,因为服务器上下文系统基于每次请求的数据存储(通过 React 的缓存 机制),导致每个“上下文”会为应用程序的不同部分重新创建。在共享布局中放置提供者会破坏这种隔离,阻止服务器上下文值正确传播到你的服务器组件。
src/components/ClientComponentExample.tsx复制代码复制代码到剪贴板
布局和页面不能共享公共的服务器上下文,因为服务器上下文系统是基于每次请求的数据存储(通过 React 的 cache 机制),这导致应用程序不同段的“上下文”会被重新创建。将提供者放在共享布局中会破坏这种隔离,阻止服务器上下文值正确传播到你的服务器组件。
src/components/ClientComponentExample.tsx复制代码复制代码到剪贴板
"use client"; import type { FC } from "react"; import { useIntlayer } from "next-intlayer"; export const ClientComponentExample: FC = () => { const content = useIntlayer("client-component-example"); // 创建相关内容声明 return ( <div> <h2>{content.title}</h2> <p>{content.content}</p> </div> ); };next-intlayer是同构导入路径:react-server导出条件为服务器组件提供环境区域设置实现,而客户端组件获得上下文支持的实现。相同的调用在两侧都有效。</Tab>
src/components/ServerComponentExample.tsx复制代码复制代码到剪贴板
import type { FC } from "react"; import { useIntlayer } from "next-intlayer/server"; export const ServerComponentExample: FC = () => { const content = useIntlayer("server-component-example"); // 创建相关内容声明 return ( <div> <h2>{content.title}</h2> <p>{content.content}</p> </div> ); };</Tab> </Tabs>
如果您想在字符串属性中使用内容,比如
alt、title、href、aria-label等,可以使用函数的值,例如:html复制代码复制代码到剪贴板
要了解有关
useIntlayer钩子的更多信息,请参阅文档。配置中间件以检测语言环境
设置中间件以检测用户的首选语言环境:
src/middleware.ts复制代码复制代码到剪贴板
export { intlayerMiddleware as middleware } from "next-intlayer/middleware"; export const config = { matcher: "/((?!api|static|assets|robots|sitemap|sw|service-worker|manifest|.*\\..*|_next).*)", };intlayerMiddleware用于检测用户的首选语言环境,并根据配置将用户重定向到相应的 URL。此外,它还支持将用户的首选语言环境保存在 cookie 中。自 Intlayer v9 起,此中间件尊重
routing.enableProxy选项(默认为true)。在你的配置中设置routing.enableProxy: false以将其转换为直通,而无需删除此文件。请查看 v9 发布说明。如果您需要将多个中间件链接在一起(例如,
intlayerMiddleware与身份验证或自定义中间件),Intlayer 现在提供了一个名为multipleMiddlewares的辅助函数。ts复制代码复制代码到剪贴板
元数据的国际化
如果您想要对元数据进行国际化,例如页面标题,可以使用 Next.js 提供的
generateMetadata函数。在该函数内部,您可以通过getIntlayer函数获取内容,从而翻译您的元数据。src/app/[locale]/metadata.content.ts复制代码复制代码到剪贴板
import { type Dictionary, t } from "intlayer"; import { Metadata } from "next"; const metadataContent = { key: "page-metadata", content: { title: t({ en: "Create Next App", fr: "Créer une application Next.js", es: "Crear una aplicación Next.js", }), description: t({ en: "Generated by create next app", fr: "Généré par create next app", es: "Generado por create next app", }), }, } satisfies Dictionary<Metadata>; export default metadataContent;src/app/[locale]/layout.tsx or src/app/[locale]/page.tsx复制代码复制代码到剪贴板
import { getIntlayer, getMultilingualUrls } from "intlayer"; import type { Metadata } from "next"; import type { LocalPromiseParams } from "next-intlayer"; export const generateMetadata = async ({ params, }: LocalPromiseParams): Promise<Metadata> => { const { locale } = await params; const metadata = getIntlayer("page-metadata", locale); /** * 生成一个包含每个语言环境所有 URL 的对象。 * * 示例: * ```ts * getMultilingualUrls('/about'); * * // 返回 * // { * // en: '/about', * // fr: '/fr/about', * // es: '/es/about', * // } * ``` */ const multilingualUrls = getMultilingualUrls("/"); const localizedUrl = multilingualUrls[locale as keyof typeof multilingualUrls]; return { ...metadata, alternates: { canonical: localizedUrl, languages: { ...multilingualUrls, "x-default": "/" }, }, openGraph: { url: localizedUrl, }, }; }; // ... 代码其余部分请注意,从
next-intlayer导入的getIntlayer函数返回的是包裹在IntlayerNode中的内容,允许与可视化编辑器集成。相比之下,从intlayer导入的getIntlayer函数直接返回内容,不带额外属性。了解有关元数据优化的更多信息,请参阅 官方 Next.js 文档。
国际化您的 sitemap.xml 和 robots.txt
要实现
sitemap.xml和robots.txt的国际化,您可以使用 Intlayer 提供的getMultilingualUrls函数。该函数允许您为站点地图生成多语言 URL。src/app/sitemap.ts复制代码复制代码到剪贴板
import { getMultilingualUrls } from "intlayer"; import type { MetadataRoute } from "next"; const sitemap = (): MetadataRoute.Sitemap => [ { url: "https://example.com", alternates: { languages: { ...getMultilingualUrls("https://example.com"), "x-default": "https://example.com", }, }, }, { url: "https://example.com/login", alternates: { languages: { ...getMultilingualUrls("https://example.com/login"), "x-default": "https://example.com/login", }, }, }, { url: "https://example.com/register", alternates: { languages: { ...getMultilingualUrls("https://example.com/register"), "x-default": "https://example.com/register", }, }, }, ]; export default sitemap;src/app/robots.ts复制代码复制代码到剪贴板
import type { MetadataRoute } from "next"; import { getMultilingualUrls } from "intlayer"; // 获取所有多语言版本的 URL const getAllMultilingualUrls = (urls: string[]) => urls.flatMap((url) => Object.values(getMultilingualUrls(url)) as string[]); // 定义 robots.txt 的规则 const robots = (): MetadataRoute.Robots => ({ rules: { userAgent: "*", // 适用于所有用户代理 allow: ["/"], // 允许访问根路径 disallow: getAllMultilingualUrls(["/login", "/register"]), // 禁止访问登录和注册页面的所有语言版本 }, host: "https://example.com", // 网站主机地址 sitemap: `https://example.com/sitemap.xml`, // 网站地图地址 }); export default robots;了解有关网站地图优化的更多信息,请参阅官方 Next.js 文档。了解有关 robots.txt 优化的更多信息,请参阅官方 Next.js 文档。
更改内容语言
在 Next.js 中更改内容语言,推荐的方式是使用
Link组件将用户重定向到相应的本地化页面。Link组件支持页面预取,有助于避免完整页面重新加载。src/components/LocaleSwitcher.tsx复制代码复制代码到剪贴板
"use client"; import type { FC } from "react"; import { Locales, getHTMLTextDir, getLocaleName, getLocalizedUrl, } from "intlayer"; import { useLocale } from "next-intlayer"; import Link from "next/link"; export const LocaleSwitcher: FC = () => { const { locale, pathWithoutLocale, availableLocales, setLocale } = useLocale(); return ( <div> <button popoverTarget="localePopover">{getLocaleName(locale)}</button> <div id="localePopover" popover="auto"> {availableLocales.map((localeItem) => ( <Link href={getLocalizedUrl(pathWithoutLocale, localeItem)} hrefLang={localeItem} key={localeItem} aria-current={locale === localeItem ? "page" : undefined} onClick={() => setLocale(localeItem)} > <span> {/* 语言环境 - 例如 FR */} {localeItem} </span> <span> {/* 该语言环境中的语言名称 - 例如 Français */} {getLocaleName(localeItem, locale)} </span> <span dir={getHTMLTextDir(localeItem)} lang={localeItem}> {/* 当前语言环境中的语言名称 - 例如当前语言环境为 Locales.SPANISH 时显示 Francés */} {getLocaleName(localeItem)} </span> <span dir="ltr" lang={Locales.ENGLISH}> {/* 英文中的语言名称 - 例如 French */} {getLocaleName(localeItem, Locales.ENGLISH)} </span> </Link> ))} </div> </div> ); };另一种方法是使用
useLocale钩子提供的setLocale函数。此函数不支持页面预取,并且会重新加载页面。在这种情况下,如果不使用
router.push进行重定向,只有你的服务器端代码会更改内容的语言环境。src/components/LocaleSwitcher.tsx复制代码复制代码到剪贴板
文档参考:
创建本地化链接组件
为了确保您的应用程序导航遵循当前的语言环境,您可以创建一个自定义的
Link组件。该组件会自动为内部 URL 添加当前语言的前缀。例如,当讲法语的用户点击“关于”页面的链接时,他们会被重定向到/fr/about,而不是/about。这种行为有几个好处:
- SEO 和用户体验:本地化的 URL 有助于搜索引擎正确索引特定语言的页面,并为用户提供其偏好的语言内容。
- 一致性:通过在整个应用中使用本地化链接,您可以确保导航保持在当前语言环境内,避免意外的语言切换。 /// 可维护性:将本地化逻辑集中在单个组件中简化了 URL 的管理,使您的代码库更易于维护和扩展,随着应用程序的增长。
下面是在 TypeScript 中实现的本地化
Link组件:src/components/Link.tsx复制代码复制代码到剪贴板
"use client"; import { getLocalizedUrl } from "intlayer"; import NextLink, { type LinkProps as NextLinkProps } from "next/link"; import { useLocale } from "next-intlayer"; import type { PropsWithChildren, FC } from "react"; /** * 工具函数,用于检查给定的 URL 是否为外部链接。 * 如果 URL 以 http:// 或 https:// 开头,则视为外部链接。 */ export const checkIsExternalLink = (href?: string): boolean => /^https?:\/\//.test(href ?? ""); /** * 一个自定义的 Link 组件,根据当前语言环境动态调整 href 属性。 * 对于内部链接,使用 `getLocalizedUrl` 在 URL 前添加语言前缀(例如 /fr/about)。 * 这样可以确保导航保持在相同的语言环境上下文中。 */ export const Link: FC<PropsWithChildren<NextLinkProps>> = ({ href, children, ...props }) => { const { locale } = useLocale(); const isExternalLink = checkIsExternalLink(href.toString()); // 如果链接是内部链接且 href 有效,则获取本地化的 URL。 const hrefI18n: NextLinkProps["href"] = href && !isExternalLink ? getLocalizedUrl(href.toString(), locale) : href; return ( <NextLink href={hrefI18n} {...props}> {children} </NextLink> ); };工作原理
- 检测外部链接:
检测外部链接:
辅助函数checkIsExternalLink用于判断一个 URL 是否为外部链接。外部链接保持不变,因为它们不需要本地化。获取当前语言环境:
useLocale钩子提供当前的语言环境(例如,法语为fr)。本地化 URL:
对于内部链接(即非外部链接),使用getLocalizedUrl自动为 URL 添加当前语言环境前缀。这意味着如果用户的语言环境是法语,传入的/about会被转换为/fr/about。返回链接:
组件返回带有本地化 URL 的<a>元素,确保导航与当前语言环境保持一致。
通过在您的应用程序中集成此
Link组件,您可以保持一致且具有语言感知的用户体验,同时还受益于改进的 SEO 和可用性。优化您的Bundle 大小
使用
next-intlayer时,字典默认包含在每个页面的包中。为了优化Bundle 大小,Intlayer 提供了一个可选的 SWC 插件,该插件通过宏智能地替换useIntlayer调用。这确保字典仅包含在实际使用它们的页面的包中。src/app/actions/getLocale.ts复制代码复制代码到剪贴板
getLocale函数遵循级联策略来确定用户的语言区域设置:- 首先,它检查请求头中是否存在由中间件设置的语言区域值
- 如果在请求头中找不到语言区域,它会查找存储在 cookie 中的语言区域
- 如果没有找到 cookie,它会尝试从用户的浏览器设置中检测用户的首选语言
- 作为最后的手段,它会回退到应用程序配置的默认语言区域
这确保了根据可用的上下文选择最合适的语言区域。
优化您的 bundle 大小
可选当使用
next-intlayer时,默认情况下字典会为每个页面包含在 bundle 中。为了优化 bundle 大小,Intlayer 提供了一个可选的 SWC 插件,它可以智能地使用宏替换useIntlayer调用。这确保字典仅包含在实际使用它们的页面的 bundle 中。要启用此优化,请安装
@intlayer/swc包。安装后,next-intlayer将自动检测并使用该插件:bash复制代码复制代码到剪贴板
注意:此优化仅适用于 Next.js 13 及以上版本。
注意:此包默认未安装,因为 SWC 插件在 Next.js 上仍处于实验阶段。它可能在未来发生变化。
注意:由于 SWC 插件在 Next.js 中仍处于实验阶段,该包默认未安装,未来可能会有所变动。
在 Turbopack 上监视字典更改
当使用 next dev --turbopack 命令将 Turbopack 用作开发服务器时,默认情况下不会自动检测字典更改。
出现此限制是因为 Turbopack 无法并行运行 webpack 插件来监视内容文件中的更改。要解决此问题,您需要使用 intlayer watch 命令同时运行开发服务器和 Intlayer 构建监视器。
复制代码到剪贴板
配置 TypeScript
Intlayer 使用模块增强来利用 TypeScript 的优势,使您的代码库更健壮。


确保您的 TypeScript 配置包含自动生成的类型。
复制代码到剪贴板
Git 配置
建议忽略 Intlayer 生成的文件。这样可以避免将它们提交到你的 Git 仓库中。
为此,你可以在 .gitignore 文件中添加以下内容:
复制代码到剪贴板
VS Code 扩展
为了提升你使用 Intlayer 的开发体验,你可以安装官方的 Intlayer VS Code 扩展。
该扩展提供:
- 翻译键的 自动补全。
- 实时错误检测,用于缺失的翻译。
- 内联预览,显示翻译内容。
- 快速操作,轻松创建和更新翻译。
有关如何使用该扩展的更多详细信息,请参阅 Intlayer VS Code 扩展文档。
深入了解
要进一步使用,您可以实现可视化编辑器或使用内容管理系统(CMS)来外部化您的内容。
