本文详细介绍如何在 Next.js 15 (App Router) 中使用 next-intl 实现完整的国际化方案,包括路由国际化、内容翻译和 UI 组件库(Ant Design)的国际化。
技术栈
- Next.js 15 - React 框架
- next-intl - 国际化库
- Ant Design - UI 组件库
- TypeScript - 类型安全
项目结构
ini
src/
├── app/
│ └── [locale]/ # 动态语言路由
│ ├── layout.tsx # 布局组件
│ ├── page.tsx # 页面组件
│ └── AntdProvider.tsx # Ant Design 国际化配置
├── i18n/
│ ├── routing.ts # 路由配置
│ └── request.ts # 请求配置
└── middleware.ts # 中间件
messages/
├── en-US.json # 英文翻译
└── zh-CN.json # 中文翻译
实现步骤
1. 安装依赖
bash
npm install next-intl
npm install antd @ant-design/nextjs-registry
2. 配置路由 (src/i18n/routing.ts)
typescript
import { defineRouting } from 'next-intl/routing';
import { createNavigation } from 'next-intl/navigation';
export const routing = defineRouting({
locales: ['zh-CN', 'en-US'],
defaultLocale: 'en-US',
localePrefix: 'as-needed' // 默认语言不显示前缀
});
export const { Link, redirect, usePathname, useRouter } =
createNavigation(routing);
配置说明:
locales: 支持的语言列表defaultLocale: 默认语言(英文)localePrefix: 'as-needed': 默认语言 URL 不显示前缀
URL 结构:
bash
/ → 英文首页(默认语言,无前缀)
/about → 英文关于页
/zh-CN → 中文首页
/zh-CN/about → 中文关于页
3. 配置中间件 (src/middleware.ts)
typescript
import createMiddleware from 'next-intl/middleware';
import { routing } from './i18n/routing';
export default createMiddleware(routing);
export const config = {
matcher: ['/', '/(zh-CN|en-US)/:path*', '/((?!api|_next|_vercel|.*\\..*).*)']
};
中间件作用:
- 拦截所有请求
- 自动识别和处理语言路由
- 将无效语言重定向到默认语言
- 排除 API 路由和静态资源
4. 配置请求处理 (src/i18n/request.ts)
typescript
import { getRequestConfig } from 'next-intl/server';
import { routing } from './routing';
export default getRequestConfig(async ({ requestLocale }) => {
let locale = await requestLocale;
if (!locale || !routing.locales.includes(locale as any)) {
locale = routing.defaultLocale;
}
return {
locale,
messages: (await import(`../../messages/${locale}.json`)).default
};
});
功能:
- 验证请求的语言是否合法
- 动态导入对应的翻译文件
- 不合法时回退到默认语言
5. 配置 Next.js (next.config.ts)
typescript
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts');
export default withNextIntl({
// 其他 Next.js 配置
});
6. 创建布局组件 (src/app/[locale]/layout.tsx)
typescript
import type { Metadata } from "next";
import { NextIntlClientProvider } from 'next-intl';
import { getMessages } from 'next-intl/server';
import { notFound } from 'next/navigation';
import { routing } from '@/i18n/routing';
import AntdProvider from './AntdProvider';
import "./globals.css";
export const metadata: Metadata = {
title: "Mogotech Web",
description: "Next.js project with i18n support",
};
export default async function LocaleLayout({
children,
params
}: {
children: React.ReactNode;
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
// 验证语言参数
if (!routing.locales.includes(locale as any)) {
notFound();
}
// 获取翻译消息
const messages = await getMessages();
return (
<html lang={locale}>
<body>
<NextIntlClientProvider messages={messages}>
<AntdProvider locale={locale}>
{children}
</AntdProvider>
</NextIntlClientProvider>
</body>
</html>
);
}
关键点:
- 使用
[locale]动态路由捕获语言参数 - 验证语言合法性,不合法返回 404
NextIntlClientProvider提供翻译上下文AntdProvider配置 Ant Design 国际化
7. 配置 Ant Design 国际化 (src/app/[locale]/AntdProvider.tsx)
typescript
'use client';
import { ConfigProvider } from 'antd';
import zhCN from 'antd/locale/zh_CN';
import enUS from 'antd/locale/en_US';
const locales: Record<string, any> = {
'zh-CN': zhCN,
'en-US': enUS,
};
export default function AntdProvider({
children,
locale,
}: {
children: React.ReactNode;
locale: string;
}) {
return (
<ConfigProvider locale={locales[locale] || enUS}>
{children}
</ConfigProvider>
);
}
作用:
- 配置 Ant Design 组件的语言
- 影响日期选择器、表单验证、分页等组件的文本
8. 创建翻译文件
英文翻译 (messages/en-US.json):
json
{
"common": {
"welcome": "Welcome",
"home": "Home",
"about": "About",
"contact": "Contact Us"
},
"home": {
"title": "Welcome to Mogotech",
"description": "This is a Next.js project with internationalization support"
}
}
中文翻译 (messages/zh-CN.json):
json
{
"common": {
"welcome": "欢迎",
"home": "首页",
"about": "关于",
"contact": "联系我们"
},
"home": {
"title": "欢迎来到 Mogotech",
"description": "这是一个支持国际化的 Next.js 项目"
}
}
组织方式:
- 使用命名空间(
common、home)组织翻译 - 支持嵌套结构
- JSON 格式,易于维护
9. 在页面中使用 (src/app/[locale]/page.tsx)
typescript
import { useTranslations } from 'next-intl';
import { Link } from '@/i18n/routing';
import { Button } from 'antd';
export default function Home() {
const t = useTranslations('home');
const tc = useTranslations('common');
return (
<div className="min-h-screen p-8">
<nav className="mb-8 flex gap-4">
<Link href="/" locale="zh-CN">
<Button>中文</Button>
</Link>
<Link href="/" locale="en-US">
<Button>English</Button>
</Link>
</nav>
<main className="max-w-4xl mx-auto">
<h1 className="text-4xl font-bold mb-4">{t('title')}</h1>
<p className="text-lg text-gray-600 mb-8">{t('description')}</p>
<div className="flex gap-4">
<Button type="primary">{tc('home')}</Button>
<Button>{tc('about')}</Button>
<Button>{tc('contact')}</Button>
</div>
</main>
</div>
);
}
使用方式:
useTranslations('namespace'): 获取指定命名空间的翻译函数t('key'): 获取翻译文本Link组件: 使用国际化路由,自动处理语言前缀
工作流程
bash
用户访问 /about
↓
middleware.ts 拦截请求
↓
识别语言为 en-US(默认)
↓
request.ts 加载 messages/en-US.json
↓
layout.tsx 接收 locale 和 messages
↓
NextIntlClientProvider 提供翻译上下文
↓
AntdProvider 配置 Ant Design 语言
↓
page.tsx 使用 useTranslations 获取翻译
↓
渲染英文内容
语言切换流程
typescript
// 用户点击语言切换按钮
<Link href="/" locale="zh-CN">中文</Link>
// Link 组件生成 URL: /zh-CN
// 页面跳转到 /zh-CN
// middleware 识别语言为 zh-CN
// 加载 messages/zh-CN.json
// 重新渲染页面,显示中文内容
核心特性
1. 路由国际化
- URL 包含语言信息,SEO 友好
- 默认语言无前缀,URL 简洁
- 支持语言切换时保持当前路径
2. 服务端渲染
- 翻译在服务端完成
- 首屏加载即显示正确语言
- 有利于 SEO
3. 按需加载
- 翻译文件动态导入
- 减少初始包体积
- 提升加载性能
4. 类型安全
- TypeScript 支持
- 编译时检查翻译键
- 减少运行时错误
5. UI 组件国际化
- Ant Design 组件自动适配语言
- 日期、表单、分页等组件文本自动翻译
最佳实践
1. 翻译文件组织
json
{
"common": {
// 全局通用翻译
},
"home": {
// 首页专用翻译
},
"about": {
// 关于页专用翻译
}
}
2. 使用命名空间
typescript
// 避免翻译键冲突
const t = useTranslations('home');
t('title') // home.title
const tc = useTranslations('common');
tc('title') // common.title
3. 语言切换保持路径
typescript
// 在任何页面切换语言,保持当前路径
<Link href={pathname} locale="zh-CN">中文</Link>
<Link href={pathname} locale="en-US">English</Link>
4. 处理缺失翻译
typescript
// request.ts 中设置回退
return {
locale,
messages: (await import(`../../messages/${locale}.json`)).default,
defaultTranslationValues: {
// 设置默认值
}
};
常见问题
Q1: 如何添加新语言?
- 在
routing.ts中添加语言代码 - 创建对应的翻译文件
messages/ja-JP.json - 在
AntdProvider.tsx中添加 Ant Design 语言包 - 更新 middleware matcher
Q2: 如何让所有语言都显示前缀?
typescript
// routing.ts
localePrefix: 'always' // 改为 always
Q3: 如何在服务端组件中使用翻译?
typescript
import { getTranslations } from 'next-intl/server';
export default async function Page() {
const t = await getTranslations('home');
return <h1>{t('title')}</h1>;
}
Q4: 如何根据用户浏览器语言自动跳转?
middleware 会自动处理,基于 Accept-Language 请求头。
总结
这套方案实现了:
- 完整的路由国际化
- 服务端渲染支持
- UI 组件库国际化
- 类型安全
- SEO 友好
- 性能优化
适用于需要多语言支持的 Next.js 项目,特别是面向国际用户的公开网站。