Complete Guide to Internationalization (i18n) in Next.js 15
Learn how to add multi-language support to your Next.js application using next-intl. Step-by-step tutorial with examples for English, Spanish, and French.
December 8, 2024
4 min read
By FastSaaS Team
Complete Guide to Internationalization (i18n) in Next.js 15
Going global with your SaaS application? This guide covers everything you need to know about implementing internationalization in Next.js using next-intl.
Why Internationalization Matters
- Reach global markets - 75% of internet users prefer content in their native language
- Increase conversions - Localized content can increase conversion rates by 70%
- Improve SEO - Multi-language sites rank better in local search results
Setting Up next-intl
Installation
npm install next-intl
Project Structure
├── messages/
│ ├── en.json
│ ├── es.json
│ └── fr.json
├── middleware.ts
└── app/
└── [locale]/
├── layout.tsx
└── page.tsx
Step 1: Create Translation Files
// messages/en.json
{
"navigation": {
"home": "Home",
"features": "Features",
"pricing": "Pricing",
"blog": "Blog"
},
"home": {
"title": "Build Your SaaS Faster",
"subtitle": "Launch in days, not months",
"cta": "Get Started"
}
}
// messages/es.json
{
"navigation": {
"home": "Inicio",
"features": "CaracterÃsticas",
"pricing": "Precios",
"blog": "Blog"
},
"home": {
"title": "Construye Tu SaaS Más Rápido",
"subtitle": "Lanza en dÃas, no meses",
"cta": "Comenzar"
}
}
Step 2: Configure next-intl
// i18n.config.ts
export const locales = ["en", "es", "fr"] as const;
export type Locale = (typeof locales)[number];
export const defaultLocale: Locale = "en";
// middleware.ts
import createMiddleware from "next-intl/middleware";
import { locales, defaultLocale } from "./i18n.config";
export default createMiddleware({
locales,
defaultLocale,
localePrefix: "as-needed",
});
export const config = {
matcher: ["/((?!api|_next|.*\\..*).*)"],
};
Step 3: Create Layout with Locale
// app/[locale]/layout.tsx
import { NextIntlClientProvider } from "next-intl";
import { getMessages } from "next-intl/server";
export default async function LocaleLayout({
children,
params: { locale },
}: {
children: React.ReactNode;
params: { locale: string };
}) {
const messages = await getMessages();
return (
<html lang={locale}>
<body>
<NextIntlClientProvider messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}
Step 4: Use Translations in Components
Server Components
import { getTranslations } from "next-intl/server";
export default async function HomePage() {
const t = await getTranslations("home");
return (
<div>
<h1>{t("title")}</h1>
<p>{t("subtitle")}</p>
<button>{t("cta")}</button>
</div>
);
}
Client Components
"use client";
import { useTranslations } from "next-intl";
export function Navigation() {
const t = useTranslations("navigation");
return (
<nav>
<a href="/">{t("home")}</a>
<a href="/features">{t("features")}</a>
<a href="/pricing">{t("pricing")}</a>
</nav>
);
}
Step 5: Language Switcher Component
"use client";
import { useLocale } from "next-intl";
import { useRouter, usePathname } from "next/navigation";
export function LanguageSwitcher() {
const locale = useLocale();
const router = useRouter();
const pathname = usePathname();
const changeLanguage = (newLocale: string) => {
const newPath = pathname.replace(`/${locale}`, `/${newLocale}`);
router.push(newPath);
};
return (
<select value={locale} onChange={(e) => changeLanguage(e.target.value)}>
<option value="en">English</option>
<option value="es">Español</option>
<option value="fr">Français</option>
</select>
);
}
Advanced Features
Dynamic Content Translation
const t = useTranslations("products");
// With variables
t("price", { amount: 199 }); // "Price: $199"
// With pluralization
t("items", { count: 5 }); // "5 items"
Date & Number Formatting
import { useFormatter } from "next-intl";
const format = useFormatter();
format.dateTime(new Date(), { dateStyle: "full" });
// English: "Monday, December 9, 2024"
// Spanish: "lunes, 9 de diciembre de 2024"
format.number(1234.56, { style: "currency", currency: "USD" });
// English: "$1,234.56"
// Spanish: "1.234,56 US$"
SEO for Multi-Language Sites
// Generate alternate language links
export function generateMetadata({ params }: { params: { locale: string } }) {
return {
alternates: {
languages: {
en: "/en",
es: "/es",
fr: "/fr",
},
},
};
}
Conclusion
Internationalization opens your SaaS to global markets. FastSaaS comes with next-intl pre-configured with English, Spanish, and French translations ready to use.
Get FastSaaS with built-in i18n support!