Files
Rohit Ghumare d86fedaa51 fix: dark-mode mermaid fills, Apple Silicon Docker build, fnm unzip, ROADMAP rows, site chrome translations (#477)
* fix: dark-mode mermaid fills, Apple Silicon Docker build, fnm unzip, ROADMAP rows, site chrome translations

- site/lesson.html: mermaidPreprocess handles 3-digit hex fills so fill:#dfd stays legible in dark mode (#433)
- 07-docker-for-ai: pin FROM to linux/amd64 and document why the cu124 layer fails on Apple Silicon (#476)
- 01-dev-environment: add unzip to the apt line, fnm's installer needs it (#473)
- ROADMAP.md: add Phase 11 lessons 16 and 17, 521 rows to 523
- site: translate interface strings for the eight CI languages via ui-i18n.js + ui-strings.js, picker dispatches aifs:lang, drift guarded by test_ui_i18n.js in CI (#469, #404)

* docs: describe fnm's unzip check and scope the CUDA image to x86_64 hosts

- 01-dev-environment: the installer checks for unzip up front and exits with its own message; macOS goes through Homebrew
- 07-docker-for-ai: the linux/amd64 pin means the image is for x86_64 Linux hosts with an NVIDIA GPU

* feat(i18n): generate site chrome translations in the translate pipeline

The hand dictionary becomes site/ui-strings.json: an English key list plus
per-language overrides. scripts/translate_ui_strings.py fills every other key
through the lesson translator's provider layer, reuses what is already
published, protects file names, paths, and commands behind the same
placeholders, and writes i18n/<lang>/ui.json. A new ui-strings job in
translate.yml runs it per CI language and publishes to the translations
branch with the same race-safe worktree loop, so a new label or a new
language needs no translation written by hand.

site/ui-i18n.js now fetches i18n/<lang>/ui.json from the translations branch
at runtime, caches it per language, and falls back to English until a language
is published. Tests cover source consistency, precedence, placeholder
protection, the page drift guard, and the fetch path.

* fix(i18n): retranslate keys whose override was removed and keep failed dictionary loads retryable

- ui.json now carries {strings, pinned}; a key that was pinned in the last publication but has no override now is translated again instead of reusing the old pin
- the runtime no longer caches a failed fetch, so a language published later is picked up on the next switch without a reload

* fix(i18n): refresh flat ui.json values once when pin provenance is missing

A flat published file predates the {strings, pinned} shape and cannot say
which values came from overrides, so every value in it counts as pinned and
is retranslated on the first run instead of being reused blindly.
2026-09-24 09:22:11 +05:30
..