Next.js 国际化实现方案详解

本文详细介绍如何在 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 项目"
  }
}

组织方式:

  • 使用命名空间(commonhome)组织翻译
  • 支持嵌套结构
  • 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: 如何添加新语言?

  1. routing.ts 中添加语言代码
  2. 创建对应的翻译文件 messages/ja-JP.json
  3. AntdProvider.tsx 中添加 Ant Design 语言包
  4. 更新 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 项目,特别是面向国际用户的公开网站。

参考资源

相关推荐
掘金挖土5 小时前
手摸手快速搭建 Vue3 + ElementPlus 后台管理系统模板,使用 JavaScript
前端·javascript
CoderHing5 小时前
告别 try/catch 地狱:用三元组重新定义 JavaScript 错误处理
前端·javascript·react.js
一念之间lq5 小时前
Elpis 第三阶段· 领域模型架构建设
前端·后端
哆啦A梦15885 小时前
商城后台管理系统 01 Vue-i18n国际化
前端·javascript·vue.js
期待のcode5 小时前
Vue的安装创建与运行
前端·javascript·vue.js
百锦再5 小时前
国产数据库的平替亮点——关系型数据库架构适配
android·java·前端·数据库·sql·算法·数据库架构
旺仔Sec5 小时前
2025年海南省职业院校技能大赛“应用软件系统开发“赛项竞赛样题
前端·应用软件系统开发
FakeOccupational6 小时前
【树莓派 002】 RP2040 实现示波器 PIO来驱动 ADC10080 并抓取数据方案+ 内置12-bitADC&DMA&网页前端可视化方案
前端