Multi-language Setup with i18n in Next.js

by Sachin 3 minute read 7 views

Implementing i18n in Next.js enhances user experience, improves accessibility, and enables a global reach with minimal setup and efficient language-switching support.

Key Points

  • 90% of users prefer content in their native language for better understanding and trust.
  • Websites with i18n see up to a 70% increase in international engagement rates.
  • Multilingual support reduces bounce rates by 50% in global markets and enhances retention.

In today’s digital-first world, creating applications that speak to global audiences is essential. If you're building with Next.js, integrating internationalization (i18n) is straightforward and powerful using the next-intl library. Whether you’re offering custom app development or running a full-scale app development company, supporting multiple languages can greatly improve user engagement.

This guide walks you through a step-by-step setup of i18n in a Next.js App Router project, making it easy to support languages like English and Farsi.

Step 1 – Install next-intl

Start by installing next-intl, a developer-friendly package that adds i18n support to Next.js App Router.

                                        npm install next-intl
                                    

If you're involved in mobile app development, this package ensures consistent localization for your web front-end experience.

Step 2 – Prepare Translation Files

Create a directory to hold your locale-based JSON files for managing translations.

Folder Structure:

                                        src/
  └── messages/
        ├── en.json
        └── fa.json
                                    

Example en.json:

                                        {
  "Header": {
    "register_trademark": "Register Trademark",
    "login_to_store": "Login to My Store",
    "about_food_waste": "About Food Waste",
    "about_us": "About Us",
    "business_solutions": "Business Solutions",
    "program": "Program",
    "dropdown_action": "Action",
    "dropdown_another_action": "Another Action",
    "dropdown_something_else": "Something Else Here"
  },


  "HomeBanner": {
    "title_part1": "Save",
    "title_highlight": "Good Food",
    "description": "Rescue perfectly good food and give it a second chance to nourish. Join the movement to save food, save money, and protect the planet.",
    "button": "Download the App"
  },
  "AppStore": {
    "title": "Daschin is a social impact company on a mission to inspire and empower everyone to fight food waste.",
    "description": "Our app is the world’s largest marketplace for surplus food. We help users rescue good food from going to waste and offer great value for money at local stores, cafés, and restaurants."
  },
  "ChooseDaschin": {
    "title": "Why choose Daschin?",
    "description": "Healthy food fuels your body with essential nutrients. It boosts energy, improves focus, and strengthens immunity. Choosing fresh, balanced meals helps prevent illness. Eat well today for a healthier, happier tomorrow.",
    "item1": "Rescue food near you",
    "item2": "Enjoy good food at half price or less",
    "item3": "Try new things from local cafés, bakeries, or restaurants",
    "item4": "Help the environment by reducing food waste"
  },
}
                                    

Creating clear and well-structured messages is essential in custom app development, especially when expanding across different regions.

Step 3 – Configure Locale Detection

Create a config file to detect and load the correct translation based on cookies.

File: src/i18n/request.ts

                                        import { cookies } from "next/headers";
import { getRequestConfig } from "next-intl/server";


export default getRequestConfig(async () => {
  // Read locale from cookie
  const cookieStore = await cookies();
  const locale = cookieStore.get("NEXT_LOCALE")?.value || "fa";


  console.log(locale);
  return {
    locale,
    messages: (await import(`../../messages/${locale}.json`)).default,
  };
});
                                    

This setup is excellent for any app development company serving diverse clients and users across different regions.

Step 4 – Update Root Layout with i18n Provider

Wrap your application with NextIntlClientProvider in your root layout to enable internationalisation support throughout your app.

File: app/layout.tsx

                                        import type { Metadata } from "next";
import "./globals.css";
import { NextIntlClientProvider } from "next-intl";
import { getLocale } from "next-intl/server";


export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};


export default async function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  const locale = (await getLocale()) || "fa";


  console.log(locale);
  return (
    <html lang={locale}>
      <head>
        <link
          rel="stylesheet"
          href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css"
        />
        <link
          href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/css/bootstrap.min.css"
          rel="stylesheet"
          integrity="sha384-4Q6Gf2aSP4eDXB8Miphtr37CMZZQ5oXLH2yaXMJ2w8e2ZtHTl7GptT4jmndRuHDT"
          crossOrigin="anonymous"
        ></link>
      </head>
      <body>
        <NextIntlClientProvider>{children}</NextIntlClientProvider>
      </body>
    </html>
  );
}
                                    

This global provider ensures that any component can access localized content—crucial for mobile app development with multilingual requirements.

Step 5 – Build a Language Switcher

Let users switch between languages with a simple dropdown.

Component Example:

                                        <nav className="top-nav">
        <div className="container">
          <div className="d-flex justify-content-between">
            <div className="position-relative">
              <img src="/images/down-arrow.svg" />{" "}
              <img src="/images/farsi-flag.svg" className="flag-img" />
              <select
                value={locale}
                onChange={(e) => {
                  const newLocale = e.target.value;
                  localStorage.setItem("locale", newLocale); // optional, for select value
                  document.cookie = `NEXT_LOCALE=${newLocale}; path=/;`; // critical
                  window.location.reload(); // reload so getRequestConfig picks up new locale
                }}
              >
                <option value="fa">Farsi</option>
                <option value="en">English</option>
              </select>
            </div>


            <div className="d-flex gap-3">
              <p className="m-0">
                abcdef@gmail.com <i className="bi bi-envelope"></i>
              </p>
              <p className="m-0">
                56577 56786 <i className="bi bi-telephone"></i>
              </p>
            </div>
          </div>
        </div>
      </nav>
                                    

This type of real-time locale toggle is especially appreciated in custom app development where UX is a top priority.

Step 6 – Use Translations in Components

To use your localized messages in a component, leverage the useTranslations hook.

Example: HomeBanner.tsx

                                        "use client";
import { useTranslations } from "next-intl";


const HomeBanner = () => {
  const t = useTranslations("HomeBanner");


  return (
    <section className="home-banner">
      <div className="container">
        <h1>
          {t("title_part1")}{" "}
          <span className="gradient-text">{t("title_highlight")}</span>
        </h1>
        <p>{t("description")}</p>
        <button className="btn green-bg">{t("button")}</button>
      </div>
    </section>
  );
};


export default HomeBanner;
                                    

export default HomeBanner;

This modular approach makes localization easy, even for teams at an app development company working on large-scale international projects.

Step 7 – Final Output

At this point, your app:

  • Automatically detects and loads the user’s language
  • Lets users switch languages via a UI control
  • Displays translated content using organized JSON files
  • Provides scalability for adding more languages in the future

Whether you're a freelancer offering custom app development or a full-scale app development company, integrating i18n into your mobile app development pipeline ensures your applications are ready for global users.

Final Words

Supporting multiple languages in a Next.js app has never been easier. With next-intl, you can provide seamless, localized experiences in just a few steps. This is essential not only for user satisfaction but also for scaling your product internationally.

For companies focused on mobile app development or offering custom app development services, this i18n setup can help future-proof your applications and enhance their usability worldwide.

Looking to expand your app's reach? Internationalization isn't just an add-on—it's a must-have in today’s diverse user ecosystem.

Tech Stack & Version

Frontend

  • Next.js
  • Tailwind CSS
  • Bootstrap 5

Backend

  • Node.js
  • MySQL
  • i18n JSON

Deployment

  • Vercel
  • Netlify

img

©2025Digittrix Infotech Private Limited , All rights reserved.