jekyll-l10n 1.7.1 → 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.
@@ -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
- # Normalize both the target locale and each configured locale to BCP 47 form
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
- page.data&.dig('with_locales_data', 'locales')
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
 
@@ -8,39 +8,23 @@ require_relative '../utils/logger_formatter'
8
8
 
9
9
  module Jekyll
10
10
  module L10n
11
- # Loads and merges page-specific and compendium translations.
11
+ # Reads the translations one page needs for one locale.
12
12
  #
13
- # PageTranslationLoader combines compendium (site-wide) translations with
14
- # page-specific translations for a given locale and URL. It loads both
15
- # translation sources from PO files, merges them (page-specific takes
16
- # precedence), and returns the combined translation hash for use by
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.data)
29
- # translations = PageTranslationLoader.load(site, 'es', '/docs/index.html', config)
30
- # # Returns merged translations for that page in Spanish
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
- # Load and merge translations for a page in a specific locale.
33
- #
34
- # Loads the compendium (site-wide) translations and page-specific translations,
35
- # merges them (page-specific entries override compendium), and returns the
36
- # combined hash. Filters out untranslated entries (empty msgstr).
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
- # Translation Orchestrator - Applies PO file translations to localized pages
14
+ # Translates one localized page right after Jekyll renders it.
14
15
  #
15
- # The Translator is the main entry point for applying translations to pages. It's invoked
16
- # during the post_render phase of the Jekyll build (via a Jekyll hook) for each localized
17
- # page variant. The translator loads appropriate translations from PO files and applies
18
- # them to the page's HTML content.
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
- # The translation workflow:
21
- # 1. Check if the page is localized and has required metadata
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
- # Key responsibilities:
28
- # - Load translations for the page's locale
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
- # This runs in phase 3 of the Jekyll build pipeline (Post-Render Phase). See the
35
- # "Build Pipeline" section in lib/jekyll-l10n.rb for the complete workflow.
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
- # The Jekyll page being translated
49
- # @return [Jekyll::Page]
32
+ # @return [Jekyll::Page] The page being translated
50
33
  attr_reader :page
51
34
 
52
- # Initialize the translator
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
- # Apply translations to the page
61
- #
62
- # Main entry point for translation. Checks if the page should be translated,
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
- translations = load_and_log_translations(locale, original_url, original_page)
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, original_page)
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
- # Apply translations to page output
116
- #
117
- # Internal helper that uses HtmlTranslator to apply translations to the page's
118
- # HTML output, with configurable locale and baseurl for URL transformation.
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, original_page)
173
- translations = load_translations_for_page(locale, original_url, original_page)
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
@@ -4,51 +4,25 @@ require_relative '../constants'
4
4
 
5
5
  module Jekyll
6
6
  module L10n
7
- # Configuration Parser - Extracts and validates localization settings from page front matter
7
+ # Wraps a `with_locales_data` hash and answers questions about it, filling in
8
+ # the defaults from Constants for anything not set.
8
9
  #
9
- # PageLocalesConfig parses the `with_locales_data` front matter field in Jekyll pages and
10
- # provides a type-safe interface to localization configuration. It validates all values
11
- # against expected types and ranges, raising clear errors for invalid configurations.
10
+ # It raises InvalidConfigurationError right away for bad locale codes or bad
11
+ # LibreTranslate settings, so mistakes stop the build early.
12
12
  #
13
- # Configuration can be specified in page front matter at multiple levels:
14
- # - Translation settings (fallback modes, LibreTranslate API)
15
- # - Extraction settings (which attributes to extract, directories)
16
- # - Logging settings (debug output, statistics)
13
+ # Build it from the right data:
14
+ # - For one page, use SiteConfigAccessor.effective_page_data(page), never raw
15
+ # `page.data`; otherwise the page loses the site defaults.
16
+ # - For site-wide settings, use
17
+ # `{ 'with_locales_data' => SiteConfigAccessor.extract_locales_data(site) }`.
17
18
  #
18
- # Key responsibilities:
19
- # - Parse `with_locales_data` from page front matter
20
- # - Validate locale codes against ISO 639-1 (with optional ISO 3166-1 alpha-2 country) format
21
- # - Validate LibreTranslate configuration when enabled
22
- # - Provide getter methods with sensible defaults
23
- # - Raise detailed validation errors for invalid configurations
24
- #
25
- # @example Minimal configuration
26
- # ---
27
- # with_locales: true
28
- # with_locales_data:
29
- # locales: [es, fr, pt]
30
- # ---
31
- #
32
- # @example Full configuration with LibreTranslate
33
- # ---
34
- # with_locales: true
35
- # with_locales_data:
36
- # locales: [es, fr, pt_BR]
37
- # extract_on_build: true
38
- # update_compendium: true
39
- # extraction:
40
- # translatable_attributes: [title, alt, aria-label]
41
- # translation:
42
- # fallback: english
43
- # libretranslate_enabled: true
44
- # libretranslate_api_url: "http://localhost:5000/translate"
45
- # libretranslate_timeout: 300
46
- # logging:
47
- # debug: true
48
- # ---
19
+ # @example
20
+ # config = PageLocalesConfig.new(SiteConfigAccessor.effective_page_data(page))
21
+ # config.locales # => ["es", "fr"]
22
+ # config.fallback_mode # => "english"
49
23
  #
50
24
  class PageLocalesConfig
51
- # Delegate all constant definitions to Constants module
25
+ # Shortcuts to the defaults in Constants.
52
26
  LOCALE_PATTERN = Constants::LOCALE_PATTERN
53
27
  DEFAULT_LOCALES_DIR = Constants::DEFAULT_LOCALES_DIR
54
28
  DEFAULT_FALLBACK_MODE = Constants::DEFAULT_FALLBACK_MODE
@@ -63,18 +37,14 @@ module Jekyll
63
37
  DEFAULT_LIBRETRANSLATE_FORMAT = Constants::DEFAULT_LIBRETRANSLATE_FORMAT
64
38
 
65
39
  # @!attribute [r] data
66
- # The raw page data object this config was parsed from
40
+ # The hash this config was built from
67
41
  # @return [Hash]
68
42
  attr_reader :data
69
43
 
70
- # Initialize configuration from page front matter
71
- #
72
- # Parses the `with_locales_data` section from page front matter and validates
73
- # all configuration values. Raises detailed errors if any values are invalid.
74
- #
75
- # @param page_data [Hash] The Jekyll page data/front matter object
76
- # @raise [Jekyll::Errors::InvalidConfigurationError] If locale codes are invalid
77
- # @raise [Jekyll::Errors::InvalidConfigurationError] If LibreTranslate config is invalid
44
+ # @param page_data [Hash] A hash with a `with_locales_data` key, and
45
+ # optionally `path` (used in error messages)
46
+ # @raise [Jekyll::Errors::InvalidConfigurationError] If a locale code or a
47
+ # LibreTranslate setting is invalid
78
48
  def initialize(page_data)
79
49
  @config = page_data['with_locales_data'] || {}
80
50
  @data = page_data
@@ -84,200 +54,156 @@ module Jekyll
84
54
  validate_libretranslate!
85
55
  end
86
56
 
87
- # Get the list of locales configured for this page
57
+ # Locales to translate into. The constructor has already checked each code
58
+ # against LOCALE_PATTERN.
88
59
  #
89
- # Returns the locales specified in `with_locales_data.locales`, or an empty array
90
- # if not configured. All returned locales are guaranteed to match ISO 639-1 format,
91
- # optionally suffixed with an ISO 3166-1 alpha-2 country code.
92
- #
93
- # @return [Array<String>] BCP 47 locale codes (e.g., ['es', 'fr', 'pt_BR'])
60
+ # @return [Array<String>] Locale codes such as ["es", "pt_BR"], or []
94
61
  def locales
95
62
  @config['locales'] || []
96
63
  end
97
64
 
98
- # Get the directory where PO files are stored for this page
99
- #
100
- # Returns the directory specified in `with_locales_data.locales_dir`,
101
- # or the default "_locales" if not configured.
102
- #
103
- # @return [String] The directory path relative to site root
65
+ # @return [String] Directory for PO files, relative to the site source
104
66
  def locales_dir
105
67
  @config['locales_dir'] || DEFAULT_LOCALES_DIR
106
68
  end
107
69
 
108
- # Check if string extraction should run during Jekyll build
109
- #
110
- # @return [Boolean] true if extraction is enabled (default), false if explicitly disabled
70
+ # @return [Boolean] false only when `extract_on_build` is false
111
71
  def extract_on_build?
112
72
  @config['extract_on_build'] != false
113
73
  end
114
74
 
115
- # Check if compendium files should be updated during extraction
75
+ # Whether to merge page PO files into the locale compendium. A site-wide
76
+ # setting: read it from the site-wide config, not from a page.
116
77
  #
117
- # @return [Boolean] true if compendium updates are enabled (default), false if
118
- # explicitly disabled
78
+ # @return [Boolean] false only when `update_compendium` is false
119
79
  def update_compendium?
120
80
  @config['update_compendium'] != false
121
81
  end
122
82
 
123
- # Check if extraction statistics should be shown in logs
83
+ # Whether to print the extraction summary at the end of the build. A
84
+ # site-wide setting: Extractor reads it from the site-wide config.
124
85
  #
125
- # @return [Boolean] true if statistics are enabled (default), false if explicitly disabled
86
+ # @return [Boolean] false only when `logging.show_statistics` is false
126
87
  def show_statistics?
127
88
  @config.dig('logging', 'show_statistics') != false
128
89
  end
129
90
 
130
- # Check if debug-level logging is enabled
91
+ # Turns on HtmlTranslator's log of each translation lookup for this page.
131
92
  #
132
- # @return [Boolean] true if debug logging is configured, false otherwise
93
+ # @return [Boolean] true when `logging.debug` is true
133
94
  def debug_logging?
134
95
  @config.dig('logging', 'debug') == true
135
96
  end
136
97
 
137
- # Check if trace-level logging is enabled
138
- #
139
- # Trace logging includes detailed per-entry logs for extraction and translation operations.
140
- # This is automatically enabled if debug_logging? is true.
98
+ # Turns on per-entry LibreTranslate logging. Those lines go to Jekyll's
99
+ # debug level, so they show only with `jekyll build --verbose`.
141
100
  #
142
- # @return [Boolean] true if trace logging is enabled or debug logging is enabled
101
+ # @return [Boolean] true when `logging.trace` or `logging.debug` is true
143
102
  def trace_logging?
144
103
  @config.dig('logging', 'trace') == true || debug_logging?
145
104
  end
146
105
 
147
- # Get the fallback mode for missing translations
148
- #
149
- # Determines how to handle translations that are not found in PO files.
150
- # Valid modes: "english" (use original text), "marker" (wrap with markers),
151
- # "empty" (leave blank).
106
+ # What to show when a string has no translation: "english" (the original
107
+ # text), "marker" (the original text wrapped in markers), or "empty".
152
108
  #
153
- # @return [String] The fallback mode ("english", "marker", or "empty")
109
+ # @return [String] The fallback mode
154
110
  def fallback_mode
155
111
  @config.dig('translation', 'fallback') || DEFAULT_FALLBACK_MODE
156
112
  end
157
113
 
158
- # Get the list of HTML attributes to extract for translation
114
+ # HTML attributes whose values are extracted and translated. Defaults to
115
+ # DEFAULT_TRANSLATABLE_ATTRIBUTES.
159
116
  #
160
- # Returns attributes specified in `with_locales_data.extraction.translatable_attributes`,
161
- # or the default list if not configured (title, alt, aria-label, placeholder,
162
- # aria-description).
163
- #
164
- # @return [Array<String>] List of attribute names to extract
117
+ # @return [Array<String>] Attribute names
165
118
  def translatable_attributes
166
119
  @config.dig('extraction', 'translatable_attributes') || DEFAULT_TRANSLATABLE_ATTRIBUTES
167
120
  end
168
121
 
169
- # Check if localization is enabled for this page
170
- #
171
- # A page is considered to have localization enabled if at least one locale is configured.
172
- #
173
- # @return [Boolean] true if locales list is not empty, false otherwise
122
+ # @return [Boolean] true when at least one locale is configured
174
123
  def enabled?
175
124
  !locales.empty?
176
125
  end
177
126
 
178
- # Check if LibreTranslate automatic translation is enabled
127
+ # Whether to machine-translate with LibreTranslate. An explicit
128
+ # `libretranslate_enabled` always wins. Without it, only a
129
+ # `libretranslate_api_url` you set yourself turns it on; the default URL
130
+ # does not, so an unconfigured site never tries to reach a server.
179
131
  #
180
- # Returns true if `libretranslate_enabled` is explicitly set to true,
181
- # or if a `libretranslate_api_url` is configured (backward compatibility).
182
- #
183
- # @return [Boolean] true if LibreTranslate is enabled and configured
132
+ # @return [Boolean] true if LibreTranslate is enabled
184
133
  def libretranslate_enabled?
185
- # Priority 1: Explicit flag (when set)
186
134
  if libretranslate_config.key?('libretranslate_enabled')
187
135
  return libretranslate_config['libretranslate_enabled'] == true
188
136
  end
189
137
 
190
- # Priority 2: Backward compatibility - URL presence (when flag not set)
191
- !libretranslate_api_url.nil? && !libretranslate_api_url.empty?
138
+ url = libretranslate_config['libretranslate_api_url']
139
+ url.is_a?(String) && !url.strip.empty?
192
140
  end
193
141
 
194
- # Get the source locale for LibreTranslate translation
195
- #
196
- # The source locale is the language of the original content being translated.
197
- # Defaults to "en" (English) if not specified.
198
- #
199
- # @return [String] BCP 47 locale code (e.g., 'en', 'fr')
142
+ # @return [String] Locale code of the original content. Defaults to
143
+ # DEFAULT_LIBRETRANSLATE_SOURCE_LOCALE.
200
144
  def libretranslate_source_locale
201
145
  libretranslate_setting('libretranslate_source_locale', DEFAULT_LIBRETRANSLATE_SOURCE_LOCALE)
202
146
  end
203
147
 
204
- # Get the text format for LibreTranslate translation
205
- #
206
- # Determines how text is passed to LibreTranslate API. Valid values: 'text' or 'html'.
207
- # HTML format preserves markup and performs better with structured content.
148
+ # How strings are sent to LibreTranslate. "html" keeps inline markup intact.
208
149
  #
209
- # @return [String] Either 'text' or 'html' (default: 'html')
150
+ # @return [String] "text" or "html". Defaults to DEFAULT_LIBRETRANSLATE_FORMAT.
210
151
  def libretranslate_format
211
152
  libretranslate_setting('libretranslate_format', DEFAULT_LIBRETRANSLATE_FORMAT)
212
153
  end
213
154
 
214
- # Get the LibreTranslate API endpoint URL
155
+ # Base URL of the LibreTranslate server, without `/translate`, which
156
+ # LibreTranslator appends. Returning the default here does not turn
157
+ # LibreTranslate on; see {#libretranslate_enabled?}.
215
158
  #
216
- # Example: "https://api.libretranslate.de" or "http://localhost:5000"
217
- #
218
- # @return [String] The API URL (default: "http://localhost:5000")
159
+ # @return [String] The URL. Defaults to Constants::DEFAULT_LIBRETRANSLATE_API_URL.
219
160
  def libretranslate_api_url
220
161
  libretranslate_setting('libretranslate_api_url', Constants::DEFAULT_LIBRETRANSLATE_API_URL)
221
162
  end
222
163
 
223
- # Get the LibreTranslate API key (if required)
224
- #
225
- # Some LibreTranslate instances require authentication via API key.
226
- #
227
- # @return [String, nil] The API key, or nil if not configured
164
+ # @return [String, nil] API key for servers that require one, or nil
228
165
  def libretranslate_api_key
229
166
  libretranslate_config['libretranslate_api_key']
230
167
  end
231
168
 
232
- # Get the timeout (in seconds) for LibreTranslate API requests
233
- #
234
- # @return [Integer] Timeout in seconds (default: 300)
169
+ # @return [Integer] Request timeout in seconds. Defaults to
170
+ # DEFAULT_LIBRETRANSLATE_TIMEOUT.
235
171
  def libretranslate_timeout
236
172
  libretranslate_setting('libretranslate_timeout', DEFAULT_LIBRETRANSLATE_TIMEOUT)
237
173
  end
238
174
 
239
- # Get the batch size for LibreTranslate translations
240
- #
241
- # Controls how many strings are sent to LibreTranslate in a single API request.
242
- # Larger batches are more efficient but may hit size limits.
175
+ # Strings sent per request. Larger batches mean fewer requests but may
176
+ # exceed the server's size limit.
243
177
  #
244
- # @return [Integer] Batch size (default: 50)
178
+ # @return [Integer] Defaults to DEFAULT_LIBRETRANSLATE_BATCH_SIZE.
245
179
  def libretranslate_batch_size
246
180
  libretranslate_setting('libretranslate_batch_size', DEFAULT_LIBRETRANSLATE_BATCH_SIZE)
247
181
  end
248
182
 
249
- # Get the number of retry attempts for failed LibreTranslate requests
250
- #
251
- # @return [Integer] Number of retry attempts (default: 3)
183
+ # @return [Integer] Retries for a failed request. Defaults to
184
+ # DEFAULT_LIBRETRANSLATE_RETRY_ATTEMPTS.
252
185
  def libretranslate_retry_attempts
253
186
  libretranslate_setting('libretranslate_retry_attempts', DEFAULT_LIBRETRANSLATE_RETRY_ATTEMPTS)
254
187
  end
255
188
 
256
- # Get the delay (in seconds) between LibreTranslate retry attempts
257
- #
258
- # @return [Integer] Delay in seconds (default: 2)
189
+ # @return [Integer] Seconds to wait between retries. Defaults to
190
+ # DEFAULT_LIBRETRANSLATE_RETRY_DELAY.
259
191
  def libretranslate_retry_delay
260
192
  libretranslate_setting('libretranslate_retry_delay', DEFAULT_LIBRETRANSLATE_RETRY_DELAY)
261
193
  end
262
194
 
263
- # Check if translation should stop on LibreTranslate errors
264
- #
265
- # If true, any API error will halt the translation process. If false, errors are logged
266
- # but translation continues with other entries.
195
+ # When true, the first API error stops machine translation. When false, the
196
+ # error is logged and the remaining entries are still translated.
267
197
  #
268
- # @return [Boolean] true if errors should stop translation, false if
269
- # translation continues (default: false)
198
+ # @return [Boolean] Defaults to Constants::DEFAULT_LIBRETRANSLATE_STOP_ON_ERROR.
270
199
  def libretranslate_stop_on_error?
271
200
  val = libretranslate_config['libretranslate_stop_on_error']
272
201
  val.nil? ? Constants::DEFAULT_LIBRETRANSLATE_STOP_ON_ERROR : val != false
273
202
  end
274
203
 
275
- # Get the interval for logging LibreTranslate translation progress
276
- #
277
- # Translation progress is logged every N entries translated. Set to 0 to disable
278
- # progress logging.
204
+ # Log progress after every this many translated entries; 0 turns it off.
279
205
  #
280
- # @return [Integer] Number of entries between progress logs (default: 10)
206
+ # @return [Integer] Defaults to DEFAULT_LIBRETRANSLATE_PROGRESS_INTERVAL.
281
207
  def libretranslate_progress_interval
282
208
  libretranslate_setting('libretranslate_progress_interval', DEFAULT_LIBRETRANSLATE_PROGRESS_INTERVAL)
283
209
  end
@@ -323,19 +249,16 @@ module Jekyll
323
249
  def validate_libretranslate!
324
250
  return unless libretranslate_enabled?
325
251
 
326
- # Require URL when enabled
327
252
  if libretranslate_api_url.nil? || libretranslate_api_url.empty?
328
253
  raise Jekyll::Errors::InvalidConfigurationError,
329
254
  'LibreTranslate is enabled but libretranslate_api_url is not configured'
330
255
  end
331
256
 
332
- # Validate source locale format (ISO 639-1, optionally with ISO 3166-1 alpha-2 country)
333
257
  unless LOCALE_PATTERN.match?(libretranslate_source_locale)
334
258
  raise Jekyll::Errors::InvalidConfigurationError,
335
259
  "Invalid libretranslate_source_locale: #{libretranslate_source_locale}"
336
260
  end
337
261
 
338
- # Validate format
339
262
  return if %w[text html].include?(libretranslate_format)
340
263
 
341
264
  raise Jekyll::Errors::InvalidConfigurationError,