

Next.js har två officiella dokumentationssidor om i18n som beskriver helt olika system, utan några korshänvisningar mellan dem.
Den ena behandlar Pages Router. Den andra behandlar App Router. Ingen av dem förklarar hur de två hänger ihop, vilka bibliotek som ska användas eller hur man hanterar hreflang för flerspråkig SEO.
Vi ska koppla samman de båda routrarna. Vi kommer att gå igenom routningsstrategier, val av bibliotek, konfiguration av mellanprogramvara, översättning av serverkomponenter samt flerspråkig SEO.
Vårt mål är att skapa en användbar resurs för utvecklare som har fått i uppdrag att lägga till språkstöd i en Next.js-app och behöver en tydlig överblick innan de bestämmer sig för en lösning. Då sätter vi igång!
Internationaliseringen består av tre nivåer:
Next.js hanterar endast routningen.
Sidroutern har haft inbyggd i18n-routing sedan version 10.0.0. Ett konfigurationsblock med tre fält i filen next.config.js hanterar automatiskt språkdetektering, URL-prefix och omdirigeringar.
App Router fungerar annorlunda. På dess dokumentationssida för i18n beskrivs ett mönster som du själv sätter ihop med hjälp av middleware, en [språk] ett dynamiskt segment och ett bibliotek.
När det gäller översättningar och formatering får du klara dig själv, oavsett vilken router du använder. I dokumentationen för App Router listas alla kompatibla bibliotek, men det finns inga råd om vilket du ska välja. Ingen av dokumentationssidorna tar upp hreflang-taggar eller flerspråkiga webbplatskartor.
Metoden med Pages Router innebär en konfigurationsändring. Lägg till ett i18n-block i next.config.js med tre fält:
// next.config.js
module.exports = {
i18n: {
locales: ['en', 'fr', 'de'],
defaultLocale: 'en',
},
}Det var allt.
Next.js identifierar automatiskt språkinställningen från Accept-Language rubrik, följer en NÄSTA_LOKAL åsidosättning av cookie, och visar den aktiva språkinställningen via useRouter().locale. Du behöver varken någon mellanprogramvara eller omstrukturering av katalogerna.
App Router har ingen motsvarande konfiguration. Du skapar routningen själv utifrån tre delar:
@formatjs/intl-localematcher och förhandlare att analysera Accept-Language rubriker. I den officiella dokumentationen utelämnas själva detekteringslogiken med tre punkter: function getLocale(request) { ... }. Det tar vi upp i nästa avsnitt.[språk] det dynamiska segmentet omsluter hela din app/ katalogen. Varje rutt anpassas efter språkinställningen via mappstrukturen.generera statiska parametrar förrenderar varje språkvariant vid kompileringstillfället.Av de tre metoderna är det generateStaticParams som ersätter det som Pages Router tidigare skötte automatiskt vid kompilering.
export function generateStaticParams() {
return [{ locale: 'en' }, { locale: 'fr' }, { locale: 'de' }]
}🚨 Pages Routers inbyggda i18n-funktion fungerar inte med utdata: 'export'. Om du behöver en helt statisk export måste du istället använda manuell mappbaserad vidarebefordran. Denna begränsning gäller endast den inbyggda konfigurationen. Båda routrarna stöder statiska exporter vid manuell konfiguration.
Innan du väljer ett bibliotek bör du bestämma dig för en routningsstrategi. Det påverkar SEO, DNS-konfigurationen och hur mycket mellanprogramvara du kommer att behöva skriva:
nästa-intl anser att det är ett utmärkt alternativ.För webbplatser som är öppna för allmänheten och där sökmotoroptimering (SEO) är avgörande är sub-path-routing det rätta standardvalet. Domänrouting är värt den extra komplexiteten endast om tydliga signaler för geografisk inriktning är ett specifikt krav.
Om du inte vill hantera URL-strukturen manuellt sköter Weglot omvända proxy automatiskt vidarebefordran till underkataloger och underdomäner, inklusive infogning av hreflang-attribut och översatta URL:er.
Som vi nämnde tidigare listar den officiella dokumentationen olika bibliotek utan att rekommendera något specifikt. Här följer en jämförelse av de viktigaste alternativen:
next-intl är de facto-standarden för App Router. Stöd för RSC är inbyggt, routningen är integrerad och TypeScripts autofullständning fungerar utan extra konfiguration.
react-i18next är det bästa valet om du använder Pages Router eller redan använder i18next någon annanstans i din stack. Stöd för App Router fungerar, men kräver mer manuell konfiguration.
Lingui passar lag som redan använder .po-filer i sina arbetsflöden. Översättningarna hämtas vid kompilering, vilket innebär att meddelanden som inte används aldrig skickas med.
💡 Paraglide JS hör inte direkt till de stora aktörerna, men det är värt att nämna som ett kompilatorbaserat alternativ som ger mindre paketstorlek. Om du är intresserad måste du dock räkna med att dess ekosystem är yngre än de andras.
När det gäller formatering av datum och tal använder next-intl de inbyggda Intl-API:erna via useFormatter. De övriga biblioteken delegerar till FormatJS eller låter dig själv anropa Intl.DateTimeFormat och Intl.NumberFormat direkt.
💡 Dessa bibliotek sköter själva visningen. Det krävs fortfarande att någon tar fram översättningarna och ser till att de hålls uppdaterade när innehållet ändras. Weglot på en helt annan nivå och hanterar översättningsinnehållet via en omvänd proxy utanför kodbasen. Se det inte som en ersättning för ett bibliotek.
I Next.js 16 har filen middleware.ts bytt namn till proxy.ts. Detta gjordes eftersom termen ”middleware” var missvisande och antydde allmän logik inuti applikationen. I själva verket körs filen vid nätverksgränsen, där den avlyssnar och modifierar förfrågningar precis som en proxy innan de når applikationen.
Här är en komplett implementering för lokalisering och omdirigering som fyller i de utelämnade delarna i den officiella dokumentationen:
// 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)
}
Filer placeras under app/[språk]/, med en ordböcker/ mappen bredvid dina layouter och sidor. Rotlayouten får språkinställning som ett argument och ställer in det på html tagg:
export default async function RootLayout({ children, params }) {
const { locale } = await params
return (
<html lang={locale}>
<body>{children}</body>
</html>
)
}
När det gäller översättningar visar den officiella dokumentationen ett enkelt ordboksmönster som inte kräver något bibliotek:
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]()
Detta fungerar, men har inget stöd för pluralformer eller interpolering. nästa-intl omfattar båda via getTranslations() och useTranslations() i Serverkomponenter och klientkomponenter respektive.
Hur som helst bearbetas översättningsfilerna på servern och endast den resulterande HTML-koden skickas till webbläsaren, så storleken på meddelandefilerna påverkar inte storleken på klientpaketet.
För klientkomponenter bör du, där det är möjligt, skicka översatta strängar som egenskaper från en överordnad serverkomponent. Använd NextIntlClientProvider med en begränsad delmängd av meddelanden endast när en klientkomponent behöver hantera översättningar direkt.
I en språkväljare visar en serverkomponent språkinställningarnas etiketter, medan en klientkomponent hanterar useRouter() anrop:
// LocaleSwitcher.tsx (Server Component)
import LocaleSwitcherClient from './LocaleSwitcherClient'
export default function LocaleSwitcher({ locale }) {
return <LocaleSwitcherClient locale={locale} labels={{ en: 'English', fr: 'Français' }} />
}Klienten övervakar ändringar i valet och skickar den nya språkinställningen:
// 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>
)
}Om du använder Weglot gäller inget av detta. Weglot en inbyggd widget för språkväxling och kräver varken proxykonfiguration eller mellanprogramvara.
Ingen av routrarna hanterar flerspråkig SEO automatiskt:
html lang korrekt, men enligt dokumentationen är implementeringen av hreflang ”upp till dig”.Med App Router kommer du med Metadata API:et närmast automatisering. Definiera lokala URL:er i genereraMetadata via alternativa språk objekt och Next.js injicerar automatiskt link rel="alternate" hreflang="..." taggar:
export async function generateMetadata({ params: { locale } }) {
return {
alternates: {
languages: {
'en': 'https://example.com/en',
'fr': 'https://example.com/fr',
'de': 'https://example.com/de',
},
},
}
}Det manuella arbetet består i att samla in rätt URL för varje språkvariant per sida. Den logiken får du skriva själv.
Det finns två andra saker som måste göras manuellt, oavsett vilken router du använder. Kanoniska URL:er måste ställas in per språkversion för att undvika signaler om dubblettinnehåll. Din sitemap.ts behov xhtml:länk poster för varje språkvariant av varje sida.
På hreflang värdet i sig, användning hreflang="en-US" när man riktar sig till en viss region, och hreflang="en" när man riktar sig till alla engelsktalande. Att blanda ihop dessa skickar motstridiga signaler till sökmotorerna.
nästa-intl lägger till en delvis automatisering: dess proxy infogar automatiskt hreflang Länk svarhuvuden när du använder routning med lokaliserade sökvägar. Andra routningskonfigurationer kräver fortfarande manuell implementering.
Det innebär en betydande mängd löpande underhåll i takt med att din webbplats växer. Lyckligtvis sköter Weglot omvända proxy allt automatiskt på servern, så att översatta sidor kan indexeras fullt ut utan extra kod.
Weglot omvända proxy sköter faktiskt automatiskt allt som beskrivs i föregående avsnitt: hreflang-taggar, översatta webbadresser, kanoniska taggar och skapande av webbplatskartor. De översatta sidorna levereras på serversidan, vilket innebär att de är fullt indexerbara av sökmotorer.
⚠️ snippet Weglot JavaScript snippet ger inga SEO-fördelar. Översättningar på klientsidan kan inte indexeras. Om SEO är viktigt krävs det att man konfigurerar en omvänd proxy.
En ytterligare fördel är byggtiden. Weglot översatta sidor från sitt eget CDN istället för att generera dem vid byggtillfället. Att lägga till 10 språk till en webbplats Weglot påverkar inte hur lång tid det tar nästa version tar.
Vilket alternativ som är rätt beror på vad du vill uppnå.
Om du bygger på App Router och börjar från grunden, nästa-intl är standardvalet. Det omfattar routing, översättningar, automatisk komplettering i TypeScript och stöd för RSC i ett enda paket.
Om du använder Pages Router eller redan har i18next i din stack, react-i18next är den väg som möter minst motstånd.
Om flerspråkig SEO och löpande översättningshantering är prioriterat löser inget av biblioteken problemet fullt ut. Du måste fortfarande implementera hreflang, webbplatskartor och ett arbetsflöde för att hålla översättningarna uppdaterade när innehållet ändras. Weglot omvända proxy sköter allt detta automatiskt.
Weglot ett bibliotek på komponentnivå utesluter inte varandra. Weglot på HTML- och proxynivå, vilket innebär att det kan användas tillsammans med vilket bibliotek dina komponenter än använder.
Om den här metoden passar din situation kan du börja med att kolla in Weglot sida om JavaScript-integration och prova vår 14-dagars gratis provperiod!
Det bästa sättet att förstå Weglot kraft Weglot att se det själv. Testa det gratis och utan förpliktelser.
En demowebbplats finns tillgänglig i din instrumentpanel om du inte är redo att ansluta din webbplats ännu.