Preface
When I found myself coding a multilingual site in Jekyll, I stumbled on a lot of useful resources while surfing the Web, but I struggled quite a bit to digest and replicate their approaches due to the lack of a concrete, working example to look at.
At first, I tried to replicate their approaches directly in the site I was working on, but this quickly backfired because it proved to be too big of a bite to chew for a designer who codes.
Not giving up, I then decided to create a basic site from scratch to focus on learning how to handle multiple languages in Jekyll without any extra complexity in the picture.
That very same basic site is hosted in this repository, which I gladly share with the world as an example project, hoping to help anyone interested in coding a multilingual site using Jekyll.
Foreword
A few words before starting. Sites built with the approach illustrated in this series of articles:
- can support as many languages as needed
- can serve pages or posts that may not need to be translated into all supported languages
- have a language switch that can either direct web surfers to view the current page or post in the selected language, if available, or direct them to an alternative fallback page
- do not require you to install custom plugins
- leverage the basics of Jekyll and thus making them relatively future-proof (famous last words)
- can be published as GitHub Pages sites
Specifically, the basic site hosted in this repository and used as a concrete example to illustrate my approach:
- is visually quite crude, as the focus is on illustrating a structural (not visual) approach to building multilingual sites
- supports English and Italian as example languages
Directory structure
The directory structure of the basic site looks like this:
.
├── _data
│ └── snippets.yml
├── _includes
│ ├── head.html
│ ├── header.html
│ ├── localizations.html
│ └── references.html
├── _layouts
│ ├── base.html
│ ├── index.html
│ ├── page.html
│ └── post.html
├── _posts
│ ├── en
│ │ ├── YYYY-MM-DD-title.markdown
│ │ ├── …
│ │ └── YYYY-MM-DD-title.markdown
│ └── it
│ ├── YYYY-MM-DD-titolo.markdown
│ ├── …
│ └── YYYY-MM-DD-titolo.markdown
├── 404.html
├── config.yml
├── en
│ ├── drafts.html
│ ├── feed.xml
│ ├── postface.html
│ ├── preface.html
│ ├── sitemap.xml
│ └── stories.html
├── index.html
├── it
│ ├── bozze.html
│ ├── feed.xml
│ ├── prefazione.html
│ ├── sitemap.xml
│ └── storie.html
└── sitemap.xml
Pages
We organize the pages into as many subdirectories as the languages we plan to support, naming them using ISO language codes. The basic site has two subdirectories, one named en
for grouping the English pages and one named it
for grouping the Italian pages.
├── …
├── en
│ ├── drafts.html
│ ├── feed.xml
│ ├── postface.html
│ ├── preface.html
│ ├── sitemap.xml
│ └── stories.html
├── …
├── it
│ ├── bozze.html
│ ├── feed.xml
│ ├── prefazione.html
│ ├── sitemap.xml
│ └── storie.html
├── …
After Jekyll has built the site, we can reach, for example, the English page stories.html
and the Italian page storie.html
at the URLs www.site.ext/en/stories.html
and www.site.ext/it/storie.html
, respectively.
Exceptions
But, of course, there are exceptions. We place the pages 404.html
, index.html
, and sitemap.html
in the root directory of the site. Why?
404.html
and index.html
are unique pages. Jekyll builds and serves automatically one and only one of them at a time.
sitemap.xml
is a Sitemap index which points to other localized sitemaps in the respective language subfolders (read the section Multilingual sitemaps for more details).
Posts
We organize the posts following a similar logic. The basic site has two subdirectories in the folder named _posts
, one named en
for grouping the English posts and one named it
for grouping the Italian posts.
├── …
├── _posts
│ ├── en
│ │ ├── YYYY-MM-DD-title.markdown
│ │ ├── …
│ │ └── YYYY-MM-DD-title.markdown
│ └── it
│ ├── YYYY-MM-DD-titolo.markdown
│ ├── …
│ └── YYYY-MM-DD-titolo.markdown
├── …
Configuration
We then add the following configuration options in the _config.yml
file placed in the site’s root directory:
defaults:
-
scope:
path: '_posts/en'
type: 'posts'
values:
permalink: 'en/story/:title'
language: en
-
scope:
path: '_posts/it'
type: 'posts'
values:
permalink: 'it/storia/:title'
language: it
By setting global permalinks for posts, we can reach, for example, the English post named 2021-01-01-hello-world.markdown
and the Italian post named 2021-01-01-ciao-mondo.markdown
at the URLs www.site.ext/en/story/hello-world.html
and www.site.ext/it/storia/ciao-mondo.html
, respectively.