Mein Platz in der WordPress-Community
- Mein wordpress.org-Konto besteht seit 2006.
- Ich habe zum WordPress-Core in den Versionen 7.0 und 7.1 beigetragen.
- Ich betreue 30 Plugins auf wordpress.org.
- Ich organisiere WordCamps und trete dort als Speaker auf.
- Ich war bei jedem WordCamp Europe von 2017 bis 2026 dabei.
Warum reichen zwei Sprachen für eine Berner Website oft nicht?
Die Amtssprachen des Bundes sind nach Art. 70 der Bundesverfassung Deutsch, Französisch und Italienisch (Fedlex, SR 101). Wer von Bern aus Bundesstellen, Verbände oder Kundschaft in der ganzen Schweiz anspricht, kommt mit einer einzigen Sprachfassung selten aus. Das Bundesamt für Statistik nennt für 2024 folgende Hauptsprachen: Deutsch 61 Prozent, Französisch 23, Italienisch 8 Prozent der Bevölkerung, dazu 24 Prozent Nichtlandessprachen (BFS, Sprachen). Ebenfalls laut BFS sprachen 2024 rund 28 Prozent der Erwerbstätigen bei der Arbeit üblicherweise mehrere Sprachen.
Ich bin Mariusz Szatkowski, ein einzelner Entwickler in Gdynia, und arbeite mit WordPress seit 2006 und mit Next.js an Frontends, die mehr als eine Sprache ausliefern. Diese Seite zeigt, wie ich dreisprachiges Routing im App Router aufbaue. Der Zweisprachen-Fall Deutsch und Französisch im Kanton Bern steht bei meiner Migrationsseite für Bern. Hier geht es um die technische Seite für drei Sprachen: Sprachsegment, Spracherkennung, statische Seiten und hreflang.

Foto: Paranoid, Public domain, Wikimedia Commons.
Alle Codebeispiele unten habe ich mit Next.js 16.4.6 gebaut und ausgeführt, die Aussagen zur Dokumentation stammen von den Seiten auf nextjs.org (Stand 6. November 2026).
Wie sieht das Sprachsegment im App Router aus?
Die Dokumentation von Next.js empfiehlt, die Sprache über einen Unterpfad (/fr/produkte) oder eine Domain (meine-seite.fr/produkte) zu führen (Internationalization). Für die Schweiz nehme ich Unterpfade: /de, /fr, /it. Eine Domain pro Sprache bedeutet mehr Zertifikate, mehr DNS und getrennte Auswertung, ohne dass die Leserschaft etwas gewinnt.
Alle Spezialdateien in app/ gehören dazu unter app/[lang], damit der Router den Parameter lang an jedes Layout und jede Seite weitergibt:
app/
[lang]/
layout.tsx
page.tsx
kontakt/page.tsx
dictionaries/de.json, fr.json, it.json
proxy.tsDie Wörterbücher laden Server Components. Die Dokumentation weist darauf hin, dass die Dateigrösse der Übersetzungen damit nicht ins JavaScript-Bundle des Browsers wandert, weil der Code nur auf dem Server läuft. Eine unbekannte Sprache fängt notFound() ab:
// lib/alternates.ts
export const locales = ['de', 'fr', 'it'] as const
export type Locale = (typeof locales)[number]
export const hasLocale = (value: string): value is Locale =>
(locales as readonly string[]).includes(value)Wie erkenne ich die Sprache im Proxy?
Die Frage, ob das Middleware oder Proxy heisst, beantwortet die aktuelle Dokumentation eindeutig: Die Konvention middleware ist veraltet und heisst seit Next.js 16.0.0 proxy (proxy.js). Das Release erschien laut npm-Registry am 22. Oktober 2025. Die Funktion bleibt dieselbe, ein Codemod (npx @next/codemod@canary middleware-to-proxy .) benennt Datei und Funktion um. Auf einem Projekt mit Next.js 15 oder älter bleibt es bei middleware.ts.
Die Dokumentation gleicht die Spracheinstellung des Browsers mit der Kopfzeile Accept-Language ab, mit @formatjs/intl-localematcher und negotiator. Meine Fassung für die drei Landessprachen, ergänzt um einen Matcher, der Dateien mit Endung und /api auslässt:
// proxy.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { match } from '@formatjs/intl-localematcher'
import Negotiator from 'negotiator'
const locales = ['de', 'fr', 'it']
export function proxy(request: NextRequest) {
const { pathname } = request.nextUrl
if (locales.some((l) => pathname === `/${l}` || pathname.startsWith(`/${l}/`))) return
const headers = { 'accept-language': request.headers.get('accept-language') ?? '' }
const languages = new Negotiator({ headers }).languages()
request.nextUrl.pathname = `/${match(languages, locales, 'de')}${pathname}`
return NextResponse.redirect(request.nextUrl)
}
export const config = {
matcher: ['/((?!_next|api|.*\\..*).*)'],
}Den Matcher habe ich geändert, weil das Beispiel der Dokumentation nur _next ausschliesst. Dateien aus public wie robots.txt bekämen sonst ebenfalls ein Sprachpräfix. Im Test lieferte ein Aufruf von /kontakt mit fr-CH,fr;q=0.9 eine Weiterleitung auf /fr/kontakt, mit en-US auf /de/kontakt und mit it-CH,it;q=0.9,de;q=0.5 auf /it/kontakt. Englische Browser landen damit auf Deutsch, das ist die Standardsprache, die ich festlege.
Die Dokumentation grenzt den Proxy ausdrücklich ein: Er eignet sich nicht für langsame Datenabfragen, und für einfache Weiterleitungen soll zuerst die redirects-Konfiguration in next.config.ts geprüft werden (Proxy). Für die Sprachwahl braucht es Request-Daten, deshalb ist der Proxy hier richtig. Mehr als diese Weiterleitung gehört nicht hinein.
Wie rendert generateStaticParams jede Sprache vorab?
Mit generateStaticParams im Layout app/[lang]/layout.tsx erzeugt Next.js beim Build für jede Sprache eine statische Fassung. Die Dokumentation zeigt genau dieses Muster mit [{ lang: 'en-US' }, { lang: 'de' }]. Für Bern sieht es so aus:
// app/[lang]/layout.tsx
import type { Metadata } from 'next'
import { locales } from '@/lib/alternates'
export const dynamicParams = false
export const metadata: Metadata = {
metadataBase: new URL('https://www.example.ch'),
}
export async function generateStaticParams() {
return locales.map((lang) => ({ lang }))
}
export default async function RootLayout({
children,
params,
}: {
children: React.ReactNode
params: Promise<{ lang: string }>
}) {
const { lang } = await params
return (
<html lang={`${lang}-CH`}>
<body>{children}</body>
</html>
)
}dynamicParams = false bewirkt laut Dokumentation, dass jeder nicht erzeugte Pfad mit 404 antwortet. Damit liefert /en/kontakt keinen Inhalt, der sonst erst zur Laufzeit entstünde. metadataBase ist die Basis für die relativen Pfade in den hreflang-Links weiter unten.
Wichtig bei Seiten mit weiteren dynamischen Segmenten, etwa app/[lang]/produkte/[slug]/page.tsx: Die Dokumentation erlaubt, Parameter für Segmente oberhalb der aktuellen Seite zu erzeugen, aber nicht unterhalb. Die Seite [slug] erzeugt deshalb beide Parameter, lang und slug, in einer Liste, und zwar für jede Sprache, in der es das Produkt gibt. Fehlt eine Übersetzung, entsteht die Seite in dieser Sprache nicht, und der Rückverweis in hreflang darf sie nicht aufführen.
Wie setze ich hreflang mit der Metadata API?
Die Metadata API erzeugt hreflang-Links über alternates.languages; canonical steht im selben Objekt (generateMetadata). Das Beispiel der Dokumentation nutzt en-US und de-DE. In den Typen des Pakets next 16.4.6 sind zudem de-CH, fr-CH, it-CH und x-default als Schlüssel zugelassen. Meine Hilfsfunktion:
// lib/alternates.ts (Fortsetzung)
import type { Metadata } from 'next'
export function alternatesFor(lang: Locale, path = ''): Metadata['alternates'] {
return {
canonical: `/${lang}${path}`,
languages: {
'de-CH': `/de${path}`,
'fr-CH': `/fr${path}`,
'it-CH': `/it${path}`,
'x-default': `/de${path}`,
},
}
}// app/[lang]/kontakt/page.tsx
import type { Metadata } from 'next'
import { notFound } from 'next/navigation'
import { alternatesFor, hasLocale } from '@/lib/alternates'
export async function generateMetadata(
{ params }: { params: Promise<{ lang: string }> },
): Promise<Metadata> {
const { lang } = await params
if (!hasLocale(lang)) notFound()
return { alternates: alternatesFor(lang, '/kontakt') }
}Die gebaute Seite /fr/kontakt enthält daraufhin <link rel="canonical" href="https://www.example.ch/fr/kontakt"/> und vier rel="alternate"-Links mit hrefLang de-CH, fr-CH, it-CH und x-default, jeweils mit vollständiger Adresse. Die Alternativen gehören in die einzelne Seite, nicht ins Layout, weil sie den Pfad der Seite enthalten. Im Layout stünde auf jeder Unterseite die Adresse der Startseite.
Die Regeln dahinter stehen in der Google-Dokumentation zu lokalisierten Versionen:
- Jede Fassung verweist auf alle anderen und auf sich selbst. Fehlt ein Rückverweis, können die Angaben ignoriert werden.
- Der erste Teil ist ein Sprachcode nach ISO 639-1, der zweite optional ein Ländercode nach ISO 3166-1 Alpha 2. Nicht aufgeführte Codes wie
es-419werden nicht unterstützt. x-defaultist für Besucher gedacht, auf die keine Sprache passt, etwa für eine Seite mit Sprachwahl oder eine automatisch weiterleitende Startseite. Dass ich dafür die deutsche Fassung nehme, ist meine Wahl und keine Vorgabe.
Welche Fehler sehe ich bei mehrsprachigen Next.js-Seiten am häufigsten?
Diese Liste ist aus der Dokumentation und aus meinem Testaufbau abgeleitet, nicht aus Kundenprojekten:
| Stolperstelle | Folge | Gegenmassnahme |
|---|---|---|
Matcher des Proxys schliesst nur _next aus | robots.txt und Bilder aus public werden umgeleitet | Matcher um Dateien mit Endung und /api ergänzen |
| hreflang im Layout statt auf der Seite | Jede Unterseite verweist auf die Startseiten-Adressen | alternatesFor(lang, path) je Seite |
| Übersetzung fehlt, Seite existiert trotzdem | Leere oder gemischtsprachige Seite im Index | notFound() und Eintrag in generateStaticParams weglassen |
| Rückverweis fehlt | Google kann die Angaben ignorieren | Liste der Fassungen aus einer einzigen Quelle erzeugen |
lang im <html>-Tag fehlt oder ist falsch | Screenreader sprechen mit falscher Stimme | lang={${lang}-CH} im Layout |
| Proxy lädt Daten | Verzögerung vor jedem Seitenaufruf | Nur Header lesen und weiterleiten |
Was bringe ich mit, und was brauchen Sie von mir?
Ich baue Struktur, Routing, Wörterbücher, hreflang und die statische Ausgabe. Sie bringen die Texte in jeder Sprache mit, geprüft von jemandem, der die Sprache schreibt. Grafikdesign, Mockups und Wireframes kommen von Ihnen: Sie markieren in meiner Tabellenvorlage pro Ansicht, wo welches Element sitzt, und ich setze das responsiv um.
Der Ablauf ist schriftlich und remote, ohne Besprechungen:
- Sie schicken die Adresse der bestehenden Seite oder die Beschreibung des Vorhabens, die gewünschten Sprachen und den Termin.
- Ich stelle Rückfragen schriftlich, zum Beispiel ob alle Seiten in allen drei Sprachen existieren oder nur ein Teil.
- Ich schicke eine schriftliche Schätzung mit Umfang und Annahmen.
- Ich baue auf einer Staging-Umgebung, Sie prüfen jede Sprache dort.
- Nach Ihrer schriftlichen Abnahme geht die Seite live. Auf Wunsch betreue ich sie danach monatlich, nicht genutzte Stunden verfallen.
Technisch gelten für diese Seite die Schwellenwerte der Core Web Vitals: LCP bis 2,5 s, INP bis 200 ms, CLS bis 0,1. Eine eigene Messung pro Sprachfassung gehört zur Abnahme.
Häufige Fragen aus Bern
Heisst es middleware.ts oder proxy.ts?
Seit Next.js 16.0.0 heisst die Konvention proxy. Die Dokumentation nennt middleware veraltet und beschreibt eine Umbenennung, die Funktion bleibt dieselbe. Das Codemod npx @next/codemod@canary middleware-to-proxy benennt Datei und Funktion um. Bei Projekten auf Next.js 15 oder älter bleibt es bei middleware.ts.
Brauche ich next-intl oder reicht der Ansatz aus der Dokumentation?
Für drei Sprachen mit überschaubaren Wörterbüchern reicht der Ansatz aus der Dokumentation: Sprachsegment, JSON-Wörterbücher, ein Proxy. Eine Bibliothek wie next-intl lohnt sich bei Pluralformen, Datums- und Zahlenformaten oder wenn Redaktionen Übersetzungen pflegen. Ich entscheide das nach Umfang der Texte, nicht nach Gewohnheit.
Soll die Startseite automatisch nach Browsersprache weiterleiten?
Nur auf die Fassung mit Sprachpräfix, und jede Fassung behält ihre eigene Adresse. Google empfiehlt für Einstiegsseiten, die automatisch umleiten, einen x-default-Eintrag. Wer in Bern mit einem französischen Browser auf die deutsche Seite kommt, braucht zudem einen sichtbaren Sprachwechsel.
Übersetzen Sie die Texte?
Nein. Texte in Deutsch, Französisch und Italienisch liefern Sie oder Ihre Übersetzerin. Ich baue die Struktur, die Wörterbücher und die Ausgabe, sodass eine fehlende Übersetzung im Build auffällt und nicht erst auf der Live-Seite.
Reicht hreflang mit de, fr und it ohne Länderangabe?
Technisch ja. Wer nur die Schweiz bedient, kann mit de-CH, fr-CH und it-CH Sprache und Land angeben. Ein Länderkürzel allein ist ungültig, und Google erwartet Rückverweise: Verweist die deutsche Seite auf die französische, muss die französische auf die deutsche zurückverweisen.
Übernehmen Sie Design und Layout?
Nein. Das Layout liefern Sie: Grafikdesign, Mockups und Wireframes kommen vom Auftraggeber. In meiner Tabellenvorlage tragen Sie pro Ansicht ein, welches Element wohin gehört, und ich baue danach.
Schreiben Sie mir
Über das Kontaktformular genügen vier Angaben: die Adresse Ihrer Seite oder des Repositories, die Sprachen, die Sie ausliefern wollen, Ihr Termin und der heutige Stand mit Next.js-Version und Router. Ich antworte schriftlich an Werktagen, zuerst mit offenen Fragen und danach mit einer Einschätzung. Die erste schriftliche Schätzung kostet nichts und bindet Sie nicht.
Ausgewählte Projekte
Beispiele aus meiner Arbeit.
E-Commerce-Entwicklung: nehrebeccy.pl
nehrebeccy.pl ist eine moderne künstlerische Agentur, die Erfahrung in der Organisation kultureller Veranstaltungen mit der Präsentation eines vielfältigen k...
E-Commerce-Entwicklung: nolaclub.pl
nolaclub.pl ist ein Onlineshop für Nagellacke und Kosmetik, mit Produktkatalog, Kaufprozess und technischem SEO.
E-Commerce-Entwicklung: osiedlegalaktyka.pl
Osiedlegalaktyka.pl ist ein professionelles Projekt in meinem WordPress-Entwickler-Portfolio, das als Website zur Bewerbung einer modernen Wohnsiedlung in St...
Brauchen Sie die Leistung: Next.js-Entwickler in Bern?
Beschreiben Sie Ihr Projekt per E-Mail. Antwort innerhalb von 48 Stunden.
Projekt beschreibenWeitere WordPress-Dienste und Wissensbasis entdecken
Migration zu Astro, Next.js und Headless WordPress.
WooCommerce-Synchronisierung mit ERP und Großhandel.
Geschäftsprozessautomatisierung rund um WordPress und Firmensysteme.
Bibliothek konkreter Automatisierungsfälle.
Headless WordPress, Sanity, Strapi und Contentful mit Astro oder Next.js.
Astro, MDX, Edge Delivery und an echtem Traffic gemessene Core Web Vitals.
Individuelle WordPress-Entwicklung und Architektur.
Skalierbare Headless-, ERP- und KI-Architektur für Enterprise.
Verwandte Kategorien
Unterstützende Artikel

Sechs bis sechzehn Wochen für typische Projekte, in vier Phasen: Analyse, Scoping, Build und Umstellung, Tuning. Die Variablen sind Katalogumfang, Anzahl der Integrationen, URL-Erhalt und die Bereitschaft des Redaktionsteams, nicht die Wahl des Frameworks.

Umfassende 4-Jahres-TCO-Analyse (Total Cost of Ownership), reale Core-Web-Vitals-Benchmarks, Astro 7 GraphQL APQ-Architektur und eine 10-Punkte-Entscheidungsmatrix für Enterprise-Entscheider zwischen entkoppeltem und traditionellem WordPress.

Die Entscheidung Shopify Plus vs WooCommerce headless im Jahr 2026 ist kein binärer "Plattform vs Custom"-Kompromiss mehr. Beide laufen headless, beide integrieren KI, beide liefern am Edge aus. Die echten Achsen sind Kontrolle, Gesamtkosten über fünf Jahre und Exit-Strategie. Dieser Artikel durchläuft die Entscheidungsmatrix mit bestätigten Plattformfakten.