Introduction
Recently, I explored various internationalization solutions for my web application and settled on next-intl. In this article, I'll share my implementation journey with next-intl, including the setup process and the challenges I encountered along the way.
Target Audience
- Developers considering i18n implementation in Next.js
- Teams working with App Router
- Web developers building multilingual applications
Development Environment
- Next.js: 14.2.x
- next-intl: 3.26.x
- TypeScript: 5.x
Understanding i18n (Internationalization)
i18n stands for "Internationalization" - the term comes from counting the 18 letters between 'i' and 'n'. It refers to the process of designing and implementing web applications to support multiple languages and cultures.
Key components include:
- Language translation: UI text, messages, and error messages
- Regional settings: Date, time, number, and currency format localization
- Character encoding: Unicode (UTF-8) support for multilingual content
- RTL support: Right-to-left language support for Arabic, Hebrew, etc.
Evaluating the Need for i18n
Business Benefits
- Expanded global market reach
- Larger user base
- Regional compliance (e.g., GDPR)
Technical Benefits
- Centralized content management
- Consistent language switching
- Enhanced SEO capabilities
Why I Chose next-intl
- Strong compatibility with Next.js App Router
- Robust TypeScript support
- Seamless SSR integration
- Lightweight implementation
Alternative options:
- react-intl
- i18next
Choosing an i18n Routing Strategy
Before implementing next-intl, you need to select an appropriate routing strategy.
With i18n Routing
- Language codes in URL paths (
/en/about
,/ja/about
) - Domain-based language switching
- SEO-optimized URL structure
- Best for:
- Public websites with multilingual content
- SEO-focused sites requiring language-specific URLs
- Cases requiring explicit language selection
Without i18n Routing
- No language codes in URLs
- Clean URL structure
- System-based language switching
- Best for:
- Single-language applications
- Cases prioritizing simple URL structure
- Automatic language switching based on user settings
Implementation Steps
Reference: Next.js App Router with i18n routing
Project Directory Structure
├── messages/
│ ├── en.json
│ └── ja.json
├── next.config.mjs
└── src/
├── i18n/
│ ├── routing.ts
│ └── request.ts
├── middleware.ts
└── app/
└── [locale]/
├── layout.tsx
└── page.tsx
1. Package Installation
npm install next-intl@latest
2. Message File Creation
// messages/en.json
{
"HomePage": {
"title": "Hello world!",
"about": "Go to the about page"
}
}
3. Next.js Configuration
// next.config.mjs
import createNextIntlPlugin from 'next-intl/plugin';
const withNextIntl = createNextIntlPlugin();
/** @type {import('next').NextConfig} */
const config = {};
export default withNextIntl(config);
4. Routing Configuration
// src/i18n/routing.ts
import { defineRouting } from "next-intl/routing";
import { createNavigation } from "next-intl/navigation";
export const routing = defineRouting({
locales: ["en", "ja"],
defaultLocale: "en",
});
export const { Link, redirect, usePathname, useRouter, getPathname } = createNavigation(routing);
5. Middleware Setup
// src/middleware.ts
import createMiddleware from 'next-intl/middleware';
import {routing} from './i18n/routing';
export default createMiddleware(routing);
export const config = {
matcher: ['/', '/(de|en)/:path*']
};
6. Request Configuration
// src/i18n/request.ts
import { getRequestConfig } from "next-intl/server";
import { routing } from "./routing";
export default getRequestConfig(async ({ requestLocale }) => {
let locale = await requestLocale;
if (!locale || !routing.locales.includes(locale as "en" | "ja")) {
locale = routing.defaultLocale;
}
return {
locale,
messages: (await import(`../../messages/${locale}.json`)).default,
};
});
7. Layout Configuration
// src/app/[locale]/layout.tsx
import {NextIntlClientProvider} from 'next-intl';
import {getMessages} from 'next-intl/server';
import {notFound} from 'next/navigation';
import {routing} from '@/i18n/routing';
export default async function LocaleLayout({
children,
params: {locale}
}: {
children: React.ReactNode;
params: {locale: string};
}) {
if (!routing.locales.includes(locale as any)) {
notFound();
}
const messages = await getMessages();
return (
<html lang={locale}>
<body>
<NextIntlClientProvider messages={messages}>
{children}
</NextIntlClientProvider>
</body>
</html>
);
}
Using useTranslations
Here's how to implement translations in your components:
import {useTranslations} from 'next-intl';
import {Link} from '@/i18n/routing';
export default function HomePage() {
const t = useTranslations('HomePage');
return (
<div>
<h1>{t('title')}</h1>
<Link href="/about">{t('about')}</Link>
</div>
);
}
Common Challenges and Solutions
During my first implementation of i18n using next-intl, I encountered several challenges. Here's what I learned:
1. Version and Routing Method Compatibility
Challenges
- Different implementations for Pages Router vs App Router
- Evolving recommended implementations across versions
- Mixed information in the development community
Solutions
-
Environment Verification
- Check Next.js version
- Verify routing approach
- Confirm next-intl version
-
Implementation Pattern Selection
- App Router: Use
src/i18n/
directory structure - Pages Router: Use single
i18n.ts
file
- App Router: Use
2. Link and Navigation Implementation
Challenges
- Default
next/link
incompatible with i18n routing - Language handling issues with
next/navigation
'suseRouter
Solutions
-
Link Component Migration
- Switch from
next/link
to@/i18n/routing
Link - Use relative paths for href attributes
- Switch from
-
Router Migration
- Replace
next/navigation
with@/i18n/routing
useRouter - Enable automatic locale handling
- Replace
Conclusion
When implementing i18n with next-intl for the first time, these key points proved crucial:
- Selecting the appropriate routing strategy based on project requirements
- Ensuring version compatibility between Next.js and next-intl
- Properly implementing Link components and useRouter for multilingual support
References
I hope this guide helps you with your Next.js internationalization implementation!
Top comments (0)