fix(seo): canoniques cross-locale et URLs noindex au sitemap#264
Merged
Conversation
… noindex URLs Four defects seo-geo-auditor surfaced during #258, all pre-existing and all silent — nothing failed, Search Console would simply have reported errors weeks later. Cross-locale canonicals. faq and the three legal pages hardcoded `alternates: { canonical: '/faq' }`, never prefixed. When a segment declares alternates, Next REPLACES the parent value instead of recomputing it per locale, so /en/faq emitted a canonical pointing at the French page — telling Google the English version is a duplicate, while the hreflang header for that same URL said otherwise. The glossary index declared no alternates at all and therefore inherited the parent layout's canonical: /glossaire, /en/glossaire and /nl-BE/glossaire each canonicalised to their own homepage. Its sibling [slug] page did this correctly; the index never did. It now emits the same `languages` block too — omitting it would have repeated, on the fix itself, the canonical-without- hreflang defect this commit closes. Noindex pages in the sitemap. The three legal pages set robots.index=false yet were submitted for all five locales: 15 URLs guaranteed to come back as "Submitted URL marked noindex". They are out of PUBLIC_ROUTES. robots.txt is deliberately left alone — disallowing them would stop Google reading the very noindex tag that removes them. Untranslated locales. The sitemap advertised nl-BE, de-DE and es-ES for the marketing routes while their landing copy is still French verbatim. It now iterates LOCALES_VISIBLE. The glossary keeps its own wider GLOSSARY_LOCALES scope, because those three locales genuinely have translated terms — an asymmetry worth stating rather than silently aligning. Locale now comes from `params` rather than `getLocale()`. The latter worked only because the locale layout happens to call `cookies()` for the theme, which forces dynamic rendering; reading the segment removes that hidden coupling and matches the glossary pages. tests/seo/sitemap.test.ts locks all of it: no noindex route, no untranslated locale outside the glossary, no duplicate URL, and no hreflang pointing at a URL the sitemap omits. Verified falsifiable — restoring either regression turns two specs red. Measured on a production build: 0 legal URLs in the sitemap, /en/faq now canonicalises to itself, and the glossary index emits its three hreflang links. Left out on purpose: next-intl's middleware Link header still advertises all five locales, which is broader than what the sitemap now submits. Fixing it means touching proxy.ts, which the routing note reserves for a dedicated PR. public/llms.txt still claims Dutch is an operating language; a one-line fix, tracked separately rather than smuggled in here.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Contributor
There was a problem hiding this comment.
Sorry @thierryvm, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
thierryvm
added a commit
that referenced
this pull request
Jul 26, 2026
…SEO (#265) Handoff de fin de session. Documentation uniquement, 1 fichier. **Livré** : #261 (redirections localisées), #262 (registre des destinations de nav), #263 (sélecteur de langue), #264 (SEO) — toutes mergées. **Reste à faire, ordonné** : le lot 2 de la refonte UX en tête, avec les trois limites que le lot 1 s'est explicitement interdit de traiter reprises comme entrées plutôt que laissées à re-découvrir. Puis la reconnexion fantôme, sans diagnostic à ce jour. Puis les dettes tracées. **Frictions d'environnement consignées** parce qu'elles ont coûté du temps deux fois chacune : `playwright.config.ts` ne charge pas `.env.local`, `e2e:auth` sert un build prod où le rate limit échoue en fermé sur l'Upstash factice, la variable est `E2E_BASE_URL`, et le port 3000 appartient à un autre projet. Miroir dans le vault Obsidian, slug vérifié via `_index.md`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Corrige les 4 défauts SEO préexistants que
seo-geo-auditoravait relevés pendant #258. Tous silencieux : rien ne cassait, Search Console aurait juste remonté des erreurs des semaines plus tard.Ce qui était cassé
/faq,/legal/*)/en/faqdéclarait la page française comme canonique — soit « la version anglaise est un doublon », en contradiction avec le hreflang de la même URLalternates/glossaire,/en/glossaireet/nl-BE/glossairepointaient chacun vers leur accueilnoindexau sitemapMesuré sur build de production
/legal/*au sitemap/en/faq/faq/en/faq/en/glossaire/en/glossaireCe que l'audit a rattrapé sur mon propre correctif
L'index du glossaire n'émettait que la canonique, sans le bloc
languagesque sa page sœur[slug]produit déjà. J'aurais donc reproduit sur le correctif lui-même le défaut que la PR ferme : une canonique sans hreflang correspondant. Corrigé.Second point pris : la locale vient désormais de
paramset non degetLocale(). Ce dernier ne fonctionnait que parce que le layout appellecookies()pour le thème, ce qui force le rendu dynamique — un couplage implicite à un détail sans rapport.Tests
tests/seo/sitemap.test.ts(5 specs) verrouille : aucune route noindex, aucune locale non traduite hors glossaire, pas de doublon d'URL, et aucun hreflang pointant vers une URL absente du sitemap. Falsifiabilité vérifiée : en réintroduisant l'une ou l'autre régression, 2 specs passent au rouge.npm run test1674/1674 ·typecheck0 ·lint0 (7 warnings préexistants)Volontairement hors périmètre
Linkdu middleware next-intl annonce toujours les 5 locales, plus large que ce que le sitemap soumet désormais. Le corriger impliqueproxy.ts, que la note derouting.tsréserve à une PR dédiée.robots.txtne doit pas bloquer/legal/: Google ne pourrait plus lire lenoindexqui les retire réellement.public/llms.txtannonce toujours le néerlandais comme langue opérationnelle — correctif d'une ligne, tracé à part.