Ecrire dans sa langue natale permet de rester dans une bonne zone de confort, mais hélas sur le Web cela peut limiter son audience pour peu qu’on s’adresse à un panel assez large. C’est ce que je me dis depuis quelques temps et j’ai donc été voir comment basculer mon blog en mode multilingue pour proposer des articles en anglais. Typiquement, ce type d’article sera concerné par une version anglaise.

Ce blog reposant sur le générateur de sites statique Hugo, je vous propose de voir comment j’ai mis en oeuvre ses fonctions multilingue. Il n’y a pas de mystères, une bonne partie de cet article reposera sur la documentation officielle.

Nos objectifs sont les suivants :

  • Adapter le menu principal selon la langue choisie
  • Adapter les textes du template selon la langue
  • Pouvoir choisir la langue d’un article si disponible

Activer le mode multilingue

Hugo supporte nativement le multilingue, il suffit de l’indiquer dans le fichier config.yaml (parce que j’utilise la version YAML de la config, n’étant pas un grand fan de Toml).

J’ai d’abord ajouté les instructions suivantes :

DefaultContentLanguage: fr
DefaultContentLanguageInSubdir: true

Le premier paramètre dit que la langue par défaut sera le français avec fr. Le second indique que le contenu à afficher se trouve dans un sous dossier au nom de la langue (content/en ou content/fr).

A savoir qu’il existe plusieurs façons pour avoir un contenu multilingue dans Hugo : en nommant les fichiers avec le code langue (exemple : about.en.md et about.fr.md) ou en les plaçant dans un sous dossier nommé selon la langue (content/en/about.md, content/fr/about.md).

Nous utiliserons la seconde dans cet article.

Avoir un menu dans la langue choisie

Cette partie est tributaire du template que vous utilisez et de la façon dont son menu est présenté. Mais il me semble que ce sont des paramétrages relativement génériques.

Dans le fichier config.yaml, nous précisons la langue pour chaque entrée de menu. A l’origine, le menu de ce blog était présenté ainsi :

params:
  mainSections: ["posts"]
  description: "Tout est dans le titre !"
menu:
  main:
    - identifier: "about"
        name: "👤 A Propos"
        url: "/about/"
        weight: 10
    - identifier: "contact"
        name: "💬 Contact"
        url: "/contact/"
        weight: 20
# ...

L’entrée menu disparaît au profit de languages. Dans cet élément, vous ajouterez une sous section pour chaque langue utilisée sur votre blog. Par exemple en et fr.

Pour chaque langue, vous ajouterez une section menu, puis main en dessous et enfin un identifier pour chaque entrée de votre menu.

Dans la section de la langue, vous pouvez indiquer quelques éléments spécifiques comme la description du blog. Vous noterez donc que l’entrée params.description a ainsi disparue au profit de languages.fr.description et languages.en.description.

languages:
  fr:
    contentDir: "content/fr"
    languageName: "Français"
    weight: 1
    description: "Tout est dans le titre !"
    menu:
      main:
        - identifier: "about"
          name: "👤 A Propos"
          url: "/fr/a-propos/"
          weight: 10
        - identifier: "contact"
          name: "💬 Contact"
          url: "/fr/contact/"
          slug: "contact"
          weight: 20
# (....)
  en:
    contentDir: "content/en"
    languageName: "English"
    weight: 2
    description: "It's all in the title !"
    menu:
      main:
        - identifier: "about"
          name: "👤 About"
          url: "/en/about/"
          weight: 10
        - identifier: "contact"
          name: "💬 Contact"
          url: "/en/contact/"
          slug: "contact"
          weight: 20
# (...)

Adapter son template

Dans le cas du template Casper3 que j’utilise, le contenu du blog se trouve dans content/posts. Il s’agit du paramètre params.mainSections: ["posts]" en haut de ma config. Cela indique à Hugo que le contenu se situe dans le dossier posts.

Sur ce point, je n’ai rien eu à modifier. Par contre, j’ai ajouté quelques éléments : le choix de la langue dans le menu principal, la traduction des textes du template, et un lien vers la traduction anglaise d’un article si disponible.

Ajouter la liste des langues du blog

A l’emplacement voulu dans votre template, ajoutez la partie suivante :

{{ range $.Site.Home.AllTranslations }}
<li><a  href="{{ .Permalink }}">{{ .Language.LanguageName }}</a></li>
{{ end }}

Cela donnera un résultat similaire à ceci :

langue

Traduire les éléments statiques

Certains éléments d’affichage comme “Egalement disponible dans la langue suivante” et “Table des matières” sont écrits en dur dans le template. Il faut donc pouvoir les adapter à la langue.

langue

Pour stocker les valeurs désirées, créez un dossier i18n/ à la racine de votre site Hugo. Dedans, ajoutez des fichiers pour chacune des langues de votre site : en.yaml et fr.yaml dans mon cas. Le fichier doit être nommé selon les codes langues définis par la RFC 5646 (donc en.yaml, ou encore fr-FR.yaml…)

Dans ces fichiers, nous mettons le code technique pour le texte et la valeur dans la langue attendue.

# fr.yaml
table_of_content: # identifiant pour le texte
  other: Table des matières # valeur qui sera affichée

translations:
  other: 'Egalement disponible dans la langue suivante :'

# en.yaml
table_of_content:
  other: Table of Content

translations:
  other: 'Also available in the following language :'

Dans votre template, à l’emplacement où se situe le texte à traduire, remplacez-le comme il suit :

<section>
<h2>Table des matières</h2>
{{.TableOfContents}}
</section>

<!--- devient : -->

<section>
<h2>{{ i18n  "table_of_content" }}</h2>
{{.TableOfContents}}
</section>

Attention : l’identifiant du texte doit bien être donné entre double quotes.

Lister dans quelles langues un article est disponible

Pour ma part, j’ai mis ceci avant la table des matières d’un article. Il suffit d’ajouter l’élément suivant à votre template :

{{ if  .IsTranslated }}
<section>
<!-- affiche le titre de la liste dans la langue voulue -->
<h4>{{ i18n  "translations" }}</h4>
<ul>
{{ range  .Translations }}
<li>
<a  href="{{ .Permalink }}">{{ .Lang  | upper }} : {{ .Title }}{{ if  .IsPage }}{{ end }}</a>
</li>
{{ end }}
</ul>
</section>
{{ end }}

Résultat obtenu :

langue

Réorganiser son contenu

Trier en fonction de la langue

Il s’agit là uniquement de revoir le contenu du dossier content/ dans lequel tous les articles se trouvent. Voici comment j’étais organisé avant :

content
|── about.md
├── contact.md
├── posts
│   └── blog_hugo_multilingue.md
├── soutiens.md
├── support.md
└── uses.md

Les fichiers à la racine de content/ correspondent aux liens du menu en haut. Le dossier posts/ est celui dans lequel les articles sont stockés.

Pour trier les articles, nous créons un dossier en/ et fr/ à la racine de content/.

J’ai ensuite déplacé tous les fichiers markdown et le dossier posts/ dans le dossier fr/ (car tout mon contenu est pour le moment en français, logique !).

J’ai créé le sous dossier posts/ dans en/ pour avoir la même structure et j’ai copié les fichiers about.md, etc, dans le dossier en/ afin de les traduire en anglais.

Cela donne maintenant le résultat suivant :

content
├── en
│   ├── about.md
│   ├── coffee.md
│   ├── contact.md
│   ├── posts
│   │   └── blog_hugo_multilingue.md
│   ├── supporting.md
│   └── uses.md
└── fr
    ├── about.md
    ├── contact.md
    ├── posts
    │   ├── blog_hugo_multilingue.md
        (...)
    ├── soutiens.md
    ├── support.md
    └── uses.md

Traduire ses URL

Pour que le lien entre la version anglaise et française d’un article soit fait par Hugo, il faut que le fichier ait le même nom entre les dossiers fr/ et en/. Cependant, il serait plus approprié que le lien vers l’article soit dans la langue du lecteur, mais aussi pour faciliter le référencement et la cohérence avec la langue d’affichage.

Exemple :

  • fr/posts/creer-un-blog-multilingue-avec-hugo/
  • en/posts/create-a-multilingual-blog-with-hugo/

Alors que les fichiers s’appellent :

./content/fr/posts/blog_hugo_multilingue.md
./content/en/posts/blog_hugo_multilingue.md

Pour avoir ça, il suffit d’utiliser le paramètre slug dans l’entête de l’article.

Sur la version française :

---
title: "Créer un blog multilingue avec Hugo"
slug: "creer-un-blog-multilingue-avec-hugo"
---

Sur la version anglaise :

---
title: "Create a multilingual blog with Hugo"
slug: "create-a-multilingual-blog-with-hugo"
---

Lors de la génération, Hugo construira les liens /fr/creer-un-blog-multilingue-avec-hugo et /en/create-a-multilingual-blog-with-hugo pour chaque langue.

Attention, si vous utilisez dans vos entêtes d’articles le paramètre url, il faudra indiquer le code langue avant : fr/a-propos là où slug demande uniquement un identifiant pour l’article.

Résultat

Voyons maintenant ce que ça donne en lançant le rendu du site !

Le français était la langue par défaut, je suis redirigé dessus automatiquement.

langue

Si je clique sur “English” en haut, je suis redirigé sur la langue anglaise.

langue

Dans la mesure où seule la version anglaise de cet article est présente dans le dossier en, Hugo ne voit qu’un seul article en anglais contre tout mon historique en français.

Et voilà !