Loading...
Loading...
Configures and uses next-intl for Next.js App Router with locale-based routing. Use when adding or changing i18n, locale routing, translations, next-intl plugin, middleware/proxy, or message files in Next.js App Router projects.
npx skill4agent add liuchiawei/agent-skills next-intl-app-routernext-intl/en/about/ja/about├── 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
└── ...NextIntlClientProviderapp/[locale]/layout.tsx./i18n/request.ts// 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')src/i18n/routing.tsimport { defineRouting } from "next-intl/routing";
export const routing = defineRouting({
locales: ["en", "ja", "zh-CN", "zh-TW"],
defaultLocale: "en",
});src/i18n/request.ts[locale]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,
};
});proxy.tsmiddleware.ts// 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.ico// src/i18n/navigation.ts
import { createNavigation } from "next-intl/navigation";
import { routing } from "./routing";
export const { Link, redirect, usePathname, useRouter, getPathname } =
createNavigation(routing);Link@/i18n/navigationnext/navigationnext/linkapp/[locale]/layout.tsxlocalehasLocalenotFound()setRequestLocale(locale)NextIntlClientProvidergetMessages()// 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>
);
}[locale][locale]setRequestLocale(locale)use(params)use(params)// 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 />;
}// 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 />;
}setRequestLocalenext-intluseTranslations(namespace)"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>
);
}"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>;
}getTranslationsnext-intl/servermessages/{
"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" })next.config.tscreateNextIntlPlugin()src/i18n/routing.tsdefineRoutinglocalesdefaultLocalesrc/i18n/request.tsgetRequestConfighasLocalemessages/${locale}.jsonsrc/proxy.tsmiddleware.tscreateMiddleware(routing)src/i18n/navigation.tscreateNavigation(routing)Linkapp/[locale]/layout.tsxhasLocalenotFoundsetRequestLocalegenerateStaticParamsNextIntlClientProvidergetMessages()app/[locale]/**/page.tsxsetRequestLocale(locale)useTranslations("Namespace")Link@/i18n/navigation