
i18n next-intl
npm install next-intl
├── messages
│ ├── en.json
│ └── ...
├── next.config.ts
└── src
├── i18n
│ ├── routing.ts
│ ├── navigation.ts
│ └── request.ts
├── middleware.ts
└── app
└── [locale]
├── layout.tsx
└── page.tsx
messages/en.json
{
"HomePage": {
"title": "Hello world!",
"about": "Go to the about page"
}
}
next.config.ts
import { NextConfig } from "next";
import createNextIntlPlugin from "next-intl/plugin";
const nextConfig: NextConfig = {};
const withNextIntl = createNextIntlPlugin();
export default withNextIntl(nextConfig);
src/i18n/routing.ts
import { defineRouting } from "next-intl/routing";
export const routing = defineRouting({
// A list of all locales that are supported
locales: ["en", "de"],
// Used when no locale matches
defaultLocale: "en",
});
src/i18n/navigation.ts
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);
src/middleware.ts
import createMiddleware from "next-intl/middleware";
import { routing } from "./i18n/routing";
export default createMiddleware(routing);
export const config = {
// Match all pathnames except for
// - … if they start with `/api`, `/trpc`, `/_next` or `/_vercel`
// - … the ones containing a dot (e.g. `favicon.ico`)
matcher: "/((?!api|trpc|_next|_vercel|.*\\..*).*)",
};
src/i18n/request.ts
import { getRequestConfig } from "next-intl/server";
import { hasLocale } from "next-intl";
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/app/[locale]/layout.tsx
import { NextIntlClientProvider, hasLocale } from "next-intl";
import { notFound } from "next/navigation";
import { routing } from "@/i18n/routing";
export default async function LocaleLayout({
children,
params,
}: {
children: React.ReactNode;
params: Promise<{ locale: string }>;
}) {
// Ensure that the incoming `locale` is valid
const { locale } = await params;
if (!hasLocale(routing.locales, locale)) {
notFound();
}
return (
<html lang={locale}>
<body>
<NextIntlClientProvider>{children}</NextIntlClientProvider>
</body>
</html>
);
}
src/app/[locale]/page.tsx
import { useTranslations } from "next-intl";
import { Link } from "@/i18n/navigation";
export default function HomePage() {
const t = useTranslations("HomePage");
return (
<div>
<h1>{t("title")}</h1>
<Link href="/about">{t("about")}</Link>
</div>
);
}
app/[localidade]/page.tsx
import { getTranslations } from "next-intl/server";
export default async function HomePage() {
const t = await getTranslations("HomePage");
return <h1>{t("title")}</h1>;
}