Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
YouTube Security VideosVisual Studio Code: VS Code Learn: Extending Agents(24.09.2026 um 21:00 Uhr)
•
YouTube Security VideosGoogle Cloud Tech: Turn Audio into Action with Gemini 3.5 Transcribe(24.09.2026 um 21:00 Uhr)
••••
Unix & Linux ServerUSN-8815-1: libass vulnerabilities(24.09.2026 um 16:57 Uhr)
•••••
YouTube Security VideosVisual Studio Code: VS Code Learn: Extending Agents(24.09.2026 um 21:00 Uhr)
•
YouTube Security VideosGoogle Cloud Tech: Turn Audio into Action with Gemini 3.5 Transcribe(24.09.2026 um 21:00 Uhr)
••••
Unix & Linux ServerUSN-8815-1: libass vulnerabilities(24.09.2026 um 16:57 Uhr)
•••••
Intelligence View
⚡ tsecurity.de Intelligence

hreflang in Next.js 16: 3 mistakes that quietly delete your translated pages from Google

TL;DR — If you ship the same page in several languages, hreflang is what tells Google "these are translations of each other, not duplicates." Three mistakes make Google ignore (or actively penalize) your setup: a non-reciprocal cluster, h…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

TL;DR — If you ship the same page in several languages, hreflang is what tells Google "these are translations of each other, not duplicates." Three mistakes make Google ignore (or actively penalize) your setup: a non-reciprocal cluster, hreflang pointing at URLs that 404, and a canonical that points at the English master instead of the page itself. None throws an error. None fails your build. You only catch them by reading the rendered <head>. Here's the Next.js 16 Metadata API pattern that avoids all three.




Multilingual SEO has a cruel property: the failure mode is silence. Your translated pages render fine, your build is green, TypeScript is happy — and Google quietly decides your French page is a duplicate of your English one and drops it. No error anywhere. This post is the checklist I wish I'd had.



I'll use a fictional example.com throughout. The pattern is framework-light: no i18n library, just the Next.js 16 Metadata API's alternates field and a small helper.









The shape: one helper, per-page locale sets



alternates.languages in the Metadata API renders the <link rel="alternate" hreflang="..."> tags for you. A tiny helper keeps it consistent:




// lib/hreflang.ts
type Locale = "en" | "fr" | "es" | "de" | "nl" | "ar";

/**
* availableLocales: ONLY the locales where a translated page actually exists.
* selfLocale: so the canonical is self-referential (the page points at itself,
* never at the English master).
*/

export function buildHreflang(
path: string,
availableLocales: readonly Locale[],
selfLocale: Locale = "en",
baseUrl = "https://example.com",
) {
const suffix = path === "/" ? "" : path;
const languages: Record<string, string> = {};
for (const loc of availableLocales) {
languages[loc] = loc === "en" ? `${baseUrl}${path}` : `${baseUrl}/${loc}${suffix}`;
}
languages["x-default"] = `${baseUrl}${path}`;

const canonical =
selfLocale === "en" ? `${baseUrl}${path}` : `${baseUrl}/${selfLocale}${suffix}`;

return { canonical, languages };
}






Used per page:




// app/es/widgets/page.tsx
export const metadata: Metadata = {
alternates: buildHreflang("/widgets", ["en", "fr", "es"], "es"),
};






That availableLocales argument is the whole game. It is not the same for every page, and getting it wrong is mistake #2. Pick it per page, from what actually exists:
























Page Locales it exists in
/widgets en, fr, es
/pricing en, fr
/guide en, fr, es, de, nl


Don't translate every page into every language just to fill the grid. Translate the pages that match each market — and declare only those.









Mistake #1: non-reciprocal hreflang (the cluster-killer)



Google's rule is bidirectional. If page A says "my Spanish version is B," then B must say "my English version is A." If the link goes only one way, Google doesn't ignore just that edge — it distrusts the entire cluster.



The classic version: three pages in a cluster, two of them declare ["en", "fr", "es"], and the third declares only ["en", "es"] — missing fr.




// app/es/widgets/page.tsx — BROKEN
buildHreflang("/widgets", ["en", "es"], "es")
// ^^^^ missing "fr", but /fr/widgets exists and points here






/fr/widgets points at /es/widgets, but /es/widgets doesn't point back. Non-reciprocal → Google treats the translations as unrelated duplicates competing with each other. No error, no warning.



The only reliable defense: grep every hreflang declaration and confirm the locale arrays are identical across a cluster. Same array, every page.









Mistake #2: declaring hreflang to a URL that 404s



Worse than missed signal — this is an outright penalty. Google's docs are explicit: an hreflang annotation pointing to a URL that 404s, redirects, or is noindex is invalid. Enough invalid annotations and Google distrusts your whole setup.



The trap is an aspirational "supported locales" list:




// A loaded gun
const SUPPORTED = ["en", "fr", "es", "de", "nl"]; // ...but /de/* doesn't exist yet






The day someone wires that into a sitemap or a language switcher, it emits <link hreflang="de"> tags to a wall of 404s.



Rule: a "supported locales" list must never be aspirational. It maps to what returns 200, not what you plan to build. If /de/widgets doesn't exist, de must not appear in that page's hreflang — full stop.









Mistake #3: the canonical that deindexes your translation



The subtle one. On /fr/widgets, what should <link rel="canonical"> point to?



The intuitive, wrong answer: the English master, /widgets. "It's the same page," right?



No. A canonical from /fr/widgets → /widgets tells Google: "the French page is a duplicate; index the English one instead." You just asked Google to deindex your French page.



Canonical and hreflang do different jobs:





  • canonical = self-referential. /fr/widgets canonicals to /fr/widgets. ("This is the authoritative version of this URL.")


  • hreflang = declares the language siblings.



That's why the helper derives canonical from selfLocale, not from the English path.









How to verify (because nothing throws)



Every one of these is invisible to TypeScript, the build, and next dev. The only source of truth is the rendered HTML of a production build. So the test is a curl against next start, not a unit test:




next build && next start -p 3100 &

for p in es/widgets widgets fr/widgets; do
curl -s "http://localhost:3100/$p" | node -e '
let h=""; process.stdin.on("data",d=>h+=d).on("end",()=>{
const canon=(h.match(/<link rel="canonical" href="([^"]+)"/i)||[])[1];
const hl=[...new Set([...h.matchAll(/hreflang="([^"]+)"/gi)].map(m=>m[1]))];
console.log(`/${p}\n canonical: ${canon}\n hreflang: ${hl.join(", ")}`);
});'

done






The shape Google trusts: every page in the cluster reports the same hreflang set, and each canonical points at itself:




/es/widgets
canonical: https://example.com/es/widgets
hreflang: en, fr, es, x-default
/widgets
canonical: https://example.com/widgets
hreflang: en, fr, es, x-default
/fr/widgets
canonical: https://example.com/fr/widgets
hreflang: en, fr, es, x-default






Identical hreflang arrays, self canonicals. If your pages report different hreflang sets, you have mistake #1.









Bonus: write native, don't auto-translate



A hreflang setup is worthless if the pages behind it are machine-translated mush. Google's gotten good at detecting it, and readers feel it in two sentences. If a market matters enough to target, write the page natively. The technical wiring above is the easy 20%; native copy is the other 80%.



And if two of your localized pages are adjacent in meaning (say a "free" page and a "pro" page), differentiate them in every locale — or you've just exported keyword cannibalization into a new language.









Quick checklist




  • [ ] Every page's hreflang array is identical across its cluster (reciprocal)

  • [ ] Every hreflang URL returns 200 (no 404 / redirect / noindex targets)

  • [ ] Every localized page's canonical points at itself, not the English master

  • [ ] x-default points at your default (usually English)

  • [ ] You verified against the rendered <head> of a production build, not the source









See a reciprocal cluster in the wild



Theory is cheap — go curl a real one. These are live pages that share a reciprocal hreflang cluster, each with a self-referential canonical. Run the curl snippet above against any of them and you'll see the same hreflang line repeated across the set:





Notice the two clusters declare different locale sets — that's mistake #2 avoided in practice: each page only lists the languages it actually exists in.






I build PageStrike, a free AI landing page builder that ships pages in English, French, Spanish, German, Dutch, and Arabic — so this checklist is hard-won. If you handle the locale matrix differently (sitemap-driven or Edge-Config-driven instead of per-page args), I'd like to hear it in the comments — the per-page approach is clean at a handful of pages; I'm not sure it scales to seventy.

CTI Threat Relationship Graph2 Knoten / 1 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
SOC Incident Playbook: Remote Code Execution (RCE) Defense
Syntax validiert (0 Fehler)
title: Detect Exploitation - hreflang in Next.js 16: 3 mistakes that quietly delete your translated pages from Google
id: e8444b4b-3454-4dde-9a5f-75cb3c844b2e
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-24
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
Syntax validiert (0 Fehler)
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-24"
        description = "YARA Signature for "
    strings:
        $str = "hreflang in Next.js 16: 3 mist" ascii wide
    condition:
        any of them
}
Syntax validiert (0 Fehler)
index=security sourcetype IN ("cisco:asa", "pan:traffic", "zeek_conn", "suricata", "WinEventLog:Security")
("hreflang in Nextjs 16 3 mistakes that qu")
| stats count earliest(_time) as first_seen latest(_time) as last_seen by src_ip, dest_ip, dest_host, signature
| eval first_seen=strftime(first_seen, "%Y-%m-%d %H:%M:%S"), last_seen=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
| sort - count
Syntax validiert (0 Fehler)
message: "*hreflang in Nextjs 16 3 mistakes that qu*"
Syntax validiert (0 Fehler)
CommonSecurityLog
| where Message has "hreflang in Nextjs 16 3 mistakes that qu"
| summarize EventCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, DestinationPort, Activity
| extend DetectionRule = "iShareStuff-CTI-Compiled"
| sort by EventCount desc
🎯
MITRE ATT&CK Matrix Navigator 14 Taktiken
Reconnaissance
-
Resource Development
-
Initial Access
Execution
Persistence
-
Privilege Escalation
Defense Evasion
Credential Access
-
Discovery
-
Lateral Movement
-
Collection
-
Command and Control
Exfiltration
-
Impact
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich hreflang in Next.js 16: 3 mistakes that .... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

⚡ Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten hreflang in Next.js 16: 3 mistakes that quietly delete your translated pages from Google

Thematisch verwandte Begriffe: hreflang, Nextjs, mistakes, that · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-61823 | code16 Sharp is a Laravel-based framework for building content-managemen…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel • Rechts: nächster Artikel • unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel TTP ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...
↗ Original-Quelle