useAiWork开发者文档
介绍定制化

国际化多语言支持

学习如何在 AGENTDEVKIT 中使用 next-intl 实现多语言支持。

学习如何在 AGENTDEVKIT 中使用 next-intl 实现多语言支持

NextDevKit 使用 next-intl 构建国际化系统,提供自动路由、类型安全和无缝多语言支持。

国际化(i18n)是现代全球化应用不可缺少的功能。NextDevKit 内置了基于 next-intl 的现代化国际化系统,让你轻松实现多语言支持。

🤔 什么是 Next-intl?

next-intl 是专为 Next.js 设计的国际化库:

  • 🎯 Next.js 优化 :完美集成 App Router 和 Pages Router
  • 🔒 类型安全 :TypeScript 支持,编译时检查翻译键
  • 🌍 自动路由 :基于语言的 URL 路由管理
  • 🍪 智能检测 :浏览器语言 + Cookie 偏好设置
  • 🚀 高性能 :服务端渲染 + 消息合并优化

🏗️ 国际化架构

项目结构

src

i18n

messages.ts

navigation.ts

routing.ts

request.ts

lib

locale-cookie.ts

update-locale.ts

app/[locale]

layout.tsx

(marketing)

page.tsx

config

index.ts

middleware.ts

messages

en.json

zh.json

核心组件说明 :

  • src/i18n/ :国际化核心配置和工具
  • messages/ :存放所有语言的翻译文件
  • app/[locale]/ :基于语言的路由结构
  • middleware.ts :语言检测和重定向中间件

⚙️ 配置与初始化

应用配置

在 src/config/index.ts 中统一管理国际化配置:

src/config/index.ts

代码片段
export const appConfig = {
  i18n: {
    enabled: true,                    // 启用/禁用国际化
    defaultLocale: "en",              // 默认语言
    locales: {                        // 支持的语言
      en: { name: "English" },
      zh: { name: "简体中文" },
    },
    localeCookieName: "NEXT_LOCALE",  // Cookie 名称
  },
  // ... 其他配置
} as const;

配置说明 :

  • enabled :全局开关,可以快速禁用国际化
  • defaultLocale :默认语言,用于回退和首次访问
  • locales :语言映射,键为语言代码,值为显示名称
  • localeCookieName :存储用户语言偏好的 Cookie 名称

路由配置

src/i18n/routing.ts 定义了 next-intl 的路由行为:

src/i18n/routing.ts

代码片段
import { appConfig } from "@/config";
import { defineRouting } from "next-intl/routing";

export const routing = defineRouting({
  locales: Object.keys(appConfig.i18n.locales),    // ['en', 'zh']
  defaultLocale: appConfig.i18n.defaultLocale,     // 'en'
  localeCookie: {
    name: appConfig.i18n.localeCookieName,          // 'NEXT_LOCALE'
  },
  localeDetection: appConfig.i18n.enabled,         // 是否自动检测语言
  localePrefix: appConfig.i18n.enabled ? "as-needed" : "never",
});

路由策略 :

  • as-needed :仅非默认语言显示前缀(/zh/about,默认语言 /about)
  • never :所有语言都不显示前缀
  • always :所有语言都显示前缀(/en/about, /zh/about)

📁 翻译消息组织

消息文件结构

采用嵌套结构组织翻译消息:

英文消息示例

messages/en.json

代码片段
{
  "app": {
    "name": "AGENTDEVKIT",
    "metadata": {
      "title": "AGENTDEVKIT - Next.js SaaS Starter Kit",
      "description": "Build production-ready SaaS apps faster..."
    }
  },
  "menu": {
    "application": {
      "dashboard": {
        "title": "Dashboard"
      }
    },
    "settings": {
      "title": "Settings"
    }
  },
  "auth": {
    "login": {
      "title": "Sign in to your account",
      "email": "Email address",
      "password": "Password",
      "submit": "Sign in"
    }
  }
}

中文消息示例

messages/zh.json

代码片段
{
  "app": {
    "name": "AGENTDEVKIT",
    "metadata": {
      "title": "AGENTDEVKIT - Next.js SaaS 开发模板",
      "description": "更快构建和部署生产级 SaaS 应用..."
    }
  },
  "menu": {
    "application": {
      "dashboard": {
        "title": "仪表板"
      }
    },
    "settings": {
      "title": "设置"
    }
  },
  "auth": {
    "login": {
      "title": "登录您的账户",
      "email": "电子邮箱",
      "password": "密码",
      "submit": "登录"
    }
  }
}

组织策略

按功能模块分组 :

  • app :应用级别信息
  • common :通用词汇
  • auth :认证相关
  • menu :导航菜单
  • settings :设置页面

命名约定 :

  • 使用 驼峰命名 :firstName 而不是 first_name
  • 语义化命名 :submitButton 而不是 btn1
  • 分层结构 :auth.login.title 而不是 authLoginTitle

🎨 在组件中使用

服务端组件

src/app/[locale]/(marketing)/page.tsx

代码片段
import { getTranslations } from "next-intl/server";

export default async function HomePage() {
  const t = await getTranslations("app.metadata");

  return (
    <div>
      <h1>{t("title")}</h1>
      <p>{t("description")}</p>
    </div>
  );
}

客户端组件

src/components/auth/login-form.tsx

代码片段
'use client';

import { useTranslations } from "next-intl";

export function LoginForm() {
  const t = useTranslations("auth.login");

  return (
    <form>
      <h2>{t("title")}</h2>
      <input
        type="email"
        placeholder={t("email")}
      />
      <input
        type="password"
        placeholder={t("password")}
      />
      <button type="submit">
        {t("submit")}
      </button>
    </form>
  );
}

🧭 国际化导航

NextDevKit 提供的 Link 组件会自动处理语言路由:

src/components/shared/header/index.tsx

代码片段
import { Link } from "@/i18n/navigation";
import { useTranslations } from "next-intl";

export function Header() {
  const t = useTranslations("menu");

  return (
    <nav>
      {/* 基础用法 - 自动添加语言前缀 */}
      <Link href="/">首页</Link>
      <Link href="/blog">博客</Link>
      <Link href="/docs">文档</Link>

      {/* 使用翻译文本 */}
      <Link href="/app/dashboard">
        {t("application.dashboard.title")}
      </Link>
    </nav>
  );
}

自动语言前缀 :

代码片段
// 当前语言为 zh 时
<Link href="/about">关于</Link>
// 渲染为: <a href="/zh/about">关于</a>

// 当前语言为 en(默认语言)时
<Link href="/about">About</Link>
// 渲染为: <a href="/about">About</a>

编程式导航 :

代码片段
'use client';

import { useRouter, usePathname } from "@/i18n/navigation";

export function NavigationExample() {
  const router = useRouter();
  const pathname = usePathname();

  const handleNavigation = () => {
    // 导航到其他页面
    router.push('/dashboard');

    // 带查询参数导航
    router.push('/search?q=nextjs');

    // 替换当前历史记录
    router.replace('/new-page');

    // 返回上一页
    router.back();
  };

  return (
    <div>
      <p>当前路径: {pathname}</p>
      <button onClick={handleNavigation}>导航</button>
    </div>
  );
}

服务端重定向 :

代码片段
import { redirect } from "@/i18n/navigation";
import { getTranslations } from "next-intl/server";

export default async function ProtectedPage() {
  const session = await getSession();

  if (!session) {
    // 自动添加语言前缀进行重定向
    redirect('/auth/login');
  }

  return <div>受保护的内容</div>;
}

中间件配置

middleware.ts

代码片段
import createMiddleware from "next-intl/middleware";
import { routing } from "@/i18n/routing";

export default createMiddleware(routing);

export const config = {
  // 匹配所有路径,除了 api、_next/static、_next/image 和文件扩展名
  matcher: ["/((?!api|_next/static|_next/image|.*\\..*).*)"]
};

🔧 添加新语言

1. 创建翻译文件

在 messages/ 目录创建新语言文件:

messages/ja.json

代码片段
{
  "app": {
    "name": "AGENTDEVKIT",
    "metadata": {
      "title": "AGENTDEVKIT - Next.js SaaS スターターキット",
      "description": "より高速にプロダクション対応のSaaSアプリを構築..."
    }
  },
  "auth": {
    "login": {
      "title": "アカウントにサインイン",
      "email": "メールアドレス",
      "password": "パスワード",
      "submit": "サインイン"
    }
  }
}

2. 更新应用配置

src/config/index.ts

代码片段
export const appConfig = {
  i18n: {
    enabled: true,
    defaultLocale: "en",
    locales: {
      en: { name: "English" },
      zh: { name: "简体中文" },
      ja: { name: "日本語" },  // 添加日语
    },
    localeCookieName: "NEXT_LOCALE",
  },
} as const;

3. 测试新语言

启动开发服务器并访问:

  • / (默认语言)
  • /zh (中文)
  • /ja (日语)

📚 最佳实践

翻译键命名规范

代码片段
// ✅ 好的命名
t("auth.login.submitButton")
t("common.confirmDialog.title")
t("dashboard.metrics.totalUsers")

// ❌ 避免的命名
t("button1")
t("text_for_login")
t("authLoginSubmitButtonText")

🔗 相关资源

如何组织和创建文档学习如何在 AGENTDEVKIT 中使用 Fumadocs 创建和管理文档支付概述学习如何在 AGENTDEVKIT 中使用 Stripe 或 Creem 设置和使用支付

On this page

🤔 什么是 Next-intl?🏗️ 国际化架构项目结构⚙️ 配置与初始化应用配置路由配置📁 翻译消息组织消息文件结构英文消息示例中文消息示例组织策略🎨 在组件中使用服务端组件客户端组件🧭 国际化导航使用 Link 组件Link 组件特性中间件配置🔧 添加新语言1. 创建翻译文件2. 更新应用配置3. 测试新语言📚 最佳实践翻译键命名规范🔗 相关资源

本页目录