next-intl-app-router
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesenext-intl (App Router)
next-intl(App Router)
Setup and usage of with prefix-based locale routing (e.g. , ). Use this skill in any Next.js App Router project.
next-intl/en/about/ja/aboutExample code: Copy-paste examples live in this skill's examples/ folder. See examples/README.md for where each file goes in your project.
在Next.js App Router中设置并使用实现基于前缀的区域路由(例如、)。可在任意Next.js App Router项目中使用本方案。
next-intl/en/about/ja/about示例代码: 可直接复制粘贴的示例存放在本技能的examples/文件夹中。查看examples/README.md了解各文件在项目中的存放位置。
File layout
文件布局
Keep this structure:
├── messages/
│ ├── en.json
│ ├── ja.json
│ └── ...
├── next.config.ts
└── src/
├── i18n/
│ ├── request.ts
│ ├── routing.ts
│ └── navigation.ts
├── proxy.ts # Next.js 16+ (was middleware.ts)
└── app/
├── layout.tsx # Root layout, no NextIntlClientProvider here
└── [locale]/
├── layout.tsx
├── page.tsx
└── ...Root layout does not wrap with ; only does.
NextIntlClientProviderapp/[locale]/layout.tsx请保持如下文件结构:
├── messages/
│ ├── en.json
│ ├── ja.json
│ └── ...
├── next.config.ts
└── src/
├── i18n/
│ ├── request.ts
│ ├── routing.ts
│ └── navigation.ts
├── proxy.ts # Next.js 16+(原middleware.ts)
└── app/
├── layout.tsx # 根布局,此处无需NextIntlClientProvider
└── [locale]/
├── layout.tsx
├── page.tsx
└── ...根布局不需要用包裹;仅需要。
NextIntlClientProviderapp/[locale]/layout.tsx1. Next config
1. Next.js配置
Wire the plugin (default path ):
./i18n/request.tsts
// next.config.ts
import type { NextConfig } from "next";
import createNextIntlPlugin from "next-intl/plugin";
const nextConfig: NextConfig = {
/* ... */
};
const withNextIntl = createNextIntlPlugin();
export default withNextIntl(nextConfig);Custom path: .
createNextIntlPlugin('./src/i18n/request.ts')引入插件(默认路径为):
./i18n/request.tsts
// next.config.ts
import type { NextConfig } from "next";
import createNextIntlPlugin from "next-intl/plugin";
const nextConfig: NextConfig = {
/* ... */
};
const withNextIntl = createNextIntlPlugin();
export default withNextIntl(nextConfig);自定义路径:。
createNextIntlPlugin('./src/i18n/request.ts')2. Routing config
2. 路由配置
Central config in :
src/i18n/routing.tsts
import { defineRouting } from "next-intl/routing";
export const routing = defineRouting({
locales: ["en", "ja", "zh-CN", "zh-TW"],
defaultLocale: "en",
});在中配置核心路由规则:
src/i18n/routing.tsts
import { defineRouting } from "next-intl/routing";
export const routing = defineRouting({
locales: ["en", "ja", "zh-CN", "zh-TW"],
defaultLocale: "en",
});3. Request config
3. 请求配置
src/i18n/request.ts[locale]ts
import { getRequestConfig } from "next-intl/server";
import { hasLocale } from "next-intl";
import { routing } from "./routing";
export default getRequestConfig(async ({ requestLocale }) => {
const requested = await requestLocale;
const locale = hasLocale(routing.locales, requested)
? requested
: routing.defaultLocale;
return {
locale,
messages: (await import(`../../messages/${locale}.json`)).default,
};
});src/i18n/request.ts[locale]ts
import { getRequestConfig } from "next-intl/server";
import { hasLocale } from "next-intl";
import { routing } from "./routing";
export default getRequestConfig(async ({ requestLocale }) => {
const requested = await requestLocale;
const locale = hasLocale(routing.locales, requested)
? requested
: routing.defaultLocale;
return {
locale,
messages: (await import(`../../messages/${locale}.json`)).default,
};
});4. Proxy / middleware (Next.js 16)
4. 代理/中间件(Next.js 16)
Next.js 16 uses instead of . Same API:
proxy.tsmiddleware.tsts
// src/proxy.ts
import createMiddleware from "next-intl/middleware";
import { routing } from "./i18n/routing";
export const proxy = createMiddleware(routing);
export const config = {
matcher: "/((?!api|trpc|_next|_vercel|.*\\..*).*)",
};Matcher: all pathnames except , , , , and paths containing a dot (e.g. ).
/api/trpc/_next/_vercelfavicon.icoNext.js 16使用替代,API保持一致:
proxy.tsmiddleware.tsts
// src/proxy.ts
import createMiddleware from "next-intl/middleware";
import { routing } from "./i18n/routing";
export const proxy = createMiddleware(routing);
export const config = {
matcher: "/((?!api|trpc|_next|_vercel|.*\\..*).*)",
};匹配规则:所有路径名,除了、、、以及包含点的路径(例如)。
/api/trpc/_next/_vercelfavicon.ico5. Navigation helpers
5. 导航工具
Use project navigation wrappers so links keep the current locale:
ts
// src/i18n/navigation.ts
import { createNavigation } from "next-intl/navigation";
import { routing } from "./routing";
export const { Link, redirect, usePathname, useRouter, getPathname } =
createNavigation(routing);In components: import (and others) from , not from or , for locale-aware URLs. Example: examples/Nav-client.tsx, examples/BackToHomeButton.tsx.
Link@/i18n/navigationnext/navigationnext/link使用项目封装的导航工具,确保链接保留当前区域设置:
ts
// src/i18n/navigation.ts
import { createNavigation } from "next-intl/navigation";
import { routing } from "./routing";
export const { Link, redirect, usePathname, useRouter, getPathname } =
createNavigation(routing);在组件中:从导入(及其他工具),不要从或导入,以支持区域感知的URL。示例:examples/Nav-client.tsx、examples/BackToHomeButton.tsx。
@/i18n/navigationLinknext/navigationnext/link6. Locale layout and static rendering
6. 区域布局与静态渲染
app/[locale]/layout.tsx- Validate with
locale→hasLocaleif invalid.notFound() - Call for static rendering.
setRequestLocale(locale) - Wrap children with and
NextIntlClientProvider.getMessages()
tsx
// app/[locale]/layout.tsx
import { NextIntlClientProvider, hasLocale } from "next-intl";
import { setRequestLocale } from "next-intl/server";
import { notFound } from "next/navigation";
import { routing } from "@/i18n/routing";
import { getMessages } from "next-intl/server";
type Props = {
children: React.ReactNode;
params: Promise<{ locale: string }>;
};
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }));
}
export default async function LocaleLayout({ children, params }: Props) {
const { locale } = await params;
if (!hasLocale(routing.locales, locale)) notFound();
setRequestLocale(locale);
const messages = await getMessages();
return (
<NextIntlClientProvider messages={messages}>
{children}
</NextIntlClientProvider>
);
}app/[locale]/layout.tsx- 使用验证
hasLocale→ 若无效则调用locale。notFound() - 调用以支持静态渲染。
setRequestLocale(locale) - 用包裹子组件并传入
NextIntlClientProvider获取的消息。getMessages()
tsx
// app/[locale]/layout.tsx
import { NextIntlClientProvider, hasLocale } from "next-intl";
import { setRequestLocale } from "next-intl/server";
import { notFound } from "next/navigation";
import { routing } from "@/i18n/routing";
import { getMessages } from "next-intl/server";
type Props = {
children: React.ReactNode;
params: Promise<{ locale: string }>;
};
export function generateStaticParams() {
return routing.locales.map((locale) => ({ locale }));
}
export default async function LocaleLayout({ children, params }: Props) {
const { locale } = await params;
if (!hasLocale(routing.locales, locale)) notFound();
setRequestLocale(locale);
const messages = await getMessages();
return (
<NextIntlClientProvider messages={messages}>
{children}
</NextIntlClientProvider>
);
}7. Pages under [locale]
[locale]7. [locale]
下的页面
[locale]For static rendering, every page under that uses next-intl must call (and use if needed). Examples: app-locale-page.tsx, app-locale-about-page.tsx. (and use if needed). Layout already sets it; pages that render server components using locale should set it too.
[locale]setRequestLocale(locale)use(params)use(params)tsx
// app/[locale]/page.tsx
import { use } from "react";
import { setRequestLocale } from "next-intl/server";
export default function IndexPage({
params,
}: {
params: Promise<{ locale: string }>;
}) {
const { locale } = use(params);
setRequestLocale(locale);
return <TokyoPage />;
}tsx
// app/[locale]/about/page.tsx
import { use } from "react";
import { setRequestLocale } from "next-intl/server";
import AboutContainer from "./components/AboutContainer";
export default function AboutPage({
params,
}: {
params: Promise<{ locale: string }>;
}) {
const { locale } = use(params);
setRequestLocale(locale);
return <AboutContainer />;
}Call before any APIs in that layout/page.
setRequestLocalenext-intl对于静态渲染,下所有使用next-intl的页面必须调用(必要时使用)。示例:app-locale-page.tsx、app-locale-about-page.tsx。(必要时使用)。布局已设置该方法;使用区域设置渲染服务端组件的页面也需调用。
[locale]setRequestLocale(locale)use(params)use(params)tsx
// app/[locale]/page.tsx
import { use } from "react";
import { setRequestLocale } from "next-intl/server";
export default function IndexPage({
params,
}: {
params: Promise<{ locale: string }>;
}) {
const { locale } = use(params);
setRequestLocale(locale);
return <TokyoPage />;
}tsx
// app/[locale]/about/page.tsx
import { use } from "react";
import { setRequestLocale } from "next-intl/server";
import AboutContainer from "./components/AboutContainer";
export default function AboutPage({
params,
}: {
params: Promise<{ locale: string }>;
}) {
const { locale } = use(params);
setRequestLocale(locale);
return <AboutContainer />;
}在该布局/页面中调用任何 API之前,需先调用。
next-intlsetRequestLocale8. Using translations
8. 使用翻译功能
Client components: :
useTranslations(namespace)tsx
"use client";
import { useTranslations } from "next-intl";
import { Link } from "@/i18n/navigation";
export default function BackToHomeButton() {
const t = useTranslations("BackToHomeButton");
return (
<Link href="/">
<span>{t("buttonText")}</span>
</Link>
);
}tsx
"use client";
import { useTranslations } from "next-intl";
import { Link } from "@/i18n/navigation";
export default function Nav() {
const t = useTranslations("Navigation");
return <Link href="/about">{t("links.about")}</Link>;
}Server components: use from (await with locale/namespace as needed).
getTranslationsnext-intl/server客户端组件: 使用:
useTranslations(namespace)tsx
"use client";
import { useTranslations } from "next-intl";
import { Link } from "@/i18n/navigation";
export default function BackToHomeButton() {
const t = useTranslations("BackToHomeButton");
return (
<Link href="/">
<span>{t("buttonText")}</span>
</Link>
);
}tsx
"use client";
import { useTranslations } from "next-intl";
import { Link } from "@/i18n/navigation";
export default function Nav() {
const t = useTranslations("Navigation");
return <Link href="/about">{t("links.about")}</Link>;
}服务端组件: 使用中的(根据需要传入区域设置/命名空间并await)。
next-intl/servergetTranslations9. Messages format
9. 消息文件格式
One JSON file per locale under . Nested keys map to namespaces and keys:
messages/json
{
"HomePage": {
"title": "Hello world!"
},
"LandingPage": {
"title": "Tokyo Sounds",
"navbar": {
"home": "Home",
"about": "About"
}
},
"BackToHomeButton": {
"buttonText": "Back to Home",
"tooltip": "Return to the main page"
}
}- →
useTranslations("LandingPage"),t("title").t("navbar.about") - Interpolation: →
"selectColor": "Select {color} color".t("selectColor", { color: "Blue" })
每个区域对应一个JSON文件,存放在目录下。嵌套键对应命名空间和翻译键:
messages/json
{
"HomePage": {
"title": "Hello world!"
},
"LandingPage": {
"title": "Tokyo Sounds",
"navbar": {
"home": "Home",
"about": "About"
}
},
"BackToHomeButton": {
"buttonText": "Back to Home",
"tooltip": "Return to the main page"
}
}- →
useTranslations("LandingPage")、t("title")。t("navbar.about") - 插值语法:→
"selectColor": "Select {color} color"。t("selectColor", { color: "Blue" })
Checklist
检查清单
- :
next.config.tswraps config.createNextIntlPlugin() - :
src/i18n/routing.tswithdefineRoutingandlocales.defaultLocale - :
src/i18n/request.ts+getRequestConfig+ dynamichasLocale.messages/${locale}.json - (or
src/proxy.ts):middleware.tsand matcher.createMiddleware(routing) - :
src/i18n/navigation.tsand re-exportcreateNavigation(routing), etc.Link - :
app/[locale]/layout.tsx→hasLocale,notFound,setRequestLocale,generateStaticParams+NextIntlClientProvider.getMessages() - Each :
app/[locale]/**/page.tsxwhen using static rendering.setRequestLocale(locale) - Client components: ; links use
useTranslations("Namespace")fromLink.@/i18n/navigation
- :使用
next.config.ts包裹配置。createNextIntlPlugin() - :使用
src/i18n/routing.ts配置defineRouting和locales。defaultLocale - :配置
src/i18n/request.ts+getRequestConfig+ 动态引入hasLocale。messages/${locale}.json - (或
src/proxy.ts):配置middleware.ts和匹配规则。createMiddleware(routing) - :使用
src/i18n/navigation.ts并重新导出createNavigation(routing)等工具。Link - :通过
app/[locale]/layout.tsx验证→无效则hasLocale,调用notFound,配置setRequestLocale,使用generateStaticParams+NextIntlClientProvider。getMessages() - 每个:使用静态渲染时需调用
app/[locale]/**/page.tsx。setRequestLocale(locale) - 客户端组件:使用;链接使用
useTranslations("Namespace")中的@/i18n/navigation。Link
Reference
参考资料
- Copy-paste examples: examples/ — standalone files for use in any project.
- Extended config (localePrefix, pathnames, etc.): reference.md
- Official: next-intl App Router, Routing setup
- 可复制示例: examples/ — 独立文件,可用于任意项目。
- 扩展配置(localePrefix、pathnames等):reference.md
- 官方文档:next-intl App Router、Routing setup