jekyll-theme-zer0 1.27.0 → 1.28.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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +386 -4
  3. data/_data/consumers.yml +147 -0
  4. data/_data/features.yml +77 -5
  5. data/_data/i18n/fr.yml +98 -0
  6. data/_data/i18n/manifest.yml +1502 -0
  7. data/_data/navigation/docs.yml +2 -0
  8. data/_data/navigation/main.yml +6 -0
  9. data/_data/series.yml +19 -0
  10. data/_data/theme-manifest.yml +348 -266
  11. data/_includes/README.md +21 -2
  12. data/_includes/analytics/google-tag-manager-body.html +11 -2
  13. data/_includes/analytics/google-tag-manager-head.html +16 -6
  14. data/_includes/analytics/posthog.html +33 -4
  15. data/_includes/components/abc-letter.html +43 -0
  16. data/_includes/components/book-card.html +42 -0
  17. data/_includes/components/book-nav.html +80 -0
  18. data/_includes/components/book-plate.html +31 -0
  19. data/_includes/components/book-toc.html +47 -0
  20. data/_includes/components/bookshelf.html +68 -0
  21. data/_includes/components/card-grid.html +60 -0
  22. data/_includes/components/data-card.html +95 -0
  23. data/_includes/components/halfmoon.html +5 -1
  24. data/_includes/components/page-feedback.html +65 -2
  25. data/_includes/components/theme-controls-bar.html +10 -2
  26. data/_includes/components/theme-customizer.html +8 -2
  27. data/_includes/content/seo.html +9 -3
  28. data/_includes/core/color-mode-init.html +13 -4
  29. data/_includes/core/favicon.html +46 -0
  30. data/_includes/core/head.html +9 -0
  31. data/_includes/custom/body-end.html +18 -0
  32. data/_includes/custom/body-start.html +17 -0
  33. data/_includes/custom/footer.html +18 -0
  34. data/_includes/custom/head.html +18 -0
  35. data/_includes/navigation/local-graph.html +28 -2
  36. data/_includes/navigation/nav-tree.html +3 -3
  37. data/_includes/navigation/sidebar-config.html +21 -0
  38. data/_includes/navigation/sidebar-nav.html +4 -0
  39. data/_includes/navigation/sidebar-pagetree.html +150 -0
  40. data/_includes/navigation/unified-drawer.html +8 -2
  41. data/_includes/obsidian/full-graph.html +165 -136
  42. data/_layouts/404.html +260 -0
  43. data/_layouts/README.md +2 -0
  44. data/_layouts/book-abc.html +106 -0
  45. data/_layouts/book-story.html +91 -0
  46. data/_layouts/book.html +113 -0
  47. data/_layouts/collection.html +17 -5
  48. data/_layouts/home.html +5 -2
  49. data/_layouts/landing.html +9 -0
  50. data/_layouts/news.html +155 -31
  51. data/_layouts/root.html +16 -2
  52. data/_layouts/section.html +57 -15
  53. data/_sass/components/_book.scss +423 -0
  54. data/_sass/core/_navbar.scss +13 -0
  55. data/_sass/core/_obsidian.scss +286 -6
  56. data/_sass/theme/_backgrounds.scss +21 -8
  57. data/assets/css/main.scss +1 -0
  58. data/assets/js/auto-hide-nav.js +5 -1
  59. data/assets/js/halfmoon.js +26 -0
  60. data/assets/js/obsidian-graph.js +702 -264
  61. data/assets/js/obsidian-local-graph.js +161 -54
  62. data/assets/js/search-modal.js +4 -1
  63. data/scripts/bin/manifest +31 -4
  64. data/scripts/bin/validate +5 -1
  65. data/scripts/install/README.md +47 -6
  66. data/scripts/install/ai/client.sh +302 -93
  67. data/scripts/install/ai/prompts/spec.schema.json +1 -1
  68. data/scripts/install/ai/wizard.sh +10 -5
  69. data/scripts/install/apply.sh +7 -3
  70. data/scripts/install/cli.sh +54 -4
  71. data/scripts/install/config.sh +167 -0
  72. data/scripts/install/doctor.sh +38 -0
  73. data/scripts/install/plan.sh +10 -0
  74. data/scripts/install/spec.sh +15 -7
  75. data/scripts/install/template.sh +4 -0
  76. data/scripts/propagate.rb +277 -0
  77. data/scripts/translate.rb +90 -0
  78. metadata +27 -2
data/scripts/translate.rb CHANGED
@@ -90,6 +90,14 @@ module Zer0Translate
90
90
  permalink redirect_from redirect_to aliases lang
91
91
  translation_of translation_source_url machine_translated translated_from_sha
92
92
  ].freeze
93
+ # Layouts that only work for a document INSIDE a Jekyll collection. The
94
+ # translated tree is deliberately flat — fr/** are plain pages, not collection
95
+ # documents — so Jekyll never sets `page.collection` there and these layouts
96
+ # have nothing to enumerate. `collection` is worse than useless: it sorts
97
+ # site[page.collection], which is nil for a plain page, and a nil sort aborts
98
+ # the whole Jekyll build. Drop the key so the `path: <lang>` front-matter
99
+ # default in _config.yml (layout: default) applies instead.
100
+ COLLECTION_ONLY_LAYOUTS = %w[collection].freeze
93
101
 
94
102
  DEFAULT_CONFIG = {
95
103
  "enabled" => false,
@@ -367,6 +375,42 @@ module Zer0Translate
367
375
  end
368
376
  end
369
377
 
378
+ # Test-only variant of StubProvider that soft-wraps its output, reproducing
379
+ # the one thing a real provider does that no prompt can reliably prevent.
380
+ # Exists so the prose-normalisation pass has something to actually fix —
381
+ # asserting "output is unwrapped" against the plain stub would pass whether
382
+ # or not normalisation ran.
383
+ class WrappingStubProvider
384
+ WRAP_AT = 40
385
+
386
+ def name = "stub-wrap"
387
+
388
+ def translate(segments, target_lang, _context)
389
+ segments.to_h { |key, text| [key, wrap("#{text} [#{target_lang}]")] }
390
+ end
391
+
392
+ private
393
+
394
+ # Greedy wrap on spaces. Never splits a line that has no space past the
395
+ # column (a long URL or placeholder token stays intact).
396
+ def wrap(text)
397
+ out = []
398
+ line = +""
399
+ text.split(" ").each do |word|
400
+ if line.empty?
401
+ line << word
402
+ elsif line.length + 1 + word.length > WRAP_AT
403
+ out << line
404
+ line = +word
405
+ else
406
+ line << " " << word
407
+ end
408
+ end
409
+ out << line unless line.empty?
410
+ out.join("\n")
411
+ end
412
+ end
413
+
370
414
  class ClaudeProvider
371
415
  ENDPOINT = URI("https://api.anthropic.com/v1/messages")
372
416
  API_VERSION = "2023-06-01"
@@ -762,6 +806,9 @@ module Zer0Translate
762
806
  @url_builder = UrlBuilder.new(@site_config)
763
807
  @manifest = Manifest.new(@root)
764
808
  @stats = Hash.new(0)
809
+ # Absolute paths of every markdown file this run wrote, for the
810
+ # prose-normalisation pass in `run`.
811
+ @written_pages = []
765
812
  end
766
813
 
767
814
  def run
@@ -790,6 +837,7 @@ module Zer0Translate
790
837
 
791
838
  translator = build_translator
792
839
  execute(plan, translator)
840
+ normalize_prose(@written_pages)
793
841
  prune(sources, languages)
794
842
  @manifest.save(source_lang, languages)
795
843
  summary
@@ -922,6 +970,7 @@ module Zer0Translate
922
970
  provider =
923
971
  case provider_name
924
972
  when "stub" then StubProvider.new
973
+ when "stub-wrap" then WrappingStubProvider.new
925
974
  when "claude"
926
975
  ClaudeProvider.new(
927
976
  model: @options[:model] || ENV["TRANSLATE_MODEL"] || @config["model"],
@@ -949,6 +998,45 @@ module Zer0Translate
949
998
  end
950
999
  end
951
1000
 
1001
+ # Generated pages must satisfy the repo's one-paragraph-per-line rule, which
1002
+ # CI enforces via .github/workflows/markdown-oneline.yml. The provider is
1003
+ # free to soft-wrap a translated paragraph across several lines — nothing in
1004
+ # the prompt can guarantee otherwise — so normalise deterministically after
1005
+ # the fact rather than hoping the model complies.
1006
+ #
1007
+ # tools/unwrap-prose.py is the single source of truth for the rule (it is
1008
+ # what CI runs), so shell out to it instead of reimplementing the classifier
1009
+ # here and letting the two drift.
1010
+ #
1011
+ # Best-effort by design: a missing python3 should not fail an otherwise good
1012
+ # translation run. The Translate workflow runs the same tool as a guaranteed
1013
+ # backstop before committing, so the only cost of skipping here is a local
1014
+ # run leaving wrapped prose for that step to fix.
1015
+ def normalize_prose(paths)
1016
+ paths = paths.select { |p| File.file?(p) }
1017
+ return if paths.empty?
1018
+
1019
+ # Resolve the tool relative to THIS script, not to --root. translate.rb
1020
+ # and tools/ ship together; --root points at the content tree being
1021
+ # translated, which is a different thing (and is a throwaway sandbox
1022
+ # under test).
1023
+ tool = File.expand_path("../tools/unwrap-prose.py", __dir__)
1024
+ tool = File.join(@root, "tools", "unwrap-prose.py") unless File.file?(tool)
1025
+ unless File.file?(tool)
1026
+ Log.warn "tools/unwrap-prose.py not found — skipping prose normalisation"
1027
+ return
1028
+ end
1029
+
1030
+ ok = system("python3", tool, "--write", *paths,
1031
+ out: File::NULL, err: File::NULL)
1032
+ if ok
1033
+ Log.info "Normalised prose in #{paths.size} generated page(s)"
1034
+ else
1035
+ Log.warn "prose normalisation skipped (python3 unavailable or tool failed); " \
1036
+ "run: python3 tools/unwrap-prose.py --write"
1037
+ end
1038
+ end
1039
+
952
1040
  def translate_page(job, translator)
953
1041
  file = job.source
954
1042
  segmenter = Segmenter.new(file.body)
@@ -993,6 +1081,7 @@ module Zer0Translate
993
1081
  key = "fm:#{field}"
994
1082
  fm[field] = fm_masker.unmask(translated[key]) if translated.key?(key)
995
1083
  end
1084
+ fm.delete("layout") if COLLECTION_ONLY_LAYOUTS.include?(fm["layout"].to_s)
996
1085
  fm["lang"] = job.lang
997
1086
  fm["permalink"] = "/#{job.lang}#{job.url}"
998
1087
  fm["translation_of"] = file.rel_path
@@ -1007,6 +1096,7 @@ module Zer0Translate
1007
1096
  abs = File.join(@root, out_rel)
1008
1097
  FileUtils.mkdir_p(File.dirname(abs))
1009
1098
  File.write(abs, "#{fm.to_yaml}---\n\n#{body_out.sub(/\A\n+/, '')}")
1099
+ @written_pages << abs
1010
1100
  end
1011
1101
 
1012
1102
  def translate_ui_text(job, translator)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jekyll-theme-zer0
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.27.0
4
+ version: 1.28.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amr Abdel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-07-22 00:00:00.000000000 Z
11
+ date: 2026-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -81,6 +81,7 @@ files:
81
81
  - _data/ai.yml
82
82
  - _data/authors.yml
83
83
  - _data/backlog.yml
84
+ - _data/consumers.yml
84
85
  - _data/content_statistics.yml
85
86
  - _data/features.yml
86
87
  - _data/feedback_types.yml
@@ -88,7 +89,9 @@ files:
88
89
  - _data/generate_statistics.sh
89
90
  - _data/github-actions-example.yml
90
91
  - _data/glossary.yml
92
+ - _data/i18n/fr.yml
91
93
  - _data/i18n/languages.yml
94
+ - _data/i18n/manifest.yml
92
95
  - _data/landing.yml
93
96
  - _data/navigation/README.md
94
97
  - _data/navigation/about.yml
@@ -103,6 +106,7 @@ files:
103
106
  - _data/roadmap.yml
104
107
  - _data/roadmap_plan.yml
105
108
  - _data/routing.yml
109
+ - _data/series.yml
106
110
  - _data/statistics_config.yml
107
111
  - _data/theme-manifest.yml
108
112
  - _data/theme_backgrounds.yml
@@ -115,6 +119,7 @@ files:
115
119
  - _includes/analytics/google-tag-manager-head.html
116
120
  - _includes/analytics/posthog.html
117
121
  - _includes/components/README.md
122
+ - _includes/components/abc-letter.html
118
123
  - _includes/components/admin-links.html
119
124
  - _includes/components/admin-tabs.html
120
125
  - _includes/components/ai-chat.html
@@ -125,13 +130,20 @@ files:
125
130
  - _includes/components/author-eeat.html
126
131
  - _includes/components/background-customizer.html
127
132
  - _includes/components/background-settings.html
133
+ - _includes/components/book-card.html
134
+ - _includes/components/book-nav.html
135
+ - _includes/components/book-plate.html
136
+ - _includes/components/book-toc.html
137
+ - _includes/components/bookshelf.html
128
138
  - _includes/components/callout.html
139
+ - _includes/components/card-grid.html
129
140
  - _includes/components/collection-manager.html
130
141
  - _includes/components/component-showcase.html
131
142
  - _includes/components/config-editor.html
132
143
  - _includes/components/config-viewer.html
133
144
  - _includes/components/cookie-consent.html
134
145
  - _includes/components/cta-button.html
146
+ - _includes/components/data-card.html
135
147
  - _includes/components/dev-shortcuts.html
136
148
  - _includes/components/env-dashboard.html
137
149
  - _includes/components/env-detect.html
@@ -179,6 +191,7 @@ files:
179
191
  - _includes/core/branding.html
180
192
  - _includes/core/color-mode-init.html
181
193
  - _includes/core/console-capture.html
194
+ - _includes/core/favicon.html
182
195
  - _includes/core/footer-fabs.html
183
196
  - _includes/core/footer.html
184
197
  - _includes/core/head.html
@@ -186,6 +199,10 @@ files:
186
199
  - _includes/core/hreflang.html
187
200
  - _includes/core/i18n.html
188
201
  - _includes/core/tokens-inline.html
202
+ - _includes/custom/body-end.html
203
+ - _includes/custom/body-start.html
204
+ - _includes/custom/footer.html
205
+ - _includes/custom/head.html
189
206
  - _includes/docs/bootstrap-docs.html
190
207
  - _includes/landing/landing-install-cards.html
191
208
  - _includes/landing/landing-quick-links.html
@@ -203,6 +220,7 @@ files:
203
220
  - _includes/navigation/sidebar-folders.html
204
221
  - _includes/navigation/sidebar-left.html
205
222
  - _includes/navigation/sidebar-nav.html
223
+ - _includes/navigation/sidebar-pagetree.html
206
224
  - _includes/navigation/sidebar-right.html
207
225
  - _includes/navigation/toc-fab.html
208
226
  - _includes/navigation/unified-drawer.html
@@ -216,11 +234,15 @@ files:
216
234
  - _includes/stats/stats-no-data.html
217
235
  - _includes/stats/stats-overview.html
218
236
  - _includes/stats/stats-tags.html
237
+ - _layouts/404.html
219
238
  - _layouts/README.md
220
239
  - _layouts/admin.html
221
240
  - _layouts/article.html
222
241
  - _layouts/author.html
223
242
  - _layouts/authors.html
243
+ - _layouts/book-abc.html
244
+ - _layouts/book-story.html
245
+ - _layouts/book.html
224
246
  - _layouts/collection.html
225
247
  - _layouts/default.html
226
248
  - _layouts/home.html
@@ -245,6 +267,7 @@ files:
245
267
  - _plugins/theme_version.rb
246
268
  - _sass/components/_author.scss
247
269
  - _sass/components/_back-to-top.scss
270
+ - _sass/components/_book.scss
248
271
  - _sass/components/_callout.scss
249
272
  - _sass/components/_content-tables.scss
250
273
  - _sass/components/_cookie-banner.scss
@@ -434,6 +457,7 @@ files:
434
457
  - scripts/install/ai/wizard.sh
435
458
  - scripts/install/apply.sh
436
459
  - scripts/install/cli.sh
460
+ - scripts/install/config.sh
437
461
  - scripts/install/diff.sh
438
462
  - scripts/install/doctor.sh
439
463
  - scripts/install/fs.sh
@@ -509,6 +533,7 @@ files:
509
533
  - scripts/platform/setup-macos.sh
510
534
  - scripts/platform/setup-wsl.sh
511
535
  - scripts/post-template-setup.sh
536
+ - scripts/propagate.rb
512
537
  - scripts/release
513
538
  - scripts/requirements.txt
514
539
  - scripts/setup.sh