Setting Up Internationalization for Server Components in Next.js 13 App Router
September 16, 2023
Tansel Berkant Oflaz
Internationalization for Next.js 13 URL Localization Included
Next.js
Next.js continues to push the boundaries of web development, with its latest introduction of server components in Next.js 13. This article focuses on the intricacies of integrating internationalization (i18n) for server components within the App router. Drawing from a hands-on sample repository, we’ll delve into the implementation steps and highlight the benefits of URL localization exclusive to server components.
Support for React Server Components is currently in beta. Use it at your own discretion and be prepared for possible migrations upon stable release.
1. Setting the Groundwork
Before diving into the actual implementation, ensure you have the necessary tools and packages in place.
npm install next-intl@3.0.0-beta.17
2. Structuring Your Pages
Start by wrapping your entire page structure with a [locale] folder. For instance:
└── app
└── [locale]
├── layout.tsx
└── page.tsx
3. Message Management
Create a messages folder at the root. Inside this folder, you’ll store JSON files for various language options. For instance
messages/en.json
{
"Index": {
"title": "Home Page!"
},
"Navbar": {
"main": "Go Back To Main Page",
...
}
}
4. Configuring i18n
In the root directory, create an i18n.ts file:
import {getRequestConfig} from 'next-intl/server';
export default getRequestConfig(async ({locale}) => ({
messages: (await import(`./messages/${locale}.json`)).default
}));
5. Next.js Configuration
Modify your next.config.js:
const withNextIntl = require('next-intl/plugin')('./i18n.ts');
module.exports = withNextIntl({
images: {
domains: ['images.pexels.com'],
}
});
6. Middleware Creation
Construct a middleware.ts file in the root. It matches a locale for the request and handles necessary redirects and rewrites.
import createMiddleware from 'next-intl/middleware';
import { locales, pathnames } from './navigation';
export default createMiddleware({
defaultLocale: 'en',
locales,
pathnames,
});
export const config = {
// Skip all paths that should not be internationalized. This example skips the
// folders "api", "_next" and all files with an extension (e.g. favicon.ico)
matcher: ['/((?!api|_next|.*\\..*).*)'],
};
7. Handling Layouts
import '../../../styles/globals.css';
import { Inter } from 'next/font/google';
import Navigation from '@/components/Navigation';
import { useLocale } from 'next-intl';
import { notFound } from 'next/navigation';
const inter = Inter({ subsets: ['latin'] });
export default function RootLayout({
children,
params,
}: {
children: React.ReactNode;
params: any;
}) {
const locale = useLocale();
if (params.locale !== locale) {
notFound();
}
return (
<html lang={locale}>
<body className={inter.className}>
<Navigation />
{children}
</body>
</html>
);
}
8. URL Localization
A unique feature with server components is URL localization. Set this up by creating a navigation.ts in the root.
import {
createLocalizedPathnamesNavigation,
Pathnames,
} from 'next-intl/navigation';
export const locales = ['en', 'tr'] as const;
export const pathnames = {
'/': '/',
'/hakkimizda': {
en: '/about',
tr: '/hakkimizda',
},
'/egitimler': {
en: '/courses',
tr: '/egitimler',
},
'/blogs': {
en: '/',
tr: '/blogs',
},
'/iletisim': {
en: '/contact',
tr: '/iletisim',
},
} satisfies Pathnames<typeof locales>;
export const { Link, redirect, usePathname, useRouter } =
createLocalizedPathnamesNavigation({ locales, pathnames });
It gives you the flexibility to route URLs based on your desired structure.
9. Language Switcher Component
A vital part of any i18n setup is allowing users to switch between languages effortlessly:
'use client';
import { usePathname } from '@/navigation';
import { useLocale } from 'next-intl';
import { useRouter } from 'next/navigation';
const Switcher = () => {
const router = useRouter();
const pathName = usePathname();
const locale = useLocale();
const handleLanguageChange = (event: any) => {
const locale = event.target.value;
const cleanedPathName = pathName.startsWith('/')
? pathName
: '/' + pathName;
if (locale === 'en') {
router.push(`/en${cleanedPathName}`);
} else {
router.push(`/tr${cleanedPathName}`);
}
};
return (
<select onChange={handleLanguageChange} defaultValue={locale}>
<option value="tr">Turkish</option>
<option value="en">English</option>
</select>
);
};
export default Switcher;
This component switches languages while keeping the user on the current page, translated to the chosen language.
Conclusion
The Next.js 13 server components, combined with the power of internationalization, pave the way for more inclusive web applications. The steps outlined above guide you to create a system optimized for multiple languages, providing a seamless experience for international audiences.
For a more in-depth exploration and understanding, be sure to check out the sample repository here and the detailed documentation here.
Liked the project? Consider giving it a star on GitHub. Thank you for your support!