[Epic][Bug] Localize lesson code-template comments (Spanish) across all playgrounds #296

Closed
opened 2026-06-30 15:52:21 +00:00 by spikerj · 11 comments
Owner

Summary (confirmed root cause)

Lesson code-editor starter templates are never localized — the comments inside the editable code (e.g. C# lesson 301: // return one label when flag is true, the other when false) always render in English even when UI + lesson text are Spanish. Verified in code:

  • LessonStrategyBase.Localization.csFinalizeAttemptWithLocale overlays Instructions / Hints / TutorialPanels only, and passes the original English built.CodeTemplate straight through to FinalizeAttemptCore.
  • The translation data model (CurriculumTranslationStore.LessonTranslationEntry) has no codeTemplate field — so a translated template can't even be expressed today.
  • Confirmed against Lesson301_IfElse.cs (the exact comment in the report) and the es/csharp.json entry for 301 (has translated instructions/hints, no template).

This is one structural root cause behind the entire per-language cluster.

Consolidates

(Older translation waves #267–274 and #196–203 are about instructions/lesson text — a different symptom, largely addressed by the #279 content work — and are NOT folded in here until individually re-confirmed.)

Plan

Phase 1 — Engineering (this epic's first PR)

  • Add an optional codeTemplate field to LessonTranslationEntry / LessonTranslation and the store loader.
  • In FinalizeAttemptWithLocale, when a translated codeTemplate exists, overlay it (with ApplySeedTokens for randomized lessons) before FinalizeAttemptCore.
  • Pilot end-to-end on one C# lesson (301) + unit coverage.

Phase 2 — Content fan-out (per track)

  • Author Spanish codeTemplate entries (comments only; keep identifiers/keywords as code) for every Challenge lesson, per track: C#, Python, JavaScript, C, C++, x86, Regex, SQL.

Known follow-up (track separately)

  • Offline/WASM path: the browser grader serves English attempts (LessonStrategyBase.Localization.cs is server-only). Connected mode is fixed by Phase 1; offline localization of the template needs a separate SPA/WASM change.

Acceptance criteria

  • Translation model + overlay support a localized code template (Phase 1).
  • C# pilot lesson serves Spanish comments in ?contentLocale=es with passing tests.
  • Per-track content added (Phase 2) for all Challenge lessons.
  • Spanish UI shows translated starter-comment text in connected mode across all 8 playgrounds.

Severity

Medium (localization completeness; comprehension for Spanish-speaking learners).

## Summary (confirmed root cause) Lesson **code-editor starter templates are never localized** — the comments inside the editable code (e.g. C# lesson 301: `// return one label when flag is true, the other when false`) always render in English even when UI + lesson text are Spanish. Verified in code: - `LessonStrategyBase.Localization.cs` → `FinalizeAttemptWithLocale` overlays **Instructions / Hints / TutorialPanels** only, and passes the original English `built.CodeTemplate` straight through to `FinalizeAttemptCore`. - The translation data model (`CurriculumTranslationStore.LessonTranslationEntry`) has **no `codeTemplate` field** — so a translated template can't even be expressed today. - Confirmed against `Lesson301_IfElse.cs` (the exact comment in the report) and the `es/csharp.json` entry for 301 (has translated instructions/hints, no template). This is **one structural root cause** behind the entire per-language cluster. ## Consolidates - #288 C# · #289 Python · #290 JavaScript · #291 C · #292 C++ · #293 x86 · #294 Regex · #295 SQL (Older translation waves #267–274 and #196–203 are about *instructions/lesson text* — a different symptom, largely addressed by the #279 content work — and are NOT folded in here until individually re-confirmed.) ## Plan ### Phase 1 — Engineering (this epic's first PR) - Add an optional `codeTemplate` field to `LessonTranslationEntry` / `LessonTranslation` and the store loader. - In `FinalizeAttemptWithLocale`, when a translated `codeTemplate` exists, overlay it (with `ApplySeedTokens` for randomized lessons) before `FinalizeAttemptCore`. - Pilot end-to-end on one C# lesson (301) + unit coverage. ### Phase 2 — Content fan-out (per track) - Author Spanish `codeTemplate` entries (comments only; keep identifiers/keywords as code) for every Challenge lesson, per track: C#, Python, JavaScript, C, C++, x86, Regex, SQL. ### Known follow-up (track separately) - **Offline/WASM path**: the browser grader serves English attempts (`LessonStrategyBase.Localization.cs` is server-only). Connected mode is fixed by Phase 1; offline localization of the template needs a separate SPA/WASM change. ## Acceptance criteria - [ ] Translation model + overlay support a localized code template (Phase 1). - [ ] C# pilot lesson serves Spanish comments in `?contentLocale=es` with passing tests. - [ ] Per-track content added (Phase 2) for all Challenge lessons. - [ ] Spanish UI shows translated starter-comment text in connected mode across all 8 playgrounds. ## Severity Medium (localization completeness; comprehension for Spanish-speaking learners).
spikerj added the bug label 2026-06-30 15:52:21 +00:00
Author
Owner

Triage note — extra untranslated surfaces folded in from #288–#295

Reading the full reports, a few of the closed duplicates point at surfaces beyond the starter-template comments. Capturing them here so they aren't lost (each needs its own data/overlay work under Phase 2):

  1. Starter-template comments (the structural fix, Phase 1 / PR #36): #288 C#, #290 JS, #291 C, #292 C++, #293 x86 (; Flat Assembler file), #295 SQL (-- Welcome to the SQL playground.). Python (#289) # replace this with your code is the auto-generated pass-placeholder annotation — needs localizing in AnnotatePlaceholdersForLanguage, not JSON.
  2. "Lección Concepts" side panel still English (e.g. "Return a value", "Standard output stream", "Newline escape sequence") — reported in #289 (Python), #291 (C), #292 (C++). Separate concept-card content, not part of the attempt overlay.
  3. Regex hints ("Pistas") in English — #294. This is the regex hint pipeline, overlaps older #273 / #202; not a code template at all.
  4. SQL instructions still English ("Concept focus…", "Write a query…") — #295, overlaps older #274 / #203.
  5. x86 terminal/emulator strings ("Initializing blink emulator… blink ready!") — #293; emulator UI, separate from lesson content.

PR #36 covers (1) for C# as the pilot. Suggest tracking (2)–(5) as explicit Phase-2 sub-items so per-surface ownership is clear.

### Triage note — extra untranslated surfaces folded in from #288–#295 Reading the full reports, a few of the closed duplicates point at surfaces **beyond** the starter-template comments. Capturing them here so they aren't lost (each needs its own data/overlay work under Phase 2): 1. **Starter-template comments** (the structural fix, Phase 1 / PR #36): #288 C#, #290 JS, #291 C, #292 C++, #293 x86 (`; Flat Assembler file`), #295 SQL (`-- Welcome to the SQL playground.`). Python (#289) `# replace this with your code` is the auto-generated `pass`-placeholder annotation — needs localizing in `AnnotatePlaceholdersForLanguage`, not JSON. 2. **"Lección Concepts" side panel** still English (e.g. "Return a value", "Standard output stream", "Newline escape sequence") — reported in #289 (Python), #291 (C), #292 (C++). Separate concept-card content, not part of the attempt overlay. 3. **Regex hints ("Pistas")** in English — #294. This is the regex hint pipeline, overlaps older #273 / #202; not a code template at all. 4. **SQL instructions** still English ("Concept focus…", "Write a query…") — #295, overlaps older #274 / #203. 5. **x86 terminal/emulator strings** ("Initializing blink emulator… blink ready!") — #293; emulator UI, separate from lesson content. PR #36 covers (1) for C# as the pilot. Suggest tracking (2)–(5) as explicit Phase-2 sub-items so per-surface ownership is clear.
Author
Owner

Phase 2 progress — content batch 1 (C# Tiers 1-3)

PR #36 (engine) merged to master. First content batch is up in spikersoft-backend PR #37: Spanish codeTemplate for the beginner C# path — Tier 01 Foundations (100-107), Tier 02 Operators (200-206), Tier 03 Control Flow (300, 302-307); 301 shipped with Phase 1. 23 C# lessons now serve Spanish starter comments.

Comments-only invariant is enforced by tests (line-count + non-comment-line equality vs English), so translations can't drift the actual code.

Remaining (per-track content):

  • C# Tiers 04-16 (~80 lessons)
  • Python (incl. pass-placeholder annotation in AnnotatePlaceholdersForLanguage)
  • JavaScript
  • C / C++
  • x86 / Regex / SQL
  • Non-template surfaces from triage note (concept panels, regex hints, x86 terminal)
### Phase 2 progress — content batch 1 (C# Tiers 1-3) PR #36 (engine) merged to `master`. First content batch is up in spikersoft-backend PR #37: Spanish `codeTemplate` for the beginner C# path — Tier 01 Foundations (100-107), Tier 02 Operators (200-206), Tier 03 Control Flow (300, 302-307); 301 shipped with Phase 1. 23 C# lessons now serve Spanish starter comments. Comments-only invariant is enforced by tests (line-count + non-comment-line equality vs English), so translations can't drift the actual code. **Remaining (per-track content):** - [ ] C# Tiers 04-16 (~80 lessons) - [ ] Python (incl. `pass`-placeholder annotation in `AnnotatePlaceholdersForLanguage`) - [ ] JavaScript - [ ] C / C++ - [ ] x86 / Regex / SQL - [ ] Non-template surfaces from triage note (concept panels, regex hints, x86 terminal)
Author
Owner

Phase 2, Batch 2 — C# Tiers 4-16 (PR spikersoft-backend#38, open)

Following PR #37 (Tiers 1-3), this batch finishes Spanish codeTemplate comment localization for the entire C# curriculum:

  • Tier 04 Methods (400-406), Tier 05 Collections (500-505), Tier 06 Strings (600-605), Tier 07 Classes (700-707, 710), Tier 08 Inheritance (801-804), Tier 09 Generics (900-903), Tier 10 Exceptions (1000-1003), Tier 11 LINQ (1100-1105), Tier 12 Delegates (1200-1203), Tier 13 Patterns (1300-1303), Tier 14 Nullability (1400-1402), Tier 15 Async (1500-1503), Tier 16 Advanced (1600-1602, 1604).
  • Intentionally skipped (no prose to localize): lessons whose only comments are pure code skeletons (506, 507, 708, 709) or inline comments on code lines that would break the code-line guard (800, 805, 1603).
  • Seed-token placeholders ({className}, {propName}, etc.) preserved so ApplySeedTokens still binds randomized values.
  • All 38 CurriculumLocaleTests pass, including the SpanishCodeTemplates_OnlyDifferInComments_FromEnglish guard now covering the full C# track.

C# track status: complete (pending #38 merge). Remaining content work for other languages (Python, JavaScript, C, C++, SQL, x86, Regex) and the broader untranslated surfaces noted earlier in this epic (regex hints, concept panels, x86 terminal strings) are still open.

**Phase 2, Batch 2 — C# Tiers 4-16 (PR spikersoft-backend#38, open)** Following PR #37 (Tiers 1-3), this batch finishes Spanish `codeTemplate` comment localization for the **entire C# curriculum**: - Tier 04 Methods (400-406), Tier 05 Collections (500-505), Tier 06 Strings (600-605), Tier 07 Classes (700-707, 710), Tier 08 Inheritance (801-804), Tier 09 Generics (900-903), Tier 10 Exceptions (1000-1003), Tier 11 LINQ (1100-1105), Tier 12 Delegates (1200-1203), Tier 13 Patterns (1300-1303), Tier 14 Nullability (1400-1402), Tier 15 Async (1500-1503), Tier 16 Advanced (1600-1602, 1604). - **Intentionally skipped** (no prose to localize): lessons whose only comments are pure code skeletons (506, 507, 708, 709) or inline comments on code lines that would break the code-line guard (800, 805, 1603). - Seed-token placeholders (`{className}`, `{propName}`, etc.) preserved so `ApplySeedTokens` still binds randomized values. - All 38 `CurriculumLocaleTests` pass, including the `SpanishCodeTemplates_OnlyDifferInComments_FromEnglish` guard now covering the full C# track. **C# track status: complete** (pending #38 merge). Remaining content work for other languages (Python, JavaScript, C, C++, SQL, x86, Regex) and the broader untranslated surfaces noted earlier in this epic (regex hints, concept panels, x86 terminal strings) are still open.
Author
Owner

Phase 2 — Python track done. Opened spikersoft-backend PR #39 (fix/issue-296-python-codetemplate-contentmaster).

Localized starter codeTemplate comments for all 74 Python challenge lessons in es/python.json. Same discipline as the C# track: only comment lines translated, code lines byte-identical to the live English (enforced by SpanishCodeTemplates_OnlyDifferInComments_FromEnglish, 38/38 locale tests green). Comment-less code skeletons and tutorial lessons were skipped (nothing to translate). Lesson 20105 uses the {value} seed key instead of the build-time-only {literal} interpolation token so no raw token leaks under Spanish.

Track status (content fan-out):

  • C# — Phase 1 pilot #36, Tiers 1-3 #37, Tiers 4-16 #38 (merged)
  • Python — #39 (open)
  • JavaScript
  • C / C++ / SQL / x86 / Regex

Remaining es/*.json tracks already have title/instructions/hints translated; only codeTemplate comments are outstanding.

**Phase 2 — Python track done.** Opened spikersoft-backend PR #39 (`fix/issue-296-python-codetemplate-content` → `master`). Localized starter `codeTemplate` comments for **all 74 Python challenge lessons** in `es/python.json`. Same discipline as the C# track: only comment lines translated, code lines byte-identical to the live English (enforced by `SpanishCodeTemplates_OnlyDifferInComments_FromEnglish`, 38/38 locale tests green). Comment-less code skeletons and tutorial lessons were skipped (nothing to translate). Lesson 20105 uses the `{value}` seed key instead of the build-time-only `{literal}` interpolation token so no raw token leaks under Spanish. **Track status (content fan-out):** - [x] C# — Phase 1 pilot #36, Tiers 1-3 #37, Tiers 4-16 #38 (merged) - [x] Python — #39 (open) - [ ] JavaScript - [ ] C / C++ / SQL / x86 / Regex Remaining `es/*.json` tracks already have title/instructions/hints translated; only `codeTemplate` comments are outstanding.
Author
Owner

Phase 2 — JavaScript track done. Opened spikersoft-backend PR #40 (fix/issue-296-javascript-codetemplate-contentmaster).

Localized starter codeTemplate comments for all 127 JavaScript challenge lessons in es/javascript.json. This track was unusually uniform — 125 of 127 templates share one generic boilerplate comment, with only the Hello World lesson (30100) bespoke. No seed-token interpolation in any JS template comment, so no leak risk there. Same discipline as C#/Python: only comments translated, code lines byte-identical to the live English (38/38 locale tests green).

Track status (content fan-out):

  • C# — merged (#36, #37, #38)
  • Python — merged (#39)
  • JavaScript — #40 (open)
  • C / C++ / SQL / x86 / Regex

Remaining tracks already have title/instructions/hints translated; only codeTemplate comments outstanding.

**Phase 2 — JavaScript track done.** Opened spikersoft-backend PR #40 (`fix/issue-296-javascript-codetemplate-content` → `master`). Localized starter `codeTemplate` comments for **all 127 JavaScript challenge lessons** in `es/javascript.json`. This track was unusually uniform — 125 of 127 templates share one generic boilerplate comment, with only the Hello World lesson (30100) bespoke. No seed-token interpolation in any JS template comment, so no leak risk there. Same discipline as C#/Python: only comments translated, code lines byte-identical to the live English (38/38 locale tests green). **Track status (content fan-out):** - [x] C# — merged (#36, #37, #38) - [x] Python — merged (#39) - [x] JavaScript — #40 (open) - [ ] C / C++ / SQL / x86 / Regex Remaining tracks already have title/instructions/hints translated; only `codeTemplate` comments outstanding.
Author
Owner

Pausing the content fan-out here. While starting the C track, found that the Phase 1 overlay can't actually reach the starter source for C, C++, x86, SQL, and Regex — those five strategies ship their starter(s) inside a JSON blob (TestCode) that the SPA's browser grader reads client-side, never through BuiltAttempt.CodeTemplate. Translating their es/*.json codeTemplate fields the way we did for C#/Python/JS would have had zero visible effect.

Filed #299 with the root-cause detail and a proposed Phase 1.5 engineering fix (per-track translation model: single starter for Clang, per-dialect map for x86, per-theme map for SQL; Regex needs an audit first to see if it even has translatable comments).

Current state:

  • C# — merged (#36, #37, #38)
  • Python — merged (#39)
  • JavaScript — merged (#40)
  • C, C++, x86, SQL, Regex — blocked on #299

Resuming once #299's engineering lands.

**Pausing the content fan-out here.** While starting the C track, found that the Phase 1 overlay can't actually reach the starter source for **C, C++, x86, SQL, and Regex** — those five strategies ship their starter(s) inside a JSON blob (`TestCode`) that the SPA's browser grader reads client-side, never through `BuiltAttempt.CodeTemplate`. Translating their `es/*.json` `codeTemplate` fields the way we did for C#/Python/JS would have had **zero visible effect**. Filed **#299** with the root-cause detail and a proposed Phase 1.5 engineering fix (per-track translation model: single starter for Clang, per-dialect map for x86, per-theme map for SQL; Regex needs an audit first to see if it even has translatable comments). **Current state:** - [x] C# — merged (#36, #37, #38) - [x] Python — merged (#39) - [x] JavaScript — merged (#40) - [ ] C, C++, x86, SQL, Regex — **blocked on #299** Resuming once #299's engineering lands.
Author
Owner

Engineering fix for the C/C++/x86 blocker is up for review: spikersoft-backend PR #41 (spikerj/spikersoft-backend#41), resolving #299.

Also resolved as part of that work: audited Regex and SQL and confirmed neither has any starter content to localize today (no lesson uses a non-empty starter for either track), so they're not blocked — there's simply nothing to translate for them right now. Will drop them from the "blocked" list below once #299 merges.

Once #41 merges, content fan-out can resume for C, C++, and x86 (translating codeTemplate/codeTemplates per lesson in es/c.json, es/cpp.json, es/x86.json, the same way Python/JavaScript were done).

Engineering fix for the C/C++/x86 blocker is up for review: spikersoft-backend PR #41 (https://git.spikersoft.com/spikerj/spikersoft-backend/pulls/41), resolving #299. Also resolved as part of that work: audited Regex and SQL and confirmed neither has any starter content to localize today (no lesson uses a non-empty starter for either track), so they're **not blocked** — there's simply nothing to translate for them right now. Will drop them from the "blocked" list below once #299 merges. Once #41 merges, content fan-out can resume for C, C++, and x86 (translating `codeTemplate`/`codeTemplates` per lesson in `es/c.json`, `es/cpp.json`, `es/x86.json`, the same way Python/JavaScript were done).
Author
Owner

Status update: the engineering blocker (#299) is resolved and merged (spikersoft-backend PR #41). LocalizeEmbeddedStarter now lets Clang (C/C++) and x86 localize their plan-embedded starters, piloted on C lesson 80100 and x86 lesson 50100. Regex and SQL confirmed as no-ops (no translatable starter content exists today; tripwire test guards against silent regression if that changes).

Phase 2 content fan-out can now resume for C, C++, x86 whenever we pick it back up. SQL/Regex need no further work on this front.

Unrelated side-finding while auditing test coverage for this epic's work: filed and fixed a general regression guard (SpanishTranslations_NoUnresolvedSeedTokensLeak, in PR #41) for translations referencing seed-token names that don't exist for that lesson — generalizes the one-off Lesson20105_VarBool fix into a permanent test across the whole curriculum.

Status update: the engineering blocker (#299) is resolved and merged (spikersoft-backend PR #41). `LocalizeEmbeddedStarter` now lets Clang (C/C++) and x86 localize their plan-embedded starters, piloted on C lesson 80100 and x86 lesson 50100. Regex and SQL confirmed as no-ops (no translatable starter content exists today; tripwire test guards against silent regression if that changes). Phase 2 content fan-out can now resume for **C, C++, x86** whenever we pick it back up. SQL/Regex need no further work on this front. Unrelated side-finding while auditing test coverage for this epic's work: filed and fixed a general regression guard (`SpanishTranslations_NoUnresolvedSeedTokensLeak`, in PR #41) for translations referencing seed-token names that don't exist for that lesson — generalizes the one-off Lesson20105_VarBool fix into a permanent test across the whole curriculum.
Author
Owner

Housekeeping: individually re-confirmed and closed the older translation-wave tickets this epic referenced as "not folded in until individually re-confirmed":

One partial exception: #271 (C++) reported both an instructions-panel symptom (now fixed) and an English-only Concept Reference dictionary panel symptom. The latter is a separate, frontend-only static-data system with no i18n at all (affects C#, Python, C, and C++ playgrounds). Split that into a new ticket, #301, and left #271 open until it lands.

Housekeeping: individually re-confirmed and closed the older translation-wave tickets this epic referenced as "not folded in until individually re-confirmed": - #196 (JS), #197 (C#), #198 (Python), #199 (C), #200 (C++), #202 (Regex), #203 (SQL) — all confirmed fixed by the #279 backend content PRs (#25–#32). - #267, #268, #269, #270, #272, #273, #274 (the newer per-playground wave with the same symptom) — same confirmation, closed. One partial exception: #271 (C++) reported both an instructions-panel symptom (now fixed) **and** an English-only Concept Reference dictionary panel symptom. The latter is a separate, frontend-only static-data system with no i18n at all (affects C#, Python, C, and C++ playgrounds). Split that into a new ticket, #301, and left #271 open until it lands.
Author
Owner

x86 content fan-out is done — backend PR spikersoft-backend#310 (branch feat/296-x86-starter-es, not merged yet).

Added per-dialect codeTemplates Spanish overlays to all 33 comment-bearing x86 Challenge lessons (50101–50905) in es/x86.json — the pilot #299 had only localized 50100, leaving the rest serving the English >>> your code goes here <<< marker and the Chapter 6–9 body hints under a Spanish UI. Comments only; every code line is byte-identical to the English starter (grading unaffected), and each lesson's AllowedDialects is honored (Chapter 9 single-dialect lessons get one starter). Also localized lesson 50004's tutorial prose that quoted the marker, and added a permanent tripwire EveryX86ChallengeStarter_IsLocalizedToSpanish so a future un-localized lesson fails the build.

Verified locally: SpikerSoft.UnitTests.slnf + SpikerSoft.Wasm build clean; CurriculumLocaleTests 43/43; tripwire confirmed to fail pre-change.

That leaves x86 alongside C#/Python/JS/C/C++ as fully localized (Regex/SQL are intentional no-ops), so all 8 playgrounds are covered. Leaving this open for you to close after #310 merges.

x86 content fan-out is done — backend PR spikersoft-backend#310 (branch `feat/296-x86-starter-es`, **not merged yet**). Added per-dialect `codeTemplates` Spanish overlays to all **33** comment-bearing x86 Challenge lessons (50101–50905) in `es/x86.json` — the pilot #299 had only localized 50100, leaving the rest serving the English `>>> your code goes here <<<` marker and the Chapter 6–9 body hints under a Spanish UI. Comments only; every code line is byte-identical to the English starter (grading unaffected), and each lesson's `AllowedDialects` is honored (Chapter 9 single-dialect lessons get one starter). Also localized lesson 50004's tutorial prose that quoted the marker, and added a permanent tripwire `EveryX86ChallengeStarter_IsLocalizedToSpanish` so a future un-localized lesson fails the build. Verified locally: `SpikerSoft.UnitTests.slnf` + `SpikerSoft.Wasm` build clean; `CurriculumLocaleTests` 43/43; tripwire confirmed to fail pre-change. That leaves x86 alongside C#/Python/JS/C/C++ as fully localized (Regex/SQL are intentional no-ops), so all 8 playgrounds are covered. Leaving this open for you to close after #310 merges.
Author
Owner

Board-sweep verified complete: the formatter mechanism (PR #36) fanned out across all 8 playgrounds — C# #37/#38, Python #39, JS #40, C #47, C++ #49, x86 #310 — all merged (es/x86.json verified in tree). The last comment's own condition was 'close after #310 merges'; it merged. Closing.

Board-sweep verified complete: the formatter mechanism (PR #36) fanned out across all 8 playgrounds — C# #37/#38, Python #39, JS #40, C #47, C++ #49, x86 #310 — all merged (es/x86.json verified in tree). The last comment's own condition was 'close after #310 merges'; it merged. Closing.
Sign in to join this conversation.