Skip to main content
Next.js

next-intl tutorial: shipping a multilingual Next.js site

Published Apr 27, 20267 min read
next-intl tutorial: shipping a multilingual Next.js site

next-intl tutorial: shipping a multilingual Next.js site

EN-only is fine for indie SaaS. The moment you sell to an EU customer, run an agency, or target a non-English market, monolingual becomes a tax, every page is a translation away from a sale you cannot close. next-intl is how most Next.js teams ship multilingual without rebuilding routing.

The minimum setup

Four pieces and a working multilingual app:

1. Install and configure. pnpm add next-intl. Add a next.config.ts plugin (createNextIntlPlugin) and a src/i18n/request.ts file that maps the active locale to a messages file. Hedge the exact API to the current next-intl docs, the package iterates on configuration shape across majors.

2. Locale-prefixed routes. Move your app routes inside src/app/[locale]/. Every page now sits at /<locale>/<path>, /en/about, /fr/about, /es/about. The middleware (src/middleware.ts) handles locale detection from the URL, the Accept-Language header, and a cookie.

3. Messages files. A messages/en.json per supported language with namespaced keys. Use useTranslations("Namespace") in client components and getTranslations() in server components. Keep the structure parallel across languages, a missing key in fr.json falls back to en.json, but a structurally different file is a silent bug.

4. Locale switcher. A small component that links to the same path with a different locale prefix. Use usePathname and replace the leading segment. The switcher should preserve the rest of the URL, sending a French visitor from /fr/blog/post-name to /en/ instead of /en/blog/post-name is the kind of bug that loses sessions.

The full wiring, middleware, request config, locale switcher, RTL handling, and the SEO concerns, ships in /features/next-intl-i18n-boilerplate as production code.

SEO that does not break

Multilingual SEO is the part most tutorials skip. Three additions that matter:

  • hreflang tags. Every page should declare its language alternates in the <head>. The Next.js metadata API takes an alternates.languages object, pass it the map of locale to URL. Without this, Google has to guess which version to show a French searcher, and it guesses wrong often enough to matter.
  • Canonical URLs include the locale. The canonical for /fr/about is /fr/about, not /about. A canonical pointing at the English version tells Google the French page is a duplicate, which is the opposite of what you want.
  • Sitemap per locale or one unified sitemap. Either works. The unified sitemap with <xhtml:link rel="alternate" hreflang="..."> entries is the more compact option. The Next.js sitemap route handler can generate this, verify the current sitemap API in the Next.js docs.

For LTR languages (English, French, Spanish, German, Italian) the layout work is minimal. For RTL languages (Arabic, Hebrew), set dir="rtl" on the <html> tag conditionally and audit every Tailwind class that uses left-*, right-*, ml-*, mr-*, most of those should be start-* / end-* so they flip correctly.

Keeping translations in sync

The operational problem is not the library, it is the team workflow:

  • One source language. Pick English (or your primary market) as the source. New copy lands in en.json first; every other locale catches up.
  • A way to flag stale translations. A simple script that diffs message keys across locales and prints missing or extra keys. Run it in CI so a forgotten translation fails the build instead of shipping silently.
  • A translation service or process. For agency work, this is usually a human translator working from a CSV export. For solo products, machine translation (DeepL, GPT) gives a working draft. Tag machine-translated keys so a human can revisit them later.

For agencies shipping multilingual marketing sites for clients, the use case next-intl is most often picked for, /saasforge-agency ships EN/FR/ES, a translated CMS via Directus, and the SEO wiring above as a working starter. Saves the week of i18n setup that every agency project starts with.

Newsletter

Get the BoilerlyKit newsletter

Practical Next.js SaaS launch tips, delivered when we ship something worth sharing.

We respect your inbox. See our privacy policy.