jekyll-locale 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +127 -1
- data/lib/jekyll/locale/drop.rb +6 -0
- data/lib/jekyll/locale/handler.rb +44 -10
- data/lib/jekyll/locale/page.rb +40 -0
- data/lib/jekyll/locale/page_generator.rb +30 -0
- data/lib/jekyll/locale/version.rb +1 -1
- data/lib/jekyll/patches/site.rb +2 -2
- data/lib/jekyll/patches/utils.rb +1 -1
- data/lib/jekyll-locale.rb +33 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95f578476bc1531c27696fd1218bc914ec176686
|
4
|
+
data.tar.gz: e3723615a5e94829370795bcc51a4d70c27b20db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cd1ed64b59d8f5f8f308abba21bc6d1cbf29ed54f79d317dcd6741d1b73c37ebed95a12e2349c0bf65e5d3531394fcefb83c6a0edde6c40dac85e606a93080b
|
7
|
+
data.tar.gz: d37d608b72baff43775909273f1ebe3cf73452d1dcac35baa7bf168174d379fccc8fa4cd4d5266260a654cbb14e9292acad2f854a440c1b320c43f661b96ed79
|
data/README.md
CHANGED
@@ -1,3 +1,129 @@
|
|
1
1
|
# Jekyll Locale
|
2
2
|
|
3
|
-
A localization plugin for Jekyll
|
3
|
+
A localization plugin for Jekyll.
|
4
|
+
|
5
|
+
|
6
|
+
## Features
|
7
|
+
|
8
|
+
* Exposes a `{{ locale }}` object for your Liquid templates. The *payload* for this object is derived from data files and
|
9
|
+
has been *preconfigured* with the following:
|
10
|
+
|
11
|
+
```yaml
|
12
|
+
locale : en # Sets the 'default locale' for the site
|
13
|
+
locales_dir : locales # Sets the base location for translation data, within your configured `data_dir`.
|
14
|
+
# Therefore, this setting implies that the plugin looks for translation data in
|
15
|
+
# either `_data/locales/` or a data file named `locales`. e.g. `_data/locales.yml`.
|
16
|
+
```
|
17
|
+
Ergo, `{{ locale }}` is simply a *syntactic sugar* for the construct `{{ site.data[site.locales_dir][site.locale] }}`.
|
18
|
+
* Generates a *copy* of every page that renders into a HTML file, and every document set to be written, and renders
|
19
|
+
them into dedicated urls prepended by a supported locale.
|
20
|
+
For example, if one were to configure the plugin with `available_locales: ["de", "fr", "en", "es"]`, then a file
|
21
|
+
named `about.md` with custom permalink set to `/about/` will result in the following files:
|
22
|
+
* `_site/about/index.html`
|
23
|
+
* `_site/de/about/index.html`
|
24
|
+
* `_site/es/about/index.html`
|
25
|
+
* `_site/fr/about/index.html`
|
26
|
+
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
1. Add plugin to the `:jekyll_plugins` group in your Gemfile:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
group :jekyll_plugins do
|
34
|
+
gem "jekyll-locale", "~> 0.1"
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
2. Decide what the default locale for your site is going to be, what other locales need to be rendered, and where you'd
|
39
|
+
place the translation data files. Then edit your config file to override the default plugin configuration, as required.
|
40
|
+
(See above section for default settings). For example, to render the site with data for just the custom `fr` locale:
|
41
|
+
|
42
|
+
```yaml
|
43
|
+
# _config.yml
|
44
|
+
|
45
|
+
author: John Doe
|
46
|
+
locale: "fr"
|
47
|
+
```
|
48
|
+
|
49
|
+
But if you'd like the site to be rendered using both the default `en` and custom `fr` locales, then
|
50
|
+
|
51
|
+
```yaml
|
52
|
+
# _config.yml
|
53
|
+
|
54
|
+
author: John Doe
|
55
|
+
available_locales: ["fr"] # or ["fr", "en"] if you want
|
56
|
+
```
|
57
|
+
|
58
|
+
3. Prepare your locale data file(s) with appropriate key-value pairs. For example,
|
59
|
+
|
60
|
+
```yaml
|
61
|
+
# _data/locales.yml
|
62
|
+
|
63
|
+
en:
|
64
|
+
home-page: Home
|
65
|
+
about me : About Me
|
66
|
+
portfolio: Portfolio
|
67
|
+
fr:
|
68
|
+
home-page: Accueil
|
69
|
+
about me : À propos
|
70
|
+
portfolio: Portefeuille
|
71
|
+
```
|
72
|
+
*(Note the use of heterogeneous format of keys..)*
|
73
|
+
|
74
|
+
4. Use the data above in a template or a document through the {{ locale }} object. For example,
|
75
|
+
|
76
|
+
```
|
77
|
+
List of link names in my navbar:
|
78
|
+
* {{ locale.home_page }}
|
79
|
+
* {{ locale.about_me }}
|
80
|
+
* {{ locale.portfolio }}
|
81
|
+
```
|
82
|
+
*(Note that the ids passed to the `locale` object contain an underscore instead.)*
|
83
|
+
The locale data keys are stored internally as `snake_case` strings. So `about me` or `about-me` will always be stored
|
84
|
+
as `about_me` internally and the corresponding value can only be retrieved by using the snake_cased key.
|
85
|
+
|
86
|
+
Additionally, every page can determine its own locale via the `{{ page.locale }} construct. For example,
|
87
|
+
|
88
|
+
```html
|
89
|
+
<!DOCTYPE html>
|
90
|
+
<html lang="{{ page.locale }}">
|
91
|
+
```
|
92
|
+
|
93
|
+
|
94
|
+
## Advanced Usage
|
95
|
+
|
96
|
+
Each generated locale page is aware of its canonical page and its sibling locale page (for sites rendering three or more
|
97
|
+
locales) and can be used to render meta tags for optimal SEO.
|
98
|
+
|
99
|
+
Adding the following Liquid construct inside your `<head />` tag will render the markup that tells the crawler how the
|
100
|
+
pages are related to each other:
|
101
|
+
|
102
|
+
```html
|
103
|
+
{% for item in page.hreflangs %}
|
104
|
+
<link rel="{{ item.relation }}" hreflang="{{ item.locale }}" href="{{ item.url | absolute_url }}" />
|
105
|
+
{% endfor %}
|
106
|
+
```
|
107
|
+
|
108
|
+
For example, `about.md` page with `permalink: /about/` in a site setup to render for locales `["en", "es", "fr"]`
|
109
|
+
and hosted at `http://example.com` will render with the following:
|
110
|
+
|
111
|
+
```html
|
112
|
+
<link rel="canonical" hreflang="en" href="http://example.com/about/" />
|
113
|
+
<link rel="alternate" hreflang="es" href="http://example.com/es/about/" />
|
114
|
+
<link rel="alternate" hreflang="fr" href="http://example.com/fr/about/" />
|
115
|
+
```
|
116
|
+
|
117
|
+
*The above use of `rel="canonical"` with `hreflang` attribute is generally frowned upon and not recommended by Google.* </br>
|
118
|
+
Instead filter out the canonical url from the for-loop, and render the canonical link as an `alternate` with the
|
119
|
+
`x-default` tag, along with a self-referencing declaration:
|
120
|
+
|
121
|
+
```html
|
122
|
+
<link rel="alternate" hreflang="{{ page.locale }}" href="{{ page.url | absolute_url }}" />
|
123
|
+
{% for item in page.hreflangs %}
|
124
|
+
{% unless item.relation == 'canonical' %}
|
125
|
+
<link rel="{{ item.relation }}" hreflang="{{ item.locale }}" href="{{ item.url | absolute_url }}" />
|
126
|
+
{% endunless %}
|
127
|
+
{% endfor %}
|
128
|
+
<link rel="alternate" hreflang="x-default" href="{{ page.url | absolute_url }}" />
|
129
|
+
```
|
data/lib/jekyll/locale/drop.rb
CHANGED
@@ -2,29 +2,60 @@
|
|
2
2
|
|
3
3
|
module Jekyll
|
4
4
|
class Locale::Handler
|
5
|
+
attr_writer :current_locale
|
6
|
+
|
5
7
|
def initialize(site)
|
6
8
|
@site = site
|
7
9
|
@config = site.config
|
8
10
|
end
|
9
11
|
|
10
12
|
def reset
|
11
|
-
@
|
13
|
+
@locale_data = nil
|
14
|
+
@portfolio = nil
|
12
15
|
end
|
13
16
|
|
14
17
|
def data
|
15
|
-
|
16
|
-
|
17
|
-
return {} unless fallback.is_a?(Hash)
|
18
|
+
locale_data[current_locale] || locale_data[default_locale]
|
19
|
+
end
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
+
def portfolio
|
22
|
+
@portfolio ||= (site.docs_to_write + html_pages)
|
23
|
+
end
|
24
|
+
|
25
|
+
def available_locales
|
26
|
+
@available_locales ||= begin
|
27
|
+
locales = Array(config["available_locales"]) - [default_locale]
|
28
|
+
locales.compact!
|
29
|
+
locales
|
21
30
|
end
|
22
31
|
end
|
23
32
|
|
33
|
+
def current_locale
|
34
|
+
@current_locale ||= default_locale
|
35
|
+
end
|
36
|
+
|
37
|
+
def default_locale
|
38
|
+
@default_locale ||= begin
|
39
|
+
value = config["locale"]
|
40
|
+
value.to_s.empty? ? "en" : value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def inspect
|
45
|
+
"#<#{self.class} @site=#{site}>"
|
46
|
+
end
|
47
|
+
|
24
48
|
private
|
25
49
|
|
26
50
|
attr_reader :site, :config
|
27
51
|
|
52
|
+
def html_pages
|
53
|
+
@html_pages ||= begin
|
54
|
+
pages = site.site_payload["site"]["html_pages"] || []
|
55
|
+
pages.reject { |page| page.name == "404.html" }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
28
59
|
def locales_dir
|
29
60
|
@locales_dir ||= begin
|
30
61
|
value = config["locales_dir"]
|
@@ -32,10 +63,13 @@ module Jekyll
|
|
32
63
|
end
|
33
64
|
end
|
34
65
|
|
35
|
-
def
|
36
|
-
@
|
37
|
-
|
38
|
-
|
66
|
+
def locale_data
|
67
|
+
@locale_data ||= begin
|
68
|
+
ldata = site.site_data[locales_dir]
|
69
|
+
return {} unless ldata.is_a?(Hash)
|
70
|
+
|
71
|
+
# transform hash to one with "latinized lowercased string keys"
|
72
|
+
Jekyll::Utils.snake_case_keys(ldata)
|
39
73
|
end
|
40
74
|
end
|
41
75
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
class Locale::Page < Page
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_reader :canon, :locale
|
8
|
+
attr_accessor :data, :content, :output
|
9
|
+
|
10
|
+
def_delegators :@canon, :site, :extname, :relative_path
|
11
|
+
|
12
|
+
def initialize(canon, locale)
|
13
|
+
@canon = canon
|
14
|
+
@locale = locale
|
15
|
+
end
|
16
|
+
|
17
|
+
def url
|
18
|
+
@url ||= File.join(locale, canon.url)
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_liquid
|
22
|
+
@to_liquid ||= Locale::PageDrop.new(self)
|
23
|
+
end
|
24
|
+
|
25
|
+
def setup_hreflangs
|
26
|
+
@hreflangs = (canon.locale_pages + [canon] - [self]).map do |locale_page|
|
27
|
+
{
|
28
|
+
"locale" => locale_page.locale || site.locale_handler.default_locale,
|
29
|
+
"relation" => locale_page.locale ? "alternate" : "canonical",
|
30
|
+
"url" => locale_page.url,
|
31
|
+
}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def inspect
|
36
|
+
"#<#{self.class} @canon=#{canon.inspect} @locale=#{locale.inspect}>"
|
37
|
+
end
|
38
|
+
alias_method :to_s, :inspect
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Jekyll
|
4
|
+
class Locale::PageGenerator < Generator
|
5
|
+
safe true
|
6
|
+
priority :lowest
|
7
|
+
|
8
|
+
def generate(site)
|
9
|
+
@site = site
|
10
|
+
handler = site.locale_handler
|
11
|
+
return if handler.available_locales.empty?
|
12
|
+
|
13
|
+
handler.available_locales.each do |locale|
|
14
|
+
handler.portfolio.each do |canon_doc|
|
15
|
+
locale_page = Locale::Page.new(canon_doc, locale)
|
16
|
+
locale_page.content = canon_doc.content
|
17
|
+
locale_page.data = canon_doc.data
|
18
|
+
|
19
|
+
# add locale_page to parent document and base array of pages
|
20
|
+
canon_doc.locale_pages << locale_page
|
21
|
+
site.pages << locale_page
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def inspect
|
27
|
+
"#<#{self.class} @site=#{@site}>"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/jekyll/patches/site.rb
CHANGED
@@ -3,13 +3,13 @@
|
|
3
3
|
module Jekyll
|
4
4
|
class Drops::UnifiedPayloadDrop
|
5
5
|
def locale
|
6
|
-
@locale ||=
|
6
|
+
@locale ||= Locale::Drop.new(@obj.locale_handler)
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
10
|
class Site
|
11
11
|
def locale_handler
|
12
|
-
@locale_handler ||=
|
12
|
+
@locale_handler ||= Locale::Handler.new(self)
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
data/lib/jekyll/patches/utils.rb
CHANGED
data/lib/jekyll-locale.rb
CHANGED
@@ -3,13 +3,46 @@
|
|
3
3
|
module Jekyll
|
4
4
|
module Locale
|
5
5
|
autoload :Drop, "jekyll/locale/drop"
|
6
|
+
autoload :Page, "jekyll/locale/page"
|
6
7
|
autoload :Handler, "jekyll/locale/handler"
|
7
8
|
end
|
9
|
+
|
10
|
+
#
|
11
|
+
|
12
|
+
module LocaleSupport
|
13
|
+
attr_reader :locale
|
14
|
+
|
15
|
+
def hreflangs
|
16
|
+
@hreflangs ||= locale_pages.map do |locale_page|
|
17
|
+
{
|
18
|
+
"locale" => locale_page.locale,
|
19
|
+
"relation" => "alternate",
|
20
|
+
"url" => locale_page.url,
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def locale_pages
|
26
|
+
@locale_pages ||= []
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Enhance Jekyll::Page and Jekyll::Document classes
|
31
|
+
[Page, Document].each { |klass| klass.include LocaleSupport }
|
8
32
|
end
|
9
33
|
|
34
|
+
require_relative "jekyll/locale/page_generator"
|
35
|
+
|
10
36
|
require_relative "jekyll/patches/site"
|
11
37
|
require_relative "jekyll/patches/utils"
|
12
38
|
|
13
39
|
Jekyll::Hooks.register :site, :after_reset do |site|
|
14
40
|
site.locale_handler.reset
|
15
41
|
end
|
42
|
+
|
43
|
+
Jekyll::Hooks.register [:pages, :documents], :pre_render do |document, payload|
|
44
|
+
handler = document.site.locale_handler
|
45
|
+
handler.current_locale = document.locale
|
46
|
+
document.setup_hreflangs if document.is_a?(Jekyll::Locale::Page)
|
47
|
+
payload["page"]["hreflangs"] = document.hreflangs
|
48
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-locale
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ashwin Maroli
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jekyll
|
@@ -36,6 +36,8 @@ files:
|
|
36
36
|
- lib/jekyll-locale.rb
|
37
37
|
- lib/jekyll/locale/drop.rb
|
38
38
|
- lib/jekyll/locale/handler.rb
|
39
|
+
- lib/jekyll/locale/page.rb
|
40
|
+
- lib/jekyll/locale/page_generator.rb
|
39
41
|
- lib/jekyll/locale/version.rb
|
40
42
|
- lib/jekyll/patches/site.rb
|
41
43
|
- lib/jekyll/patches/utils.rb
|