The Problem:
How can I implement internalization (i18n) in a Next.js 13 application using App Route (not Pages Route) without creating sub-routes or domains? I want to fetch the user’s preferred language from the database and apply it to the entire application dynamically.
The Solutions:
Solution 1: I18n using Server Components, Client Components and middleware
Implement i18n by leveraging server components, client components, and a custom middleware:
-
Install Necessary Packages:
npm install @formatjs/intl-localematcher negotiator next-int && npm install -D @types/negotiator server-only
-
Define i18n Configuration:
- Create
i18n.config.ts
to manage i18n configuration. - Define the default locale and available locales.
- Create
-
Create a Dictionary for Server Components:
- In
dictionary.ts
, define a function to fetch JSON translations for each locale.
- In
-
Detect Locale:
- Implement a
getLocale
function to detect the user’s preferred locale from request headers.
- Implement a
-
Create Middleware:
- Define a middleware in
middleware.ts
to handle locale detection and internationalization. - Utilize the
next-intl/middleware
package for internationalization.
- Define a middleware in
-
Define Types for Server Component IntelliSense:
- Add type definitions for server component IntelliSense in
global.d.ts
.
- Add type definitions for server component IntelliSense in
-
Create a Provider for Client Components:
- In
providers.tsx
, define a client component provider (Providers
) that wraps the app with internationalization context.
- In
-
Move Routes to [lang] Folders:
- Move each route from the app directory to a corresponding
[lang]
folder.
- Move each route from the app directory to a corresponding
-
Root Layout with Locale Handling:
- Create a layout component (
layout.tsx
) that wraps app content and handles locale-specific JSON translations.
- Create a layout component (
-
Client Component Usage:
- Use
useTranslations
fromnext-intl
to access translations in client components.
- Use
-
Server Component Usage:
- Utilize
getDictionary
to fetch translations for server components.
- Utilize
Solution 2: Using Next.js Headers
You can leverage the next/headers
module to read the browser header related to the language and use it as a value without changing the route or using sub-routes.
-
Import the
headers
module:import { headers } from 'next/headers';
-
Use the
headers
module to get theaccept-language
header:const headersList = headers(); const lang = headersList.get('accept-language');
-
Use the
lang
value to set the language for your application:const locale = lang.split('-')[0]; // Get the first part of the language code (e.g., 'en') i18n.changeLanguage(locale); // Set the language in your i18n library
-
Display the localized content based on the selected language:
const { t } = useTranslation(); return ( <div> {t('lang')} </div> );
This approach allows you to set the language based on the browser’s accept-language
header without modifying the URL or using sub-routes.
Q&A
Can I use internalization without changing the route or using sub-routes?
Yes, you can use next/headers
to read browser header related to language without changing the route or using sub-routes.
Do I need to use sub-routes like /en
or domain like mywebsite.lang
to use internalization?
No, you don’t have to use sub-routes or change the domain.
Video Explanation:
The following video, titled "Internationalization (i18n) with Next.js! - YouTube", provides additional insights and in-depth exploration related to the topics discussed in this post.
Learn how to use Internationalized Routing with Next.js to support multiple languages on your site! 0:00 – Introduction 0:46 – Routing + ...
The following video, titled "Internationalization (i18n) with Next.js! - YouTube", provides additional insights and in-depth exploration related to the topics discussed in this post.
Learn how to use Internationalized Routing with Next.js to support multiple languages on your site! 0:00 – Introduction 0:46 – Routing + ...