Sp4ce.net
How to have language support with Jekyll
Jekyll doesn't provide any support for localization of posts and pages. This article explains how this website use jekyll and add a multilingual support for posts and pages. There is also a small code of php (even if I am not a big fan of the language) at the end.
Languages
The site is both in English and French. Jekyll doesn’t provide any support to have posts in two languages. It means that in your website meta data, the variable site.posts
contains all your posts (both in English and French).
However, I wanted two versions of the home page, one version that contains only the English posts and the French only posts, and another version that contains only the French posts and the English only posts. So I am sure that every post is displayed, and available in the user favorite language. There is one home page called index.en.html
and index.fr.html
, both are laid out with _layout/index.html
layout.
Categories
The site contains three categories of posts: site , computer and miscellaneous The _layout/index.html
layout contains three widgets with the posts related to a category. Jekyll allows you to include part of pages in another using the include
statemenent. So for a category (for example computer) it is:
<div class="panel">
<h2>{{ page.computer_activities }}</h2>
<ul>
{% for post in site.categories.computer %}
{% include category.html %}
{% endfor %}
</ul>
</div>
page.computer_activities
contains the localized title of the category, specified in index.fr.thml
(in French) and index.en.html
(in English).
site.categories.computer
is a list of all the posts in the computer category.
Then the file _includes/category.html
is very simple:
{% if post.multilingual != true %}
<li>{% include post_link.html %}
{% if post.language == 'en' %}
{% include english_only.html %}
{% elsif post.language == 'fr' %}
{% include french_only.html %}
{% endif %}
</p></li>
{% elsif post.language == page.language %}
<li>{% include post_link.html %}</p></li>
{% endif %}
So if it is not a multilingual post, I display it with a small flag that explain that it is a French only or English only post, else I display only the posts which have the same language as the page. (_includes/post_link.html
is a small code that displays a post link, and open a <p> tag, for those who notified the closing </p>)
Get the page language
I choose these conventions:
- When a page is multilingual, it is named
page_name.language.textile
(language
isfr
oren
) - When a page is only in one language, you don’t put the
language
extension, you set the language in the jekyllyaml
header of the post.
So, in both case, you know the language of a page, by looking at the url, if it is a multilingual post, or by looking at the post meta data. Then I extend the Page
and Post
class using ruby monkey patching in order to make this information available in the post and the page meta data in both case. For example, in the _plugins/page.rb
require '_plugins/get_language'
module Jekyll
class Page
# Return the data of the page with additional
# information if the page has a specific language.
alias orig_to_liquid to_liquid
def to_liquid
# Gather all the basic information of the page.
self.data = orig_to_liquid
# Get the language of the page from the name of the post
language = GetLanguage.get_language(self.url)
# merge the language information with the page meta data.
return GetLanguage.merge_data(self.data, language)
end
end
end
The method GetLanguage.merge_date
looks like:
# Merge the data with the language values.
def GetLanguage.merge_data(data, language)
if (language)
title = data['title'] != nil ? data['title'] : ''
data = data.deep_merge({
'language' => language,
'multilingual' => true,
# remove the language extension of the title
'title' => title.gsub(".#{language}",''),
})
end
return data
end
So now, I know the language of each page, available in page.language
or post.language
, and I know also if it is multilingual page or not. Then I can display the small french or english flag at the bottom left corner when another language is available for a post. I also create two rss feeds atom.en.xml
and atom.fr.xml
Get user favorite language
At the top level of the site, there is a small index.php
page, that redirects the request to the correct index.fr.html
or index.en.html
. This is the only piece of php code I have on the site, because it was available on my hosting server, but you could do the same thing in JavaScript if you want. The goal is to get the user favorite language by reading this information in the browser.
<?php
// Définir ici les langues disponibles
$lang_list = array("fr","en");
$accept_lang = explode(",", $_SERVER['HTTP_ACCEPT_LANGUAGE']);
reset($accept_lang);
while (list($index, $language) = @each($accept_lang)) {
if (eregi( "^(.+);q=([0-9.]*)$", $language , $part)) {
$accept_lang[$index] = $part[2] . ';' . $part[1];
} else {
$accept_lang[$index] = '1.0;' . $accept_lang[$index];
}
}
arsort($accept_lang); //tri par ordre de préférence
reset($accept_lang);
while (list( , $a_lang) = @each($accept_lang) ) {
reset($lang_list);
while ( list( , $language) = @each($lang_list) ) {
if (strpos($a_lang,$language)!=0) {
$selected_language = $language;
break 2;
}
}
}
unset($accept_lang, $a_lang, $language);
// langague par default (english)
if (!isset($selected_language)) {
$selected_language = 'en';
}
?>
<html>
<head>
<meta http-equiv="Refresh" content="0; url=/index.<?php echo $selected_language ?>.html" />
</head>
<body>
</body>
</html>
I get this code from my old web site and I don’t remember if it really comes out of my mind. I am definitly not a php guru, so please be kind with my skills :p I am open to any improvement you may suggest.