Next.js localization: A step-by-step guide with examples

In this tutorial, you’ll learn how to implement Next.js i18n application using the next-globe-gen plugin. We’ll cover everything from managing translation files and handling pluralization to creating a language switcher, all with practical multi-language examples.

Localization is a key step in the Next.js internationalization (i18n) process. While internationalization prepares an application to support multiple languages and cultures, localization focuses on adapting it to a specific language through translations. Let’s get started!

The source code for this article can be found on GitHub.

    Prerequisites and assumptions for Next.js i18n

    Before jumping into website translation, let’s cover some necessary prerequisites:

    • We will be using Next.js version 15.x in this tutorial.
    • You have basic knowledge of JavaScript and React.
    • Node.js and npm are installed on your system.
    • Your development domain is set to localhost. If not, replace localhost with your domain name or IP address.

    To get started, let’s create a new Next.js application by running:

    npx create-next-app@latest next-lokalise-i18n-demo

    This will scaffold a new Next.js project ready for localization.

    During the setup process, you’ll be prompted with several configuration options. Here’s a breakdown of the choices we’ll make for this tutorial:

    • TypeScript: Enable TypeScript for better type safety and modern JavaScript practices.
    • ESLint: Enable ESLint to maintain code quality and catch potential issues early.
    • Tailwind CSS: Enable Tailwind CSS for a utility-first styling approach that integrates well with Next.js.
    • src/ Directory: Choose “yes” to use the src directory structure.
    • App Router: Enable the App Router, as it’s the recommended way to manage routes in Next.js 13+.
    • Turbopack: Enable Turbopack for faster builds during development.
    • Import Alias (@/*): Select “No” to stick with the default import structure, as it’s clean and sufficient for this project.

    Introducing NextGlobeGen: Simplifying Next.js i18n

    NextGlobeGen is a TypeScript package that makes it easy to add internationalization (i18n) to your Next.js app, especially if you’re using the Next.js App Router. This solution is younger than i18next or next-intl but it’s a solid and easy to use package. It automates the setup of language-specific routes, saving time and effort while providing a smooth developer experience.

    Whether you’re creating a blog, an e-commerce site, or a large-scale application, NextGlobeGen is the perfect tool to make your app accessible to users worldwide.

    Key features

    • Automatic language routes: Generates routes for each supported language automatically.
    • Locale detection: Built-in middleware handles detecting and redirecting users to the correct language.
    • Smart translations: Supports dynamic ICU-style placeholders in your translations.
    • Developer-friendly: Works seamlessly in both server and client components, with built-in TypeScript support.

    How does it work?

    NextGlobeGen uses smart automation to handle localization for you:

    1. Analyzes routes: It examines your app’s routing structure.
    2. Generates language routes: Automatically creates routes for each supported locale.
    3. TypeScript integration: Generates types to make working with localization safe and easy.
    4. Locale-aware API: Provides tools that always know which language is active.

    Installing NextGlobeGen for Next.js localization

    Now that you’ve set up your Next.js application, it’s time to install NextGlobeGen. Just run the following command:

    npm install next-globe-gen@latest

    Keep in mind, this library is compatible with Next.js 14 and newer.

    Preparing for Next.js i18n

    Configuring NextGlobeGen

    As the next step, create an i18n.config.ts file in the root of your project. This file will define the global configuration for i18n. At a minimum, you’ll need to specify the supported locales and the default locale:

    import type { Config } from "next-globe-gen";
    
    const config: Config = {
      locales: ["en", "fr"],
      defaultLocale: "en",
    };
    
    export default config;

    In this tutorial, we’re adding support for English (en, default, can also be set to something like en-US) and French.

    Next, open the next.config.ts file in the project root and integrate the i18n configuration by enabling the plugin:

    import type { NextConfig } from "next";
    import createNextGlobeGenPlugin from "next-globe-gen/plugin";
    
    const withNextGlobeGen = createNextGlobeGenPlugin();
    
    const nextConfig: NextConfig = {
      // Your other Next.js settings
    };
    
    export default withNextGlobeGen(nextConfig);

    That’s it! The plugin is now enabled for your application.

    Creating translation files

    By default, NextGlobeGen looks for translation files in the src/messages directory. These files should be named after their language codes, like en.json and fr.json. If you want to use multiple namespaces, you can follow this pattern: src/messages/<locale>/<namespace>.json.

    For now, let’s keep it simple—create en.json and fr.json inside the src/messages folder.

    If you’re not using the src folder or prefer to store translations elsewhere, you can reconfigure NextGlobeGen. Check the official documentation for details on how to do that.

    Setting up your project structure

    NextGlobeGen requires your tsx files to be stored in a special directory: src/_app (note the leading underscore!). Here’s what you need to do:

    1. Create the src/_app folder: Don’t remove the existing app directory; just add this new folder.
    2. Move files: Move your layout.tsx and page.tsx files into the newly created _app folder.
    3. Organize styles: Create a src/styles folder and move your globals.css file into it.

    Now, open the layout.tsx file and replace its content with the following:

    import { Metadata } from "next";
    import { Link, useLocale, useTranslations } from "next-globe-gen";
    import { ReactNode } from "react";
    import "@/styles/globals.css";
    
    export const metadata: Metadata = {
      title: { template: "%s | Lokalise", default: "Lokalise" },
    };
    
    export default function RootLayout({ children }: { children: ReactNode }) {
      const locale = useLocale();
    
      return (
        <html lang={locale}>
          <body>
            <header className="flex flex-col items-center p-4 bg-gray-100 dark:bg-gray-800">
              <nav className="mt-4">
                <ul className="flex space-x-4">
                </ul>
              </nav>
            </header>
            <main className="min-h-screen">{children}</main>
          </body>
        </html>
      );
    }

    What this does:

    • Basic layout: Sets up a clean structure with a header, navigation, and main content area.
    • Metadata: Defines the page title and template format.
    • Locale support: Fetches the current locale and applies it to the <html> tag via the lang attribute.
    • Header component: We’ll provide language switcher and other links here.

    Adding middleware

    To enable locale negotiation and add alternate links to your pages, you’ll need to set up middleware. Create a src/middleware.ts file and add the following code:

    export { middleware } from "next-globe-gen/middleware";
    
    export const config = {
      // Matcher ignoring next internals and static assets
      matcher: ["/((?!_next|.*\\.).*)"],
    };
    • Locale negotiation: The middleware determines the best language for the user based on their preferences.
    • Alternate links: Adds alternate language links to the response headers for improved SEO.

    Adjusting Tailwind configuration

    Since our tsx files are now located in the _app folder, we need to update the Tailwind configuration. Open your tailwind.config.ts file and make the following adjustments:

    import type { Config } from "tailwindcss";
    
    export default {
      content: ["./src/**/*.{js,ts,jsx,tsx,mdx}"], // Include all files in src
      theme: {
        extend: {
          colors: {
            background: "var(--background)",
            foreground: "var(--foreground)",
          },
        },
      },
      plugins: [],
    } satisfies Config;

    The content parameter was updated to ensure Tailwind scans all files under the src directory, including the _app folder.

    That’s all! Tailwind is now configured to pick up styles from your updated project structure.

    Performing simple translations with Next.js localization

    Loading translations

    Let’s add translations to our page. Open the src/_app/page.tsx file and add the following code:

    import type { Metadata } from "next";
    import { getTranslations, useTranslations } from "next-globe-gen";
    
    export function generateMetadata(): Metadata {
      const t = getTranslations();
      return {
        title: t("title"),
        description: t("description", { company: "Lokalise" }),
      };
    }
    
    export default function Home() {
      const t = useTranslations();
      return (
        <main className="flex justify-center items-center min-h-screen bg-gray-50 dark:bg-gray-900">
          <section
            aria-labelledby="main-title"
            className="text-center p-8 max-w-2xl"
          >
            <h1
              id="main-title"
              className="text-4xl font-bold text-gray-900 dark:text-gray-100"
            >
              {t("title")}
            </h1>
            <p className="mt-4 text-lg text-gray-700 dark:text-gray-300">
              {t("description", { company: "Lokalise" })}
            </p>
          </section>
        </main>
      );
    }

    Here, we’re translating both the metadata and the page content.

    • getTranslations() loads translation values from the src/messages folder.
    • t("title") fetches the value for the title key.
    • t("description", { company: "Lokalise" }) uses interpolation, where {company} is replaced with "Lokalise".

    Providing translations

    Now, let’s add the actual translations. Open the src/messages/en.json file and add this:

    {
      "title": "Homepage",
      "description": "Tutorial presented by {company}"
    }

    Next, open the src/messages/fr.json file for French translations:

    {
      "title": "Page d'accueil",
      "description": "Tutoriel présenté par {company}"
    }

    Note how we use the {company} placeholder in both files—it’s dynamically replaced during translation.

    Testing it out

    Start your development server:

    npm run dev

    Note that the i18n package will automatically create a bunch of files inside the app folder.

    Now visit localhost:3000 to see the English version. Navigate to localhost:3000/fr (sub-path routing) to check the French translated content. Everything should work smoothly. Nice!

    Adding a language switcher for Next.js localization

    Creating a language switcher component

    So far, we’ve set up translations and are displaying localized content. Now, let’s add a component to allow users to easily switch between locales in our app.

    Create a new file at src/components/LanguageSwitcher.tsx and add the following code:

    "use client";
    
    import {
      Link,
      useLocale,
      useRoute,
      useSchema,
      type RouteParams,
    } from "next-globe-gen";
    import { useParams } from "next/navigation";
    
    export default function LanguageSwitcher() {
      const activeLocale = useLocale();
      const schema = useSchema();
      const route = useRoute();
      const params = useParams<RouteParams<typeof route>>();
    
      return (
        <div className="flex gap-x-4">
          {schema.locales.map((locale) => (
            <Link
              key={locale}
              href={route}
              locale={locale}
              params={params}
              className={`px-3 py-2 rounded-md ${
                locale === activeLocale
                  ? "bg-gray-300 text-gray-500 cursor-not-allowed"
                  : "bg-blue-500 text-white hover:bg-blue-600"
              }`}
              aria-disabled={locale === activeLocale}
            >
              {locale === "en" && "English"}
              {locale === "fr" && "French"}
            </Link>
          ))}
        </div>
      );
    }
    1. Core functionality:
      • The LanguageSwitcher component dynamically generates a list of links for all configured locales (schema.locales).
      • Each link retains the current route and parameters but switches to the selected locale when clicked.
    2. Styling:
      • Tailwind classes are used to style the links:
        • Active Locale: Styled with bg-gray-300, text-gray-500, and cursor-not-allowed to indicate it’s not clickable.
        • Other Locales: Styled with bg-blue-500 and hover effects for a distinct appearance.
    3. Accessibility:
      • The aria-disabled attribute is added to mark the current locale as inactive for screen readers.
    4. Dynamic rendering:
      • The useLocale, useSchema, useRoute, and useParams hooks from next-globe-gen dynamically fetch locale-related information, making the component flexible and responsive to route changes.

    Using language switcher

    Now that we’ve created the LanguageSwitcher component, let’s add it to the layout. Open src/_app/layout.tsx and update the file as follows:

    // imports ...
    import LanguageSwitcher from "@/components/LanguageSwitcher"; // <=== New import
    
    // metadata ...
    
    export default function RootLayout({ children }: { children: ReactNode }) {
      const locale = useLocale();
    
      return (
        <html lang={locale}>
          <body>
            <header className="flex flex-col items-center p-4 bg-gray-100 dark:bg-gray-800">
              <LanguageSwitcher />
              <nav className="mt-4">
                <ul className="flex space-x-4">
                </ul>
              </nav>
            </header>
            <main className="min-h-screen">{children}</main>
          </body>
        </html>
      );
    }
    
    1. Import statement:
      • Imported LanguageSwitcher from the components folder.
    2. Added component:
      • Inserted the <LanguageSwitcher /> component inside the header to display the list of locales at the top of every page.

    Translating additional pages

    Now that we have the basics of localization in place, let’s add another page to our application. We’ll create a /dashboard route, organize its translations using a namespace, and even translate its URL to use /tableau for French users.

    Creating the dashboard page

    To start, create a new dashboard directory inside the _app folder. Inside that directory, add a page.tsx file:

    import type { Metadata } from "next";
    import { getTranslations, useTranslations } from "next-globe-gen";
    
    export function generateMetadata(): Metadata {
      const t = getTranslations("dashboard");
      return { title: t("title") };
    }
    
    export default function Dashboard() {
      const t = useTranslations("dashboard");
      return (
        <section>
          <h1>{t("title")}</h1>
        </section>
      );
    }

    Inside the Dashboard component, useTranslations("dashboard") provides access to the translations for this namespace. The t function fetches the localized value for the title key.

    Translating the route slug

    Let’s make the /dashboard route more user-friendly for French speakers by translating it to /tableau. To do this, create a file at dashboard/i18n.ts with the following content:

    const segmentTranslations = {
      fr: "tableau",
    };
    
    export default segmentTranslations;

    With this in place, the English version of the app will continue using /dashboard, while the French request will automatically use /tableau. You can even translate the slug for other languages by extending the segmentTranslations object.

    Adding namespaced translations

    Since we’re using the dashboard namespace, let’s update our translation files.

    In src/messages/en.json, add:

    {
      "dashboard": {
        "title": "Dashboard"
      }
    }

    In src/messages/fr.json, add:

    {
      "dashboard": {
        "title": "Tableau de bord"
      }
    }

    The title key will be used on the dashboard page, and thanks to the namespace, it’s neatly scoped under dashboard.

    Providing links in the layout

    Now, we need to update the navigation in the layout to include links to the homepage and the dashboard. Open the layout.tsx file and modify it like this:

    // ... other code ...
    
    export default function RootLayout({ children }: { children: ReactNode }) {
      const locale = useLocale();
      const t = useTranslations(); // <=== add this
      
      return (
        <html lang={locale}>
          <body>
            <header className="flex flex-col items-center p-4 bg-gray-100 dark:bg-gray-800">
              <LanguageSwitcher />
              <nav className="mt-4">
                <ul className="flex space-x-4">
                <li>
                    <Link
                      href="/"
                      className="text-blue-500 hover:underline"
                      aria-current="page"
                    >
                      {t("title")}
                    </Link>
                  </li>
                  <li>
                    <Link
                      href="/dashboard"
                      className="text-blue-500 hover:underline"
                    >
                      {t("dashboard.title")}
                    </Link>
                  </li>
                </ul>
              </nav>
            </header>
            <main className="min-h-screen">{children}</main>
          </body>
        </html>
      );
    }
    

    This adds a link to the dashboard route alongside the existing homepage link. The t("dashboard.title") fetches the localized title, so it will display “Dashboard” in English and “Tableau de bord” in French.

    Pluralization in Next.js

    One of the key features of localization is displaying messages that change depending on a value, such as showing a different message when a user has no projects, one project, or multiple projects. Let’s see how to handle this with pluralization in Next.js using next-globe-gen.

    Updating the dashboard page

    To start, let’s modify the page.tsx file for the dashboard. Open it up and update the content like this:

    // ...
    
    export default function Dashboard() {
      const t = useTranslations("dashboard");
    
      return (
        <section>
          <h1>{t("title")}</h1>
          <p>
            {t("projects", {
              count: 1, // The count determines the plural form used
              b: (children) => <b>{children}</b>, // Custom formatting for <b> tags
            })}
          </p>
        </section>
      );
    }

    Here’s what’s happening in the code:

    • useTranslations("dashboard"): This hook provides the translations scoped to the dashboard namespace.
    • Pluralization with t():
      • The count parameter determines which plural form to use. For example, count: 1 will pick the singular form, and count: 0 or count: 5 will pick the appropriate plural form.
      • You can also pass a b function to handle custom formatting. This allows us to wrap parts of the translated text with <b> tags, making “one project” or “# projects” bold.

    Adding translations

    Next, we need to define the pluralization logic in our translation files. Let’s start with English. Open src/messages/en.json and add the following:

    {
      "dashboard": {
        "title": "Dashboard",
        "projects": "You have {count, plural, =0 {no projects} =1 {<b>one</b> project} other {<b>#</b> projects}}."
      }
    }

    For French, update src/messages/fr.json:

    {
      "dashboard": {
        "title": "Tableau de bord",
        "projects": "Vous avez {count, plural, =0 {aucun projet} =1 {<b>un</b> projet} other {<b>#</b> projets}}."
      }
    }

    Here’s how the translations work:

    • {count, plural, ...}:
      • =0: Used when count is 0.
      • =1: Used when count is 1.
      • other: Used for any other value of count.
    • <b> formatting:
      • Wrapping text with <b> makes parts of the message bold. This is achieved using the b function passed to t().

    Date and time: Next.js localization

    Displaying dates and times in a user’s preferred format is a critical part of localization. Users expect date and time values to match their cultural norms, whether that’s the format of the date, the way time is displayed, or even the language used. Let’s enhance the main page of our Next.js app by adding a localized display of the current date and time.

    Updating the main page

    Open src/_app/page.tsx and update the file to include the localized date-time display:

    import type { Metadata } from "next";
    import { getTranslations, useTranslations, useLocale } from "next-globe-gen"; // <=== update this
    
    // metadata ...
    
    export default function Home() {
      const t = useTranslations();
      const locale = useLocale();
    
      // Work with datetime:
      const now = new Date();
      const formattedDate = new Intl.DateTimeFormat(locale, {
        dateStyle: "medium", // Medium-length date format
        timeStyle: "short", // Short time format
      }).format(now);
    
      return (
        <main className="flex justify-center items-center min-h-screen bg-gray-50 dark:bg-gray-900">
          <section
            aria-labelledby="main-title"
            className="text-center p-8 max-w-2xl"
          >
            <h1
              id="main-title"
              className="text-4xl font-bold text-gray-900 dark:text-gray-100"
            >
              {t("title")}
            </h1>
            <p className="mt-4 text-lg text-gray-700 dark:text-gray-300">
              {t("description", { company: "Lokalise" })}
            </p>
            <p className="mt-2 text-gray-600 dark:text-gray-400">
              {t("currentTime", { time: formattedDate })}
            </p>
          </section>
        </main>
      );
    }
    1. Locale retrieval:
      • The useLocale() hook fetches the user’s active locale, ensuring the displayed date and time match their preferences.
    2. Formatting the date and time:
      • Intl.DateTimeFormat is a built-in JavaScript API that formats dates and times based on a specified locale.
      • The dateStyle and timeStyle options control the level of detail:
        • "medium" produces a moderately detailed date (e.g., “Jan 16, 2025”).
        • "short" creates a simple time format (e.g., “3:45 PM” or “15:45”).
      • format(now) applies this configuration to the current date and time.
    3. Dynamic translation:
      • The {time: formattedDate} placeholder is dynamically replaced in the translation strings, making it easy to adapt to any language.

    Why use Intl.DateTimeFormat?

    JavaScript has built-in support for localization using Intl.DateTimeFormat API. This feature is highly efficient for simple localization tasks:

    • Locale-aware: It automatically adjusts date and time formats based on the user’s locale.
    • Customizable: Provides options to control the granularity of formatting.
    • Lightweight: No additional libraries or dependencies are needed.

    For more advanced use cases, such as time zone handling or relative dates (e.g., “5 minutes ago”), you might consider a library like Luxon or Day.js. However, for most scenarios, Intl.DateTimeFormat is more than sufficient.

    Adding translations

    To support localized date and time strings, update your translation files with a new key for the current time.

    English (en.json):

    {
      "currentTime": "Current date and time: {time}"
    }

    French (fr.json):

    {
      "currentTime": "Date et heure actuelles : {time}"
    }

    Translating MDX pages in Next.js

    MDX files are a powerful way to combine Markdown with React components, and localizing them ensures your content is accessible to users in different languages. Let’s walk through the process of setting up and translating MDX pages in a Next.js app.

    Configuring MDX

    First, install the necessary packages to work with MDX in your Next.js project:

    npm install @next/mdx @mdx-js/loader @mdx-js/react @types/mdx

    Next, update your next.config.ts file to enable MDX and integrate it with next-globe-gen:

    import createMDX from "@next/mdx";
    import type { NextConfig } from "next";
    import createNextGlobeGenPlugin from "next-globe-gen/plugin";
    
    const withMDX = createMDX();
    const withNextGlobeGen = createNextGlobeGenPlugin();
    
    const nextConfig: NextConfig = {
      pageExtensions: ["js", "jsx", "md", "mdx", "ts", "tsx"],
    };
    
    export default withNextGlobeGen(withMDX(nextConfig));

    This configuration ensures MDX files are recognized as valid page extensions and seamlessly work with localization provided by next-globe-gen.

    Setting up MDX components

    If you plan to use React components within your MDX files, you’ll need to define custom components. Create a new file called src/mdx-components.tsx:

    import type { MDXComponents } from "mdx/types";
    
    export function useMDXComponents(components: MDXComponents): MDXComponents {
      return {
        ...components,
      };
    }

    This setup allows you to extend or customize MDX components globally as needed.

    Creating localized MDX files

    Now, let’s create localized MDX content. Inside the src/_app/markdown folder, create two files: page.en.mdx and page.fr.mdx.

    page.en.mdx:

    export const metadata = { title: "Markdown page" };
    
    # Markdown page
    
    This content is shown on `/en/markdown` path.

    page.fr.mdx:

    export const metadata = { title: "Page Markdown" };
    
    # Page Markdown
    
    Ce contenu est affiché sur le chemin `/fr/markdown`.

    Each file corresponds to a specific locale, and Next.js will automatically serve the correct file based on the active language.

    Adding a link to the layout

    To make the Markdown page accessible, add a new a new URL to your site’s navigation. Update the RootLayout component as follows:

    export default function RootLayout({ children }: { children: ReactNode }) {
      const locale = useLocale();
      const t = useTranslations();
      
      return (
        <html lang={locale}>
          <body>
            <header className="flex flex-col items-center p-4 bg-gray-100 dark:bg-gray-800">
              <LanguageSwitcher />
              <nav className="mt-4">
                <ul className="flex space-x-4">
                <li>
                    <Link
                      href="/"
                      className="text-blue-500 hover:underline"
                      aria-current="page"
                    >
                      {t("title")}
                    </Link>
                  </li>
                  <li>
                    <Link
                      href="/dashboard"
                      className="text-blue-500 hover:underline"
                    >
                      {t("dashboard.title")}
                    </Link>
                  </li>
                  <li>
                    <Link
                      href="/markdown"
                      className="text-blue-500 hover:underline"
                    >
                      {t("markdown.title")}
                    </Link>
                  </li>
                </ul>
              </nav>
            </header>
            <main className="min-h-screen">{children}</main>
          </body>
        </html>
      );
    }

    This adds a navigation link to the Markdown page.

    Adding translations

    Finally, update the translation files to provide titles for the Markdown page:

    English (en.json):

    {
      "markdown": {
        "title": "Markdown"
      }
    }

    French (fr.json):

    {
      "markdown": {
        "title": "Markdown"
      }
    }

    Translating the “Not found” page in Next.js

    A 404 page is essential for any web application, and localizing it ensures that users see messages in their preferred language. Here’s how you can create and translate a 404 page in your Next.js app using next-globe-gen.

    Create the catchall route

    First, set up a catchall route to handle all unmatched paths. Inside the _app folder, create a new directory called [...catchAll]. In this directory, add a page.tsx file with the following content:

    import { getTranslations } from "next-globe-gen";
    import { notFound } from "next/navigation";
    
    export function generateMetadata() {
      const t = getTranslations();
      return { title: t("notFound.title") }; // Localized title for the 404 page
    }
    
    export default function CatchAllPage() {
      notFound(); // This triggers the 404 behavior
    }

    Here:

    • notFound() is a Next.js utility that redirects the user to the 404 page when the route doesn’t exist.
    • The generateMetadata function ensures the page title is localized.

    Create the 404 page

    Next, create a not-found.tsx file directly in the _app folder. This file defines the content displayed on the 404 page:

    import { useTranslations } from "next-globe-gen";
    
    export default function NotFoundPage() {
      const t = useTranslations("notFound");
      return (
        <>
          <h1>
            {t("title")}
          </h1>
          <p>
            {t("description")}
          </p>
        </>
      );
    }

    Here:

    • useTranslations("notFound") fetches the translations for the notFound namespace.
    • The t function dynamically retrieves the localized title and description.

    Add translations

    Now, provide translations for the 404 page in your JSON files.

    English (en.json):

    {
      "notFound": {
        "title": "Not found (404)",
        "description": "This page cannot be found!"
      }
    }

    French (fr.json):

    {
      "title": "Page d'accueil",
      "description": "Tutoriel présenté par {company}",
      "currentTime": "Date et heure actuelles : {time}",
      "dashboard": {
        "title": "Tableau de bord",
        "projects": "Vous avez {count, plural, =0 {aucun projet} =1 {<b>un</b> projet} other {<b>#</b> projets}}."
      },
      "markdown": {
        "title": "Markdown"
      },
      "notFound": {
        "title": "Non trouvé (404)",
        "description": "Cette page est introuvable!"
      }
    }

    These translations ensure that the 404 page displays messages in the user’s language.

    Lokalise: Simplifying Next.js localization

    When working on Next.js localization, translating all your text can be the most time-consuming part of the process. Luckily, a powerful translation management solution like Lokalise can save you from being overwhelmed. Lokalise streamlines the translation workflow, making it faster and more efficient. Here’s how you can integrate Lokalise with your Next.js project.

    Getting started with Lokalise

    1. Sign up for a free trial: Start by creating an account on Lokalise to explore its features.
    2. Install the Lokalise CLI: The command-line tool allows you to create projects, upload translations, and download files directly to your project. If you prefer, Lokalise also provides a user-friendly GUI.
    3. Generate an API token:
      • Log in to the Lokalise website.
      • Go to the API tokens section on your profile page and generate a new read/write token.

    Setting up Lokalise for Next.js

    1. Create a new project:
      • Set up a new translation project in Lokalise and use English (or your primary language) as the base language.
      • In the project settings, copy the Project ID.
    2. Upload your Next.js translation files:
      • If you’re using translation files in JSON format (e.g., stored in src/messages/), you can upload them to Lokalise. For example: lokalise2 file upload --token --project-id --lang_iso en --file ./src/messages/en.json
    3. Manage translations in Lokalise:
      • Once uploaded, your translation keys and values will appear in the Lokalise dashboard.
      • Edit, delete, or add new translations directly in the GUI. Lokalise provides powerful filtering options, making it easy to spot untranslated keys.
    4. Download edited translations:
      • After completing your translations, download them back into your Next.js project. For example: lokalise2 file download --token --project-id --format json --dest ./src/messages/

    Why Lokalise?

    Lokalise supports multiple platforms and formats, making it incredibly versatile for Next.js projects and other software. Here are some of its standout features:

    • Professional translations: Order various translation types directly from language professionals within Lokalise.
    • Support for various formats: Translate JSON, YAML, XML, HTML, DOCX, XLSX, and many others.
    • Screenshot support: Upload screenshots to give translators better context for the text.
    • Collaboration tools: Work with your team in real time to review, edit, and approve translations.
    • Automation: Use Lokalise CLI or integrations to automate your translation workflow.

    Conclusion to Next.js i18n

    In this step-by-step guide, we set up localization for a Next.js application using next-globe-gen. We configured language settings, created translation files, and built pages with localized content and routes. Additionally, we explored how to handle pluralization, translate Markdown and 404 pages, and display localized date and time. With these steps, your Next.js app is now ready to provide a seamless experience for a global audience.

    Thank you for staying with me, and until next time!

    Further reading

    Related articles
    Stop wasting time with manual localization tasks. 

    Launch global products days from now.