Skip to main content

Kompletny przewodnik po internacjonalizacji Next.js

Skonfiguruj next-intl z App Routerem, ustaw trasy językowe i zautomatyzuj tłumaczenia za pomocą AI.

1

Instalacja next-intl

next-intl to pojedynczy pakiet obsługujący trasy językowe, wczytywanie wiadomości i hooki tłumaczeń dla App Routera w Next.js.

Terminal
npm install next-intl
Dlaczego next-intl zamiast next-i18next? next-intl powstał dla App Routera i komponentów serwerowych. next-i18next zaprojektowano dla Pages Routera, a jego obsługa App Routera jest ograniczona.
2

Tworzenie konfiguracji żądań i18n

Utwórz dwa pliki: src/i18n/request.ts do wczytywania wiadomości i src/i18n/routing.ts do definicji języków. Określają one, jak next-intl rozwiązuje wiadomości i trasy.

src/i18n/routing.ts
// src/i18n/routing.ts
import { defineRouting } from 'next-intl/routing';
import { createNavigation } from 'next-intl/navigation';

export const routing = defineRouting({
  locales: ['en', 'de', 'ja', 'es'],
  defaultLocale: 'en',
  localePrefix: 'as-needed',  // /about for en, /de/about for de
});

export const { Link, redirect, usePathname, useRouter } =
  createNavigation(routing);
Turbopack, domyślny bundler w Next.js 15, wymaga experimental.turbo.resolveAlias w next.config.js. Bez tego pojawia się błąd "Couldn't find next-intl config file".
3

Konfigurowanie middleware

Dodaj middleware.ts do wykrywania języka, przepisywania adresów URL i przekierowań. Middleware przechwytuje każde żądanie i zapewnia zastosowanie właściwego języka.

middleware.ts
// middleware.ts  <- Must be in project ROOT, not src/
import createMiddleware from 'next-intl/middleware';
import { routing } from './src/i18n/routing';

export default createMiddleware(routing);

export const config = {
  matcher: ['/((?!api|_next|.*\\..*).*)'],
};
middleware.ts MUSI znajdować się w katalogu głównym projektu, a nie w src/. To najczęstszy błąd konfiguracji next-intl.
4

Konfigurowanie struktury katalogu [locale]

Przenieś trasy aplikacji do app/[locale]/. Dodaj generateStaticParams, aby generować strony dla każdego języka podczas kompilacji. Powstanie struktura adresów /en/about, /de/about itd.

app/[locale]/layout.tsx
// app/[locale]/layout.tsx
import { routing } from '@/i18n/routing';

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}
setRequestLocale(locale) MUSI być wywołane w każdym page.tsx i layout.tsx korzystającym z tłumaczeń. Bez tego Next.js przechodzi na renderowanie dynamiczne, a wydajność kompilacji znacznie spada.
5

Aktualizowanie głównego layoutu

Wczytaj wiadomości przez getMessages() i przekaż je do NextIntlClientProvider w głównym layoucie językowym. Ustaw atrybut lang elementu html na podstawie parametru locale.

app/[locale]/layout.tsx
// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, setRequestLocale } from 'next-intl/server';
import { routing } from '@/i18n/routing';
import { notFound } from 'next/navigation';

export function generateStaticParams() {
  return routing.locales.map((locale) => ({ locale }));
}

export default async function LocaleLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: { locale: string };
}) {
  const { locale } = await params;
  if (!routing.locales.includes(locale as any)) notFound();

  setRequestLocale(locale);
  const messages = await getMessages();

  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider locale={locale} messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  );
}
NextIntlClientProvider wymaga jawnego parametru locale. Jego brak powoduje subtelne i trudne do zdiagnozowania błędy w komponentach klienckich.
6

Używanie tłumaczeń w komponentach

Komponenty serwerowe używają getTranslations (async, await), a klienckie — hooka useTranslations. Wybór zależy od miejsca renderowania. Komponenty serwerowe całkowicie wyłączają tłumaczenia z pakietu JavaScript klienta.

app/[locale]/page.tsx
// Server Component (default)
import { getTranslations, setRequestLocale } from 'next-intl/server';

export default async function AboutPage({
  params,
}: { params: { locale: string } }) {
  const { locale } = await params;
  setRequestLocale(locale);
  const t = await getTranslations('AboutPage');

  return <h1>{t('title')}</h1>;
}

// Client Component ('use client')
'use client';
import { useTranslations } from 'next-intl';

export default function SearchBar() {
  const t = useTranslations('SearchBar');
  return <input placeholder={t('placeholder')} />;
}
Dla przetłumaczonej treści preferuj komponenty serwerowe. Nie dodają tekstów tłumaczeń do JavaScript klienta, co skraca czas wczytywania.
7

Dodawanie SEO: metadane i hreflang

Użyj generateMetadata do tworzenia tytułów i opisów właściwych dla języka. Dodaj alternates.languages dla znaczników hreflang, aby wyszukiwarki odkryły wszystkie wersje każdej strony.

app/[locale]/layout.tsx
// app/[locale]/layout.tsx or any page.tsx
import { getTranslations } from 'next-intl/server';
import { routing } from '@/i18n/routing';

export async function generateMetadata({
  params,
}: { params: { locale: string } }) {
  const { locale } = await params;
  const t = await getTranslations({ locale, namespace: 'Metadata' });

  return {
    title: t('title'),
    description: t('description'),
    alternates: {
      languages: Object.fromEntries(
        routing.locales.map((l) => [l, `/${l}`])
      ),
    },
  };
}
Podczas kompilacji w Vercel adresem kanonicznym może stać się localhost, jeśli metadataBase nie jest ustawione. Zawsze ustaw metadataBase w głównym layoucie na domenę produkcyjną.
8

Obsługa stron błędów i not-found

error.tsx i not-found.tsx wymagają specjalnej obsługi, ponieważ mogą renderować się poza zwykłym layoutem językowym. Główny not-found.tsx potrzebuje własnej konfiguracji dostawcy i18n do wyświetlania zlokalizowanych błędów.

app/[locale]/error.tsx
// app/[locale]/error.tsx
'use client';
import { useTranslations } from 'next-intl';

export default function Error() {
  const t = useTranslations('Error');
  return (
    <div>
      <h1>{t('title')}</h1>
      <p>{t('description')}</p>
    </div>
  );
}

// app/not-found.tsx (root level -- needs own provider)
import { routing } from '@/i18n/routing';

export default async function GlobalNotFound() {
  return (
    <html lang={routing.defaultLocale}>
      <body>
        <h1>404 - Page Not Found</h1>
      </body>
    </html>
  );
}
Next.js renderuje zlokalizowaną stronę 404 tylko po jawnym wywołaniu notFound() w kodzie. Nieznane trasy bez pasującej strony pokazują domyślną stronę 404 Next.js, a nie wersję zlokalizowaną.
9

Automatyzacja tłumaczeń

Po skonfigurowaniu i18n tłumacz pliki wiadomości za pomocą AI bezpośrednio ze środowiska programistycznego albo użyj CLI i18n Agent w pipeline CI/CD, aby automatyzować każde wdrożenie.

Terminal
# In your IDE, ask your AI assistant:
> Translate messages/en.json to German, Japanese, and Spanish

✓ messages/de.json created (1.1s)
✓ messages/ja.json created (1.4s)
✓ messages/es.json created (1.0s)
Użyj next-intl-localechain dla inteligentnych języków rezerwowych — użytkownik pt-BR zobaczy pt-PT zamiast angielskiego, gdy brazylijski portugalski jest niedostępny.

Automatyczna kontrola jakości tłumaczeń

Wykryj brakujące klucze i uszkodzone symbole zastępcze przed wydaniem za pomocą i18n-validate. Przetestuj interfejs przy użyciu sztucznych tłumaczeń z i18n-pseudo, zanim pojawią się prawdziwe tłumaczenia.

Narzędzia open source dla Next.js i18n

Te pakiety open source rozwiązują częste problemy w przepływach internacjonalizacji Next.js.

next-intl-localechain

Standardowy next-intl przy braku tłumaczenia przechodzi bezpośrednio do języka domyślnego. Użytkownik brazylijskiego portugalskiego widzi angielski zamiast poprawnego pt-PT. next-intl-localechain dodaje inteligentne łańcuchy i głęboko scala powiązane tłumaczenia, aby zawsze pokazywać najbliższy wariant.

src/i18n/request.ts
import { getRequestConfig } from 'next-intl/server';
import { withLocaleChain } from 'next-intl-localechain';

export default getRequestConfig(withLocaleChain({
  loadMessages: (locale) =>
    import(`../../messages/${locale}.json`).then(m => m.default),
  defaultLocale: 'en'
}));
Automatyczne głębokie scalanie tłumaczeń w łańcuchach
Wbudowane łańcuchy dla portugalskiego, hiszpańskiego, francuskiego, niemieckiego i innych
Pomijanie brakujących plików wiadomości bez błędów
Konfiguracja w jednym wierszu — opakowuje istniejący getRequestConfig
Zobacz na GitHubie

@i18n-agent/cli

Narzędzie wiersza poleceń do tłumaczenia plików wiadomości Next.js bez opuszczania terminala. Tłumacz pliki, sprawdzaj status zadań i pobieraj wyniki. Obsługa pipeline CI/CD i uwierzytelnianie kluczem API umożliwiają pełną automatyzację.

Terminal
# Install the CLI
npm install -g @i18n-agent/cli

# Authenticate
i18nagent login

# Translate your message files
i18nagent translate ./messages/en.json --lang de,ja,es

# Or use in CI/CD with an API key
export I18N_AGENT_API_KEY=your-key-here
i18nagent translate ./messages/en.json --lang de,ja,es
Tłumaczenie JSON, YAML, PO i innych formatów i18n z terminala
Gotowe do CI/CD — uwierzytelnianie przez zmienną środowiskową
Śledzenie statusu, wznawianie nieudanych zadań i pobieranie wyników
Czytelny maszynowo wynik JSON do skryptów i automatyzacji
Zobacz na GitHubie

Częste pułapki

"Unable to find next-intl locale"

Middleware nie dopasował żądania. Sprawdź: czy middleware.ts znajduje się w katalogu głównym? Czy matcher poprawnie wyklucza pliki statyczne? Czy język znajduje się w konfiguracji tras?

Nieoczekiwane renderowanie dynamiczne

W stronie lub layoucie brakuje setRequestLocale(locale). Bez niego next-intl wykrywa język z nagłówków lub cookies, co wymusza renderowanie dynamiczne i uniemożliwia generowanie statyczne.

Trasy równoległe nie działają z i18n

Trasy równoległe (@modal) i przechwytujące ((.)photo) mają znane niezgodności z dynamicznym segmentem [locale]. Dla tych zaawansowanych wzorców użyj jako obejścia trasowania za pomocą middleware.

Zmiana języka traci bieżącą trasę

Podczas zmiany języka zachowaj bieżące pathname przez usePathname() i zastąp tylko segment języka. Uważaj na dynamiczne parametry tras — trzeba je ponownie rozwiązać dla nowego języka.

Zalecana struktura plików

Project Structure
my-nextjs-app/
├── middleware.ts              # Locale routing (project root!)
├── next.config.mjs
├── messages/
│   ├── en.json                # Source messages
│   ├── de.json
│   └── ja.json
├── src/
│   ├── i18n/
│   │   ├── request.ts         # Message loading config
│   │   └── routing.ts         # Locale definitions
│   └── app/
│       └── [locale]/
│           ├── layout.tsx     # Root locale layout
│           ├── page.tsx       # Home page
│           ├── error.tsx      # Localized error page
│           ├── not-found.tsx  # Localized 404
│           └── about/
│               └── page.tsx
└── package.json

Wypróbuj i18n Agent

Upuść tutaj plik tłumaczenia

JSON, YAML, PO, XML, CSV, Markdown, Properties

lub kliknij, aby go wybrać

Języki docelowe

Rejestracja nie jest wymaganaNatychmiastowa wycena

Łańcuch rezerwowy z next-intl-localechain

Gdy brakuje klucza tłumaczenia w regionalnych ustawieniach takich jak pt-BR, next-intl od razu przechodzi do języka domyślnego zamiast najpierw sprawdzić nadrzędny pt.

Terminal
npm install next-intl-localechain
Configuration
import { withLocaleChain } from 'next-intl-localechain';

export default withLocaleChain({
  fallbacks: {
    'pt-BR': ['pt', 'en'],
    'zh-Hant-HK': ['zh-Hant', 'zh', 'en'],
  },
  defaultLocale: 'en',
  loadMessages: (locale) => import(`./messages/${locale}.json`),
});

Zobacz przewodnik po rezerwowych ustawieniach regionalnych, aby poznać pełną listę obsługiwanych frameworków i 75 wbudowanych łańcuchów. Learn more →

Częste pytania