Internationalization (i18n) in Next.js

Use Next.js’s built-in internationalization (i18n) features to effortlessly manage translations for your website or app. Seamlessly detect user locale and switch languages on the fly, ensuring a smooth user experience for a worldwide audience.

Table of Contents

Internationalization (i18n) in Next.js

Next.js offers built-in support for internationalization (i18n), allowing you to create multilingual applications that adapt content and functionality to different languages and locales. This is crucial for reaching a broader audience and delivering a user experience tailored to their specific language preferences.

Key Concepts:

  • Locale Detection: Next.js can automatically detect the user’s preferred language based on browser settings or URL parameters.
  • Translations: You can define translations for your application’s content in different languages using JSON or other translation file formats.
  • Dynamic Routing: Next.js supports dynamic routing with locale prefixes (e.g., /en/about, /fr/contact) to manage different language versions of your application.

Key Points

  • Next.js has built-in i18n support with routing.
  • Consider a library like next-i18next for smooth integration.
  • Choose a namespace structure to organize translations.

Additional Considerations

  • Locale Detection: Next.js can auto-detect user locales.
  • Language Switcher: Create a UI component for selection.
  • Complex Translations: Libraries like i18next offer features for formatting, plurals, and more.

Locale Detection

Next.js offers built-in features for i18n, including automatic locale detection. This functionality simplifies displaying content in the user’s preferred language, enhancing the overall user experience for a global audience.

import { useRouter } from 'next/router';

function MyComponent() {
    const router = useRouter();
    const locale = router.locale; // Access the detected locale

    // Logic to handle user based on locale (e.g., redirect)
    if (locale === 'en-US') {
        // User's browser is set to US English
    } else if (locale === 'es-ES') {
        // User's browser is set to Spanish (Spain)
        router.push(`/es`); // Redirect to Spanish version (replace `/es` with your actual path)
    } else {
        // Default behavior for other locales

    // Rest of your component logic
    return (
            {/* Your page content */}

export default MyComponent;


  • Line 1: Imports the useRouter hook from next/router for accessing routing information.
  • Line 3: Defines a functional component named MyComponent.
  • Line 4: Uses the useRouter hook to get the router object.
  • Line 5: Extracts the user’s detected locale from the router.locale property.
  • Lines 7-15: Implement logic based on the detected locale:
    • Check for specific language codes (e.g., ‘en-US‘ for US English, ‘es-ES‘ for Spanish (Spain)).
    • You can redirect users to different language versions of your site using router.push().
    • Implement a default behavior for unsupported locales.
  • Line 17: This section represents the rest of your component where you might display content or handle other functionalities.

Remember: This is a basic example. Real-world i18n often involves translation libraries and more comprehensive logic for handling multiple languages.

Handling Translations

Internationalization (i18n) in Next.js involves managing translations for your website’s content across different languages. Next.js offers flexibility in handling translations, allowing you to store them in JSON files or leverage external translation providers.

Install i18n libraries

npm install next-i18next react-i18next

JSON Translation Files

  1. Create separate JSON files for each language (e.g., en.jsones.json).
  2. Inside each JSON file, define key-value pairs where the key represents the translation ID and the value is the actual translation string in that language.

Project Structure

├── pages/
│   ├── index.js 
│   ├── about.js 
│   └── ...
├── locales/   // Folder for translation files
│   ├── en.json
│   └── es.json
├── ...

locales/en.json (English Translations)

  "title": "Welcome to Our Website",
  "description": "Explore our products and services."

locales/es.json (Spanish Translations)

  "title": "Bienvenido a Nuestro Sitio Web",
  "description": "Explora nuestros productos y servicios."


import { useRouter } from 'next/router';
import { useTranslation } from 'next-i18next';
import { serverSideTranslations } from 'next-i18next/serverSideTranslations';

function HomePage() {
    const router = useRouter();
    const { t } = useTranslation('common'); // Use your preferred namespace

    return (

export async function getStaticProps({ locale }) {
    return {
        props: {
            ...(await serverSideTranslations(locale, ['common'])), // Load translations

export default HomePage;

Page Component (index.js)

  1. Import useTranslation for translation access.
  2. getStaticProps is used for pre-rendering translated content.
  3. The t function is used to render translated text.

Import Statements

  • Line 1: Imports the useRouter hook for accessing routing information and navigation control within the component.
  • Line 2: Imports the useTranslation hook for accessing translations in your application.
  • Line 3: Imports serverSideTranslations to load translations for server-side rendering.

HomePage Component

  • Line 5: Defines a functional component named HomePage.
  • Line 6: Uses the useRouter hook to get access to the router object.
  • Line 7: Uses the useTranslation hook (from next-i18next) to access the t translation function with the “common” namespace.
  • Lines 9-14: Render the home page content:
    • Line 11: Displays a heading (<h1>) using the translated “title” from the ‘common’ namespace.
    • Line 12: Displays a paragraph <p> using the translated “description” from the ‘common’ namespace.

getStaticProps Function

  • Line 17: The getStaticProps function is used for pre-rendering the page with translated content.
  • Line 17: Receives the locale as part of the context object.
  • Lines 17-23:
    • Line 20: Loads translations for the specified locale and "common" namespace using serverSideTranslations.
    • Line 19: Returns the loaded translations as props for the HomePage component.

Line 25: Exports the HomePage component as the default export.

Dynamic Routing with Locale Prefixes

Next.js supports dynamic routing, allowing you to create flexible URL structures that match different content. When combined with internationalization (i18n), you can create dynamic routes prefixed with a locale code to represent content in various languages. This approach provides a clean URL structure and simplifies content management for multilingual websites.


// pages/en/blog/[slug].js

function BlogPostPage({ slug }) {
    // Fetch blog post data based on the 'slug' and user's locale ('en' in this case)
    // ...

    return (
            <h1>Blog Post: {slug}</h1>
            {/* Display blog post content */}

export async function getStaticPaths() {
    // Fetch available blog post slugs
    // ...

    // Return the paths
    return {
        paths: [
            { params: { slug: 'sample-slug' } }, // Sample slug, replace with actual slugs
        fallback: false,

export async function getStaticProps({ locale, params }) {
    const { slug } = params;

    // Fetch blog post data for the 'slug' in the 'en' locale
    // ...

    return {
        props: {

export default BlogPostPage;


File Structure

  • pages/en/blog/[slug].js: This file indicates a dynamic route for English blog posts (en). The [slug] part indicates that the URL will contain a different “slug” (e.g., /en/blog/my-article).

BlogPostPage Component

  • Line 3: Defines a functional component named BlogPostPage. It receives the slug as a prop.
  • Line 4-5: Inside the component, you’d implement logic to fetch the blog post data using the provided slug and the user’s locale (en).
  • Lines 7-10: Renders the blog post title using the slug and a placeholder for displaying the content.


  • Line 15: Defines the getStaticPaths function, responsible for pre-rendering pages at build time. This is essential for dynamic routes.
  • Line 16-17: This section represents where you’d fetch a list of valid blog post slugs (e.g., from a database).
  • Lines 20-24: Returns an object with two properties:
    • paths: Contains an array of objects, each defining a params object with the slug to pre-render. Replace the sample slug with those fetched in the previous step.
    • fallback: Set to false, meaning other blog post slugs not returned in the paths array will lead to a 404 page.


  • Line 28: Defines the getStaticProps function, executed during the build process to prepare data for a pre-rendered page.
  • Line 29: Destructures the slug from the params object within the context.
  • Lines 31-32: Implements the logic to fetch the specific blog post content for the given slug and en locale.
  • Lines 34-36: Returns an object with a props property, containing the slug passed to the BlogPostPage component.

This example demonstrates a dynamic route prefixed with the locale (en/blog/[slug].js). You can create similar routes for other languages (e.g., fr/blog/[slug].js) to represent content in those locales. The getStaticProps function ensures that content is pre-rendered for each combination of locale and slug, improving performance.

Language Switcher in Next.js

For multilingual websites built with Next.js, a language switcher empowers users to easily switch between available languages. This enhances user experience by allowing them to navigate and consume content in their preferred language.

Example of a Language Switcher Component

import { useRouter } from 'next/router';

function LanguageSwitcher() {
    const router = useRouter();
    const { locale } = router;

    const handleLocaleChange = (newLocale) => {
        router.push(`/`, { locale: newLocale });

    return (
            <button onClick={() => handleLocaleChange('en')}>English</button>
            <button onClick={() => handleLocaleChange('es')}>Spanish</button>

export default LanguageSwitcher;


  • Line 1: Imports the useRouter hook from next/router for routing operations.
  • Line 3: Defines a functional component named LanguageSwitcher.
  • Line 4: Uses useRouter to access the router object and then destructures the locale property.
  • Line 7: Defines a function handleLocaleChange that takes a new locale code as input.
  • Line 8: Uses router.push to redirect the user to the root path (/) while setting the desired locale using the locale property in the query object.
  • Lines 11-15: Renders a label and two buttons representing the available languages (English and Spanish). Clicking a button triggers the handleLocaleChange function with the corresponding locale code.

This is a basic example. In a real-world scenario, you’d likely fetch available locales from your data source and dynamically populate the language options. Additionally, you can highlight the currently selected language for a better user experience.