
Next.js 国际化完整指南
为 App Router 设置 next-intl、配置语言路由,并利用 AI 自动翻译。
安装 next-intl
next-intl 是一个用于 Next.js App Router 的软件包,负责语言路由、消息加载和翻译 hook。
npm install next-intl创建 i18n 请求配置
创建两个文件:src/i18n/request.ts 用于加载消息,src/i18n/routing.ts 用于定义语言。它们用于配置 next-intl 解析消息和路由的方式。
// src/i18n/routing.ts
import { defineRouting } from 'next-intl/routing';
import { createNavigation } from 'next-intl/navigation';
export const routing = defineRouting({
locales: ['en', 'de', 'ja', 'es'],
defaultLocale: 'en',
localePrefix: 'as-needed', // /about for en, /de/about for de
});
export const { Link, redirect, usePathname, useRouter } =
createNavigation(routing);配置中间件
添加 middleware.ts 以处理语言检测、URL 重写和重定向。中间件会拦截每个请求,并确保使用正确语言。
// middleware.ts <- Must be in project ROOT, not src/
import createMiddleware from 'next-intl/middleware';
import { routing } from './src/i18n/routing';
export default createMiddleware(routing);
export const config = {
matcher: ['/((?!api|_next|.*\\..*).*)'],
};设置 [locale] 文件夹结构
将应用路由移入 app/[locale]/。添加 generateStaticParams,在构建时为每种语言生成页面。这样会创建 /en/about、/de/about 等 URL 结构。
// app/[locale]/layout.tsx
import { routing } from '@/i18n/routing';
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }));
}更新根布局
使用 getMessages() 加载消息,并在根语言布局中传给 NextIntlClientProvider。根据语言参数设置 html 的 lang 属性。
// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, setRequestLocale } from 'next-intl/server';
import { routing } from '@/i18n/routing';
import { notFound } from 'next/navigation';
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }));
}
export default async function LocaleLayout({
children,
params,
}: {
children: React.ReactNode;
params: { locale: string };
}) {
const { locale } = await params;
if (!routing.locales.includes(locale as any)) notFound();
setRequestLocale(locale);
const messages = await getMessages();
return (
<html lang={locale}>
<body>
<NextIntlClientProvider locale={locale} messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}在组件中使用译文
服务器组件使用 getTranslations(异步,需 await),客户端组件使用 useTranslations(hook)。应根据组件渲染位置选择;服务器组件能让译文完全不进入 JavaScript bundle。
// Server Component (default)
import { getTranslations, setRequestLocale } from 'next-intl/server';
export default async function AboutPage({
params,
}: { params: { locale: string } }) {
const { locale } = await params;
setRequestLocale(locale);
const t = await getTranslations('AboutPage');
return <h1>{t('title')}</h1>;
}
// Client Component ('use client')
'use client';
import { useTranslations } from 'next-intl';
export default function SearchBar() {
const t = useTranslations('SearchBar');
return <input placeholder={t('placeholder')} />;
}添加 SEO:元数据与 Hreflang
使用 generateMetadata 生成特定语言的页面标题和描述。为 hreflang 标签添加 alternates.languages,让搜索引擎发现每个页面的所有语言版本。
// app/[locale]/layout.tsx or any page.tsx
import { getTranslations } from 'next-intl/server';
import { routing } from '@/i18n/routing';
export async function generateMetadata({
params,
}: { params: { locale: string } }) {
const { locale } = await params;
const t = await getTranslations({ locale, namespace: 'Metadata' });
return {
title: t('title'),
description: t('description'),
alternates: {
languages: Object.fromEntries(
routing.locales.map((l) => [l, `/${l}`])
),
},
};
}处理错误页和未找到页面
error.tsx 和 not-found.tsx 可能在正常语言布局之外渲染,因此需要特殊处理。根 not-found.tsx 需要单独设置 i18n provider 才能显示本地化错误消息。
// app/[locale]/error.tsx
'use client';
import { useTranslations } from 'next-intl';
export default function Error() {
const t = useTranslations('Error');
return (
<div>
<h1>{t('title')}</h1>
<p>{t('description')}</p>
</div>
);
}
// app/not-found.tsx (root level -- needs own provider)
import { routing } from '@/i18n/routing';
export default async function GlobalNotFound() {
return (
<html lang={routing.defaultLocale}>
<body>
<h1>404 - Page Not Found</h1>
</body>
</html>
);
}自动翻译
完成 i18n 设置后,直接从 IDE 使用 AI 翻译消息文件,或在 CI/CD 管线中使用 i18n Agent CLI,在每次部署时自动翻译。
# In your IDE, ask your AI assistant:
> Translate messages/en.json to German, Japanese, and Spanish
✓ messages/de.json created (1.1s)
✓ messages/ja.json created (1.4s)
✓ messages/es.json created (1.0s)自动保证翻译质量
Next.js i18n 开源工具
这些开源软件包可解决 Next.js 国际化工作流中的常见痛点。
next-intl-localechain
标准 next-intl 在缺少译文时会直接回退到默认语言。巴西葡萄牙语用户会看到英语,而不是完全可用的 pt-PT 译文。next-intl-localechain 会添加智能回退链,深度合并相关语言的译文,让区域用户始终看到最接近的可用译文。
import { getRequestConfig } from 'next-intl/server';
import { withLocaleChain } from 'next-intl-localechain';
export default getRequestConfig(withLocaleChain({
loadMessages: (locale) =>
import(`../../messages/${locale}.json`).then(m => m.default),
defaultLocale: 'en'
}));@i18n-agent/cli
一款命令行工具,让您无需离开终端即可翻译 Next.js 消息文件。可直接翻译文件、检查任务状态并下载结果。通过 API 密钥进行身份验证后,可在 CI/CD 管线中实现全自动本地化工作流。
# Install the CLI
npm install -g @i18n-agent/cli
# Authenticate
i18nagent login
# Translate your message files
i18nagent translate ./messages/en.json --lang de,ja,es
# Or use in CI/CD with an API key
export I18N_AGENT_API_KEY=your-key-here
i18nagent translate ./messages/en.json --lang de,ja,es常见问题
"Unable to find next-intl locale"
中间件没有匹配请求。请检查:middleware.ts 是否位于项目根目录?matcher 模式是否正确排除静态文件?路由配置中是否包含该语言?
意外的动态渲染
页面或布局缺少 setRequestLocale(locale)。如果未调用,next-intl 会使用请求头或 Cookie 检测语言,从而强制动态渲染并阻止静态生成。
并行路由与 i18n 冲突
并行路由(@modal)和拦截路由((.)photo)与 [locale] 动态区段存在已知兼容问题。这些高级路由模式可改用基于中间件的路由作为变通方案。
切换语言后丢失当前路由
切换语言时,使用 usePathname() 保留当前路径,只替换语言区段。请注意动态路由参数,它们需要针对新语言重新解析。
推荐的文件结构
my-nextjs-app/
├── middleware.ts # Locale routing (project root!)
├── next.config.mjs
├── messages/
│ ├── en.json # Source messages
│ ├── de.json
│ └── ja.json
├── src/
│ ├── i18n/
│ │ ├── request.ts # Message loading config
│ │ └── routing.ts # Locale definitions
│ └── app/
│ └── [locale]/
│ ├── layout.tsx # Root locale layout
│ ├── page.tsx # Home page
│ ├── error.tsx # Localized error page
│ ├── not-found.tsx # Localized 404
│ └── about/
│ └── page.tsx
└── package.json立即试用 i18n Agent
将翻译文件拖放到此处
JSON, YAML, PO, XML, CSV, Markdown, Properties
或点击选择文件
目标语言
使用 next-intl-localechain 实现语言回退
如果 pt-BR 等区域语言缺少翻译键,next-intl 会直接跳到默认语言,而不会先检查父语言 pt。
npm install next-intl-localechainimport { withLocaleChain } from 'next-intl-localechain';
export default withLocaleChain({
fallbacks: {
'pt-BR': ['pt', 'en'],
'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
},
defaultLocale: 'en',
loadMessages: (locale) => import(`./messages/${locale}.json`),
});查看语言回退指南,了解受支持框架的完整列表和 75 条内置回退链。 Learn more →