国际化多语言支持
学习如何在 NEXTDEVKIT 中使用 next-intl 实现多语言支持
NextDevKit 使用 next-intl 构建国际化系统,提供自动路由、类型安全和无缝多语言支持。
国际化(i18n)是现代全球化应用不可缺少的功能。NextDevKit 内置了基于 next-intl 的现代化国际化系统,让你轻松实现多语言支持。
🤔 什么是 Next-intl?
next-intl 是专为 Next.js 设计的国际化库:
- 🎯 Next.js 优化:完美集成 App Router 和 Pages Router
- 🔒 类型安全:TypeScript 支持,编译时检查翻译键
- 🌍 自动路由:基于语言的 URL 路由管理
- 🍪 智能检测:浏览器语言 + Cookie 偏好设置
- 🚀 高性能:服务端渲染 + 消息合并优化
🏗️ 国际化架构
项目结构
messages.ts
navigation.ts
routing.ts
request.ts
locale-cookie.ts
update-locale.ts
layout.tsx
page.tsx
index.ts
middleware.ts
en.json
zh.json
核心组件说明:
src/i18n/:国际化核心配置和工具messages/:存放所有语言的翻译文件app/[locale]/:基于语言的路由结构middleware.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 的路由行为:
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)
📁 翻译消息组织
消息文件结构
采用嵌套结构组织翻译消息:
英文消息示例
{
"app": {
"name": "NEXTDEVKIT",
"metadata": {
"title": "NEXTDEVKIT - 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"
}
}
}中文消息示例
{
"app": {
"name": "NEXTDEVKIT",
"metadata": {
"title": "NEXTDEVKIT - 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
🎨 在组件中使用
服务端组件
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>
);
}客户端组件
'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>
);
}🧭 国际化导航
使用 Link 组件
NextDevKit 提供的 Link 组件会自动处理语言路由:
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>
);
}Link 组件特性
自动语言前缀:
// 当前语言为 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>;
}中间件配置
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/ 目录创建新语言文件:
{
"app": {
"name": "NEXTDEVKIT",
"metadata": {
"title": "NEXTDEVKIT - Next.js SaaS スターターキット",
"description": "より高速にプロダクション対応のSaaSアプリを構築..."
}
},
"auth": {
"login": {
"title": "アカウントにサインイン",
"email": "メールアドレス",
"password": "パスワード",
"submit": "サインイン"
}
}
}2. 更新应用配置
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")