jekyll-l10n 1.7.0 → 2.0.0
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 +1 -1
- data/lib/jekyll-l10n/extraction/config_loader.rb +25 -55
- data/lib/jekyll-l10n/extraction/extractor.rb +29 -42
- data/lib/jekyll-l10n/jekyll/generator.rb +38 -40
- data/lib/jekyll-l10n/jekyll/post_write_html_reprocessor.rb +14 -26
- data/lib/jekyll-l10n/jekyll/regeneration_checker.rb +59 -45
- data/lib/jekyll-l10n/jekyll/url_filter.rb +5 -6
- data/lib/jekyll-l10n/po_file/reader.rb +2 -4
- data/lib/jekyll-l10n/translation/page_translation_loader.rb +13 -29
- data/lib/jekyll-l10n/translation/translator.rb +29 -61
- data/lib/jekyll-l10n/utils/page_locales_config.rb +72 -149
- data/lib/jekyll-l10n/utils/site_config_accessor.rb +77 -39
- data/lib/jekyll-l10n/version.rb +1 -1
- data/lib/jekyll-l10n.rb +64 -176
- metadata +15 -1
|
@@ -5,6 +5,7 @@ require_relative '../constants'
|
|
|
5
5
|
require_relative '../utils/error_handler'
|
|
6
6
|
require_relative '../utils/locale_name_resolver'
|
|
7
7
|
require_relative '../utils/locale_url_formatter'
|
|
8
|
+
require_relative '../utils/site_config_accessor'
|
|
8
9
|
|
|
9
10
|
module Jekyll
|
|
10
11
|
module L10n
|
|
@@ -192,29 +193,27 @@ module Jekyll
|
|
|
192
193
|
return false if locale.nil? || locale.empty?
|
|
193
194
|
return true if locale == 'en' # English is always valid
|
|
194
195
|
|
|
195
|
-
# Get configured locales from page or site config
|
|
196
196
|
locales_config = configured_locales
|
|
197
197
|
|
|
198
|
-
#
|
|
199
|
-
# before comparing, so 'es-ES' matches 'es_ES' and vice versa.
|
|
198
|
+
# Compare URL forms so 'es-ES' matches 'es_ES' and the other way round.
|
|
200
199
|
url_locale = LocaleUrlFormatter.to_url_segment(locale)
|
|
201
200
|
locales_config.any? { |l| LocaleUrlFormatter.to_url_segment(l) == url_locale }
|
|
202
201
|
end
|
|
203
202
|
|
|
203
|
+
# Locales of the page being rendered. A Hash comes from Liquid and already
|
|
204
|
+
# has the site defaults merged in; a page object needs the same merge.
|
|
204
205
|
def configured_locales
|
|
205
206
|
page = @context.registers[:page]
|
|
206
207
|
|
|
207
|
-
# Try to get from page data first (most specific)
|
|
208
208
|
if page
|
|
209
209
|
locales = if page.is_a?(Hash)
|
|
210
210
|
page.dig('with_locales_data', 'locales')
|
|
211
211
|
else
|
|
212
|
-
|
|
212
|
+
SiteConfigAccessor.page_locales_data(page)['locales']
|
|
213
213
|
end
|
|
214
214
|
return locales if locales && !locales.empty?
|
|
215
215
|
end
|
|
216
216
|
|
|
217
|
-
# Fallback to empty array if not configured
|
|
218
217
|
[]
|
|
219
218
|
end
|
|
220
219
|
|
|
@@ -297,7 +297,7 @@ module Jekyll
|
|
|
297
297
|
end
|
|
298
298
|
|
|
299
299
|
# Unified metadata extraction: extracts reference, fuzzy flag, and previous msgid.
|
|
300
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
300
|
+
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
301
301
|
def self.extract_metadata_before_msgid(lines, msgid_idx, include_fuzzy: false)
|
|
302
302
|
reference = nil
|
|
303
303
|
fuzzy = false
|
|
@@ -317,7 +317,6 @@ module Jekyll
|
|
|
317
317
|
|
|
318
318
|
include_fuzzy ? [reference, fuzzy, previous_msgid] : reference
|
|
319
319
|
end
|
|
320
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
321
320
|
|
|
322
321
|
def self.extract_reference_from_line(comment_line)
|
|
323
322
|
comment_line.sub(/^#:\s*/, '').strip if comment_line.start_with?('#:')
|
|
@@ -457,7 +456,7 @@ module Jekyll
|
|
|
457
456
|
previous_msgid, with_metadata: with_metadata)
|
|
458
457
|
end
|
|
459
458
|
|
|
460
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
459
|
+
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
461
460
|
def self.build_translation_entry(msgstr, reference, fuzzy, previous_msgid = nil,
|
|
462
461
|
with_metadata: false)
|
|
463
462
|
# Simple format when no metadata requested and none provided
|
|
@@ -471,7 +470,6 @@ module Jekyll
|
|
|
471
470
|
entry[:comment] = nil if !fuzzy.nil? || !reference.nil?
|
|
472
471
|
entry
|
|
473
472
|
end
|
|
474
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
475
473
|
|
|
476
474
|
# Kept for backward compatibility with existing tests
|
|
477
475
|
# Supports both positional and keyword argument calling styles
|
|
@@ -8,39 +8,23 @@ require_relative '../utils/logger_formatter'
|
|
|
8
8
|
|
|
9
9
|
module Jekyll
|
|
10
10
|
module L10n
|
|
11
|
-
#
|
|
11
|
+
# Reads the translations one page needs for one locale.
|
|
12
12
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# HtmlTranslator.
|
|
18
|
-
#
|
|
19
|
-
# Key responsibilities:
|
|
20
|
-
# * Load compendium translations for a locale
|
|
21
|
-
# * Convert page URLs to PO file paths
|
|
22
|
-
# * Load page-specific translations
|
|
23
|
-
# * Merge compendium and page-specific translations
|
|
24
|
-
# * Filter empty translations (untranslated entries)
|
|
25
|
-
# * Log loading progress at debug level
|
|
13
|
+
# It combines two PO files: the locale compendium (`es.po`) and the page's
|
|
14
|
+
# own file (`es/<page url>/index.html.po`). When both have a string, the
|
|
15
|
+
# page file wins. With the default `update_compendium: true` the page file
|
|
16
|
+
# no longer exists after extraction, so the compendium provides everything.
|
|
26
17
|
#
|
|
27
18
|
# @example
|
|
28
|
-
# config = PageLocalesConfig.new(page
|
|
29
|
-
#
|
|
30
|
-
# #
|
|
19
|
+
# config = PageLocalesConfig.new(SiteConfigAccessor.effective_page_data(page))
|
|
20
|
+
# PageTranslationLoader.load(site, 'es', '/docs/index.html', config)
|
|
21
|
+
# # => { "Welcome" => "Bienvenido", ... }
|
|
31
22
|
class PageTranslationLoader
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
# @param site [Jekyll::Site] Jekyll site object
|
|
39
|
-
# @param locale [String] Target locale code (e.g., 'es', 'fr')
|
|
40
|
-
# @param original_url [String] Original page URL (e.g., '/docs/index.html')
|
|
41
|
-
# @param config [PageLocalesConfig] Localization configuration for the page
|
|
42
|
-
# @return [Hash] Merged translation hash { msgid => msgstr }, filtered to only
|
|
43
|
-
# include non-empty translations
|
|
23
|
+
# @param site [Jekyll::Site] The Jekyll site
|
|
24
|
+
# @param locale [String] Locale code, e.g. 'es'
|
|
25
|
+
# @param original_url [String] URL of the English page, e.g. '/docs/index.html'
|
|
26
|
+
# @param config [PageLocalesConfig] The page's settings (for `locales_dir`)
|
|
27
|
+
# @return [Hash] msgid => msgstr, without untranslated entries
|
|
44
28
|
def self.load(site, locale, original_url, config)
|
|
45
29
|
po_manager = PoFileManager.new(site, config.locales_dir)
|
|
46
30
|
page_path = construct_po_page_path(original_url)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../utils/page_locales_config'
|
|
4
|
+
require_relative '../utils/site_config_accessor'
|
|
4
5
|
require_relative '../utils/html_parser'
|
|
5
6
|
require_relative '../utils/logger_formatter'
|
|
6
7
|
require_relative '../utils/error_handler'
|
|
@@ -10,65 +11,38 @@ require_relative 'page_translation_loader'
|
|
|
10
11
|
|
|
11
12
|
module Jekyll
|
|
12
13
|
module L10n
|
|
13
|
-
#
|
|
14
|
+
# Translates one localized page right after Jekyll renders it.
|
|
14
15
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
16
|
+
# A `:pages, :post_render` hook in lib/jekyll-l10n.rb calls it for every
|
|
17
|
+
# LocalizedPage. It loads the translations for the page's locale, replaces
|
|
18
|
+
# the English text and attributes in the rendered HTML, and applies the
|
|
19
|
+
# page's fallback mode to strings without a translation.
|
|
19
20
|
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# 2. Load translations from PO files (page-specific and compendium)
|
|
23
|
-
# 3. Apply translations to text nodes and attributes in HTML
|
|
24
|
-
# 4. Handle missing translations with configured fallback modes
|
|
25
|
-
# 5. Preserve special elements like external link icons
|
|
21
|
+
# Settings come from the English page's merged `with_locales_data`, so a
|
|
22
|
+
# page can override, for example, `translation.fallback` for itself.
|
|
26
23
|
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
# - Apply translations to HTML with DOM manipulation
|
|
30
|
-
# - Handle fallback modes (english, marker, empty)
|
|
31
|
-
# - Preserve special formatting and elements (icons, badges, etc.)
|
|
32
|
-
# - Log translation progress and errors
|
|
24
|
+
# @example
|
|
25
|
+
# Translator.new(localized_page).translate
|
|
33
26
|
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
# @example Usage (typically invoked via Jekyll hook)
|
|
38
|
-
# # Automatically invoked for localized pages in post_render phase
|
|
39
|
-
# translator = Translator.new(localized_page)
|
|
40
|
-
# translator.translate
|
|
41
|
-
#
|
|
42
|
-
# @see Jekyll::L10n for Build Pipeline documentation
|
|
43
|
-
# @see Jekyll::L10n::HtmlTranslator for low-level DOM translation logic
|
|
44
|
-
# @see Jekyll::L10n::PageTranslationLoader for loading translations from PO files
|
|
27
|
+
# @see HtmlTranslator changes the HTML
|
|
28
|
+
# @see PageTranslationLoader reads the PO files
|
|
45
29
|
#
|
|
46
30
|
class Translator
|
|
47
31
|
# @!attribute [r] page
|
|
48
|
-
#
|
|
49
|
-
# @return [Jekyll::Page]
|
|
32
|
+
# @return [Jekyll::Page] The page being translated
|
|
50
33
|
attr_reader :page
|
|
51
34
|
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
# @param page [Jekyll::Page] The page to translate (should be a LocalizedPage)
|
|
35
|
+
# @param page [Jekyll::Page] Usually a LocalizedPage
|
|
55
36
|
def initialize(page)
|
|
56
37
|
@page = page
|
|
57
38
|
@site = page.site
|
|
58
39
|
end
|
|
59
40
|
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
# loads the appropriate translations from PO files, applies them to the HTML,
|
|
64
|
-
# and updates the page's output.
|
|
65
|
-
#
|
|
66
|
-
# This method is called automatically by Jekyll's post_render hook for each
|
|
67
|
-
# LocalizedPage during the build process.
|
|
41
|
+
# Replaces the page output with its translated HTML. Does nothing for
|
|
42
|
+
# pages without `locale` and `original_url`, pages whose English page
|
|
43
|
+
# cannot be found, or when there are no translations.
|
|
68
44
|
#
|
|
69
45
|
# @return [void]
|
|
70
|
-
# @note Only translates pages with localized: true and matching locale/original_url
|
|
71
|
-
# @note Gracefully handles missing translations with configured fallback mode
|
|
72
46
|
def translate
|
|
73
47
|
return unless should_translate?
|
|
74
48
|
|
|
@@ -79,21 +53,20 @@ module Jekyll
|
|
|
79
53
|
original_page = find_and_log_original_page(original_url)
|
|
80
54
|
return unless original_page
|
|
81
55
|
|
|
82
|
-
|
|
56
|
+
config = PageLocalesConfig.new(SiteConfigAccessor.effective_page_data(original_page))
|
|
57
|
+
translations = load_and_log_translations(locale, original_url, config)
|
|
83
58
|
return if translations.nil? || translations.empty?
|
|
84
59
|
|
|
85
|
-
apply_translations_to_page(original_page, translations, locale, baseurl)
|
|
60
|
+
apply_translations_to_page(original_page, config, translations, locale, baseurl)
|
|
86
61
|
end
|
|
87
62
|
|
|
88
63
|
private
|
|
89
64
|
|
|
90
|
-
def load_translations_for_page(locale, original_url,
|
|
91
|
-
config = PageLocalesConfig.new(original_page.data)
|
|
65
|
+
def load_translations_for_page(locale, original_url, config)
|
|
92
66
|
PageTranslationLoader.load(@site, locale, original_url, config)
|
|
93
67
|
end
|
|
94
68
|
|
|
95
|
-
def apply_translations_to_page(original_page, translations, locale, baseurl)
|
|
96
|
-
config = PageLocalesConfig.new(original_page.data)
|
|
69
|
+
def apply_translations_to_page(original_page, config, translations, locale, baseurl)
|
|
97
70
|
translator = HtmlTranslator.new(
|
|
98
71
|
config.fallback_mode,
|
|
99
72
|
config.translatable_attributes,
|
|
@@ -112,16 +85,11 @@ module Jekyll
|
|
|
112
85
|
ExternalLinkIconPreserver.preserve(original_html, translated_html)
|
|
113
86
|
end
|
|
114
87
|
|
|
115
|
-
#
|
|
116
|
-
#
|
|
117
|
-
#
|
|
118
|
-
#
|
|
119
|
-
#
|
|
120
|
-
# @param translator [HtmlTranslator] The translator instance to use
|
|
121
|
-
# @param translations [Hash] Translation hash mapping text to translations
|
|
122
|
-
# @param locale [String, nil] Target locale code (defaults to nil). If nil, uses "en"
|
|
123
|
-
# @param baseurl [String] Base URL for relative URL transformation (defaults to "")
|
|
124
|
-
# @return [String, nil] Translated HTML string, or nil on error
|
|
88
|
+
# @param translator [HtmlTranslator]
|
|
89
|
+
# @param translations [Hash] msgid => msgstr
|
|
90
|
+
# @param locale [String, nil] Target locale; nil means "en"
|
|
91
|
+
# @param baseurl [String] Site baseurl, used when rewriting links
|
|
92
|
+
# @return [String, nil] Translated HTML, or nil after logging an error
|
|
125
93
|
def apply_translations(translator, translations, locale = nil, baseurl = '')
|
|
126
94
|
if locale && locale != 'en'
|
|
127
95
|
translator.translate(@page.output, translations, locale, baseurl)
|
|
@@ -169,8 +137,8 @@ module Jekyll
|
|
|
169
137
|
original_page
|
|
170
138
|
end
|
|
171
139
|
|
|
172
|
-
def load_and_log_translations(locale, original_url,
|
|
173
|
-
translations = load_translations_for_page(locale, original_url,
|
|
140
|
+
def load_and_log_translations(locale, original_url, config)
|
|
141
|
+
translations = load_translations_for_page(locale, original_url, config)
|
|
174
142
|
LoggerFormatter.debug_if_enabled('Translator',
|
|
175
143
|
"Loaded #{translations&.length || 0} translations")
|
|
176
144
|
translations
|