Zola est le générateur statique de site (SSG) utilisé pour faire tourner ce site. La structure du site vient directement de la structure de fichiers Markdown qui sont transformés par zola. Il supporte les sites multilingues nativement. Dans cet article, je partage quelques astuces pour configurer correctement un tel site.
Internationalisation avec Zola
Zola est un programme écrit en rust, qui transforme des pages de contenus (des fichiers .md
dans le dossier content/
)
et des templates (des fichiers html définissant comment afficher le contenu) en un site web statiquement généré. Par exemple,
le contenu de cette page est écrit en français dans le fichier /content/blog/2025-08-20-zola-intl-routing.md
et
en anglais dans le fichier /content/blog/2025-08-20-zola-intl-routing.en.md
, et rundu en utilisant un template page.html
.
Dans les templates, quand un texte doit être traduit, il faut définir une traduction dans le
fichier config.toml
à la racine. C'est le cas pour les liens en haut de la page. Ils ne sont
pas définis dans des pages de contenus, mais ajoutés dans les templates qui s'affichent sur
toutes les pages.
Ces liens sont ajoutés ainsi:
<a href="{{ get_url(path="@/projects/_index.md", lang=lang) }}">{{ trans(key="projects", lang=lang) }}</a>
<a href="{{ get_url(path="@/blog/_index.md", lang=lang) }}">{{ trans(key="blog", lang=lang) }}</a>
<a href="{{ get_url(path="@/about.md", lang=lang) }}">{{ trans(key="about", lang=lang) }}</a>
Le paramètre lang
est une variable rendue disponible par zola, qui représente la langue
courante, get_url
permet d'obtenir l'URL de la page indiquée dans la langue spécifiée, et
trans()
permet d'obtenir une traduction définie dans le fichier config.toml
.
URL canonique et alternatives
Les bonnes pratiques SEO suggèrent d'indiquer sur chaque page d'un site multilingue:
- La langue de la page, avec un attribut
lang
sur le taghtml
- L'URL canonique pour cette langue et cette page avec des balises
<link rel="canonical" href="...">
- Les URL de cette pages dans toutes les langues disponibles, avec des balises
<link rel="alternate" hreflang="en" href="...">
Avec zola, cela peut être fait en utilisant la variable section.translations
(pour les répertoires contenant plusieurs pages), ou page.translations
pour les
pages individuelles. Il faut tout d'abord identifier les URL de la page dans chaque langue. Cela
peut être fait dans le template de base, par exemple base.html
(celui dont les autres
templates dérivent).
{% set translations = section.translations | default(value=page.translations) %}
{% if translations %}
{% set en = translations | filter(attribute="lang", value="en") | first %}
{% if en %}
{% set en_url = en.permalink %}
{% endif %}
{% set fr = translations | filter(attribute="lang", value="fr") | first %}
{% if fr %}
{% set fr_url = fr.permalink %}
{% endif %}
{% endif %}
On obtient alors l'URL canonique selon la langue courante :
{% if lang == "en" %}
{% set canonical_url = en_url %}
{% else %}
{% set canonical_url = fr_url %}
{% endif %}
Puis dans entre les balises head
:
<link rel="canonical" href="{{ canonical_url }}" />
{% if fr_url %}
<link rel="alternate" hreflang="fr" href="{{ fr_url }}" />
{% endif %}
{% if en_url %}
<link rel="alternate" hreflang="en" href="{{ en_url }}" />
{% endif %}
Ne pas oublier d'ajouter l'attribut langue à la racine:
<html lang="{{ lang }}">
Pagination
Les sections sont définies par un fichier _index.md
dans un dossier, avec quelques
méta-données, et permettent de grouper des pages. Par exemple, une section peut afficher
une liste paginée de projets, ou de posts de blog. C'est le cas par exemple de la
section blog de ce site. Dans ce cas, la page peut être paginée. Quand c'est le cas,
zola fournit une variable paginator
. Mais juste en.permalink
ne contient pas
les informations de pagination. Il faut rajouter manuellement /page/<pageNumber>
comme ceci:
{% set translations = section.translations | default(value=page.translations) %}
{% if translations %}
{% set en = translations | filter(attribute="lang", value="en") | first %}
{% if en and paginator and paginator.current_index > 1 %}
{% set en_url = en.permalink ~ "page/" ~ paginator.current_index %}
{% elif en %}
{% set en_url = en.permalink %}
{% endif %}
{% set fr = translations | filter(attribute="lang", value="fr") | first %}
{% if fr and paginator and paginator.current_index > 1 %}
{% set fr_url = fr.permalink ~ "page/" ~ paginator.current_index %}
{% elif fr %}
{% set fr_url = fr.permalink %}
{% endif %}
{% endif %}
De cette manière, la page 2 de la section blog en anglais peut référencer la page 2 de la section blog en français.
De plus, nous pouvons également spécifier que cette page fait partie d'une série paginée en ajoutant des méta-données indiquant la page précédente et suivante :
{% if paginator.previous %}
<link rel="prev" href="{{ paginator.previous }}">
{% endif %}
{% if paginator.next %}
<link rel="next" href="{{ paginator.next }}">
{% endif %}
Changement de langue
Avec les éléments définis précédement, nous pouvons facilement implémenter un commuteur de langue. il suffit d'ajouter un lien vers l'autre langue conditionnellement.
{% if lang == "en" and fr_url %}
<div class="lang-switch">
<a href="{{ fr_url }}" aria-label="Switch to French">
FR
</a>
</div>
{% elif lang == "fr" and en_url %}
<div class="lang-switch">
<a href="{{ en_url }}" aria-label="Switch to English">
EN
</a>
</div>
{% endif %}
Si la langue courante est la seule disponible, l'autre URL sera nulle et le lien ne serra pas affiché. Il pourrait également être simplement désactivé ou renvoyer vers l'accueil.
Conclusion
Configurer un site multilingues avec zola est tout à fait possible, mais représentait quelques petits ajustements qui ne m'étaient pas directement évidents en lisant la documentation de zola. Cet article est ma tentative de partager les quelques astuces apprises lors de la mise en place de ce site. J'espère que ça pourra aider certains, et je serai heureux de lire vos suggestions pour améliorer cette approche.