Skip to content

Instantly share code, notes, and snippets.

@sp3c73r2038
Last active August 29, 2015 14:01
Show Gist options
  • Save sp3c73r2038/f2ddcc0f386bcea2964f to your computer and use it in GitHub Desktop.
Save sp3c73r2038/f2ddcc0f386bcea2964f to your computer and use it in GitHub Desktop.
multilingualism support for jekyll
# example
# .
# |-- about.md
# |-- _config.yml
# |-- css
# | `-- main.css
# |-- feed.xml
# |-- .gitignore
# |-- _includes
# | |-- footer.html
# | |-- header.html
# | `-- head.html
# |-- index.html
# |-- _layouts
# | |-- default.html
# | |-- page.html
# | `-- post.html
# |-- _plugins
# | `-- multilingualism.rb
# |-- _posts
# | |-- 2014-05-12-hello-world.en.md
# | |-- 2014-05-12-hello-world.ja.md
# | `-- 2014-05-13-hello-world.md
# `-- _site
# |-- about
# | `-- index.html
# |-- css
# | `-- main.css
# |-- en
# | `-- 2014
# | `-- 05
# | `-- 12
# | `-- hello-world
# | `-- index.html
# |-- feed.xml
# |-- index.html
# `-- ja
# `-- 2014
# `-- 05
# `-- 12
# `-- hello-world
# `-- index.html
#
# 18 directories, 22 files
# require 'jekyll/mpultiple/languages/plugin'
module Jekyll
class Site
attr_accessor :i18n
alias :process_orig :process
def process()
i18n_config = "#{self.source}/_i18n.yml"
if File.exists? i18n_config
@i18n = YAML.load(File.read(i18n_config))
p @i18n
else
Jekyll.logger.warn "Your site lacks a _i18n.yml config, it's required for multilingualism plugin."
end
process_orig
end
end
class Post
LANG_MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*?)(\.[\w]{2})?(\.[^.]+)$/
attr_accessor :lang
alias :process_orig :process
def process(name)
m, cats, date, slug, lang, ext = *name.match(LANG_MATCHER)
self.date = Time.parse(date)
self.slug = slug
self.ext = ext
self.lang = (lang && lang.gsub('.', '')) || site.config['languages'].first
rescue ArgumentError
path = File.join(@dir || "", name)
msg = "Post '#{path}' does not have a valid date.\n"
msg << "Fix the date, or exclude the file or directory from being processed"
raise FatalException.new(msg)
end
def path_in_lang(lang)
path.gsub(".#{@lang}", "").gsub("#{ext}", "") + ".#{lang}" + ext
end
def path_without_lang
path.gsub(".#{@lang}", "")
end
def in_language?(lang)
return true if lang == self.lang
return true if File.exists? path_in_lang(lang)
(lang == site.config['languages'].first) && (File.exists? path_without_lang)
end
def template
case site.permalink_style
when :pretty
"/:lang/:categories/:year/:month/:day/:title/"
when :none
"/:lang/:categories/:title.html"
when :date
"/:lang/:categories/:year/:month/:day/:title.html"
when :ordinal
"/:lang/:categories/:year/:y_day/:title.html"
else
site.permalink_style.to_s
end
end
def url_placeholders
{
:year => date.strftime("%Y"),
:month => date.strftime("%m"),
:day => date.strftime("%d"),
:title => slug,
:i_day => date.strftime("%d").to_i.to_s,
:i_month => date.strftime("%m").to_i.to_s,
:categories => (categories || []).map { |c| c.to_s }.join('/'),
:short_month => date.strftime("%b"),
:short_year => date.strftime("%y"),
:y_day => date.strftime("%j"),
:output_ext => output_ext,
:lang => @lang
}
end
end
class Page
LANG_MATCHER = /^(.*?)(\.[\w]{2})?(\.[^.]+)$/
attr_accessor :lang
alias :process_orig :process
def process(name)
m, basename, lang, ext = *name.match(LANG_MATCHER)
self.basename = basename
self.lang = (lang && lang.gsub('.', '')) || site.config['languages'].first
self.ext = ext
end
def path_in_lang(lang)
path.gsub(".#{@lang}", "").gsub("#{ext}", "") + ".#{lang}" + ext
end
def path_without_lang
path.gsub(".#{@lang}", "")
end
def in_language?(lang)
File.exists? path_in_lang(lang)
return true if lang == self.lang
return true if File.exists? path_in_lang(lang)
(lang == site.config['languages'].first) && (File.exists? path_without_lang)
end
def template
if site.permalink_style == :pretty
if index? && html?
"/:path/"
elsif html?
"/:lang/:path/:basename/"
elsif excluded?
"/:path/:basename:output_ext"
else
"/:lang/:path/:basename:output_ext"
end
else
"/:lang/:path/:basename:output_ext"
end
end
def url_placeholders
{
:path => @dir,
:basename => basename,
:output_ext => output_ext,
:lang => lang
}
end
def excluded?
site.config['multilingual_exclude'].include? name
end
end
module Convertible
def write(dest)
path = destination(dest)
FileUtils.mkdir_p(File.dirname(path))
File.open(path, 'wb') do |f|
f.write(output)
end
end
end
class LocalizeTag < Liquid::Tag
def initialize(tag_name, params, tokens)
super
@key, @lang = params.strip.split(' ')
end
def render(context)
lang = @lang || context.registers[:site].config['languages'].first
if (context.registers[:site].i18n.include? @key) &&
(context.registers[:site].i18n[@key].include? lang)
context.registers[:site].i18n[@key][lang]
else
raise KeyError.new "I found no key: #{@key} in #{lang} defined in _i18n.yml"
end
end
end
end
Liquid::Template.register_tag('t', Jekyll::LocalizeTag)
@sp3c73r2038
Copy link
Author

With multilingual plugin, posts/pages should be named in yyyy-mm-dd-foo-bar.#{lang}.ext form, which #{lang} is the ISO 639 codes. Posts/pages which lack a #{lang} part is considered as in default language.

use in_language?(lang) method to check if the post is in the corresponding language (useful when show link in templates).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment