

Next.js posiada dwie oficjalne strony dokumentacji dotyczące i18n, które opisują zupełnie różne systemy i nie zawierają żadnych odnośników między sobą.
Jedna z nich dotyczy routera stron. Druga dotyczy routera aplikacji. Żadna z nich nie wyjaśnia, jak te dwa elementy się ze sobą wiążą, jakich bibliotek należy używać ani jak obsługiwać atrybut hreflang w kontekście wielojęzycznego SEO.
Połączymy oba routery. Omówimy strategie routingu, dobór bibliotek, konfigurację oprogramowania pośredniczącego, tłumaczenia komponentów serwerowych oraz wielojęzyczne SEO.
Naszym celem jest stworzenie przydatnego źródła informacji dla programistów, którzy otrzymali zadanie dodania obsługi języków obcych do aplikacji Next.js i potrzebują jasnego obrazu sytuacji przed podjęciem decyzji o wyborze konkretnego rozwiązania. Zaczynamy!
Internacjonalizacja składa się z trzech warstw:
Next.js służy wyłącznie do obsługi routingu.
Moduł Pages Router posiada wbudowaną obsługę routingu międzynarodowego (i18n) od wersji 10.0.0. Trzypolowy blok konfiguracyjny w pliku next.config.js automatycznie zajmuje się wykrywaniem ustawień regionalnych, dodawaniem prefiksów do adresów URL oraz przekierowaniami.
App Router działa inaczej. Na jego stronie dokumentacji dotyczącej i18n opisano schemat, który użytkownik sam tworzy przy użyciu oprogramowania pośredniczącego, a [język] segment dynamiczny oraz biblioteka.
Jeśli chodzi o tłumaczenia i formatowanie, musisz radzić sobie samodzielnie, niezależnie od tego, jakiego routera używasz. Dokumentacja App Router zawiera listę wszystkich kompatybilnych bibliotek, ale nie zawiera wskazówek dotyczących wyboru konkretnej biblioteki. Żadna ze stron dokumentacji nie porusza kwestii tagów hreflang ani wielojęzycznych map witryn.
Podejście oparte na Pages Router polega na zmianie konfiguracji. Dodaj blok i18n do pliku next.config.js, zawierający trzy pola:
// next.config.js
module.exports = {
i18n: {
locales: ['en', 'fr', 'de'],
defaultLocale: 'en',
},
}To wszystko.
Next.js automatycznie wykrywa ustawienia regionalne na podstawie Accept-Language nagłówek, uwzględnia NASTĘPNA_JĘZYKOWA zastąpienie pliku cookie oraz udostępnia aktualne ustawienia regionalne poprzez useRouter().locale. Nie potrzebujesz żadnego oprogramowania pośredniczącego ani zmiany struktury katalogów.
W App Routerze nie ma odpowiednika pliku config. Trzeba samodzielnie skonfigurować routing, korzystając z trzech elementów:
@formatjs/intl-localematcher oraz negocjator przetworzyć Accept-Language nagłówki. W oficjalnej dokumentacji rzeczywista logika wykrywania została pominięta: function getLocale(request) { ... }. Omówimy to w następnym rozdziale.[język] segment dynamiczny obejmuje całość app/ katalog. Dzięki strukturze folderów każda trasa uwzględnia ustawienia regionalne.generujParametryStatyczne wstępnie renderuje każdy wariant językowy w trakcie kompilacji.Spośród tych trzech elementów to właśnie `generateStaticParams` zastępuje funkcje, które router Pages realizował automatycznie w trakcie kompilacji.
export function generateStaticParams() {
return [{ locale: 'en' }, { locale: 'fr' }, { locale: 'de' }]
}🚨 Wbudowana obsługa międzynarodowości (i18n) modułu Pages Router nie działa z wynik: „eksport”. Jeśli potrzebujesz w pełni statycznego eksportu, musisz zamiast tego skorzystać z ręcznego routingu opartego na folderach. Ograniczenie to dotyczy wyłącznie wbudowanej konfiguracji. Oba routery obsługują statyczne eksporty przy ręcznej konfiguracji.
Zanim wybierzesz bibliotekę, zdecyduj się na strategię routingu. Ma to wpływ na SEO, konfigurację DNS oraz to, ile kodu pośredniczącego będziesz musiał napisać:
next-intl uznaje to za doskonałą opcję.W przypadku witryn publicznych, dla których optymalizacja pod kątem wyszukiwarek (SEO) ma kluczowe znaczenie, domyślnym ustawieniem powinno być kierowanie na podścieżki. Kierowanie na domeny jest uzasadnione tylko wtedy, gdy wymagane jest zastosowanie silnych sygnałów geolokalizacyjnych.
Jeśli nie chcesz ręcznie zarządzać strukturą adresów URL, odwrotny serwer proxyWeglot automatycznie zajmuje się przekierowaniami do podkatalogów i subdomen, w tym dodawaniem atrybutu hreflang oraz przetłumaczonymi adresami URL.
Jak wspomnieliśmy wcześniej, w oficjalnej dokumentacji wymieniono biblioteki, nie polecając jednak żadnej z nich. Oto porównanie głównych opcji:
next-intl to de facto standard dla App Router. Obsługa RSC jest wbudowana, routing jest zintegrowany, a autouzupełnianie w TypeScript działa bez dodatkowej konfiguracji.
react-i18next będzie lepszym wyborem, jeśli korzystasz z routingu Pages lub już używasz i18next w innych częściach swojego stosu technologicznego. Obsługa routingu App Router działa, ale wymaga więcej ręcznej konfiguracji.
Lingui sprawdza się w zespołach, które korzystają już z procesów przetwarzania plików .po. Tłumaczenia są pobierane w trakcie kompilacji, dzięki czemu nieużywane komunikaty nigdy nie trafiają do dystrybucji.
💡 Paraglide JS nie zalicza się co prawda do grona największych graczy, ale warto o nim wspomnieć jako o opartej na kompilatorze alternatywie, która generuje mniejsze pliki pakietów. Jeśli jednak jesteś tym zainteresowany, musisz pogodzić się z faktem, że jego ekosystem jest mniej rozwinięty niż w przypadku innych rozwiązań.
W przypadku formatowania daty i liczb biblioteka next-intl wykorzystuje natywne interfejsy API Intl za pośrednictwem metody useFormatter. Pozostałe biblioteki przekazują tę funkcję do FormatJS lub pozostawiają użytkownikowi możliwość bezpośredniego wywołania metod Intl.DateTimeFormat i Intl.NumberFormat.
💡 Biblioteki te zajmują się renderowaniem. Ktoś nadal musi tworzyć tłumaczenia i aktualizować je w miarę zmian treści. Weglot na zupełnie innym poziomie, zarządzając treściami tłumaczeniowymi za pośrednictwem serwera proxy odwrotnego poza kodem źródłowym. Nie należy traktować go jako zamiennika biblioteki.
W Next.js 16 plik middleware.ts został przemianowany na proxy.ts. Zrobiono to, ponieważ nazwa „middleware” była myląca i sugerowała ogólną logikę wewnątrz aplikacji. W rzeczywistości plik ten działa na granicy sieci, przechwytując i modyfikując żądania niczym serwer proxy, zanim dotrą one do aplikacji.
Oto kompletna implementacja funkcji wykrywania ustawień regionalnych i przekierowania, która uzupełnia wspomniane wcześniej pominięcia w oficjalnej dokumentacji:
// proxy.ts
import { match } from '@formatjs/intl-localematcher'
import Negotiator from 'negotiator'
import { NextRequest, NextResponse } from 'next/server'
const locales = ['en', 'fr', 'de']
const defaultLocale = 'en'
function getLocale(request: NextRequest): string {
const cookie = request.cookies.get('NEXT_LOCALE')?.value
if (cookie && locales.includes(cookie)) return cookie
const headers = { 'accept-language': request.headers.get('accept-language') ?? '' }
const languages = new Negotiator({ headers }).languages()
return match(languages, locales, defaultLocale)
}
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl
const hasLocale = locales.some(l => pathname.startsWith(`/${l}/`) || pathname === `/${l}`)
if (hasLocale) return
const locale = getLocale(request)
request.nextUrl.pathname = `/${locale}${pathname}`
return NextResponse.redirect(request.nextUrl)
}
Pliki są zagnieżdżone pod app/[język]/, z słowniki/ folder obok twoich układów i stron. Układ główny otrzymuje ustawienia regionalne jako parametr i ustawia go na html tag:
export default async function RootLayout({ children, params }) {
const { locale } = await params
return (
<html lang={locale}>
<body>{children}</body>
</html>
)
}
W przypadku tłumaczeń w oficjalnej dokumentacji przedstawiono prosty wzorzec słownikowy, który nie wymaga użycia żadnej biblioteki:
const dictionaries = {
en: () => import('./dictionaries/en.json').then(m => m.default),
fr: () => import('./dictionaries/fr.json').then(m => m.default),
}
export const getDictionary = async (locale: string) => dictionaries[locale]()
To działa, ale nie obsługuje tworzenia liczby mnogiej ani interpolacji. next-intl obejmuje obie te kwestie poprzez getTranslations() oraz useTranslations() w Elementy serwera i elementy klienta odpowiednio.
Tak czy inaczej, pliki tłumaczeń są przetwarzane na serwerze, a do przeglądarki trafia wyłącznie wynikowy kod HTML, więc rozmiar pliku z komunikatami nie ma wpływu na rozmiar pakietu klienckiego.
W przypadku komponentów klienckich, w miarę możliwości przekazuj przetłumaczone ciągi znaków jako właściwości z nadrzędnego komponentu serwerowego. Używaj NextIntlClientProvider z podzbiorem komunikatów z zakresem tylko wtedy, gdy komponent kliencki musi bezpośrednio obsługiwać tłumaczenia.
W przypadku modułu zmiany języka komponent serwerowy wyświetla etykiety ustawień regionalnych, podczas gdy komponent kliencki obsługuje useRouter() zadzwoń:
// LocaleSwitcher.tsx (Server Component)
import LocaleSwitcherClient from './LocaleSwitcherClient'
export default function LocaleSwitcher({ locale }) {
return <LocaleSwitcherClient locale={locale} labels={{ en: 'English', fr: 'Français' }} />
}Klient monitoruje zmiany w wyborze ustawień i wysyła nową trasę lokalizacji:
// LocaleSwitcherClient.tsx
'use client'
import { useRouter } from 'next/navigation'
export default function LocaleSwitcherClient({ locale, labels }) {
const router = useRouter()
return (
<select value={locale} onChange={e => router.push(`/${e.target.value}`)}>
{Object.entries(labels).map(([value, label]) => (
<option key={value} value={value}>{label}</option>
))}
</select>
)
}Jeśli korzystasz z Weglot, powyższe informacje nie mają zastosowania. Weglot wbudowany widget do zmiany języka i nie wymaga konfiguracji serwera proxy ani oprogramowania pośredniczącego.
Żaden z routerów nie obsługuje automatycznie wielojęzycznego SEO:
html lang poprawnie, ale w dokumentacji jest napisane, że wdrożenie atrybutu hreflang „zależy od Ciebie”.Dzięki App Routerowi interfejs API metadanych pozwala w największym stopniu zbliżyć się do automatyzacji. Zdefiniuj adresy URL ustawień regionalnych w generujMetadane poprzez języki alternatywne obiekt, a Next.js automatycznie go wstrzykuje link rel="alternate" hreflang="..." tagi:
export async function generateMetadata({ params: { locale } }) {
return {
alternates: {
languages: {
'en': 'https://example.com/en',
'fr': 'https://example.com/fr',
'de': 'https://example.com/de',
},
},
}
}Najtrudniejsze jest zebranie właściwego adresu URL dla każdego wariantu językowego na każdej stronie. To zadanie należy do Ciebie.
Są jeszcze dwie inne kwestie, które wymagają ręcznej konfiguracji niezależnie od tego, jakiego routera używasz. Należy ustawić kanoniczne adresy URL dla poszczególnych ustawień regionalnych, aby uniknąć sygnałów wskazujących na zduplikowaną treść. Twoje sitemap.ts potrzeby xhtml:link wpisy dla każdego wariantu regionalnego każdej strony.
Na hreflang sama wartość, użyj hreflang="en-US" przy kierowaniu reklam do konkretnego regionu oraz hreflang="en" gdy kierujesz swoją ofertę do wszystkich osób posługujących się językiem angielskim. Pomieszanie tych elementów wysyła sprzeczne sygnały do wyszukiwarek.
next-intl wprowadza jedną częściową automatyzację: jego serwer proxy automatycznie dodaje atrybut hreflang Link nagłówki odpowiedzi w przypadku korzystania z routingu opartego na zlokalizowanych ścieżkach. Pozostałe konfiguracje routingu nadal wymagają ręcznego wdrożenia.
W miarę rozwoju witryny wiąże się to ze sporym nakładem pracy związanej z bieżącą konserwacją. Na szczęście odwrotny serwer proxy Weglot automatycznie zajmuje się wszystkim na serwerze, dzięki czemu przetłumaczone strony są w pełni indeksowalne bez konieczności stosowania dodatkowego kodu.
W rzeczywistości odwrotny serwer proxy Weglot automatycznie zajmuje się wszystkimi kwestiami omówionymi w poprzedniej sekcji: tagami hreflang, przetłumaczonymi adresami URL, tagami kanonicznymi oraz generowaniem mapy witryny. Przetłumaczone strony są wyświetlane po stronie serwera, dzięki czemu są w pełni indeksowalne przez wyszukiwarki.
⚠️ snippet kodu JavaScript Weglot nie zapewnia korzyści w zakresie SEO. Tłumaczenia po stronie klienta nie są indeksowane przez roboty wyszukiwarek. Jeśli SEO ma dla Ciebie znaczenie, konieczna jest konfiguracja serwera proxy odwrotnego.
Dodatkową zaletą jest czas kompilacji. Weglot przetłumaczone strony za pośrednictwem własnej sieci CDN, zamiast generować je podczas kompilacji. Dodanie 10 języków do witryny Weglot nie ma wpływu na czas kolejna wersja trwa.
Właściwy wybór zależy od tego, co chcesz osiągnąć.
Jeśli tworzysz aplikację w oparciu o App Router i zaczynasz od zera, next-intl jest domyślnym wyborem. W jednym pakiecie obejmuje routing, tłumaczenia, autouzupełnianie w TypeScript oraz obsługę RSC.
Jeśli korzystasz z Pages Router lub masz już i18next w swoim stosie, react-i18next to droga najmniejszego oporu.
Jeśli priorytetem jest wielojęzyczne SEO i bieżące zarządzanie tłumaczeniami, żadna z tych bibliotek nie rozwiązuje problemu w całości. Nadal konieczne będzie wdrożenie atrybutu hreflang, map witryn oraz procedury zapewniającej aktualność tłumaczeń w miarę zmian treści. Serwer proxy odwrócone Weglot zajmuje się tym wszystkim automatycznie.
Weglot biblioteka na poziomie komponentów nie wykluczają się wzajemnie. Weglot na poziomie kodu HTML i warstwy proxy, dzięki czemu może współistnieć z każdą biblioteką używaną przez Twoje komponenty.
Jeśli to rozwiązanie pasuje do Twojej sytuacji, zajrzyj na stronę poświęconą integracji z JavaScriptem Weglot i skorzystaj z naszej 14-dniowej bezpłatnej wersji próbnej!
Najlepszym sposobem, aby zrozumieć potęgę Weglot wypróbowanie go samodzielnie. Wypróbuj go za darmo i bez żadnych zobowiązań.
Jeśli nie jesteś jeszcze gotowy, aby połączyć swoją stronę internetową, w panelu administracyjnym dostępna jest strona demonstracyjna.