jekyll-open-sdg-plugins 1.6.1 → 1.7.0.pre.beta1
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/.editorconfig +16 -16
- data/.github/workflows/test-pull-requests.yml +17 -17
- data/.gitignore +6 -6
- data/LICENSE +21 -21
- data/Makefile +33 -33
- data/README.md +7 -7
- data/jekyll-open-sdg-plugins.gemspec +18 -18
- data/lib/jekyll-open-sdg-plugins/backwards_compatibility.rb +64 -64
- data/lib/jekyll-open-sdg-plugins/create_goals.rb +85 -85
- data/lib/jekyll-open-sdg-plugins/create_indicators.rb +206 -206
- data/lib/jekyll-open-sdg-plugins/create_pages.rb +135 -135
- data/lib/jekyll-open-sdg-plugins/fetch_remote_data.rb +188 -188
- data/lib/jekyll-open-sdg-plugins/helpers.rb +132 -132
- data/lib/jekyll-open-sdg-plugins/metadata_schema_to_config.rb +72 -72
- data/lib/jekyll-open-sdg-plugins/schema-indicator-config.json +787 -709
- data/lib/jekyll-open-sdg-plugins/schema-site-config.json +1652 -1607
- data/lib/jekyll-open-sdg-plugins/sdg_variables.rb +614 -549
- data/lib/jekyll-open-sdg-plugins/search_index.rb +102 -102
- data/lib/jekyll-open-sdg-plugins/site_configuration.rb +73 -73
- data/lib/jekyll-open-sdg-plugins/translate_date.rb +122 -122
- data/lib/jekyll-open-sdg-plugins/translate_key.rb +20 -20
- data/lib/jekyll-open-sdg-plugins/translate_metadata_field.rb +111 -111
- data/lib/jekyll-open-sdg-plugins/validate_indicator_config.rb +52 -52
- data/lib/jekyll-open-sdg-plugins/validate_site_config.rb +34 -34
- data/lib/jekyll-open-sdg-plugins/version.rb +3 -3
- data/lib/jekyll-open-sdg-plugins.rb +18 -18
- data/tests/Gemfile +7 -7
- data/tests/_config.yml +168 -168
- metadata +5 -5
@@ -1,135 +1,135 @@
|
|
1
|
-
require "jekyll"
|
2
|
-
require_relative "helpers"
|
3
|
-
|
4
|
-
module JekyllOpenSdgPlugins
|
5
|
-
class CreatePages < Jekyll::Generator
|
6
|
-
safe true
|
7
|
-
priority :normal
|
8
|
-
|
9
|
-
def generate(site)
|
10
|
-
# If site.create_pages is set, create the 4 required pages. These include:
|
11
|
-
# - the home page: /
|
12
|
-
# - the indicators json page: /indicators.json
|
13
|
-
# - the search results page: /search
|
14
|
-
# - the reporting status page: /reporting-status
|
15
|
-
#
|
16
|
-
# These can be overridden though, with a create_pages.pages setting in
|
17
|
-
# _config.yml, like so:
|
18
|
-
#
|
19
|
-
# create_pages:
|
20
|
-
# pages:
|
21
|
-
# - folder: ''
|
22
|
-
# layout: frontpage
|
23
|
-
# - filename: my-json-file.json
|
24
|
-
# folder: my-subfolder
|
25
|
-
# layout: indicator-json
|
26
|
-
#
|
27
|
-
# Note the optional "filename" setting for when the page needs a specific
|
28
|
-
# filename (as opposed to being "index.html" inside a named folder).
|
29
|
-
#
|
30
|
-
# To use the default 4 pages, simply put:
|
31
|
-
#
|
32
|
-
# create_pages: true
|
33
|
-
if (site.config['languages'] and site.config['create_pages'])
|
34
|
-
|
35
|
-
default_pages = [
|
36
|
-
{
|
37
|
-
'folder' => '/',
|
38
|
-
'layout' => 'frontpage'
|
39
|
-
},
|
40
|
-
{
|
41
|
-
'folder' => '/reporting-status',
|
42
|
-
'layout' => 'reportingstatus',
|
43
|
-
'title' => 'status.reporting_status',
|
44
|
-
},
|
45
|
-
{
|
46
|
-
'filename' => 'indicators.json',
|
47
|
-
'folder' => '/',
|
48
|
-
'layout' => 'indicator-json',
|
49
|
-
},
|
50
|
-
{
|
51
|
-
'folder' => '/search',
|
52
|
-
'layout' => 'search',
|
53
|
-
'title' => 'search.search',
|
54
|
-
}
|
55
|
-
]
|
56
|
-
pages = default_pages
|
57
|
-
if (site.config['create_pages'].is_a?(Hash) and site.config['create_pages'].key?('pages'))
|
58
|
-
# Backwards compatability to support the deprecated "pages" key.
|
59
|
-
pages = site.config['create_pages']['pages']
|
60
|
-
elsif site.config['create_pages'].is_a?(Array)
|
61
|
-
pages = site.config['create_pages']
|
62
|
-
end
|
63
|
-
|
64
|
-
# Clone pages so that we don't edit the original.
|
65
|
-
pages = pages.clone
|
66
|
-
|
67
|
-
# Hardcode the site configuration page if it's not already there.
|
68
|
-
form_settings = site.config['site_config_form']
|
69
|
-
config_page = pages.find { |page| page['layout'] == 'config-builder' }
|
70
|
-
if config_page == nil
|
71
|
-
if form_settings && form_settings['enabled']
|
72
|
-
pages.push({
|
73
|
-
'folder' => '/config',
|
74
|
-
'layout' => 'config-builder',
|
75
|
-
'title' => 'Open SDG site configuration',
|
76
|
-
'config_type' => 'site',
|
77
|
-
'config_filename' => 'site_config.yml',
|
78
|
-
})
|
79
|
-
end
|
80
|
-
end
|
81
|
-
# Make sure the form settings are set.
|
82
|
-
config_page = pages.find { |page| page['layout'] == 'config-builder' }
|
83
|
-
if config_page != nil && form_settings && form_settings['enabled']
|
84
|
-
config_page['form_settings'] = form_settings
|
85
|
-
end
|
86
|
-
|
87
|
-
# See if we need to "map" any language codes.
|
88
|
-
languages_public = Hash.new
|
89
|
-
if site.config['languages_public']
|
90
|
-
languages_public = opensdg_languages_public(site)
|
91
|
-
end
|
92
|
-
|
93
|
-
# Loop through the languages.
|
94
|
-
site.config['languages'].each_with_index do |language, index|
|
95
|
-
# Get the "public language" (for URLs) which may be different.
|
96
|
-
language_public = language
|
97
|
-
if languages_public[language]
|
98
|
-
language_public = languages_public[language]
|
99
|
-
end
|
100
|
-
# Loop through the pages.
|
101
|
-
pages.each do |page|
|
102
|
-
# Add the language subfolder for all except the default (first) language.
|
103
|
-
dir = index == 0 ? page['folder'] : File.join(language_public, page['folder'])
|
104
|
-
# Create the page.
|
105
|
-
site.collections['pages'].docs << OpenSdgPage.new(site, site.source, dir, page, language)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
# A Page subclass used in the `CreatePages` class.
|
113
|
-
class OpenSdgPage < Jekyll::Page
|
114
|
-
def initialize(site, base, dir, page, language)
|
115
|
-
@site = site
|
116
|
-
@base = base
|
117
|
-
|
118
|
-
index_files = (!page.key?('filename') or page['filename'] == 'index.html' or page['filename'] == '')
|
119
|
-
@dir = index_files ? File.join(dir, '/') : dir
|
120
|
-
@name = index_files ? 'index.html' : page['filename']
|
121
|
-
|
122
|
-
self.process(@name)
|
123
|
-
self.data = {}
|
124
|
-
self.data['language'] = language
|
125
|
-
|
126
|
-
# Add anything else besides "folder" and "filename". This will catch
|
127
|
-
# things like "layout" and "title", and anything else.
|
128
|
-
page.each do |key, value|
|
129
|
-
if key != 'folder' && key != 'filename'
|
130
|
-
self.data[key] = value
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
1
|
+
require "jekyll"
|
2
|
+
require_relative "helpers"
|
3
|
+
|
4
|
+
module JekyllOpenSdgPlugins
|
5
|
+
class CreatePages < Jekyll::Generator
|
6
|
+
safe true
|
7
|
+
priority :normal
|
8
|
+
|
9
|
+
def generate(site)
|
10
|
+
# If site.create_pages is set, create the 4 required pages. These include:
|
11
|
+
# - the home page: /
|
12
|
+
# - the indicators json page: /indicators.json
|
13
|
+
# - the search results page: /search
|
14
|
+
# - the reporting status page: /reporting-status
|
15
|
+
#
|
16
|
+
# These can be overridden though, with a create_pages.pages setting in
|
17
|
+
# _config.yml, like so:
|
18
|
+
#
|
19
|
+
# create_pages:
|
20
|
+
# pages:
|
21
|
+
# - folder: ''
|
22
|
+
# layout: frontpage
|
23
|
+
# - filename: my-json-file.json
|
24
|
+
# folder: my-subfolder
|
25
|
+
# layout: indicator-json
|
26
|
+
#
|
27
|
+
# Note the optional "filename" setting for when the page needs a specific
|
28
|
+
# filename (as opposed to being "index.html" inside a named folder).
|
29
|
+
#
|
30
|
+
# To use the default 4 pages, simply put:
|
31
|
+
#
|
32
|
+
# create_pages: true
|
33
|
+
if (site.config['languages'] and site.config['create_pages'])
|
34
|
+
|
35
|
+
default_pages = [
|
36
|
+
{
|
37
|
+
'folder' => '/',
|
38
|
+
'layout' => 'frontpage'
|
39
|
+
},
|
40
|
+
{
|
41
|
+
'folder' => '/reporting-status',
|
42
|
+
'layout' => 'reportingstatus',
|
43
|
+
'title' => 'status.reporting_status',
|
44
|
+
},
|
45
|
+
{
|
46
|
+
'filename' => 'indicators.json',
|
47
|
+
'folder' => '/',
|
48
|
+
'layout' => 'indicator-json',
|
49
|
+
},
|
50
|
+
{
|
51
|
+
'folder' => '/search',
|
52
|
+
'layout' => 'search',
|
53
|
+
'title' => 'search.search',
|
54
|
+
}
|
55
|
+
]
|
56
|
+
pages = default_pages
|
57
|
+
if (site.config['create_pages'].is_a?(Hash) and site.config['create_pages'].key?('pages'))
|
58
|
+
# Backwards compatability to support the deprecated "pages" key.
|
59
|
+
pages = site.config['create_pages']['pages']
|
60
|
+
elsif site.config['create_pages'].is_a?(Array)
|
61
|
+
pages = site.config['create_pages']
|
62
|
+
end
|
63
|
+
|
64
|
+
# Clone pages so that we don't edit the original.
|
65
|
+
pages = pages.clone
|
66
|
+
|
67
|
+
# Hardcode the site configuration page if it's not already there.
|
68
|
+
form_settings = site.config['site_config_form']
|
69
|
+
config_page = pages.find { |page| page['layout'] == 'config-builder' }
|
70
|
+
if config_page == nil
|
71
|
+
if form_settings && form_settings['enabled']
|
72
|
+
pages.push({
|
73
|
+
'folder' => '/config',
|
74
|
+
'layout' => 'config-builder',
|
75
|
+
'title' => 'Open SDG site configuration',
|
76
|
+
'config_type' => 'site',
|
77
|
+
'config_filename' => 'site_config.yml',
|
78
|
+
})
|
79
|
+
end
|
80
|
+
end
|
81
|
+
# Make sure the form settings are set.
|
82
|
+
config_page = pages.find { |page| page['layout'] == 'config-builder' }
|
83
|
+
if config_page != nil && form_settings && form_settings['enabled']
|
84
|
+
config_page['form_settings'] = form_settings
|
85
|
+
end
|
86
|
+
|
87
|
+
# See if we need to "map" any language codes.
|
88
|
+
languages_public = Hash.new
|
89
|
+
if site.config['languages_public']
|
90
|
+
languages_public = opensdg_languages_public(site)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Loop through the languages.
|
94
|
+
site.config['languages'].each_with_index do |language, index|
|
95
|
+
# Get the "public language" (for URLs) which may be different.
|
96
|
+
language_public = language
|
97
|
+
if languages_public[language]
|
98
|
+
language_public = languages_public[language]
|
99
|
+
end
|
100
|
+
# Loop through the pages.
|
101
|
+
pages.each do |page|
|
102
|
+
# Add the language subfolder for all except the default (first) language.
|
103
|
+
dir = index == 0 ? page['folder'] : File.join(language_public, page['folder'])
|
104
|
+
# Create the page.
|
105
|
+
site.collections['pages'].docs << OpenSdgPage.new(site, site.source, dir, page, language)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# A Page subclass used in the `CreatePages` class.
|
113
|
+
class OpenSdgPage < Jekyll::Page
|
114
|
+
def initialize(site, base, dir, page, language)
|
115
|
+
@site = site
|
116
|
+
@base = base
|
117
|
+
|
118
|
+
index_files = (!page.key?('filename') or page['filename'] == 'index.html' or page['filename'] == '')
|
119
|
+
@dir = index_files ? File.join(dir, '/') : dir
|
120
|
+
@name = index_files ? 'index.html' : page['filename']
|
121
|
+
|
122
|
+
self.process(@name)
|
123
|
+
self.data = {}
|
124
|
+
self.data['language'] = language
|
125
|
+
|
126
|
+
# Add anything else besides "folder" and "filename". This will catch
|
127
|
+
# things like "layout" and "title", and anything else.
|
128
|
+
page.each do |key, value|
|
129
|
+
if key != 'folder' && key != 'filename'
|
130
|
+
self.data[key] = value
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -1,188 +1,188 @@
|
|
1
|
-
require "jekyll"
|
2
|
-
require 'json'
|
3
|
-
require 'deep_merge'
|
4
|
-
require 'open-uri'
|
5
|
-
require_relative "helpers"
|
6
|
-
|
7
|
-
module JekyllOpenSdgPlugins
|
8
|
-
class FetchRemoteData < Jekyll::Generator
|
9
|
-
safe true
|
10
|
-
priority :highest
|
11
|
-
|
12
|
-
# Fix a Unix path in case we are on Windows.
|
13
|
-
def fix_path(path)
|
14
|
-
path_parts = path.split('/')
|
15
|
-
return path_parts.join(File::SEPARATOR)
|
16
|
-
end
|
17
|
-
|
18
|
-
# Our hardcoded list of pieces of the build that we expect.
|
19
|
-
def get_endpoints()
|
20
|
-
return {
|
21
|
-
'meta' => 'meta/all.json',
|
22
|
-
'headlines' => 'headline/all.json',
|
23
|
-
'schema' => 'meta/schema.json',
|
24
|
-
'reporting' => 'stats/reporting.json',
|
25
|
-
'disaggregation' => 'stats/disaggregation.json',
|
26
|
-
'translations' => 'translations/translations.json',
|
27
|
-
'zip' => 'zip/all_indicators.json',
|
28
|
-
'indicator_downloads' => 'downloads/indicator-downloads.json',
|
29
|
-
'data_packages' => 'data-packages/all.json',
|
30
|
-
}
|
31
|
-
end
|
32
|
-
|
33
|
-
# Get a build from a local folder on disk or a remote URL on the Internet.
|
34
|
-
def fetch_build(path)
|
35
|
-
|
36
|
-
is_remote = opensdg_is_path_remote(path)
|
37
|
-
build = {}
|
38
|
-
get_endpoints().each do |key, value|
|
39
|
-
endpoint = is_remote ? path + '/' + value : File.join(path, fix_path(value))
|
40
|
-
|
41
|
-
begin
|
42
|
-
json_file = is_remote ? open(endpoint) : File.open(endpoint)
|
43
|
-
build[key] = JSON.load(json_file)
|
44
|
-
rescue StandardError => e
|
45
|
-
# For backwards compatibility, forego the exception in some cases.
|
46
|
-
abort_build = true
|
47
|
-
if ['translations', 'indicator_downloads', 'disaggregation', 'data_packages'].include? key
|
48
|
-
abort_build = false
|
49
|
-
elsif endpoint.include? '/untranslated/'
|
50
|
-
abort_build = false
|
51
|
-
end
|
52
|
-
if abort_build
|
53
|
-
puts e.message
|
54
|
-
abort 'Unable to read data from: ' + endpoint
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
return build
|
60
|
-
end
|
61
|
-
|
62
|
-
# Predict (before data has been fetched) whether the site is using
|
63
|
-
# translated builds or not.
|
64
|
-
def site_uses_translated_builds(path)
|
65
|
-
|
66
|
-
is_remote = opensdg_is_path_remote(path)
|
67
|
-
endpoints = get_endpoints()
|
68
|
-
# For a quick test, we just use 'meta'.
|
69
|
-
meta = endpoints['meta']
|
70
|
-
endpoint = is_remote ? path + '/' + meta : File.join(path, fix_path(meta))
|
71
|
-
|
72
|
-
begin
|
73
|
-
json_file = is_remote ? open(endpoint) : File.open(endpoint)
|
74
|
-
rescue StandardError => e
|
75
|
-
# If we didn't find an untranslated 'meta', we assume translated builds.
|
76
|
-
return true
|
77
|
-
end
|
78
|
-
|
79
|
-
# Other wise assume untranslated builds.
|
80
|
-
return false
|
81
|
-
end
|
82
|
-
|
83
|
-
def generate(site)
|
84
|
-
|
85
|
-
# For below, make sure there is at least an empty hash at
|
86
|
-
# site.data.translations.
|
87
|
-
if !site.data.has_key?('translations')
|
88
|
-
site.data['translations'] = {}
|
89
|
-
end
|
90
|
-
|
91
|
-
remote = site.config['remote_data_prefix']
|
92
|
-
local = site.config['local_data_folder']
|
93
|
-
|
94
|
-
if !remote && !local
|
95
|
-
abort 'Site config must include "remote_data_prefix".'
|
96
|
-
end
|
97
|
-
|
98
|
-
build_location = remote ? remote : local
|
99
|
-
is_remote = opensdg_is_path_remote(build_location)
|
100
|
-
|
101
|
-
build_location = is_remote ? build_location : File.join(Dir.pwd, build_location)
|
102
|
-
translated_builds = site_uses_translated_builds(build_location)
|
103
|
-
|
104
|
-
if translated_builds
|
105
|
-
# For translated builds, we get a build for each language, and
|
106
|
-
# place them in "subfolders" (so to speak) of site.data.
|
107
|
-
subfolders = site.config['languages'].clone
|
108
|
-
subfolders.append('untranslated')
|
109
|
-
subfolders.each do |language|
|
110
|
-
data_target = site.data[language]
|
111
|
-
translated_build = is_remote ? build_location + '/' + language : File.join(build_location, language)
|
112
|
-
data_source = fetch_build(translated_build)
|
113
|
-
if !data_source.empty?
|
114
|
-
if data_target
|
115
|
-
data_target.deep_merge(data_source)
|
116
|
-
else
|
117
|
-
site.data[language] = data_source
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
# We move the language-specific translations to the
|
122
|
-
# site.data.translations location, where all translations are kept.
|
123
|
-
site.config['languages'].each do |language|
|
124
|
-
translation_target = site.data['translations'][language]
|
125
|
-
translation_source = site.data[language]['translations']
|
126
|
-
if translation_target
|
127
|
-
translation_target.deep_merge(translation_source)
|
128
|
-
else
|
129
|
-
site.data['translations'][language] = translation_source
|
130
|
-
end
|
131
|
-
end
|
132
|
-
# And there are some parts of the build that don't need to be translated
|
133
|
-
# and should be moved to the top level.
|
134
|
-
first_language = site.config['languages'][0]
|
135
|
-
site.data['reporting'] = site.data[first_language]['reporting']
|
136
|
-
site.data['schema'] = site.data[first_language]['schema']
|
137
|
-
site.data['zip'] = site.data[first_language]['zip']
|
138
|
-
else
|
139
|
-
# For untranslated builds, we download one build only, and place it
|
140
|
-
# in the "root" (so to speak) of site.data. Nothing else is needed.
|
141
|
-
target = site.data
|
142
|
-
source = fetch_build(build_location)
|
143
|
-
if !source.empty?
|
144
|
-
target.deep_merge(source)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
# Finally support the deprecated 'remote_translations' option.
|
149
|
-
# This is deprecated because translations should now be in the
|
150
|
-
# data repository, where they will be fetched in fetch_build().
|
151
|
-
if site.config['remote_translations']
|
152
|
-
key = 'translations'
|
153
|
-
target = site.data[key]
|
154
|
-
site.config['remote_translations'].each do |endpoint|
|
155
|
-
begin
|
156
|
-
source = JSON.load(open(endpoint))
|
157
|
-
if target
|
158
|
-
target.deep_merge(source)
|
159
|
-
else
|
160
|
-
site.data[key] = source
|
161
|
-
end
|
162
|
-
rescue StandardError => e
|
163
|
-
puts e.message
|
164
|
-
abort 'Unable to fetch remote translation from: ' + endpoint
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
# This makes sure that the contents of the "local_data_folder" get copied
|
172
|
-
# into the Jekyll build, so that they can be served from the website.
|
173
|
-
Jekyll::Hooks.register :site, :post_write do |site|
|
174
|
-
if site.config['local_data_folder']
|
175
|
-
source = File.join(Dir.pwd, site.config['local_data_folder'], '.')
|
176
|
-
destination = site.config['destination']
|
177
|
-
FileUtils.cp_r(source, destination)
|
178
|
-
# Do the same in the case that "remote_data_prefix" is being used for a local
|
179
|
-
# data folder (since "local_data_folder" is deprecated and undocumented).
|
180
|
-
elsif site.config['remote_data_prefix']
|
181
|
-
if !opensdg_is_path_remote(site.config['remote_data_prefix'])
|
182
|
-
source = File.join(Dir.pwd, site.config['remote_data_prefix'], '.')
|
183
|
-
destination = site.config['destination']
|
184
|
-
FileUtils.cp_r(source, destination)
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
1
|
+
require "jekyll"
|
2
|
+
require 'json'
|
3
|
+
require 'deep_merge'
|
4
|
+
require 'open-uri'
|
5
|
+
require_relative "helpers"
|
6
|
+
|
7
|
+
module JekyllOpenSdgPlugins
|
8
|
+
class FetchRemoteData < Jekyll::Generator
|
9
|
+
safe true
|
10
|
+
priority :highest
|
11
|
+
|
12
|
+
# Fix a Unix path in case we are on Windows.
|
13
|
+
def fix_path(path)
|
14
|
+
path_parts = path.split('/')
|
15
|
+
return path_parts.join(File::SEPARATOR)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Our hardcoded list of pieces of the build that we expect.
|
19
|
+
def get_endpoints()
|
20
|
+
return {
|
21
|
+
'meta' => 'meta/all.json',
|
22
|
+
'headlines' => 'headline/all.json',
|
23
|
+
'schema' => 'meta/schema.json',
|
24
|
+
'reporting' => 'stats/reporting.json',
|
25
|
+
'disaggregation' => 'stats/disaggregation.json',
|
26
|
+
'translations' => 'translations/translations.json',
|
27
|
+
'zip' => 'zip/all_indicators.json',
|
28
|
+
'indicator_downloads' => 'downloads/indicator-downloads.json',
|
29
|
+
'data_packages' => 'data-packages/all.json',
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get a build from a local folder on disk or a remote URL on the Internet.
|
34
|
+
def fetch_build(path)
|
35
|
+
|
36
|
+
is_remote = opensdg_is_path_remote(path)
|
37
|
+
build = {}
|
38
|
+
get_endpoints().each do |key, value|
|
39
|
+
endpoint = is_remote ? path + '/' + value : File.join(path, fix_path(value))
|
40
|
+
|
41
|
+
begin
|
42
|
+
json_file = is_remote ? open(endpoint) : File.open(endpoint)
|
43
|
+
build[key] = JSON.load(json_file)
|
44
|
+
rescue StandardError => e
|
45
|
+
# For backwards compatibility, forego the exception in some cases.
|
46
|
+
abort_build = true
|
47
|
+
if ['translations', 'indicator_downloads', 'disaggregation', 'data_packages'].include? key
|
48
|
+
abort_build = false
|
49
|
+
elsif endpoint.include? '/untranslated/'
|
50
|
+
abort_build = false
|
51
|
+
end
|
52
|
+
if abort_build
|
53
|
+
puts e.message
|
54
|
+
abort 'Unable to read data from: ' + endpoint
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
return build
|
60
|
+
end
|
61
|
+
|
62
|
+
# Predict (before data has been fetched) whether the site is using
|
63
|
+
# translated builds or not.
|
64
|
+
def site_uses_translated_builds(path)
|
65
|
+
|
66
|
+
is_remote = opensdg_is_path_remote(path)
|
67
|
+
endpoints = get_endpoints()
|
68
|
+
# For a quick test, we just use 'meta'.
|
69
|
+
meta = endpoints['meta']
|
70
|
+
endpoint = is_remote ? path + '/' + meta : File.join(path, fix_path(meta))
|
71
|
+
|
72
|
+
begin
|
73
|
+
json_file = is_remote ? open(endpoint) : File.open(endpoint)
|
74
|
+
rescue StandardError => e
|
75
|
+
# If we didn't find an untranslated 'meta', we assume translated builds.
|
76
|
+
return true
|
77
|
+
end
|
78
|
+
|
79
|
+
# Other wise assume untranslated builds.
|
80
|
+
return false
|
81
|
+
end
|
82
|
+
|
83
|
+
def generate(site)
|
84
|
+
|
85
|
+
# For below, make sure there is at least an empty hash at
|
86
|
+
# site.data.translations.
|
87
|
+
if !site.data.has_key?('translations')
|
88
|
+
site.data['translations'] = {}
|
89
|
+
end
|
90
|
+
|
91
|
+
remote = site.config['remote_data_prefix']
|
92
|
+
local = site.config['local_data_folder']
|
93
|
+
|
94
|
+
if !remote && !local
|
95
|
+
abort 'Site config must include "remote_data_prefix".'
|
96
|
+
end
|
97
|
+
|
98
|
+
build_location = remote ? remote : local
|
99
|
+
is_remote = opensdg_is_path_remote(build_location)
|
100
|
+
|
101
|
+
build_location = is_remote ? build_location : File.join(Dir.pwd, build_location)
|
102
|
+
translated_builds = site_uses_translated_builds(build_location)
|
103
|
+
|
104
|
+
if translated_builds
|
105
|
+
# For translated builds, we get a build for each language, and
|
106
|
+
# place them in "subfolders" (so to speak) of site.data.
|
107
|
+
subfolders = site.config['languages'].clone
|
108
|
+
subfolders.append('untranslated')
|
109
|
+
subfolders.each do |language|
|
110
|
+
data_target = site.data[language]
|
111
|
+
translated_build = is_remote ? build_location + '/' + language : File.join(build_location, language)
|
112
|
+
data_source = fetch_build(translated_build)
|
113
|
+
if !data_source.empty?
|
114
|
+
if data_target
|
115
|
+
data_target.deep_merge(data_source)
|
116
|
+
else
|
117
|
+
site.data[language] = data_source
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
# We move the language-specific translations to the
|
122
|
+
# site.data.translations location, where all translations are kept.
|
123
|
+
site.config['languages'].each do |language|
|
124
|
+
translation_target = site.data['translations'][language]
|
125
|
+
translation_source = site.data[language]['translations']
|
126
|
+
if translation_target
|
127
|
+
translation_target.deep_merge(translation_source)
|
128
|
+
else
|
129
|
+
site.data['translations'][language] = translation_source
|
130
|
+
end
|
131
|
+
end
|
132
|
+
# And there are some parts of the build that don't need to be translated
|
133
|
+
# and should be moved to the top level.
|
134
|
+
first_language = site.config['languages'][0]
|
135
|
+
site.data['reporting'] = site.data[first_language]['reporting']
|
136
|
+
site.data['schema'] = site.data[first_language]['schema']
|
137
|
+
site.data['zip'] = site.data[first_language]['zip']
|
138
|
+
else
|
139
|
+
# For untranslated builds, we download one build only, and place it
|
140
|
+
# in the "root" (so to speak) of site.data. Nothing else is needed.
|
141
|
+
target = site.data
|
142
|
+
source = fetch_build(build_location)
|
143
|
+
if !source.empty?
|
144
|
+
target.deep_merge(source)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Finally support the deprecated 'remote_translations' option.
|
149
|
+
# This is deprecated because translations should now be in the
|
150
|
+
# data repository, where they will be fetched in fetch_build().
|
151
|
+
if site.config['remote_translations']
|
152
|
+
key = 'translations'
|
153
|
+
target = site.data[key]
|
154
|
+
site.config['remote_translations'].each do |endpoint|
|
155
|
+
begin
|
156
|
+
source = JSON.load(open(endpoint))
|
157
|
+
if target
|
158
|
+
target.deep_merge(source)
|
159
|
+
else
|
160
|
+
site.data[key] = source
|
161
|
+
end
|
162
|
+
rescue StandardError => e
|
163
|
+
puts e.message
|
164
|
+
abort 'Unable to fetch remote translation from: ' + endpoint
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# This makes sure that the contents of the "local_data_folder" get copied
|
172
|
+
# into the Jekyll build, so that they can be served from the website.
|
173
|
+
Jekyll::Hooks.register :site, :post_write do |site|
|
174
|
+
if site.config['local_data_folder']
|
175
|
+
source = File.join(Dir.pwd, site.config['local_data_folder'], '.')
|
176
|
+
destination = site.config['destination']
|
177
|
+
FileUtils.cp_r(source, destination)
|
178
|
+
# Do the same in the case that "remote_data_prefix" is being used for a local
|
179
|
+
# data folder (since "local_data_folder" is deprecated and undocumented).
|
180
|
+
elsif site.config['remote_data_prefix']
|
181
|
+
if !opensdg_is_path_remote(site.config['remote_data_prefix'])
|
182
|
+
source = File.join(Dir.pwd, site.config['remote_data_prefix'], '.')
|
183
|
+
destination = site.config['destination']
|
184
|
+
FileUtils.cp_r(source, destination)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|