localize.dev

Docs / Next.js

Next.js i18n for the App Router, automated

Localize a Next.js App Router app: server components get an awaited translator, client components useTranslation, and the language follows a cookie. One command or one pull request.

How it works

Files under app/ without 'use client' are server components, which can’t call hooks. They get const { t } = await getTranslation() instead, from a generated i18n.server module that reads the lang cookie, then Accept-Language.

Client components keep useTranslation(), and the root layout passes them the same language, so a page renders in one language on the server and the client.

Before and after

The engine’s real output for this file. In a real run, the hosted model names the keys from context.

app/page.tsx · before
export default function Home() {
  return (
    <main>
      <h1>Ship in every language</h1>
      <p>Start a free trial today.</p>
    </main>
  );
}
app/page.tsx · after
import { useTranslation } from 'react-i18next';

export default function Home() {
  const { t } = useTranslation();
  return (
    <main>
      <h1>{t('home.ship_in_every_language')}</h1>
      <p>{t('home.start_a_free_trial_today')}</p>
    </main>
  );
}
locales/en.json
{
  "home": {
    "ship_in_every_language": "Ship in every language",
    "start_a_free_trial_today": "Start a free trial today."
  }
}

What the setup adds

The first run sets up react-i18next (server and client) if the project doesn’t have it yet:

  • i18next and react-i18next, src/i18n.ts and i18n.server.ts
  • An <I18nProvider> around the root layout, and <html lang> that follows the language
  • A language switcher that sets the cookie and refreshes, so server components re-render

Run it

The CLI needs Node.js 22 or later.

npm install --save-dev localize-dev
npx localize-dev login

# Preview, then write the changes
npx localize-dev run --dry-run -l es,fr,de
npx localize-dev run -l es,fr,de

# Or open a pull request instead
npx localize-dev pr -l es,fr,de

Or add the GitHub Action and get a pull request on every push. Try it on your own code first in the playground.