Goal
- Support multi-language, mainly in English and supplemented by Chinese;
- When visiting pages begin with
/
, e.g./about.html
,/posts/hello-world
, English pages would be shown; - When visiting pages began with
/zh/
, e.g./zh/about.html
,/zh/posts/hello-world
, Chinese pages would be shown; - When visiting
../hello-world
posts, corresponding langugage posts would be jumped via the link; - Posts which are specified language would only be shown in
archive
andindex
pages.
Defect
- As
404.html
page was not supported for separate language file, two langugage content would be shown on it at the same time. - The
jekyll-paginate-v2
, a plugin supports pagination for multi-language, is not supported by GitHub Pages. So the blog has not been supported pagination so far. See details below. - It is a little bit tricky to show date in multi-language way. Some string formatting work should be taken as it is able to have done that but is not a better way. Please see Jekyll Date Formatting.
Setup
Firstly, I found a i18n
plugin Jekyll Multiple Languages Plugin.
The number of stars in this plugin is the most among multi-language plugins, and there are many other related multi-language plugins listed. You can use it without hesitate if you don’t want to setup custom configuration.
Currently for simplistic and customize, and also omitting unnecessary features in the plugin, I choose to use custom rules to support multi-language.
1. Single Post Setting
There are two properties needed to added for every posts and pages
uid
for unique post whose English and Chinese are the sameuid
;- Note:
uid
can be declared in any other name, e.gdocument_id
.
- Note:
locale
for language symbol which specify what pages should be shown.
So add configuration in Front Matter
of every posts
---
uid: hello-world
locale: zh
---
2. For Posts
It is very redundant that locale
has to be added in Front Matter
every posts at every time. Do not repeat yourself. I am going to use different folders to distinguish posts in different languages and set a default value to locale
in config file.
Create zh
folder to store Chinese posts in _posts
directory, which origin _posts
folder is used to store English posts. When visiting /zh/posts/some-posts
Chinese pages are shown.
(Of course, follow below to set another path
to use different directory)
defaults:
- values: #1
locale: en
- scope: #2
path: _posts/zh/**
type: posts
values:
locale: zh
- #1 not set for
scope
means global default: all posts and pages are default toen
; - #2 set for
scope
means in the path of_posts/zh/**
: all posts are default tozh
.
3. For Common String
The common string is such as Archive
and About
from menu or Next Page
.
By the feature of site.data
, create locales
folder in /_data
directory, and create en.yaml
and zh.yaml
for storing English and Chinese string.
# in /_data/locales/en.yml
menu:
about: About
archive: Archive
# in /_data/locales/zh.yml
menu:
about: 关于
archive: 归档
Replace the old words specified by locale
<nav class="menu-content">
<a href="/about">{{ site.data.locales[page.locale].menu.about }}</a>
</nav>
4. For Pages
The pages are archive.html
and about.html
such page
type in Jekyll.
As use of collection
, _zh
folder need to be created independently in root directory.
collections:
zh:
output: true
And create corresponding files in _zh
folder
/menu/archive.html
/menu/about.html
5. Language Selector
The selector is a button for switching pages or posts between different locale
.
Create a new file named language-selector.html
in _includes
folder.
Finding corresponding language page from posts
, pages
and collections
.
{% if page.uid %} <!-- #1 -->
<div class="language-selector">
{% assign postsOrPages = site.posts <!-- #2 -->
| concat: site.pages
| concat: site.zh
| where: "uid", page.uid
| sort: "locale" %}
{% for item in postsOrPages %}
{% unless item.url contains '/page/' %} <!-- #3 -->
<a href="{{ item.url }}" class="{{ item.locale }}">
{{ site.data.locales[item.locale].name }} <!-- #4 -->
</a>
{% endunless %}
{% endfor %}
</div>
{% endif %}
- #1 Selector is shown only on
uid
existed; - #2 Concat the list of
posts
,pages
andzh
to find the sameuid
pages; - #3 Filter the pages not in
/pages/
folder; - #4 Get the common string of language symbol form
locale
6. For Archive Page
The posts should be filtered in specified locale
language manually in archive.html
.
There is a convenient method to get the next post by post.next
which dose not guarantee the same locale
posts shown in one page. Should do an alternative way
<!-- archive.html -->
<!-- use the index of posts instead of post.next -->
{% assign posts = site.posts | where: "locale", page.locale %}
{% for index in (0..posts.size) limit: posts.size %}
{% assign post = posts[index] %}
{% assign prevIndex = index | minus: 1 %}
{% assign prev = posts[prevIndex] %}
{% capture year %}{{ post.date | date: '%Y' }}{% endcapture %}
{% capture prevYear %}{{ prev.date | date: '%Y' }}{% endcapture %}
{% if year != prevYear or index == 0 %}
<h3>{{ year }}</h3>
{% endif %}
<li itemscope>
<a href="{{ post.url }}">{{ post.title }}</a>
<p class="post-date"><span>{{ post.date | date: "%B %-d" }}</span></p>
</li>
{% endfor %}
The key point is that using the index
of posts after filtered by locale
instead of post.next
.
7. Multi-Language SEO
Create a new page named language-seo.html
in _included
folder to specify corresponding language pages by hreflang
.
{% assign posts = site.posts | where:"uid", page.uid | sort: 'locale' %}
{% for post in posts %}
<link rel="alternate" hreflang="{{ post.locale }}" href="{{ post.url }}" />
{% endfor %}
As well as include in head.html
.
<!-- Language SEO -->
{% include language-seo.html %}
Lastly
Some unimportant and regular configuration are omitted, please to see the Source: lexcao.github.io if you want to learn the full setup.
References
- Jekyll Multiple Language Plugin
- Making Jekyll Multilingual
- Multi Languages with Jekyll
- Deploy A Multi-Language Jekyll Site
- Jekyll-Paginate-V2
One More Thing
Support Pagination
The old pagination plugin jekyll-pagination-v1
is no longer suitable for the short of filtering by the criteria. It is not able to show the one language list of posts on specified language.
Fortunately, jekyll-pagination-v2
announced to support pagination on multi-language way. As I mentioned above, the permitted plugins provided by GitHub Pages does not contain this plugin. Which you need to deploy automated manually if you want to use. Here are setup jekyll-pagination-v2
.
Gemfile install
$ gem 'jekyll-paginate-v2'
_config.yaml setup
Note: the configuration of v2
and v1
is not compatible.
plugins:
- jekyll-paginate-v2
pagination:
enabled: true
per_page: 5
permalink: /page/:num/
sort_reverse: true
pages configs
You need add more configuration in Front Matter
of index.html
to paginate.
# /index.html
---
pagination:
enabled: true # yes, enable is needed here
locale: en
---
pagination.locale
is to specify the criteria of the language according to locale
of the pages. I use locale
for my custom rules for multi-language so that the pagination use the same filed for reusable.
Correspondly, create index.html
in _zh
folder.
# /_zh/index.html
---
permalink: /zh/ # I don't like suffix of .html so do this
pagination:
enabled: true
locale: zh
---
Note: I came cross a problem here that the pagination was not working after I put the index.html
into _zh
folder, which has not been solved yet.
The temporary solution was to put zh/index.html
file to the root directory, and renamed to index_zh.html
.
paginating
The use of paginating is as same as the v1
does. Please see Pagination.