jekyll-uj-powertools 1.5.2 → 1.6.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 +4 -4
- data/README.md +113 -4
- data/jekyll-uj-powertools.gemspec +2 -1
- data/lib/filters/main.rb +37 -19
- data/lib/generators/inject-properties.rb +29 -7
- data/lib/hooks/inject-properties.rb +10 -0
- data/lib/hooks/markdown-images.rb +40 -0
- data/lib/jekyll-uj-powertools.rb +12 -1
- data/lib/tags/fake_comments.rb +72 -0
- data/lib/tags/icon.rb +262 -0
- data/lib/tags/iffalsy.rb +38 -0
- data/lib/tags/iftruthy.rb +38 -0
- data/lib/tags/image.rb +208 -0
- data/lib/tags/language.rb +301 -0
- data/lib/tags/member.rb +204 -0
- data/lib/tags/post.rb +258 -0
- data/lib/tags/readtime.rb +73 -0
- data/lib/tags/social.rb +84 -0
- data/lib/tags/translation_url.rb +154 -0
- metadata +28 -3
- data/lib/tags/ifistruthy.rb +0 -161
data/lib/tags/post.rb
ADDED
@@ -0,0 +1,258 @@
|
|
1
|
+
# Libraries
|
2
|
+
require "jekyll"
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
class UJPostTag < Liquid::Tag
|
6
|
+
def initialize(tag_name, markup, tokens)
|
7
|
+
super
|
8
|
+
@markup = markup.strip
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(context)
|
12
|
+
# Parse arguments
|
13
|
+
args = parse_arguments_with_quotes(@markup)
|
14
|
+
post_input = args[0]
|
15
|
+
property_input = args[1] || "'title'" # Default to title if no property specified
|
16
|
+
|
17
|
+
# Strip quotes from property if present
|
18
|
+
property = property_input.gsub(/^['"]|['"]$/, '')
|
19
|
+
|
20
|
+
# Check if the post input was originally quoted
|
21
|
+
is_quoted = post_input && post_input.match(/^['"]/)
|
22
|
+
|
23
|
+
# Resolve post ID
|
24
|
+
if is_quoted
|
25
|
+
# If quoted, strip quotes and use as literal
|
26
|
+
post_id = post_input.gsub(/^['"]|['"]$/, '')
|
27
|
+
else
|
28
|
+
# Otherwise resolve as variable
|
29
|
+
post_id = resolve_post_id(context, post_input)
|
30
|
+
end
|
31
|
+
return '' unless post_id
|
32
|
+
|
33
|
+
# Find post in site collections
|
34
|
+
site = context.registers[:site]
|
35
|
+
post = find_post(site, post_id)
|
36
|
+
return '' unless post
|
37
|
+
|
38
|
+
# Return the requested property
|
39
|
+
case property
|
40
|
+
when 'title'
|
41
|
+
post.data['title'] || ''
|
42
|
+
when 'description'
|
43
|
+
post.data['description'] || post.data['excerpt'] || ''
|
44
|
+
when 'url'
|
45
|
+
site_url = site.config['url'] || ''
|
46
|
+
site_url + post.url
|
47
|
+
when 'path'
|
48
|
+
post.url
|
49
|
+
when 'image'
|
50
|
+
# Use the custom post.post.id if available, otherwise fall back to extracting from post.id
|
51
|
+
custom_id = (post.data['post'] && post.data['post']['id']) || post.id.gsub(/^\/(\w+)\//, '')
|
52
|
+
# Extract the slug from the Jekyll post ID
|
53
|
+
post_id_clean = post.id.gsub(/^\/(\w+)\//, '')
|
54
|
+
slug = post_id_clean.gsub(/^\d{4}-\d{2}-\d{2}-/, '')
|
55
|
+
"/assets/images/blog/post-#{custom_id}/#{slug}.jpg"
|
56
|
+
when 'date'
|
57
|
+
post.data['date'] ? post.data['date'].strftime('%Y-%m-%d') : ''
|
58
|
+
when 'author'
|
59
|
+
(post.data['post'] && post.data['post']['author']) || post.data['author'] || ''
|
60
|
+
when 'category'
|
61
|
+
post.data['category'] || post.data['categories']&.first || ''
|
62
|
+
when 'categories'
|
63
|
+
Array(post.data['categories']).join(', ')
|
64
|
+
when 'tags'
|
65
|
+
Array(post.data['tags']).join(', ')
|
66
|
+
when 'id'
|
67
|
+
post.id
|
68
|
+
when 'image-tag'
|
69
|
+
# Generate image path
|
70
|
+
# Use the custom post.post.id if available, otherwise fall back to extracting from post.id
|
71
|
+
custom_id = (post.data['post'] && post.data['post']['id']) || post.id.gsub(/^\/(\w+)\//, '')
|
72
|
+
# Extract the slug from the Jekyll post ID
|
73
|
+
post_id_clean = post.id.gsub(/^\/(\w+)\//, '')
|
74
|
+
slug = post_id_clean.gsub(/^\d{4}-\d{2}-\d{2}-/, '')
|
75
|
+
image_path = "/assets/images/blog/post-#{custom_id}/#{slug}.jpg"
|
76
|
+
|
77
|
+
# Parse additional options for the image tag
|
78
|
+
image_options = parse_image_options(args[2..-1], context)
|
79
|
+
|
80
|
+
# Set default alt text if not provided
|
81
|
+
if !image_options['alt']
|
82
|
+
# Try to get the title from post.post.title first, then fall back to post.title
|
83
|
+
default_alt = (post.data['post'] && post.data['post']['title']) || post.data['title']
|
84
|
+
image_options['alt'] = default_alt if default_alt
|
85
|
+
end
|
86
|
+
|
87
|
+
# Build the markup string for uj_image tag
|
88
|
+
image_markup = build_image_markup(image_path, image_options)
|
89
|
+
|
90
|
+
# Parse and render the uj_image tag using Liquid template
|
91
|
+
template_content = "{% uj_image #{image_markup} %}"
|
92
|
+
template = Liquid::Template.parse(template_content)
|
93
|
+
template.render!(context)
|
94
|
+
else
|
95
|
+
# Try to access any other property dynamically
|
96
|
+
(post.data['post'] && post.data['post'][property]) || post.data[property] || ''
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def parse_arguments_with_quotes(markup)
|
103
|
+
# Parse arguments preserving quotes for detection
|
104
|
+
args = []
|
105
|
+
current_arg = ''
|
106
|
+
in_quotes = false
|
107
|
+
quote_char = nil
|
108
|
+
|
109
|
+
markup.each_char.with_index do |char, i|
|
110
|
+
if !in_quotes && (char == '"' || char == "'")
|
111
|
+
in_quotes = true
|
112
|
+
quote_char = char
|
113
|
+
current_arg += char
|
114
|
+
elsif in_quotes && char == quote_char
|
115
|
+
in_quotes = false
|
116
|
+
current_arg += char
|
117
|
+
quote_char = nil
|
118
|
+
elsif !in_quotes && char == ','
|
119
|
+
args << current_arg.strip
|
120
|
+
current_arg = ''
|
121
|
+
else
|
122
|
+
current_arg += char
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
args << current_arg.strip if current_arg.strip.length > 0
|
127
|
+
args
|
128
|
+
end
|
129
|
+
|
130
|
+
def parse_arguments(markup)
|
131
|
+
# Parse arguments that can be quoted or unquoted
|
132
|
+
args = []
|
133
|
+
current_arg = ''
|
134
|
+
in_quotes = false
|
135
|
+
quote_char = nil
|
136
|
+
|
137
|
+
markup.each_char.with_index do |char, i|
|
138
|
+
if !in_quotes && (char == '"' || char == "'")
|
139
|
+
in_quotes = true
|
140
|
+
quote_char = char
|
141
|
+
elsif in_quotes && char == quote_char
|
142
|
+
in_quotes = false
|
143
|
+
quote_char = nil
|
144
|
+
elsif !in_quotes && char == ','
|
145
|
+
args << current_arg.strip
|
146
|
+
current_arg = ''
|
147
|
+
else
|
148
|
+
current_arg += char
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
args << current_arg.strip if current_arg.strip.length > 0
|
153
|
+
args
|
154
|
+
end
|
155
|
+
|
156
|
+
def resolve_post_id(context, post_input)
|
157
|
+
if post_input.nil? || post_input.empty?
|
158
|
+
# No input, use current page if it's a post
|
159
|
+
page = context['page']
|
160
|
+
return nil unless page
|
161
|
+
|
162
|
+
# Check if current page is a post
|
163
|
+
if page['post'] || page['collection'] == 'posts'
|
164
|
+
page['id']
|
165
|
+
else
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
else
|
169
|
+
# Resolve the variable
|
170
|
+
resolve_variable(context, post_input)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def resolve_variable(context, variable_name)
|
175
|
+
# Handle nested variable access
|
176
|
+
parts = variable_name.split('.')
|
177
|
+
current = context
|
178
|
+
|
179
|
+
parts.each do |part|
|
180
|
+
return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
|
181
|
+
current = current[part]
|
182
|
+
return nil if current.nil?
|
183
|
+
end
|
184
|
+
|
185
|
+
current
|
186
|
+
end
|
187
|
+
|
188
|
+
def find_post(site, post_id)
|
189
|
+
post_id_clean = post_id.to_s.strip
|
190
|
+
|
191
|
+
# Search in posts collection first
|
192
|
+
if site.collections['posts']
|
193
|
+
post = site.collections['posts'].docs.find do |doc|
|
194
|
+
# Check standard ID match
|
195
|
+
doc.id == post_id_clean ||
|
196
|
+
doc.id.include?(post_id_clean) ||
|
197
|
+
# Also check if the post has a custom post.id field that matches
|
198
|
+
(doc.data['post'] && doc.data['post']['id'] == post_id_clean)
|
199
|
+
end
|
200
|
+
return post if post
|
201
|
+
end
|
202
|
+
|
203
|
+
# Search in other collections that might contain posts
|
204
|
+
site.collections.each do |name, collection|
|
205
|
+
next if name == 'posts' # Already checked
|
206
|
+
|
207
|
+
post = collection.docs.find do |doc|
|
208
|
+
(doc.id == post_id_clean ||
|
209
|
+
doc.id.include?(post_id_clean) ||
|
210
|
+
# Check custom post.id field
|
211
|
+
(doc.data['post'] && doc.data['post']['id'] == post_id_clean)) &&
|
212
|
+
doc.data['post']
|
213
|
+
end
|
214
|
+
return post if post
|
215
|
+
end
|
216
|
+
|
217
|
+
nil
|
218
|
+
end
|
219
|
+
|
220
|
+
def parse_image_options(option_args, context)
|
221
|
+
options = {}
|
222
|
+
|
223
|
+
option_args.each do |arg|
|
224
|
+
if arg.include?('=')
|
225
|
+
key, value = arg.split('=', 2)
|
226
|
+
key = key.strip
|
227
|
+
|
228
|
+
# Check if the value is quoted (literal) or unquoted (variable)
|
229
|
+
if value.strip.match(/^['"].*['"]$/)
|
230
|
+
# It's a literal string, strip quotes
|
231
|
+
value = value.strip.gsub(/^['"]|['"]$/, '')
|
232
|
+
else
|
233
|
+
# It's a variable, resolve it
|
234
|
+
resolved_value = resolve_variable(context, value.strip)
|
235
|
+
value = resolved_value || value.strip
|
236
|
+
end
|
237
|
+
|
238
|
+
options[key] = value
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
options
|
243
|
+
end
|
244
|
+
|
245
|
+
def build_image_markup(image_path, options)
|
246
|
+
# Build markup string in the format expected by uj_image tag
|
247
|
+
markup_parts = ["\"#{image_path}\""]
|
248
|
+
|
249
|
+
options.each do |key, value|
|
250
|
+
markup_parts << "#{key}=\"#{value}\""
|
251
|
+
end
|
252
|
+
|
253
|
+
markup_parts.join(', ')
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
Liquid::Template.register_tag('uj_post', Jekyll::UJPostTag)
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# Libraries
|
2
|
+
require "jekyll"
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
class UJReadtimeTag < Liquid::Tag
|
6
|
+
def initialize(tag_name, markup, tokens)
|
7
|
+
super
|
8
|
+
@markup = markup.strip
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(context)
|
12
|
+
# Get the content to analyze
|
13
|
+
content = resolve_content(context)
|
14
|
+
return '1' unless content
|
15
|
+
|
16
|
+
# Strip HTML tags
|
17
|
+
stripped_content = strip_html(content)
|
18
|
+
|
19
|
+
# Count words
|
20
|
+
words = count_words(stripped_content)
|
21
|
+
|
22
|
+
# Calculate readtime (200 words per minute, minimum 1 minute)
|
23
|
+
readtime = (words / 200.0).ceil
|
24
|
+
readtime = 1 if readtime < 1
|
25
|
+
|
26
|
+
readtime.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def resolve_content(context)
|
32
|
+
if @markup.empty?
|
33
|
+
# No argument, use page content
|
34
|
+
page = context['page']
|
35
|
+
return nil unless page
|
36
|
+
page['content']
|
37
|
+
else
|
38
|
+
# Resolve the variable name
|
39
|
+
resolve_variable(context, @markup)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def resolve_variable(context, variable_name)
|
44
|
+
# Handle nested variable access like page.content or include.content
|
45
|
+
parts = variable_name.split('.')
|
46
|
+
current = context
|
47
|
+
|
48
|
+
parts.each do |part|
|
49
|
+
return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
|
50
|
+
current = current[part]
|
51
|
+
return nil if current.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
current
|
55
|
+
end
|
56
|
+
|
57
|
+
def strip_html(content)
|
58
|
+
# Remove HTML tags
|
59
|
+
content = content.to_s.gsub(/<script.*?<\/script>/m, '')
|
60
|
+
content = content.gsub(/<style.*?<\/style>/m, '')
|
61
|
+
content = content.gsub(/<[^>]+>/, ' ')
|
62
|
+
content = content.gsub(/\s+/, ' ')
|
63
|
+
content.strip
|
64
|
+
end
|
65
|
+
|
66
|
+
def count_words(text)
|
67
|
+
# Count words (split by whitespace)
|
68
|
+
text.split(/\s+/).length
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
Liquid::Template.register_tag('uj_readtime', Jekyll::UJReadtimeTag)
|
data/lib/tags/social.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Libraries
|
2
|
+
require "jekyll"
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
class UJSocialTag < Liquid::Tag
|
6
|
+
# Social platform URL patterns
|
7
|
+
SOCIAL_URLS = {
|
8
|
+
'facebook' => 'https://facebook.com/%s',
|
9
|
+
'twitter' => 'https://twitter.com/%s',
|
10
|
+
'linkedin' => 'https://linkedin.com/in/%s',
|
11
|
+
'youtube' => 'https://youtube.com/@%s',
|
12
|
+
'instagram' => 'https://instagram.com/%s',
|
13
|
+
'tumblr' => 'https://%s.tumblr.com',
|
14
|
+
'slack' => 'https://%s.slack.com',
|
15
|
+
'discord' => 'https://discord.gg/%s',
|
16
|
+
'github' => 'https://github.com/%s',
|
17
|
+
'dev' => 'https://dev.to/%s',
|
18
|
+
'tiktok' => 'https://tiktok.com/@%s',
|
19
|
+
'twitch' => 'https://twitch.tv/%s',
|
20
|
+
'soundcloud' => 'https://soundcloud.com/%s',
|
21
|
+
'spotify' => 'https://open.spotify.com/user/%s',
|
22
|
+
'mixcloud' => 'https://mixcloud.com/%s'
|
23
|
+
}
|
24
|
+
|
25
|
+
def initialize(tag_name, markup, tokens)
|
26
|
+
super
|
27
|
+
@markup = markup.strip
|
28
|
+
end
|
29
|
+
|
30
|
+
def render(context)
|
31
|
+
# Parse the platform name (can be quoted or unquoted)
|
32
|
+
platform_input = parse_argument(@markup)
|
33
|
+
|
34
|
+
# Resolve the platform name (could be a variable or literal string)
|
35
|
+
platform = resolve_variable(context, platform_input)
|
36
|
+
|
37
|
+
# If it didn't resolve to anything, use the input as a literal string
|
38
|
+
platform = platform_input if platform.nil? || platform.empty?
|
39
|
+
|
40
|
+
# Get the social handle from page.resolved.socials.{platform}
|
41
|
+
page = context['page']
|
42
|
+
return '' unless page
|
43
|
+
|
44
|
+
social_handle = page['resolved'] && page['resolved']['socials'] && page['resolved']['socials'][platform]
|
45
|
+
return '' unless social_handle && !social_handle.empty?
|
46
|
+
|
47
|
+
# Get the URL pattern for this platform
|
48
|
+
url_pattern = SOCIAL_URLS[platform]
|
49
|
+
return '' unless url_pattern
|
50
|
+
|
51
|
+
# Build the URL
|
52
|
+
url_pattern % social_handle
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def parse_argument(markup)
|
58
|
+
# Remove quotes if present
|
59
|
+
cleaned = markup.strip
|
60
|
+
if (cleaned.start_with?('"') && cleaned.end_with?('"')) ||
|
61
|
+
(cleaned.start_with?("'") && cleaned.end_with?("'"))
|
62
|
+
cleaned[1..-2]
|
63
|
+
else
|
64
|
+
cleaned
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def resolve_variable(context, variable_name)
|
69
|
+
# Handle nested variable access like page.social
|
70
|
+
parts = variable_name.split('.')
|
71
|
+
current = context
|
72
|
+
|
73
|
+
parts.each do |part|
|
74
|
+
return nil unless current.respond_to?(:[]) || current.is_a?(Hash)
|
75
|
+
current = current[part]
|
76
|
+
return nil if current.nil?
|
77
|
+
end
|
78
|
+
|
79
|
+
current
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
Liquid::Template.register_tag('uj_social', Jekyll::UJSocialTag)
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# Libraries
|
2
|
+
require "jekyll"
|
3
|
+
|
4
|
+
module Jekyll
|
5
|
+
class UJTranslationUrlTag < Liquid::Tag
|
6
|
+
def initialize(tag_name, markup, tokens)
|
7
|
+
super
|
8
|
+
@markup = markup.strip
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(context)
|
12
|
+
# Parse arguments that can be quoted or unquoted
|
13
|
+
parts = parse_arguments(@markup)
|
14
|
+
|
15
|
+
# Return root if no arguments
|
16
|
+
return '/' if parts.empty? || parts[0].nil?
|
17
|
+
|
18
|
+
language_code_input = parts[0]
|
19
|
+
url_path_input = parts[1] || '/'
|
20
|
+
|
21
|
+
# Resolve language code (literal or variable)
|
22
|
+
language_code = resolve_argument_value(context, language_code_input)
|
23
|
+
# Resolve URL path (literal or variable)
|
24
|
+
url_path = resolve_argument_value(context, url_path_input)
|
25
|
+
|
26
|
+
# Get site and translation config from context
|
27
|
+
site = context.registers[:site]
|
28
|
+
return '/' unless site
|
29
|
+
|
30
|
+
translation_config = site.config['translation'] || {}
|
31
|
+
default_language = translation_config['default'] || 'en'
|
32
|
+
available_languages = translation_config['languages'] || [default_language]
|
33
|
+
|
34
|
+
# Validate that the requested language is available
|
35
|
+
unless available_languages.include?(language_code)
|
36
|
+
# Fall back to default language if requested language is not available
|
37
|
+
language_code = default_language
|
38
|
+
end
|
39
|
+
|
40
|
+
# Normalize the URL path
|
41
|
+
normalized_path = normalize_path(url_path)
|
42
|
+
|
43
|
+
# Generate the language-specific URL
|
44
|
+
generate_language_url(language_code, normalized_path, default_language)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def parse_arguments(markup)
|
50
|
+
# Parse arguments that can be quoted or unquoted
|
51
|
+
# Examples: 'es', '/pricing' OR language, page.canonical.path OR 'es', page.url
|
52
|
+
args = []
|
53
|
+
current_arg = ''
|
54
|
+
in_quotes = false
|
55
|
+
quote_char = nil
|
56
|
+
|
57
|
+
markup.each_char.with_index do |char, i|
|
58
|
+
if !in_quotes && (char == '"' || char == "'")
|
59
|
+
# Start of quoted string - include the quote in the arg
|
60
|
+
in_quotes = true
|
61
|
+
quote_char = char
|
62
|
+
current_arg += char
|
63
|
+
elsif in_quotes && char == quote_char
|
64
|
+
# End of quoted string - include the quote in the arg
|
65
|
+
current_arg += char
|
66
|
+
in_quotes = false
|
67
|
+
quote_char = nil
|
68
|
+
elsif !in_quotes && char == ','
|
69
|
+
# Argument separator
|
70
|
+
args << current_arg.strip
|
71
|
+
current_arg = ''
|
72
|
+
else
|
73
|
+
# Regular character
|
74
|
+
current_arg += char
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add the last argument
|
79
|
+
args << current_arg.strip if current_arg.strip.length > 0
|
80
|
+
|
81
|
+
args
|
82
|
+
end
|
83
|
+
|
84
|
+
def resolve_argument_value(context, argument_input)
|
85
|
+
return '' if argument_input.nil? || argument_input.empty?
|
86
|
+
|
87
|
+
# Check if the argument was originally quoted (literal string)
|
88
|
+
is_quoted = argument_input.match(/^['"].*['"]$/)
|
89
|
+
|
90
|
+
# If quoted, remove quotes and use as literal. Otherwise, try to resolve as variable
|
91
|
+
if is_quoted
|
92
|
+
# Remove quotes from literal string
|
93
|
+
resolved_value = argument_input[1..-2]
|
94
|
+
else
|
95
|
+
# Try to resolve as a variable
|
96
|
+
resolved_value = resolve_variable(context, argument_input)
|
97
|
+
# If variable resolved to nil, return empty string
|
98
|
+
return '' if resolved_value.nil?
|
99
|
+
# If it didn't resolve to a string, use the resolved value
|
100
|
+
resolved_value = resolved_value.to_s if resolved_value
|
101
|
+
end
|
102
|
+
|
103
|
+
resolved_value.to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
def resolve_variable(context, variable_name)
|
107
|
+
parts = variable_name.split('.')
|
108
|
+
current = context
|
109
|
+
|
110
|
+
parts.each do |part|
|
111
|
+
if current.respond_to?(:[])
|
112
|
+
current = current[part]
|
113
|
+
elsif current.respond_to?(:key?) && current.key?(part)
|
114
|
+
current = current[part]
|
115
|
+
else
|
116
|
+
return nil
|
117
|
+
end
|
118
|
+
return nil if current.nil?
|
119
|
+
end
|
120
|
+
|
121
|
+
current
|
122
|
+
end
|
123
|
+
|
124
|
+
def normalize_path(path)
|
125
|
+
return '' if path.nil? || path.empty?
|
126
|
+
|
127
|
+
# Remove leading slash for processing
|
128
|
+
clean_path = path.start_with?('/') ? path[1..-1] : path
|
129
|
+
|
130
|
+
# Handle empty path (home page)
|
131
|
+
return '' if clean_path.empty?
|
132
|
+
|
133
|
+
clean_path
|
134
|
+
end
|
135
|
+
|
136
|
+
def generate_language_url(language_code, normalized_path, default_language)
|
137
|
+
# If it's the default language, return the original path
|
138
|
+
if language_code == default_language
|
139
|
+
return normalized_path.empty? ? '/' : "/#{normalized_path}"
|
140
|
+
end
|
141
|
+
|
142
|
+
# For non-default languages, prefix with language code
|
143
|
+
if normalized_path.empty?
|
144
|
+
# Home page: /es
|
145
|
+
"/#{language_code}"
|
146
|
+
else
|
147
|
+
# Other pages: /es/pricing
|
148
|
+
"/#{language_code}/#{normalized_path}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
Liquid::Template.register_tag('uj_translation_url', Jekyll::UJTranslationUrlTag)
|
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.
|
4
|
+
version: 1.6.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-
|
11
|
+
date: 2025-08-22 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: simplecov
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
75
89
|
- !ruby/object:Gem::Dependency
|
76
90
|
name: nokogiri
|
77
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,8 +116,19 @@ files:
|
|
102
116
|
- lib/filters/main.rb
|
103
117
|
- lib/generators/inject-properties.rb
|
104
118
|
- lib/hooks/inject-properties.rb
|
119
|
+
- lib/hooks/markdown-images.rb
|
105
120
|
- lib/jekyll-uj-powertools.rb
|
106
|
-
- lib/tags/
|
121
|
+
- lib/tags/fake_comments.rb
|
122
|
+
- lib/tags/icon.rb
|
123
|
+
- lib/tags/iffalsy.rb
|
124
|
+
- lib/tags/iftruthy.rb
|
125
|
+
- lib/tags/image.rb
|
126
|
+
- lib/tags/language.rb
|
127
|
+
- lib/tags/member.rb
|
128
|
+
- lib/tags/post.rb
|
129
|
+
- lib/tags/readtime.rb
|
130
|
+
- lib/tags/social.rb
|
131
|
+
- lib/tags/translation_url.rb
|
107
132
|
homepage: https://github.com/itw-creative-works/jekyll-uj-powertools
|
108
133
|
licenses:
|
109
134
|
- MIT
|