Mis Ă  jour le 28/07/2026 !

Cet article a été rédigé sous le framework Jekyll. Il a depuis migré vers Astro !

Mis Ă  jour le 15/09/2024 !

C’était bien d’offrir un support multilingue, mais la maintenance est devenue trop difficile et complexe, j’ai donc annulĂ© l’application du plugin et suis revenu Ă  l’état antĂ©rieur. Pour un vrai support multilingue, il faut retoucher bien plus d’élĂ©ments qu’on ne le pense, ce qui rend le processus de fusion avec le thĂšme d’origine trĂšs complexe — un inconvĂ©nient Ă  accepter.

Présentation du plugin

Il existe principalement deux plugins Jekyll pour implĂ©menter le multilingue dans l’environnement GitHub Blog : jekyll-polyglot et jekyll-multiple-languages-plugin. J’ai utilisĂ© le premier, jekyll-polyglot. Ce plugin gĂ©nĂšre des pages de traduction multilingue en insĂ©rant le code de langue I18N aprĂšs l’URL racine, selon la valeur lang dĂ©finie dans le front matter de chaque article. Ce plugin aurait Ă©tĂ© créé sur le modĂšle du second, jekyll-multiple-languages-plugin. Le guide officiel, de l’installation aux prĂ©cautions d’utilisation, est dĂ©taillĂ© sur le dĂ©pĂŽt GitHub Polyglot.

Travail préparatoire

Installation et configuration du plugin

group :jekyll_plugins do
  gem "jekyll-polyglot"
end

Ajoutez le plugin comme ci-dessus dans Gemfile, puis installez-le avec la commande gem install jekyll-polyglot.

plugins:
  - jekyll-polyglot

languages: ["ko", "en"]
default_lang: "ko"
exclude_from_localization: ['javascript', 'images', 'css', 'sitemap.xml']
parallel_localizaion: true

Une fois le plugin installĂ©, ajoutez ces Ă©lĂ©ments Ă  _config.yml. Dans languages, indiquez les langues que la page supportera, et dans default_lang, la langue par dĂ©faut de la page. Attention : sous Windows, l’option parallel_localization ne fonctionne pas correctement, il faut donc impĂ©rativement la dĂ©finir sur false.

Correction d’un bug d’expression rĂ©guliĂšre

AprĂšs avoir installĂ© le plugin et effectuĂ© une compilation, on rencontre l’erreur : 'relative_url_regex': target of repeat operator is not specified:. Cette erreur se produit parce que certaines expressions rĂ©guliĂšres du fichier site.rb du plugin ne gĂšrent pas les caractĂšres gĂ©nĂ©riques (*) comme exlude: *.gem *.gemspec *.config.js dans le _config.yml du thĂšme Chirpy. J’ai contactĂ© l’auteur du plugin Ă  ce sujet, mais on m’a rĂ©pondu, en se rĂ©fĂ©rant Ă  cette documentation, que le thĂšme Chirpy utilisait incorrectement les motifs globaux dans _config.yml.

Cependant, d’autres thĂšmes Jekyll comme Minimal-Mistakes utilisent Ă©galement des motifs globaux, ce qui suggĂšre qu’il faut modifier le code du plugin lui-mĂȘme. J’ai donc forkĂ© le projet dans mon dĂ©pĂŽt GitHub et l’ai chargĂ© dans Gemfile comme suit :

gem 'jekyll-polyglot', git: 'https://github.com/hyngng/jekyll-polyglot', branch: 'master'

Ensuite, j’ai modifiĂ© les deux fonctions relative_url_regex() et absolute_url_regex() dans le fichier site.rb situĂ© dans jekyll-polyglot-1.8.0/lib/jekyll/polyglot/patches/jekyll, comme ci-dessous :

def relative_url_regex(disabled = false)
  regex = ''
  unless disabled
    @exclude.each do |x|
      escaped_x = Regexp.escape(x)
      regex += "(?!#{escaped_x})"
    end
    @languages.each do |x|
      escaped_x = Regexp.escape(x)
      regex += "(?!#{escaped_x}\/)"
    end
  end
  start = disabled ? 'ferh' : 'href'
  %r{#{start}="?#{@baseurl}/((?:#{regex}[^,'"\s/?.]+\.?)*(?:/[^\]\[)("'\s]*)?)"}
end

...

def absolute_url_regex(url, disabled = false)
  regex = ''
  unless disabled
    @exclude.each do |x|
      escaped_x = Regexp.escape(x)
      regex += "(?!#{escaped_x})"
    end
    @languages.each do |x|
      escaped_x = Regexp.escape(x)
      regex += "(?!#{escaped_x}\/)"
    end
  end
  start = disabled ? 'ferh' : 'href'
  %r{(?<!hreflang="#{@default_lang}" )#{start}="?#{url}#{@baseurl}/((?:#{regex}[^,'"\s/?.]+\.?)*(?:/[^\]\[)("'\s]*)?)"}
end

AprĂšs avoir modifiĂ© les fonctions, j’ai entrĂ© la commande bundle exec jekyll s et confirmĂ© que la compilation s’effectuait sans problĂšme.

Modification des attributs des fichiers d’articles

---
lang: en
permalink: example-url-here
---

Il faut spĂ©cifier la valeur de la langue dans le front matter des articles Ă  traduire. Utilisez les codes de pays I18N comme ko, en. Dans mon cas, j’ai utilisĂ© ko-KR et en. Le champ permalink dĂ©termine le chemin URL de l’article, car dans Jekyll, deux fichiers ayant la mĂȘme URL sont considĂ©rĂ©s comme identiques par dĂ©faut, il faut donc distinguer artificiellement l’original de la traduction.

_posts/2010-03-01-salad-recipes-en.md
_posts/2010-03-01-salad-recipes-sv.md
_posts/2010-03-01-salad-recipes-fr.md

Si vous n’aimez pas distinguer la langue de l’article via permalink dans le front matter, vous pouvez Ă©galement modifier le nom du fichier comme ci-dessus. Cependant, dans ce cas, l’URL de la page pourrait contenir une rĂ©pĂ©tition, comme example.github.io/en/2010-03-01-salad-recipes-en.

Modification du template

Ces informations Ă©tant spĂ©cifiques au thĂšme Chirpy, si vous utilisez un autre template Jekyll, vous pouvez passer cette section et passer directement Ă  la section suivante. Cependant, si vous devez modifier le template Chirpy comme moi, les informations suivantes peuvent vous ĂȘtre utiles.

  • Variables utilisables dans le plugin jekyll-polyglot :
    • site.default_lang : la langue par dĂ©faut dĂ©clarĂ©e dans _config.yml.
    • site.active_lang : la langue activĂ©e sur la page web actuelle.
    • page.lang : la langue de l’article dĂ©clarĂ©e dans le front matter.

En utilisant ces trois variables, on peut par exemple Ă©crire des conditions comme {% raw %}{% if page.lang == site.default_lang %}{% endraw %}, et limiter l’affichage de la langue sur la page en fonction du contexte.

Chargement de la langue du site

{% if site.active_lang %}
  {% assign lang = site.active_lang %}
{% elsif site.data.locales[page.lang] %}
  {% assign lang = page.lang %}
{% elsif site.data.locales[site.lang] %}
  {% assign lang = site.lang %}
{% else %}
  {% assign lang = 'site.default_lang'' %}
{% endif %}

Le template Chirpy dĂ©finit la langue dans un fichier sĂ©parĂ©, _includes/lang.html. AprĂšs avoir modifiĂ© ce fichier comme ci-dessus, on peut l’utiliser en important lang.html dans les fichiers de mise en page dĂ©taillĂ©s.

Affichage du contenu par langue

{% include lang.html %}

La plupart du temps, j’ai traitĂ© les choses en important lang.html comme ci-dessus. Pour la pagination et d’autres cas, simplement changer la langue dĂ©signĂ©e ne suffisait pas, j’ai donc créé des formules supplĂ©mentaires. La plupart du temps, j’ai modifiĂ© les pages pour qu’elles n’affichent que les informations liĂ©es aux articles rĂ©digĂ©s dans la langue spĂ©cifique.

<div id="post-list" class="flex-grow-1 px-xl-1">
  {% for post in posts %}
    {% if post.lang == site.active_lang %}
      <article class="card-wrapper card">...</article>
    {% endif %}
  {% endfor %}
</div>

Par exemple, j’ai ajoutĂ© la condition {% raw %}{% if post.lang == site.active_lang %}{% endraw %} dans _layouts/home.html pour que la page d’accueil n’affiche que les articles rĂ©digĂ©s dans la langue active du site. Voici les autres fichiers que j’ai modifiĂ©s en dĂ©tail :

UsageChemin du fichier
ModĂšle de cadre commun_layouts/default.html
Page d’accueil_layouts/home.html
Catégories_layouts/category.html
Page de tags_layouts/tags.html
Page d’archives_layouts/archive.html
Page À propos_layouts/about.html
Articles récemment modifiés_includes/update-list.html
Exploration de tags_includes/trending_tags.html
Articles connexes_includes/related-posts.html
Navigation entre articles_includes/post-nav.html
Pagination_includes/post-paginator.html

Distinction du contenu de la page À propos

{% if site.active_lang == 'ko-KR' %}
## 자Ʞ소개 (corĂ©en)
...
{% elsif site.active_lang == 'en' %}
## English Self-Introduction
...
{% endif %}

Voici comment afficher un contenu diffĂ©rent dans la page À propos (about) selon la langue. Au dĂ©but, je pensais devoir crĂ©er des fichiers sĂ©parĂ©s comme about-en.md, mais il s’est avĂ©rĂ© que la mĂ©thode la plus simple Ă©tait d’afficher un contenu diffĂ©rent dans un seul fichier en fonction de la langue du site.

Affichage naturel du nombre de caractĂšres

<span
  class="readtime"
  data-bs-toggle="tooltip"
  data-bs-placement="bottom"
  title="{{ words }}{% if site.active_lang != 'ko-KR' %}{{ ' ' }}{% endif %}{{ site.data.locales[include.lang].post.words }}
>

Un petit dĂ©tail qui me gĂȘnait. Dans ce thĂšme, lorsqu’on survole le temps de lecture en haut de l’article, le nombre de caractĂšres s’affiche, mais indĂ©pendamment de la langue, il y a un espace entre le nombre et l’unitĂ©, ce qui donne « 1000 자 ». Je trouvais cela peu naturel, j’ai donc modifiĂ© l’affichage : en corĂ©en, cela s’affiche comme « 1000자 », et dans les autres langues, avec un espace, comme « 1000 words ».

Autres travaux

Indication de la langue de la page dans l’en-tĂȘte

{% I18n_Headers %}

C’est une recommandation du Guide international et multilingue du Centre de recherche Google. Ce n’est pas obligatoire, mais si vous ĂȘtes soucieux du SEO, il est bon d’ajouter le code ci-dessus dans l’en-tĂȘte pour indiquer la langue de la page. Le code se transforme comme suit aprĂšs compilation :

<meta http-equiv="Content-Language" content="ko-KR">
<link rel="alternate" hreflang="ko-KR" href="ttps://hyngng.github.io/posts/:title/"/>
<link rel="alternate" hreflang="en" href="https://hyngng.github.io/en/posts/:title/"/>

Inclusion du plugin dans le processus de compilation

name: Jekyll site CI

on:
  push:
    branches: [ "site" ]
  pull_request:
    branches: [ "site" ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Build the site in the jekyll/builder container
      run: |
        docker run \
        -v $:/srv/jekyll -v $/_site:/srv/jekyll/_site \
        jekyll/builder:latest /bin/bash -c "chmod -R 777 /srv/jekyll && jekyll build --future"

    - name: Push
      uses: s0/git-publish-subdir-action@develop
      env:
          REPO: self
          BRANCH: main
          FOLDER: _site
          GITHUB_TOKEN: $
          MESSAGE: "Build: ({sha}) {msg}"

Contrairement aux plugins intĂ©grĂ©s par dĂ©faut, jekyll-polyglot est considĂ©rĂ© comme un plugin externe et doit ĂȘtre compilĂ© sĂ©parĂ©ment pour des raisons de sĂ©curitĂ©. CrĂ©ez un nouveau fichier .yml dans le dossier .github/workflows/ et Ă©crivez-le comme ci-dessus pour une compilation sans problĂšme.

Inclusion de toutes les pages dans le sitemap

...
{% for lang in site.languages %}
  {% for post in site.posts %}
    {% if lang == post.lang %}
      <url>
        <loc>
          {{ site.url }}
          {% if lang == site.default_lang %}
            {{ post.url }}
          {% else %}
            {{ post.url | prepend: lang | prepend: '/' }}
          {% endif %}
        </loc>
        ...
      </url>
    {% endif %}
  {% endfor %}
{% endfor %}

Le sitemap est l’un des plus grands problĂšmes du support multilingue, car il ne gĂ©nĂšre les balises <loc> que pour les pages par dĂ©faut. Au lieu de cela, j’ai modifiĂ© le code pour qu’il vĂ©rifie chaque langue dans site.languages, tout en ignorant les Ă©lĂ©ments non valides, comme les pages corĂ©ennes automatiquement gĂ©nĂ©rĂ©es Ă  partir d’un fichier dĂ©fini avec lang: en.

Ajout d’un bouton de changement de langue sur la page

{% for lang in site.languages %}
  <div class="lang" style="display: inline;">
    <a style="
      {% if lang == site.active_lang %}
        font-weight: bold;
      {% endif %}"
      href="
      {% if lang == site.default_lang %}
        {{site.baseurl}}{{page.url}}
      {% else %}
        {{site.baseurl}}/{{ lang }}{{page.url}}
      {% endif %}">
      {{ lang }}
    </a>
    {% if forloop.last == false %}
      <span class="lang-border"> </span>
    {% endif %}
  </div>
{% endfor %}

Si nĂ©cessaire, on peut ajouter un bouton de changement de langue Ă  l’endroit souhaitĂ© avec le code ci-dessus. Personnellement, comme mon blog ne contient pas vraiment de contenu exclusif par langue, et que les visiteurs n’ont pas nĂ©cessairement besoin de voir la page dans une autre langue, je ne l’ai pas ajoutĂ©.

Distinction du contenu du flux par langue

{% assign filtered_posts = site.posts | where: "lang", site.active_lang %}

{% for post in filtered_posts limit: 5 %}
  <entry> ... </entry>
{% endfor %}

J’ai Ă©galement fait en sorte que le flux ne contienne que les articles correspondant Ă  site.active_lang dans filtered_posts, gĂ©nĂ©rĂ© dynamiquement selon la configuration linguistique. Lors de l’inscription aux outils pour webmasters, j’ai enregistrĂ© feed.xml et /en/feed.xml sĂ©parĂ©ment.

Capture d’écran de l’application

result-lightresult-dark

Conclusion

C’était Ă©prouvant. jekyll-polyglot donne plus l’impression d’ĂȘtre encombrant que flexible et pratique. Le processus d’application n’est vraiment pas facile ni agrĂ©able — c’est le moins qu’on puisse dire. J’ai mĂȘme envisagĂ© de crĂ©er une page sĂ©parĂ©e en anglais et de gĂ©rer les deux versions indĂ©pendamment, mais comme cela prĂ©sentait plus d’inconvĂ©nients (synchronisation du contenu, configuration de l’exposition dans les moteurs de recherche, etc.), j’ai choisi d’utiliser jekyll-polyglot. Cependant, une fois l’implĂ©mentation rĂ©ussie, les avantages qu’apporte jekyll-polyglot pour crĂ©er un systĂšme multilingue maison sont indĂ©niables.