jekyll-multiple-languages-plugin 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.txt +251 -78
- data/README.md +197 -59
- data/lib/jekyll-multiple-languages-plugin.rb +445 -0
- data/lib/plugin/version.rb +6 -0
- metadata +33 -39
- data/.gitignore +0 -21
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/example/Gemfile +0 -4
- data/example/LICENSE +0 -21
- data/example/README.md +0 -11
- data/example/_config.yml +0 -8
- data/example/_i18n/en.yml +0 -10
- data/example/_i18n/en/_posts/2013-12-09-example-post.md +0 -15
- data/example/_i18n/en/footer.md +0 -2
- data/example/_i18n/es.yml +0 -10
- data/example/_i18n/es/_posts/2013-12-09-example-post.md +0 -15
- data/example/_i18n/es/footer.md +0 -2
- data/example/_i18n/it.yml +0 -10
- data/example/_i18n/it/_posts/2013-12-09-example-post.md +0 -16
- data/example/_i18n/it/footer.md +0 -2
- data/example/_includes/post.html +0 -40
- data/example/_layouts/default.html +0 -60
- data/example/_layouts/post.html +0 -5
- data/example/_plugins/jekyll-multiple-languages-plugin.rb +0 -1
- data/example/css/main.css +0 -285
- data/example/css/responsive.css +0 -92
- data/example/css/syntax.css +0 -60
- data/example/favicon.ico +0 -0
- data/example/images/cover.jpg +0 -0
- data/example/images/logo.png +0 -0
- data/example/images/sidebar-button.png +0 -0
- data/example/index.html +0 -8
- data/example/scripts/responsive.js +0 -14
- data/jekyll-multiple-languages-plugin.gemspec +0 -23
- data/lib/jekyll/multiple/languages/plugin.rb +0 -208
- data/lib/jekyll/multiple/languages/plugin/version.rb +0 -9
@@ -0,0 +1,445 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
Jekyll Multiple Languages is an internationalization plugin for Jekyll. It
|
4
|
+
compiles your Jekyll site for one or more languages with a similar approach as
|
5
|
+
Rails does. The different sites will be stored in sub folders with the same name
|
6
|
+
as the language it contains.
|
7
|
+
|
8
|
+
Please visit https://github.com/screeninteraction/jekyll-multiple-languages-plugin
|
9
|
+
for more details.
|
10
|
+
|
11
|
+
=end
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
require_relative "plugin/version"
|
16
|
+
|
17
|
+
module Jekyll
|
18
|
+
|
19
|
+
##############################################################################
|
20
|
+
# class Site
|
21
|
+
##############################################################################
|
22
|
+
class Site
|
23
|
+
|
24
|
+
attr_accessor :parsed_translations # Hash that stores parsed translations read from YAML files.
|
25
|
+
|
26
|
+
alias :process_org :process
|
27
|
+
|
28
|
+
#======================================
|
29
|
+
# process
|
30
|
+
#
|
31
|
+
# Reads Jekyll and plugin configuration parameters set on _config.yml, sets
|
32
|
+
# main parameters and processes the website for each language.
|
33
|
+
#======================================
|
34
|
+
def process
|
35
|
+
# Check if plugin settings are set, if not, set a default or quit.
|
36
|
+
#-------------------------------------------------------------------------
|
37
|
+
self.parsed_translations ||= {}
|
38
|
+
|
39
|
+
self.config['exclude_from_localizations'] ||= []
|
40
|
+
|
41
|
+
if ( !self.config['languages'] or
|
42
|
+
self.config['languages'].empty? or
|
43
|
+
!self.config['languages'].all?
|
44
|
+
)
|
45
|
+
puts 'You must provide at least one language using the "languages" setting on your _config.yml.'
|
46
|
+
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# Variables
|
52
|
+
#-------------------------------------------------------------------------
|
53
|
+
|
54
|
+
# Original Jekyll configurations
|
55
|
+
baseurl_org = self.config[ 'baseurl' ] # Baseurl set on _config.yml
|
56
|
+
exclude_org = self.exclude # List of excluded paths
|
57
|
+
dest_org = self.dest # Destination folder where the website is generated
|
58
|
+
|
59
|
+
# Site building only variables
|
60
|
+
languages = self.config['languages'] # List of languages set on _config.yml
|
61
|
+
|
62
|
+
# Site wide plugin configurations
|
63
|
+
self.config['default_lang'] = languages.first # Default language (first language of array set on _config.yml)
|
64
|
+
self.config[ 'lang'] = languages.first # Current language being processed
|
65
|
+
self.config['baseurl_root'] = baseurl_org # Baseurl of website root (without the appended language code)
|
66
|
+
|
67
|
+
|
68
|
+
# Build the website for default language
|
69
|
+
#-------------------------------------------------------------------------
|
70
|
+
puts "Building site for default language: \"#{self.config['lang']}\" to: #{self.dest}"
|
71
|
+
|
72
|
+
process_org
|
73
|
+
|
74
|
+
|
75
|
+
# Build the website for the other languages
|
76
|
+
#-------------------------------------------------------------------------
|
77
|
+
|
78
|
+
# Remove .htaccess file from included files, so it wont show up on translations folders.
|
79
|
+
self.include -= [".htaccess"]
|
80
|
+
|
81
|
+
languages.drop(1).each do |lang|
|
82
|
+
|
83
|
+
# Language specific config/variables
|
84
|
+
@dest = dest_org + "/" + lang
|
85
|
+
self.config['baseurl'] = baseurl_org + "/" + lang
|
86
|
+
self.config['lang'] = lang
|
87
|
+
|
88
|
+
# exclude folders or files from being copied to all the language folders
|
89
|
+
exclude_from_localizations = self.config['exclude_from_localizations']
|
90
|
+
self.exclude = exclude_org + exclude_from_localizations
|
91
|
+
|
92
|
+
puts "Building site for language: \"#{self.config['lang']}\" to: #{self.dest}"
|
93
|
+
|
94
|
+
process_org
|
95
|
+
end
|
96
|
+
|
97
|
+
puts 'Build complete'
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
if Gem::Version.new(Jekyll::VERSION) < Gem::Version.new("3.0.0")
|
103
|
+
alias :read_posts_org :read_posts
|
104
|
+
|
105
|
+
#======================================
|
106
|
+
# read_posts
|
107
|
+
#======================================
|
108
|
+
def read_posts(dir)
|
109
|
+
translate_posts = !self.config['exclude_from_localizations'].include?("_posts")
|
110
|
+
|
111
|
+
if dir == '' && translate_posts
|
112
|
+
read_posts("_i18n/#{self.config['lang']}/")
|
113
|
+
else
|
114
|
+
read_posts_org(dir)
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
|
124
|
+
##############################################################################
|
125
|
+
# class PostReader
|
126
|
+
##############################################################################
|
127
|
+
class PostReader
|
128
|
+
|
129
|
+
if Gem::Version.new(Jekyll::VERSION) >= Gem::Version.new("3.0.0")
|
130
|
+
alias :read_posts_org :read_posts
|
131
|
+
|
132
|
+
#======================================
|
133
|
+
# read_posts
|
134
|
+
#======================================
|
135
|
+
def read_posts(dir)
|
136
|
+
translate_posts = !site.config['exclude_from_localizations'].include?("_posts")
|
137
|
+
if dir == '' && translate_posts
|
138
|
+
read_posts("_i18n/#{site.config['lang']}/")
|
139
|
+
else
|
140
|
+
read_posts_org(dir)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
|
148
|
+
##############################################################################
|
149
|
+
# class Page
|
150
|
+
##############################################################################
|
151
|
+
class Page
|
152
|
+
|
153
|
+
#======================================
|
154
|
+
# permalink
|
155
|
+
#======================================
|
156
|
+
def permalink
|
157
|
+
return nil if data.nil? || data['permalink'].nil?
|
158
|
+
|
159
|
+
if site.config['relative_permalinks']
|
160
|
+
File.join(@dir, data['permalink'])
|
161
|
+
else
|
162
|
+
# Look if there's a permalink overwrite specified for this lang
|
163
|
+
data['permalink_'+site.config['lang']] || data['permalink']
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
##############################################################################
|
172
|
+
# class Post
|
173
|
+
##############################################################################
|
174
|
+
class Post
|
175
|
+
|
176
|
+
if Gem::Version.new(Jekyll::VERSION) < Gem::Version.new("3.0.0")
|
177
|
+
alias :populate_categories_org :populate_categories
|
178
|
+
|
179
|
+
#======================================
|
180
|
+
# populate_categories
|
181
|
+
#
|
182
|
+
# Monkey patched this method to remove unwanted strings
|
183
|
+
# ("_i18n" and language code) that are prepended to posts categories
|
184
|
+
# because of how the multilingual posts are arranged in subfolders.
|
185
|
+
#======================================
|
186
|
+
def populate_categories
|
187
|
+
categories_from_data = Utils.pluralized_array_from_hash(data, 'category', 'categories')
|
188
|
+
self.categories = (
|
189
|
+
Array(categories) + categories_from_data
|
190
|
+
).map {|c| c.to_s.downcase}.flatten.uniq
|
191
|
+
|
192
|
+
self.categories.delete("_i18n")
|
193
|
+
self.categories.delete(site.config['lang'])
|
194
|
+
|
195
|
+
return self.categories
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
|
202
|
+
##############################################################################
|
203
|
+
# class Document
|
204
|
+
##############################################################################
|
205
|
+
class Document
|
206
|
+
|
207
|
+
if Gem::Version.new(Jekyll::VERSION) >= Gem::Version.new("3.0.0")
|
208
|
+
alias :populate_categories_org :populate_categories
|
209
|
+
|
210
|
+
#======================================
|
211
|
+
# populate_categories
|
212
|
+
#
|
213
|
+
# Monkey patched this method to remove unwanted strings
|
214
|
+
# ("_i18n" and language code) that are prepended to posts categories
|
215
|
+
# because of how the multilingual posts are arranged in subfolders.
|
216
|
+
#======================================
|
217
|
+
def populate_categories
|
218
|
+
data['categories'].delete("_i18n")
|
219
|
+
data['categories'].delete(site.config['lang'])
|
220
|
+
|
221
|
+
merge_data!({
|
222
|
+
'categories' => (
|
223
|
+
Array(data['categories']) + Utils.pluralized_array_from_hash(data, 'category', 'categories')
|
224
|
+
).map(&:to_s).flatten.uniq
|
225
|
+
})
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
|
232
|
+
#-----------------------------------------------------------------------------
|
233
|
+
#
|
234
|
+
# The next classes implements the plugin Liquid Tags and/or Filters
|
235
|
+
#
|
236
|
+
#-----------------------------------------------------------------------------
|
237
|
+
|
238
|
+
|
239
|
+
##############################################################################
|
240
|
+
# class LocalizeTag
|
241
|
+
#
|
242
|
+
# Localization by getting localized text from YAML files.
|
243
|
+
# User must use the "t" or "translate" liquid tags.
|
244
|
+
##############################################################################
|
245
|
+
class LocalizeTag < Liquid::Tag
|
246
|
+
|
247
|
+
#======================================
|
248
|
+
# initialize
|
249
|
+
#======================================
|
250
|
+
def initialize(tag_name, key, tokens)
|
251
|
+
super
|
252
|
+
@key = key.strip
|
253
|
+
end
|
254
|
+
|
255
|
+
|
256
|
+
|
257
|
+
#======================================
|
258
|
+
# render
|
259
|
+
#======================================
|
260
|
+
def render(context)
|
261
|
+
if "#{context[@key]}" != "" # Check for page variable
|
262
|
+
key = "#{context[@key]}"
|
263
|
+
else
|
264
|
+
key = @key
|
265
|
+
end
|
266
|
+
|
267
|
+
site = context.registers[:site] # Jekyll site object
|
268
|
+
|
269
|
+
lang = site.config['lang']
|
270
|
+
|
271
|
+
unless site.parsed_translations.has_key?(lang)
|
272
|
+
puts "Loading translation from file #{site.source}/_i18n/#{lang}.yml"
|
273
|
+
site.parsed_translations[lang] = YAML.load_file("#{site.source}/_i18n/#{lang}.yml")
|
274
|
+
end
|
275
|
+
|
276
|
+
translation = site.parsed_translations[lang].access(key) if key.is_a?(String)
|
277
|
+
|
278
|
+
if translation.nil? or translation.empty?
|
279
|
+
translation = site.parsed_translations[site.config['default_lang']].access(key)
|
280
|
+
|
281
|
+
puts "Missing i18n key: #{lang}:#{key}"
|
282
|
+
puts "Using translation '%s' from default language: %s" %[translation, site.config['default_lang']]
|
283
|
+
end
|
284
|
+
|
285
|
+
translation
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
|
290
|
+
|
291
|
+
##############################################################################
|
292
|
+
# class LocalizeInclude
|
293
|
+
#
|
294
|
+
# Localization by including whole files that contain the localization text.
|
295
|
+
# User must use the "tf" or "translate_file" liquid tags.
|
296
|
+
##############################################################################
|
297
|
+
module Tags
|
298
|
+
class LocalizeInclude < IncludeTag
|
299
|
+
|
300
|
+
#======================================
|
301
|
+
# render
|
302
|
+
#======================================
|
303
|
+
def render(context)
|
304
|
+
if "#{context[@file]}" != "" # Check for page variable
|
305
|
+
file = "#{context[@file]}"
|
306
|
+
else
|
307
|
+
file = @file
|
308
|
+
end
|
309
|
+
|
310
|
+
site = context.registers[:site] # Jekyll site object
|
311
|
+
|
312
|
+
includes_dir = File.join(site.source, '_i18n/' + site.config['lang'])
|
313
|
+
|
314
|
+
validate_file_name(file)
|
315
|
+
|
316
|
+
Dir.chdir(includes_dir) do
|
317
|
+
choices = Dir['**/*'].reject { |x| File.symlink?(x) }
|
318
|
+
|
319
|
+
if choices.include?( file)
|
320
|
+
source = File.read(file)
|
321
|
+
partial = Liquid::Template.parse(source)
|
322
|
+
|
323
|
+
context.stack do
|
324
|
+
context['include'] = parse_params( context) if @params
|
325
|
+
contents = partial.render(context)
|
326
|
+
ext = File.extname(file)
|
327
|
+
|
328
|
+
converter = site.converters.find { |c| c.matches(ext) }
|
329
|
+
contents = converter.convert(contents) unless converter.nil?
|
330
|
+
|
331
|
+
contents
|
332
|
+
end
|
333
|
+
else
|
334
|
+
raise IOError.new "Included file '#{file}' not found in #{includes_dir} directory"
|
335
|
+
end
|
336
|
+
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
|
344
|
+
##############################################################################
|
345
|
+
# class LocalizeLink
|
346
|
+
#
|
347
|
+
# Creates links or permalinks for translated pages.
|
348
|
+
# User must use the "tl" or "translate_link" liquid tags.
|
349
|
+
##############################################################################
|
350
|
+
class LocalizeLink < Liquid::Tag
|
351
|
+
|
352
|
+
#======================================
|
353
|
+
# initialize
|
354
|
+
#======================================
|
355
|
+
def initialize(tag_name, key, tokens)
|
356
|
+
super
|
357
|
+
@key = key
|
358
|
+
end
|
359
|
+
|
360
|
+
|
361
|
+
|
362
|
+
#======================================
|
363
|
+
# render
|
364
|
+
#======================================
|
365
|
+
def render(context)
|
366
|
+
if "#{context[@key]}" != "" # Check for page variable
|
367
|
+
key = "#{context[@key]}"
|
368
|
+
else
|
369
|
+
key = @key
|
370
|
+
end
|
371
|
+
|
372
|
+
site = context.registers[:site] # Jekyll site object
|
373
|
+
|
374
|
+
key = key.split
|
375
|
+
namespace = key[0]
|
376
|
+
lang = key[1] || site.config[ 'lang']
|
377
|
+
default_lang = site.config['default_lang']
|
378
|
+
baseurl = site.baseurl
|
379
|
+
pages = site.pages
|
380
|
+
url = "";
|
381
|
+
|
382
|
+
if default_lang != lang
|
383
|
+
baseurl = baseurl + "/" + lang
|
384
|
+
end
|
385
|
+
|
386
|
+
for p in pages
|
387
|
+
unless p['namespace'].nil?
|
388
|
+
page_namespace = p['namespace']
|
389
|
+
|
390
|
+
if namespace == page_namespace
|
391
|
+
permalink = p['permalink_'+lang] || p['permalink']
|
392
|
+
url = baseurl + permalink
|
393
|
+
end
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
url
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
|
402
|
+
end # End module Jekyll
|
403
|
+
|
404
|
+
|
405
|
+
|
406
|
+
################################################################################
|
407
|
+
# class Hash
|
408
|
+
################################################################################
|
409
|
+
unless Hash.method_defined? :access
|
410
|
+
class Hash
|
411
|
+
|
412
|
+
#======================================
|
413
|
+
# access
|
414
|
+
#======================================
|
415
|
+
def access(path)
|
416
|
+
ret = self
|
417
|
+
|
418
|
+
path.split('.').each do |p|
|
419
|
+
|
420
|
+
if p.to_i.to_s == p
|
421
|
+
ret = ret[p.to_i]
|
422
|
+
else
|
423
|
+
ret = ret[p.to_s] || ret[p.to_sym]
|
424
|
+
end
|
425
|
+
|
426
|
+
break unless ret
|
427
|
+
end
|
428
|
+
|
429
|
+
ret
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
|
435
|
+
|
436
|
+
################################################################################
|
437
|
+
# Liquid tags definitions
|
438
|
+
|
439
|
+
Liquid::Template.register_tag('t', Jekyll::LocalizeTag )
|
440
|
+
Liquid::Template.register_tag('translate', Jekyll::LocalizeTag )
|
441
|
+
Liquid::Template.register_tag('tf', Jekyll::Tags::LocalizeInclude)
|
442
|
+
Liquid::Template.register_tag('translate_file', Jekyll::Tags::LocalizeInclude)
|
443
|
+
Liquid::Template.register_tag('tl', Jekyll::LocalizeLink )
|
444
|
+
Liquid::Template.register_tag('translate_link', Jekyll::LocalizeLink )
|
445
|
+
|