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.
@@ -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
+
@@ -0,0 +1,6 @@
1
+ module Jekyll
2
+ module MultipleLanguagesPlugin
3
+ VERSION = "1.4.0"
4
+ end
5
+ end
6
+