Next.js作为一个流行的React框架,为构建多语言支持的应用程序提供了强大的支持。本指南将引导你完成在Next.js项目中实现国际化(i18n)的步骤。我们将涵盖路由设置、本地化处理和翻译内容管理。
理解国际化术语
区域设置(Locale)
区域设置是一组语言和格式化偏好的标识符。它包括用户的首选语言,也可能指示他们的地理区域。例如:
- 'en-US':美国使用的英语
- 'nl-NL':荷兰使用的荷兰语
- 'en':没有特定区域的英语
设置Next.js国际化
创建新的Next.js应用
如果你还没有,使用以下命令创建一个新的Next.js项目:
$ npx create-next-app@latest my-i18n-app
设置国际化路由
为用户提供无缝体验,根据他们的首选语言调整你的应用程序至关重要。这可以通过调整路由机制来实现。
利用用户的语言偏好
通过使用像@formatjs/intl-localematcher
和negotiator
这样的库,你可以根据用户的headers和你支持的区域设置来确定用户的首选区域设置。这有助于确保用户被导向到你网站的正确语言版本。
$ npm install @formatjs/intl-localematcher negotiator
实现基于区域设置的路由
Next.js允许你通过子路径(/fr/products)
或域名(my-site.fr/products)
来国际化路由。这些信息使你能够在中间件中根据用户的首选区域设置重定向用户。
在src/
目录下创建middleware.ts
文件:
// middleware.ts
import { match } from '@formatjs/intl-localematcher'
import Negotiator from 'negotiator'
import { NextRequest, NextResponse } from 'next/server'
let defaultLocale = 'en'
let locales = ['cn', 'de', 'en']
// 获取首选区域设置,类似上面或使用库
function getLocale(request: NextRequest) {
const acceptedLanguage = request.headers.get('accept-language') ?? undefined
let headers = { 'accept-language': acceptedLanguage }
let languages = new Negotiator({ headers }).languages()
return match(languages, locales, defaultLocale) // -> 'en-US'
}
export function middleware(request: NextRequest) {
// 检查路径中是否有任何支持的区域设置
const pathname = request.nextUrl.pathname
const pathnameIsMissingLocale = locales.every(
(locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
)
// 如果没有区域设置则重定向
if (pathnameIsMissingLocale) {
const locale = getLocale(request)
// 例如,传入的请求是/products
// 新的URL现在是/en-US/products
return NextResponse.redirect(new URL(`/${locale}/${pathname}`, request.url))
}
}
export const config = {
matcher: [
// 跳过所有内部路径 (_next, assets, api)
'/((?!api|assets|.*\\..*|_next).*)',
// 可选:只在根 (/) URL 上运行
// '/'
],
}
组织文件以进行基于区域设置的处理
为了使Next.js能够在路由中动态管理不同的区域设置,将所有特殊文件嵌套在app/[lang]
中。
例如:
// app/[lang]/page.tsx
export default async function Page({ params: { lang } }) {
return ...
}
实现本地化
本地化涉及根据用户的首选区域设置调整显示的内容。这可以通过为每种支持的语言维护单独的字典来实现。
创建字典
例如,我们考虑Next.js主页的英语、荷兰语和中文翻译:
app/[lang]/dictionaries
dictionaries/en.json
:
{
"get_started": "Get started by editing",
"doc": "Find in-depth information about Next.js features and API.",
"learn": "Learn about Next.js in an interactive course with quizzes!",
"template": "Explore the Next.js 13 playground.",
"deploy": "Instantly deploy your Next.js site to a shareable URL with Vercel."
}
dictionaries/de.json:
{
"get_started": "Beginnen Sie, indem Sie bearbeiten",
"doc": "Finden Sie ausführliche Informationen zu den Funktionen und der API von Next.js.",
"learn": "Erfahren Sie mehr über Next.js in einem interaktiven Kurs mit Quizfragen!",
"template": "Erkunden Sie den Next.js 13-Spielplatz.",
"deploy": "Bereiten Sie Ihre Next.js-Website sofort für die Bereitstellung auf einer gemeinsam nutzbaren URL mit Vercel vor."
}
dictionaries/cn.json:
{
"get_started": "通过编辑开始",
"doc": "查找关于 Next.js 功能和 API 的深入信息。",
"learn": "通过互动课程学习 Next.js,包括测验!",
"template": "探索 Next.js 13 的示范环境。",
"deploy": "使用 Vercel 立即部署您的 Next.js 网站到可共享的 URL。"
}
加载翻译
创建一个getDictionary函数来加载请求的区域设置的翻译。
import 'server-only'
export type Locale = keyof typeof dictionaries
const dictionaries = {
en: () => import('./dictionaries/en.json').then((module) => module.default),
de: () => import('./dictionaries/de.json').then((module) => module.default),
cn: () => import('./dictionaries/cn.json').then((module) => module.default),
}
export const getDictionary = async (locale: Locale) => dictionaries[locale]()
在组件中使用翻译
现在你可以在布局或页面中获取字典以显示翻译后的内容。
import SwitchLang from '@/components/SwitchLang/SwitchLang'
import Image from 'next/image'
import { Locale, getDictionary } from './dictionaries'
import styles from './page.module.css'
type Props = {
params: {
lang: Locale
}
}
export default async function Home({ params: { lang } }: Props) {
const intl = await getDictionary(lang)
return (
<main className={styles.main}>
<div className={styles.description}>
<p>
{intl.get_started}
<code className={styles.code}>src/app/page.tsx</code>
</p>
<SwitchLang />
{/* ... 其余代码 ... */}
</div>
{/* ... 其余代码 ... */}
<div className={styles.grid}>
<a
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Docs <span>-></span>
</h2>
<p>{intl.doc}</p>
</a>
{/* ... 其他卡片 ... */}
</div>
</main>
)
}
为多个区域设置进行静态生成
要为一组区域设置生成静态路由,在任何页面或布局中使用generateStaticParams。这可以全局设置,例如在根布局中:
// app/[lang]/layout.ts
export async function generateStaticParams() {
return [{ lang: 'en' }, { lang: 'de' }, { lang: 'cn' }]
}
export default function Root({ children, params }) {
return (
<html lang={params.lang}>
<body>{children}</body>
</html>
)
}
结论
在Next.js中实现国际化为来自不同语言背景的用户提供了无缝体验。通过调整路由,你可以为全球用户创建更加包容和易于访问的应用程序。