Skip to content

Repository files navigation

Next-Page-Router-i18n

A minimal Next.js reference project demonstrating internationalization (i18n) in the Pages Router (as opposed to the App Router), using next-i18next.

Live demo: https://next-page-router-i18n.vercel.app/

Overview

  • Serves two pages (/ and /second) that each render a translated hello string sourced from a shared common translation namespace.
  • Translation strings live in public/locales/<locale>/common.json — one JSON file per locale.
  • Locale-prefixed routing is provided out of the box by Next.js's built-in i18n support, configured in next-i18next.config.js:
    • Supported locales: en, es, fr
    • Default locale: es
    • Automatic browser-locale detection: disabled (localeDetection: false), so visiting / always serves the default locale (es) instead of redirecting based on the browser's Accept-Language header.
  • Each page fetches its translations at build time via getStaticProps + serverSideTranslations, and renders them with the useTranslation hook from react-i18next.
  • Each page links to the other. A plain <Link href="..."> preserves the locale currently being viewed, so navigating from /fr lands on /fr/second.
  • A <LocaleSwitcher /> dropdown on both pages switches locale while staying on the current page.
  • Styling uses Tailwind CSS, which follows the OS light/dark preference.

Project structure

public/locales/
  en/common.json          # "Hello!"
  es/common.json          # "¡Hola!"
  fr/common.json          # "Bonjour!"
src/
  components/
    LocaleSwitcher.js     # locale dropdown
  pages/
    _app.js               # wrapped in appWithTranslation()
    index.js              # "/"
    second.js             # "/second"
  styles/globals.css
next-i18next.config.js    # locales, defaultLocale, localeDetection
next.config.js            # re-exports the i18n config to Next.js

How the locale switcher works

LocaleSwitcher.js reads the available locales off the router and navigates imperatively on change:

router.push({ pathname, query }, asPath, { locale: e.target.value })

router.push takes (href, as, options). Passing the route pattern plus params ({ pathname, query }) as the href — rather than the already-resolved asPath — is what keeps this correct once dynamic routes such as /blog/[slug] are added, since Next.js interpolates the params itself instead of reverse-matching a concrete path.

Getting started

Install dependencies and start the dev server:

npm install
npm run dev

Open http://localhost:3000 in your browser.

How to test

This project has no automated test suite — verify the i18n behavior manually:

  1. Start the dev server (npm run dev).
  2. Visit each locale-prefixed URL and confirm the page renders the correctly translated hello text:
  3. Repeat for the second page (append /second, e.g. http://localhost:3000/en/second).
  4. Check that navigation preserves the locale: from /fr, click Go to Second Page and confirm you land on /fr/second with the French text still showing.
  5. Check the locale dropdown: on either page, pick a different locale and confirm the URL prefix updates, the text switches language, and you stay on the same page (/second stays /second).
  6. Confirm locale detection is off: visiting / with a browser set to a non-default language (e.g. English) should still serve the es default rather than redirecting.

To add or change translations, edit the corresponding public/locales/<locale>/common.json file and reload the page. To add a locale, create a new folder under public/locales/ and add it to the locales array in next-i18next.config.js — the dropdown picks it up automatically.

Building for production

npm run build
npm run start

next build prerenders every page once per locale, so the two pages produce six static HTML files.

Learn more

About

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages