jekyll-uj-powertools 1.2.7 → 1.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1eb2312be53f2c304f73706fa54b5c46ad7dc7d3f5ec430da54c41068923501
4
- data.tar.gz: 3f5529e3c48c5dd86ec556927e5eaa8eabf80d496437df3ca2f1416bfff0e841
3
+ metadata.gz: 06406f26c558d459244fad81422d210523148d4a90bd42d004fcdfcaede642e0
4
+ data.tar.gz: d6e23dd0c11253df4dfef38612049904cb251728beade6139a2d5a74f51f3a19
5
5
  SHA512:
6
- metadata.gz: 42c17aed83e227c2ace9e65c73079ca439e49cae48183a5bdef771e556c043f0cf67f166af174a0505f174f6a36f89aed4bf186b9741f23dad3fe03fbc599bf1
7
- data.tar.gz: d60994e315edf47d64e04e4d5718380293f0aa9f6719b9c3e714f034f451c2b277f3e06f5e6207d291302e70ceb200aba5bc9029e45c8967bda23b152a46bd76
6
+ metadata.gz: a40bb126326706aee31507e2ad02d83a0a1e83ff8927bf99d90f0869d4898034f282f73e27032013c5018c3553ed435964f7de170d4b502f2d3be900ef7e1666
7
+ data.tar.gz: 5c5ff4b05d49cfc03312d7eaa834ef0da25c5a56df0c5ec99fcf7452eda94d40b97809d90edfd1fdfea639008e344c5e7cc22460d00bed30a57fcd48fdd0a05d
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in jekyll-uj-powertools.gemspec
6
6
  gemspec
7
7
 
8
+ # Require Jekyll version if specified in the environment variable
8
9
  if ENV["JEKYLL_VERSION"]
9
10
  gem "jekyll", "~> #{ENV["JEKYLL_VERSION"]}"
10
11
  end
data/README.md CHANGED
@@ -69,6 +69,13 @@ Convert a string to title case.
69
69
  {{ "hello world" | uj_title_case }}
70
70
  ```
71
71
 
72
+ ### `uj.cache_breaker` Variable
73
+ Use the `uj.cache_breaker` variable to append a cache-busting query parameter to your assets.
74
+
75
+ ```liquid
76
+ <link rel="stylesheet" href="{{ "/assets/css/style.css" | prepend: site.baseurl }}?v={{ uj.cache_breaker }}">
77
+ ```
78
+
72
79
  These examples show how you can use the features of `jekyll-uj-powertools` in your Jekyll site.
73
80
 
74
81
  ## 🔧 Development
@@ -85,11 +92,17 @@ bundle exec rspec
85
92
 
86
93
  ## 💎 Build + Publish the Gem
87
94
  ```shell
88
- # Build the gem
89
- gem build jekyll-uj-powertools.gemspec
95
+ # Ensure dist folder exists
96
+ mkdir -p dist
97
+
98
+ # Build the gem and push it to RubyGems
99
+ gem build jekyll-uj-powertools.gemspec -o dist/jekyll-uj-powertools-latest.gem
100
+
101
+ # Publish the latest gem
102
+ gem push dist/jekyll-uj-powertools-latest.gem
90
103
 
91
- # Publish the gem where X.X.X is the version number
92
- gem push jekyll-uj-powertools-X.X.X.gem
104
+ # Clear the files in the dist folder
105
+ rm -rf dist/*
93
106
  ```
94
107
 
95
108
  ## 🗨️ Contributing
@@ -32,6 +32,9 @@ Gem::Specification.new do |spec|
32
32
  spec.add_development_dependency "rake"
33
33
  spec.add_development_dependency "rspec"
34
34
 
35
+ # Translation and HTML manipulation requires Nokogiri
36
+ spec.add_runtime_dependency 'nokogiri', '>= 1.17'
37
+
35
38
  # Ruby version
36
39
  spec.required_ruby_version = ">= 2.0.0"
37
40
  end
@@ -0,0 +1,223 @@
1
+ require 'json'
2
+ require 'net/http'
3
+ require 'fileutils'
4
+ require 'nokogiri'
5
+ require 'digest'
6
+
7
+ module Jekyll
8
+ class TranslatePages < Generator
9
+ safe true
10
+ priority :low
11
+
12
+ # Variables
13
+ # Translation path
14
+ CACHE_DIR = '.temp/translations'
15
+ # Re-translate pages older than this many days
16
+ RECHECK_DAYS = 30
17
+
18
+ def generate(site)
19
+ # Get target languages from site config
20
+ target_langs = site.config.dig('translation', 'languages') || []
21
+
22
+ # Log
23
+ puts "🔁 Starting translation process for supported languages (#{target_langs.length}): #{target_langs.join(', ')}"
24
+ # puts "📂 Cache directory: #{CACHE_DIR}"
25
+ # puts "🔍 All environment variables:"
26
+ # ENV.each { |k, v| puts " #{k}=#{v}" }
27
+ puts "🔍 UJ_ environment variables:"
28
+ ENV.select { |k, _| k.start_with?('UJ_') }.each { |k, v| puts " #{k}=#{v}" }
29
+
30
+ # Skip if site config translation is disabled
31
+ unless site.config.dig('translation', 'enabled')
32
+ puts "🚫 Translation is disabled in _config.yml (translation.enabled: false)"
33
+ return
34
+ end
35
+
36
+ # Quit if UJ_BUILD_MODE is false
37
+ if ENV['UJ_BUILD_MODE'] == 'false' && ENV['UJ_TRANSLATION_FORCE'] != 'true'
38
+ puts "🚫 UJ_BUILD_MODE is set to 'false' (set UJ_TRANSLATION_FORCE=true). Exiting translation process."
39
+ return
40
+ end
41
+
42
+ # Ensure OpenAI API key is set
43
+ unless ENV['OPENAI_API_KEY'] && !ENV['OPENAI_API_KEY'].strip.empty?
44
+ puts "❌ OPENAI_API_KEY not found in environment. Exiting translation process."
45
+ return
46
+ end
47
+
48
+ # Quit if no languages are configured
49
+ if target_langs.empty?
50
+ puts "🚫 No target languages configured in _config.yml (translation.languages). Exiting translation process."
51
+ return
52
+ end
53
+
54
+ # Keep track of skipped files
55
+ skipped_files = []
56
+
57
+ # Loop through all pages in the site
58
+ site.pages.clone.each do |page|
59
+ next unless page.output_ext == '.html'
60
+ original_content = page.content
61
+ original_hash = Digest::SHA256.hexdigest(original_content)
62
+ page_path = page.path.sub(/^_?site\//, '')
63
+
64
+ # Skip if page.translation.enabled is false
65
+ if page.data['translation'] && page.data['translation']['enabled'] == false
66
+ skipped_files << "#{page_path} (translation disabled)"
67
+ next
68
+ end
69
+
70
+ # Skip if page.redirect.url is set
71
+ if page.data['redirect'] && page.data['redirect']['url']
72
+ skipped_files << "#{page_path} (redirect set)"
73
+ next
74
+ end
75
+
76
+ target_langs.each do |lang|
77
+ translated_path = File.join(CACHE_DIR, lang, page_path)
78
+ meta_path = "#{translated_path}.meta.json"
79
+
80
+ # @TODO: Remove this
81
+ # Unless its pages/legal/terms.md, QUIT
82
+ uj_translation_only = ENV['UJ_TRANSLATION_ONLY']
83
+ if uj_translation_only && page_path != uj_translation_only
84
+ skipped_files << "#{page_path} (UJ_TRANSLATION_ONLY is set)"
85
+ next
86
+ end
87
+
88
+ # Log
89
+ puts "🌐 Processing page '#{page_path}' for language '#{lang}'"
90
+
91
+ # Either read cached translation or generate a new one
92
+ translated = read_or_translate(original_content, original_hash, lang, translated_path, meta_path)
93
+
94
+ next unless translated # skip this lang if translation failed
95
+
96
+ # Build new page with translated content
97
+ new_page = page.dup
98
+ new_page.data = page.data.dup
99
+ new_page.data['lang'] = lang
100
+ new_page.data['permalink'] = "/#{lang}#{page.url}"
101
+ new_page.content = rewrite_links(translated, lang)
102
+
103
+ site.pages << new_page
104
+ puts "✅ Added translated page: /#{lang}#{page.url}"
105
+ end
106
+ end
107
+
108
+ # Log skipped files at the end
109
+ if skipped_files.any?
110
+ puts "\n🚫 Skipped files:"
111
+ skipped_files.each { |f| puts " - #{f}" }
112
+ end
113
+
114
+ puts "🎉 Translation process complete."
115
+ end
116
+
117
+ private
118
+
119
+ # Return cached translation or generate new one via API
120
+ def read_or_translate(content, hash, lang, path, meta_path)
121
+ if File.exist?(path) && File.exist?(meta_path)
122
+ meta = JSON.parse(File.read(meta_path)) rescue {}
123
+ last_hash = meta['hash']
124
+ last_time = Time.at(meta['timestamp'].to_i) rescue Time.at(0)
125
+
126
+ age_days = ((Time.now - last_time) / (60 * 60 * 24)).round
127
+ puts "📅 Cache age: #{age_days}/#{RECHECK_DAYS} days"
128
+
129
+ # Determine whether we should re-check based on age
130
+ recheck_due_to_age = RECHECK_DAYS && RECHECK_DAYS > 0 && age_days >= RECHECK_DAYS
131
+
132
+ # Re-translate if hash changed or translation is too old (only if RECHECK_DAYS is truthy)
133
+ if last_hash == hash && !recheck_due_to_age
134
+ puts "📦 Using cached translation at: #{path}"
135
+ return File.read(path)
136
+ else
137
+ puts "🔁 Cache stale or hash changed, regenerating translation..."
138
+ end
139
+ else
140
+ puts "📭 No cache found, generating translation..."
141
+ end
142
+
143
+ # Log before/after content
144
+ puts "\n--- BEFORE CONTENT (#{lang}) ---\n#{content[0..500]}..."
145
+
146
+ # Translate the content using OpenAI API
147
+ begin
148
+ result = translate_with_api(content, lang)
149
+ rescue => e
150
+ puts "❌ Skipping translation for '#{lang}' due to error: #{e.message}"
151
+ return nil
152
+ end
153
+
154
+ # Log the first 500 characters of the result
155
+ puts "\n--- AFTER TRANSLATION (#{lang}) ---\n#{result[0..500]}..."
156
+
157
+ # Save the translation and metadata
158
+ FileUtils.mkdir_p(File.dirname(path))
159
+ File.write(path, result)
160
+ File.write(meta_path, {
161
+ timestamp: Time.now.to_i,
162
+ hash: hash
163
+ }.to_json)
164
+
165
+ puts "📝 Cached translation and metadata written to: #{path}"
166
+
167
+ result
168
+ end
169
+
170
+ # Perform translation via OpenAI API
171
+ def translate_with_api(content, lang)
172
+ system_prompt = "You are a professional translator. Translate the provided HTML content, preserving all original formatting, HTML structure, metadata, and links. Do not explain anything — just return the translated HTML. Translate to #{lang}."
173
+ user_message = content
174
+
175
+ uri = URI('https://api.openai.com/v1/chat/completions')
176
+
177
+ res = Net::HTTP.post(
178
+ uri,
179
+ {
180
+ model: 'gpt-4',
181
+ messages: [
182
+ { role: 'system', content: system_prompt },
183
+ { role: 'user', content: user_message }
184
+ ],
185
+ temperature: 0.3
186
+ }.to_json,
187
+ {
188
+ 'Authorization' => "Bearer #{ENV['OPENAI_API_KEY']}",
189
+ 'Content-Type' => 'application/json'
190
+ }
191
+ )
192
+
193
+ if res.code.to_i != 200
194
+ raise "HTTP #{res.code}: #{res.body}"
195
+ end
196
+
197
+ json = JSON.parse(res.body)
198
+ # Log json
199
+ puts "🔍 API response: #{json.inspect}"
200
+ result = json.dig('choices', 0, 'message', 'content')
201
+
202
+ if result.nil? || result.strip.empty?
203
+ raise "Translation returned empty or invalid content"
204
+ end
205
+
206
+ puts "🔤 Translation complete."
207
+ result
208
+ end
209
+
210
+ # Rewrite internal links to language-prefixed versions
211
+ def rewrite_links(html, lang)
212
+ doc = Nokogiri::HTML::DocumentFragment.parse(html)
213
+ doc.css('a[href^="/"]').each do |a|
214
+ href = a['href']
215
+ next if href.start_with?("/#{lang}") || href.include?('.') || href.start_with?('//')
216
+ new_href = "/#{lang}#{href}"
217
+ puts "🔗 Rewriting link: #{href} -> #{new_href}"
218
+ a['href'] = new_href
219
+ end
220
+ doc.to_html
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,253 @@
1
+ # Libraries
2
+ require 'json'
3
+ require 'net/http'
4
+ require 'fileutils'
5
+ require 'nokogiri'
6
+ require 'digest'
7
+
8
+ # Hook
9
+ Jekyll::Hooks.register :site, :post_write do |site|
10
+ # Variables
11
+ # Translation path
12
+ CACHE_DIR = '.temp/translations'
13
+ # Re-translate pages older than this many days
14
+ RECHECK_DAYS = 30
15
+
16
+ # Get target languages from site config
17
+ target_langs = site.config.dig('translation', 'languages') || []
18
+
19
+ # Log
20
+ puts "🔁 Starting translation process for supported languages (#{target_langs.length}): #{target_langs.join(', ')}"
21
+ puts "🔍 UJ_ environment variables:"
22
+ ENV.select { |k, _| k.start_with?('UJ_') }.each { |k, v| puts " #{k}=#{v}" }
23
+
24
+ # Skip if site config translation is disabled
25
+ unless site.config.dig('translation', 'enabled')
26
+ puts "🚫 Translation is disabled in _config.yml (translation.enabled: false)"
27
+ next
28
+ end
29
+
30
+ # Quit if UJ_BUILD_MODE is false
31
+ if ENV['UJ_BUILD_MODE'] == 'false' && ENV['UJ_TRANSLATION_FORCE'] != 'true'
32
+ puts "🚫 UJ_BUILD_MODE is set to 'false' (set UJ_TRANSLATION_FORCE=true). Exiting translation process."
33
+ next
34
+ end
35
+
36
+ # Ensure OpenAI API key is set
37
+ unless ENV['OPENAI_API_KEY'] && !ENV['OPENAI_API_KEY'].strip.empty?
38
+ puts "❌ OPENAI_API_KEY not found in environment. Exiting translation process."
39
+ next
40
+ end
41
+
42
+ # Quit if no languages are configured
43
+ if target_langs.empty?
44
+ puts "🚫 No target languages configured in _config.yml (translation.languages). Exiting translation process."
45
+ next
46
+ end
47
+
48
+ # Keep track of skipped files
49
+ skipped_files = []
50
+
51
+ # Loop through all pages in the site
52
+ site.pages.clone.each do |page|
53
+ # Quit if its not an HTML page
54
+ next unless page.output_ext == '.html'
55
+
56
+ # Get original content
57
+ original_content = page.output
58
+
59
+ # Extract body content
60
+ doc = Nokogiri::HTML(original_content)
61
+ original_content_body = doc.at('body')&.inner_html.to_s
62
+
63
+ # Compute original hash
64
+ original_hash = Digest::SHA256.hexdigest(original_content_body)
65
+
66
+ # Get page path and URL
67
+ page_path = page.path.sub(/^_?site\//, '')
68
+ page_url = page.url
69
+
70
+ # Skip if page.translation.enabled is false
71
+ if page.data['translation'] && page.data['translation']['enabled'] == false
72
+ skipped_files << "#{page_path} (translation disabled)"
73
+ next
74
+ end
75
+
76
+ # Skip if page.redirect.url is set
77
+ if page.data['redirect'] && page.data['redirect']['url']
78
+ skipped_files << "#{page_path} (redirect set)"
79
+ next
80
+ end
81
+
82
+ # Loop through target languages
83
+ target_langs.each do |lang|
84
+ page_new_url = "/#{lang}#{page.url}"
85
+ page_new_path = File.join(CACHE_DIR, lang, page_new_url)
86
+ page_new_meta_path = "#{page_new_path}.meta.json"
87
+
88
+ # See if we only want to test a specific page
89
+ uj_translation_only = ENV['UJ_TRANSLATION_ONLY']
90
+ if uj_translation_only && page_path != uj_translation_only
91
+ skipped_files << "#{page_path} (UJ_TRANSLATION_ONLY is set)"
92
+ next
93
+ end
94
+
95
+ # Log
96
+ puts "🌐 Processing page '#{page_url}' for language '#{lang}'"
97
+
98
+ # LOG new_page.data
99
+ # Log permalink
100
+ puts "🔗 New permalink: #{page_new_url}"
101
+
102
+ # Either read cached translation or generate a new one
103
+ translated = read_or_translate(original_content_body, original_hash, lang, page_new_path, page_new_meta_path)
104
+
105
+ # Fallback if translation failed
106
+ if translated.nil?
107
+ puts "⚠️ Translation failed for #{page_url}, using original content and marking for retry"
108
+
109
+ # Force a retry next time by setting bad hash + old timestamp
110
+ FileUtils.mkdir_p(File.dirname(page_new_meta_path))
111
+ File.write(page_new_meta_path, {
112
+ timestamp: 0,
113
+ hash: '__fail__'
114
+ }.to_json)
115
+
116
+ translated = original_content_body
117
+ end
118
+
119
+ # Rewrite internal links
120
+ translated_html = rewrite_links(translated, lang)
121
+
122
+ # Inject translated content into original HTML structure
123
+ translated_doc = Nokogiri::HTML(original_content)
124
+ translated_doc.at('body').inner_html = translated_html
125
+ final_html = translated_doc.to_html
126
+
127
+ # Determine output path
128
+ output_dir = site.config['destination']
129
+ translated_output_path = File.join(output_dir, lang, page.url)
130
+ translated_output_path = File.join(translated_output_path, 'index.html') if translated_output_path.end_with?('/')
131
+
132
+ # Write translated page to disk
133
+ FileUtils.mkdir_p(File.dirname(translated_output_path))
134
+ File.write(translated_output_path, final_html)
135
+ puts "✅ Wrote translated file: #{translated_output_path}"
136
+ end
137
+ end
138
+
139
+ # Log skipped files at the end
140
+ if skipped_files.any?
141
+ puts "\n🚫 Skipped files:"
142
+ skipped_files.each { |f| puts " - #{f}" }
143
+ end
144
+
145
+ # Log
146
+ puts "🎉 Translation process complete."
147
+ end
148
+
149
+ def read_or_translate(content, hash, lang, path, page_new_meta_path)
150
+ if File.exist?(path) && File.exist?(page_new_meta_path)
151
+ meta = JSON.parse(File.read(page_new_meta_path)) rescue {}
152
+ last_hash = meta['hash']
153
+ last_time = Time.at(meta['timestamp'].to_i) rescue Time.at(0)
154
+
155
+ age_days = ((Time.now - last_time) / (60 * 60 * 24)).round
156
+ puts "📅 Cache age: #{age_days}/#{RECHECK_DAYS} days"
157
+
158
+ # Determine whether we should re-check based on age
159
+ recheck_due_to_age = RECHECK_DAYS && RECHECK_DAYS > 0 && age_days >= RECHECK_DAYS
160
+
161
+ # Re-translate if hash changed or translation is too old (only if RECHECK_DAYS is truthy)
162
+ if last_hash == hash && !recheck_due_to_age
163
+ puts "📦 Using cached translation at: #{path}"
164
+ return File.read(path)
165
+ else
166
+ puts "🔁 Cache stale or hash changed, regenerating translation..."
167
+ end
168
+ else
169
+ puts "📭 No cache found, generating translation..."
170
+ end
171
+
172
+ # Log before/after content
173
+ puts "\n--- BEFORE CONTENT (#{lang}) ---\n#{content[0..500]}..."
174
+
175
+ # Translate the content using OpenAI API
176
+ begin
177
+ result = translate_with_api(content, lang)
178
+ rescue => e
179
+ puts "❌ Skipping translation for '#{lang}' due to error: #{e.message}"
180
+ return nil
181
+ end
182
+
183
+ # Log the first 500 characters of the result
184
+ puts "\n--- AFTER TRANSLATION (#{lang}) ---\n#{result[0..500]}..."
185
+
186
+ # Save the translation and metadata
187
+ FileUtils.mkdir_p(File.dirname(path))
188
+ File.write(path, result)
189
+ File.write(page_new_meta_path, {
190
+ timestamp: Time.now.to_i,
191
+ hash: hash
192
+ }.to_json)
193
+
194
+ puts "📝 Cached translation and metadata written to: #{path}"
195
+
196
+ result
197
+ end
198
+
199
+ def translate_with_api(content, lang)
200
+ system_prompt = "You are a professional translator. Translate the provided HTML content, preserving all original formatting, HTML structure, metadata, and links. Do not explain anything — just return the translated HTML. Translate to #{lang}."
201
+ user_message = content
202
+
203
+ uri = URI('https://api.openai.com/v1/chat/completions')
204
+
205
+ http = Net::HTTP.new(uri.host, uri.port)
206
+ http.use_ssl = true
207
+ http.read_timeout = 30 # seconds
208
+ http.open_timeout = 10 # seconds
209
+
210
+ request = Net::HTTP::Post.new(uri.path, {
211
+ 'Authorization' => "Bearer #{ENV['OPENAI_API_KEY']}",
212
+ 'Content-Type' => 'application/json'
213
+ })
214
+
215
+ request.body = {
216
+ model: 'gpt-4o',
217
+ messages: [
218
+ { role: 'system', content: system_prompt },
219
+ { role: 'user', content: user_message }
220
+ ],
221
+ temperature: 0.3,
222
+ max_tokens: 4096
223
+ }.to_json
224
+
225
+ response = http.request(request)
226
+
227
+ if response.code.to_i != 200
228
+ raise "HTTP #{response.code}: #{response.body}"
229
+ end
230
+
231
+ json = JSON.parse(response.body)
232
+ puts "🔍 API response: #{json.inspect}"
233
+ result = json.dig('choices', 0, 'message', 'content')
234
+
235
+ if result.nil? || result.strip.empty?
236
+ raise "Translation returned empty or invalid content"
237
+ end
238
+
239
+ puts "🔤 Translation complete."
240
+ result
241
+ end
242
+
243
+ def rewrite_links(html, lang)
244
+ doc = Nokogiri::HTML::DocumentFragment.parse(html)
245
+ doc.css('a[href^="/"]').each do |a|
246
+ href = a['href']
247
+ next if href.start_with?("/#{lang}") || href.include?('.') || href.start_with?('//')
248
+ new_href = "/#{lang}#{href}"
249
+ puts "🔗 Rewriting link: #{href} -> #{new_href}"
250
+ a['href'] = new_href
251
+ end
252
+ doc.to_html
253
+ end
@@ -0,0 +1,44 @@
1
+ # Libraries
2
+ # ...
3
+
4
+ module Jekyll
5
+ class InjectData < Generator
6
+ safe true
7
+ priority :low
8
+
9
+ def generate(site)
10
+ # Define a global variable accessible in templates
11
+ # site.config['cache_breaker'] = Time.now.to_i.to_s
12
+
13
+ # Process pages
14
+ site.pages.each do |page|
15
+ inject_data(page, site)
16
+ end
17
+
18
+ # Process documents in all collections
19
+ site.collections.each do |_, collection|
20
+ collection.docs.each do |document|
21
+ inject_data(document, site)
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def inject_data(item, site)
29
+ # Inject a random number into the item's data
30
+ item.data['random_id'] = rand(100) # Random number between 0 and 99
31
+
32
+ return unless item.data['layout'] # Skip items without layouts
33
+
34
+ # Find the layout file by its name
35
+ layout_name = item.data['layout']
36
+ layout = site.layouts[layout_name]
37
+
38
+ if layout && layout.data
39
+ # Merge layout front matter into item's "layout_data"
40
+ item.data['layout_data'] = layout.data
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,8 @@
1
+ # Libraries
2
+ # ...
3
+
4
+ # Hook
5
+ Jekyll::Hooks.register :site, :pre_render do |site|
6
+ site.config['uj'] ||= {}
7
+ site.config['uj']['cache_breaker'] = Jekyll::UJPowertools.cache_timestamp
8
+ end
@@ -1,5 +1,5 @@
1
1
  module Jekyll
2
2
  module UJPowertools
3
- VERSION = "1.2.7"
3
+ VERSION = "1.3.1"
4
4
  end
5
5
  end
@@ -1,5 +1,7 @@
1
+ # Libraries
1
2
  require "jekyll"
2
3
 
4
+ # Module
3
5
  module Jekyll
4
6
  module UJPowertools
5
7
  # Initialize a timestamp that will remain consistent across calls
@@ -62,65 +64,13 @@ module Jekyll
62
64
  end
63
65
  end
64
66
 
65
- # Set a global cache buster timestamp
66
- # class CacheBreakerGenerator < Jekyll::Generator
67
- # safe true
68
- # priority :highest
67
+ # Load Generators
68
+ require_relative "generators/inject-properties"
69
69
 
70
- # def generate(site)
71
- # # Define a global variable accessible in templates
72
- # site.config['cache_breaker2'] = Time.now.to_i.to_s
73
- # end
74
- # end
75
-
76
- # Inject data into pages and documents
77
- class InjectData < Generator
78
- safe true
79
- priority :low
80
-
81
- def generate(site)
82
- # Define a global variable accessible in templates
83
- # site.config['cache_breaker'] = Time.now.to_i.to_s
84
-
85
- # Process pages
86
- site.pages.each do |page|
87
- inject_data(page, site)
88
- end
89
-
90
- # Process documents in all collections
91
- site.collections.each do |_, collection|
92
- collection.docs.each do |document|
93
- inject_data(document, site)
94
- end
95
- end
96
- end
97
-
98
- private
99
-
100
- def inject_data(item, site)
101
- # Inject a random number into the item's data
102
- item.data['random_id'] = rand(100) # Random number between 0 and 99
103
-
104
- return unless item.data['layout'] # Skip items without layouts
105
-
106
- # Find the layout file by its name
107
- layout_name = item.data['layout']
108
- layout = site.layouts[layout_name]
109
-
110
- if layout && layout.data
111
- # Merge layout front matter into item's "layout_data"
112
- item.data['layout_data'] = layout.data
113
- end
114
- end
115
- end
70
+ # Load Hooks
71
+ require_relative "hooks/inject-properties"
72
+ # require_relative "hooks/translate-pages"
116
73
  end
117
74
 
118
75
  # Register the filter
119
76
  Liquid::Template.register_filter(Jekyll::UJPowertools)
120
-
121
- # Register hook
122
- Jekyll::Hooks.register :site, :pre_render do |site|
123
- site.config['uj'] ||= {}
124
- site.config['uj']['cacheBreaker'] = Jekyll::UJPowertools.cache_timestamp
125
- site.config['uj']['cache_breaker'] = Jekyll::UJPowertools.cache_timestamp
126
- end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-uj-powertools
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.7
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ITW Creative Works
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-01 00:00:00.000000000 Z
11
+ date: 2025-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: nokogiri
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '1.17'
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '1.17'
75
89
  description: jekyll-uj-powertools provides a powerful set of utilities for Jekyll,
76
90
  including functions to remove ads from strings and escape JSON characters.
77
91
  email:
@@ -85,6 +99,10 @@ files:
85
99
  - README.md
86
100
  - Rakefile
87
101
  - jekyll-uj-powertools.gemspec
102
+ - lib/_old/generators/translate-pages.rb
103
+ - lib/_old/hooks/translate-pages.rb
104
+ - lib/generators/inject-properties.rb
105
+ - lib/hooks/inject-properties.rb
88
106
  - lib/jekyll-uj-powertools.rb
89
107
  - lib/jekyll-uj-powertools/version.rb
90
108
  - spec/jekyll-uj-powertools_spec.rb