Passer au contenu
Mises à jour produits

Comment nous avons localisé notre site en 9 langues avec Astro

Alex Rivera6 min de lecture

Nous avons déployé le routage localisé pour 9 langues ce sprint. Voici la version honnête de la façon dont cela s’est passé — y compris le bug qui nous pénalisait discrètement en production avant qu’on ne le remarque.

La découverte

Lors du Sprint 1, nous avions construit l’échafaudage i18n attendu : des fichiers JSON de locale pour les 9 langues (anglais, espagnol, arabe, allemand, français, japonais, portugais, russe, chinois), un utilitaire getTranslation(), getLocalePath() pour construire des URL tenant compte de la langue, et des balises hreflang sur chaque page pointant vers les 9 variantes linguistiques.

Ce que nous n’avions pas construit : de véritables pages à ces URL localisées.

Chaque page dans src/pages/ codait en dur const locale = "en" as const. La plomberie de traduction existait et fonctionnait — mais rien ne se trouvait derrière. Cela signifiait que BaseLayout.astro émettait des balises hreflang telles que https://proman365.com/es/pricing/ sur chaque page, pour des URL qui renvoyaient une 404 en production.

Ce n’est pas un bug cosmétique. Les moteurs de recherche utilisent les balises hreflang pour comprendre quelles URL sont des variantes linguistiques les unes des autres. Annoncer des 404 à grande échelle est un signal SEO négatif actif — cela indique aux robots d’indexation que les métadonnées de votre site ne correspondent pas à la réalité, ce qui érode la confiance envers l’ensemble de vos métadonnées, pas seulement la partie défaillante.

Le correctif : extraction de templates, pas duplication

La correction naïve consiste à copier chaque page 8 fois, une par langue non anglaise, en codant en dur une constante de langue différente dans chaque copie. Nous avons rejeté cette approche immédiatement — 8 fois plus de fichiers signifie 8 fois plus de dérive dès que quelqu’un modifie une page en oubliant les 7 autres copies.

L’approche retenue à la place : extraire le contenu de chaque page dans un composant de template qui reçoit locale en tant que prop, puis faire le rendu de ce template depuis deux types de routes.

Pour les 12 pages de niveau 1 (accueil, tarifs, contact, partenaires, aide, et les six pages de fonctionnalités), chacune est passée de src/pages/*.astro à src/page-templates/*.astro, la constante de langue codée en dur étant remplacée par :

interface Props {
  locale: Locale;
}
const { locale } = Astro.props;

La route anglaise d’origine devient un wrapper léger — quelques lignes qui importent simplement le template et le rendent avec locale="en". Une nouvelle route miroir sous src/pages/[locale]/ rend le même template pour les 8 langues non anglaises, en utilisant getStaticPaths() pour générer une page par langue.

Cela a fonctionné proprement car la logique de chaque page de niveau 1 — getTranslation(locale), les générateurs de balises meta, le balisage schema — était déjà paramétrée sur cette seule constante locale héritée de l’échafaudage du Sprint 1. Nous ne rétrofittions pas l’i18n dans ces pages ; nous branchions enfin une i18n qui restait inutilisée.

Résultat : 96 nouvelles pages statiques (12 pages × 8 langues) issues du déploiement des pages de niveau 1, suivies d’une seconde passe étendant le même modèle aux 64 pages de comparaison (8 concurrents × 8 langues).

Verrouiller hreflang derrière une prop localized

Corriger la lacune de routage ne résout pas automatiquement le problème hreflang — il faut encore que les balises n’affirment que ce qui est réellement vrai. Nous avons ajouté une prop localized?: boolean à BaseLayout et PageLayout, avec une valeur par défaut de false.

Quand localized vaut false, une page émet exactement deux balises hreflang : en et x-default. Quand elle vaut true, elle émet l’ensemble complet de 10 (les 9 langues plus x-default). Seuls les templates de niveau 1 et les pages de comparaison passent localized={true}.

Fixer la valeur par défaut à false était un choix de sécurité délibéré. Une page doit explicitement opter pour affirmer qu’elle possède 9 variantes linguistiques. Si quelqu’un ajoute une nouvelle page demain et oublie de penser aux langues, l’échec est sans danger — des métadonnées uniquement en anglais, pas une nouvelle vague d’URL fantômes.

Ce que nous avons délibérément choisi de ne pas localiser

Tout n’a pas reçu le traitement linguistique, et c’était une décision, pas un oubli :

  • Le blog reste uniquement en anglais indéfiniment. C’est une pratique standard pour les blogs marketing SaaS, et la traduction automatique de contenu long produit un texte de moins bonne qualité que l’absence de traduction. Si les analyses le justifient un jour, nous reviendrons sur ce choix avec du contenu dédié par langue.
  • Les pages légales (confidentialité, conditions, politique de cookies) restent en anglais. Ce texte est généré par Termly ; le traduire n’est pas une décision que nous sommes en mesure de prendre unilatéralement.
  • La page 404 reste en anglais — l’hébergement statique sert une 404 unique quel que soit le chemin demandé, donc il n’y a pas de moyen propre de la localiser sans un modèle d’hébergement différent.
  • Le flux RSS était déjà uniquement en anglais et correctement exclu du hreflang ; aucun changement nécessaire ici.

La checklist à retenir

Si vous faites quelque chose de similaire sur un site statique Astro :

  1. Auditez avant de construire. Vérifiez si vos balises hreflang pointent vers des pages qui existent réellement. Si votre échafaudage i18n précède votre routage, vous avez peut-être déjà ce bug.
  2. Extrayez des templates, ne dupliquez pas les pages. Un template par page, des routes wrapper légères spécifiques à la langue par-dessus. La dérive se produit au niveau du wrapper si elle se produit, et les wrappers sont bon marché à maintenir synchronisés.
  3. Fixez par défaut les affirmations de métadonnées à l’énoncé vrai le plus restreint. Un indicateur localized par défaut sur « non » signifie que les nouvelles pages ne peuvent pas accidentellement surestimer leur portée.
  4. Décidez ce qui reste non traduit, délibérément, et documentez-le. Le blog, les pages légales et les pages d’erreur sont des candidats raisonnables à exclure — mais faites-en une décision documentée, pas un silence.
  5. Traduction et routage sont des problèmes distincts. Déployer les routes ne nécessite pas de terminer les traductions — un texte de repli en anglais dans une véritable route localisée reste plus honnête qu’une clé de traduction fonctionnelle sans route derrière.

Il nous reste encore du travail de traduction manuelle — de nombreuses chaînes dans les fichiers de langue non anglais sont des textes de remplacement en anglais en attente d’un traducteur humain. Mais les URL sont désormais réelles, et les métadonnées ont cessé de mentir. C’était le problème le plus urgent.

PartagerXLinkedIn

Alex Rivera

Chef de projet et consultant en flux de travail. Aide les équipes à trouver des outils adaptés à leur façon réelle de travailler.

Restez au courant

Recevez des conseils de gestion et des mises à jour produits. Pas de spam, désabonnez-vous à tout moment.

Prêt à simplifier votre suite d'outils ?

Essayez Proman gratuitement — aucune carte de crédit requise.

Commencer gratuitement →