- Published on
在 Next.js 中使用 next-intl 实现多语言支持
- Authors
- Name
- Shelton Ma
next-intl
是一个专为 Next.js App Router 设计的国际化(i18n)库,具有轻量、易用、并与 App Router 深度集成等优点。
1. 安装依赖
pnpm install next-intl
next-intl
2. 配置 messages/
目录用于存放不同语言的翻译文件,例如 messages/en.json
和 messages/zh.json
1. next.config.js
中配置 next-intl
2. import type { NextConfig } from "next";
import createNextIntlPlugin from "next-intl/plugin";
const nextConfig: NextConfig = {};
const withNextIntl = createNextIntlPlugin();
export default withNextIntl(nextConfig);
src/i18n
用于存放语言相关的配置,使用 src/i18n/en.ts
代替 messages/en.json
, 但是 message 下的文件必不可少
3. src/i18n/en.ts src/i18n/zh.ts
存放翻译内容src/i18n/index.ts
加载语言包, 使用 对象 而不是 json 文件, 这样可以更灵活import { en } from "./en"; import { zh } from "./zh"; const locales = { zh, en }; export function getI18n(locale: string) { return locales[locale as keyof typeof locales] || locales["en"]; }
src/i18n/routing.ts
import { defineRouting } from "next-intl/routing"; export const routing = defineRouting({ // A list of all locales that are supported locales: ["en", "zh"], // Used when no locale matches defaultLocale: "en", localeDetection: false, });
src/i18n/request.ts
import { hasLocale } from "next-intl"; import { getRequestConfig } from "next-intl/server"; import { routing } from "./routing"; export default getRequestConfig(async ({ requestLocale }) => { // Typically corresponds to the `[locale]` segment const requested = await requestLocale; const locale = hasLocale(routing.locales, requested) ? requested : routing.defaultLocale; return { locale, messages: (await import(`../../messages/${locale}.json`)).default, }; });
src/i18n/navigation.ts
封装后的Link
会自动处理多语言, 和当前保持一致import { createNavigation } from "next-intl/navigation"; import { routing } from "./routing"; // Lightweight wrappers around Next.js' navigation // APIs that consider the routing configuration export const { Link, redirect, usePathname, useRouter, getPathname } = createNavigation(routing);
4. layout
// src/app/[locale]/layout.tsx
import { routing } from "@/i18n/routing";
import { NextIntlClientProvider, hasLocale } from "next-intl";
import { notFound } from "next/navigation";
export default async function LocaleLayout({
children,
params,
}: {
children: React.ReactNode;
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
if (!hasLocale(routing.locales, locale)) {
notFound();
}
return (
<html lang={locale}>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<NextIntlClientProvider>{children}</NextIntlClientProvider>
</body>
</html>
);
}
next-intl
3. 使用 src/app/[locale]/page.tsx
默认使用, 只能加载 string, 当需要动态加载list时, 不如对象方便
import {useTranslations} from 'next-intl'; function About() { const t = useTranslations('About'); return <h1>{t('title')}</h1>; }
加载对象解析多语言内容
import { useLocale } from "next-intl"; export default function Header() { const locale = useLocale(); const t = getI18n(locale); } return ( <div> {t.services.items.map((service, index) => ( <Card key={index}> {service.description} </Card> ))} </div> )
使用
next-intl
的Link
组件, 此时 Link 会自动处理多语言import { Link } from "@/i18n/navigation"; <Link href={posts[0].url} className="inline-flex items-center px-6 py-3 rounded-lg bg-blue-600 text-white font-medium hover:bg-blue-700 transition-colors" > Read More → </Link>