Skip to content

Send the Comic Book readmes' missing sections to Crowdin (BL-16750) - #8233

Draft
andrew-polk wants to merge 2 commits into
masterfrom
BL-16750-comic-readme-i18n
Draft

Send the Comic Book readmes' missing sections to Crowdin (BL-16750)#8233
andrew-polk wants to merge 2 commits into
masterfrom
BL-16750-comic-readme-i18n

Conversation

@andrew-polk

@andrew-polk andrew-polk commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Problem

Three whole sections of the Paper Comic Book and Digital Comic Book template readmes — "Limitations of Bloom's current comic book support", "Tips on using the Canvas Toolbox", and "A note on White on Black Text", together with all their bullets — had never been sent to Crowdin. A user reading either readme saw those sections in English no matter which UI language they had chosen, and no translator had ever been offered the text. 26 strings in all.

Cause

Template readmes are localized as whole files: HtmlXliff.exe --extract turns ReadMe-en.htm into ReadMe-en.xlf, that goes to Crowdin, and the returned translations are injected to make ReadMe-<lang>.htm. The extractor only picks up blocks carrying an i18n attribute, which comes from an {i18n="some.id"} annotation on the block in the markdown. Those sections had no annotations, so they were skipped at every stage — and because the extractor writes the same XLIFF either way, regenerating it produced no diff. Nothing anywhere reported it.

Fix

  • Annotated the unannotated blocks in both comic readmes. The text is identical in the two files, so it uses shared comic.template.* ids rather than per-readme ones, per the note at the top of each: Crowdin translates each string once and both readmes pick it up.
  • Annotated the four n/a cells in the Leveled Reader table, whose header cells already carried inline i18n attributes. All four hold the same text, so they share one id.
  • Regenerated the English XLIFFs: 27 new trans-units. Nothing was lost — --extract --preserve keeps a unit that is no longer in the HTML, so the Obsolete as of 6.3 full-bleed unit survives, moved to the end of its file.
  • Added scripts/check-readme-i18n.js (pnpm check:readme-i18n), which found this, and wired it into build-prod with --strict so it cannot come back. Four checks: text no i18n attribute covers; an id with text but no trans-unit; one id shared by blocks whose text differs; and a live trans-unit with nothing left in the HTML — tolerating units deliberately marked obsolete.

Ref: https://issues.bloomlibrary.org/youtrack/issue/BL-16750

Devin review


This change is Reviewable

andrew-polk and others added 2 commits August 25, 2026 10:55
Three whole sections of the Paper Comic Book and Digital Comic Book
template readmes had no {i18n="..."} annotations, so 26 strings had never
been sent to Crowdin and showed in English whatever UI language the user
chose:

  ## Limitations of Bloom's current comic book support
  ## Tips on using the Canvas Toolbox
  ## A note on White on Black Text

...along with all of their bullets and paragraphs. The sections either
side of them are annotated, so these were almost certainly added later
and the annotations forgotten.

The text is identical in both readmes, so it gets shared comic.template.*
ids rather than per-readme ones, per the note at the top of each file:
Crowdin translates each string once and both readmes pick it up. Also
annotated the four "n/a" cells in the Leveled Reader table, which sit in
raw HTML whose header cells already carried inline i18n attributes; all
four hold the same text, so they share one id.

Regenerating the English XLIFFs adds 27 trans-units. Nothing was lost --
`--extract --preserve` keeps a unit that is no longer in the HTML, so the
"Obsolete as of 6.3" full-bleed unit survives, moved to the end of the
file.

Nothing was catching this. The extractor only picks up blocks carrying an
i18n attribute; text without one is skipped at every stage, and since the
extractor writes the same XLIFF either way, regenerating it produces no
diff. So this also brings in check-readme-i18n.js, which found the bug,
and wires it into build-prod with --strict so it cannot come back.
Verified both ways: it fails (exit 1) on a heading with the annotation
removed, and passes on all ten readmes as they now stand.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sharing an id between blocks that say the same thing is deliberate and
useful -- this PR does exactly that for the Leveled Reader's four "n/a"
cells, so the string is translated once. But the XLIFF holds one source
per id, so if the texts ever differ, one block silently displays the
other's translation. That is now the check's third rule, guarding the
technique the rest of this PR relies on.

Verified: changing one of those four cells to "not applicable" makes the
check fail with both texts named; restoring it passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"build:clean": "node scripts/clean.js",
"// 'build-prod': 'production build: clean, pageSizes, then build:ui and build:content, then l10n'": " ",
"build-prod": "pnpm run build:clean && pnpm --dir ../content run build:pageSizes && npm-run-all build:ui build:content && npm-run-all --parallel build:l10n:translate build:l10n:create",
"build-prod": "pnpm run build:clean && pnpm --dir ../content run build:pageSizes && npm-run-all build:ui build:content && npm-run-all --parallel build:l10n:translate build:l10n:create && pnpm run check:readme-i18n:strict",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Devin] Investigate: Strict readme check gates the whole production build

build-prod now ends with check:readme-i18n:strict, which exits non-zero on any finding. It scans every generated readme under output/browser/templates, so untranslated text in any template readme (not just the ones changed here) will now fail the full production build.


[Claude Opus 5 (1M context) during preflight] Correct reading, and it is the deliberate intent — but it is a judgment call about everyone's build, so it is going to the developer rather than being decided here.

For context on the risk: all ten readmes pass as of this PR, so the gate can only fire on a newly introduced problem, and the only way to introduce one is to add readme text without an {i18n="..."} annotation. The check is also the only enforcement point available — GitHub Actions doesn't build the front-end for PRs, so build-prod (TeamCity) is where it has to live if it is to be enforced at all.

The alternative is to leave it warn-only, which is what it was until this commit: it then reports and nobody notices, which is exactly how these 26 strings went missing for several releases.

@andrew-polk

Copy link
Copy Markdown
Contributor Author

[Claude Opus 5 (1M context) during preflight] Consulted Devin on 2026-08-25 18:05 UTC up to commit 6f817b43d28030f145d290148f2502bb36397e63.

It raised no bugs, one Investigate flag, and one informational item.

  • The Investigate flag — the strict readme check now gating build-prod — is mirrored as a review thread above and left open: it changes the build for everyone, so it is the developer's call, not ours.
  • The informational item noted that the shared comic.template.* ids appear in both comic readmes' XLIFF files. That is how these two readmes have always worked — comic.template.subscription, comic.template.tips.lettering and comic.template.tips.lettering.header are each already in both files on master — so this PR is following the existing convention rather than introducing anything. No action.

CI: pr-automation passed. Full C# suite green (3233 passed, 0 failed); front-end suite reported separately.

@greptile-apps

greptile-apps Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR annotates previously untranslated template-readme content, regenerates the corresponding English XLIFF units, and adds a production-build consistency check.

  • Adds shared localization identifiers for Paper and Digital Comic Book guidance.
  • Localizes repeated “n/a” cells in the Leveled Reader table.
  • Adds checks for uncovered text, missing or stale XLIFF units, and conflicting identifier reuse.
  • Runs the checker in strict mode at the end of build-prod.

Important Files Changed

Filename Overview
src/BloomBrowserUI/scripts/check-readme-i18n.js Adds the readme-localization validator, but its text-node ancestor traversal assigns null to every i18n id and makes strict validation fail on valid content.
src/BloomBrowserUI/package.json Adds checker scripts and makes the broken strict validator a required final step of build-prod.
src/content/templates/template books/Digital Comic Book/ReadMe-en.md Adds localization annotations to the previously uncovered comic-book sections using shared identifiers.
src/content/templates/template books/Paper Comic Book/ReadMe-en.md Adds matching localization annotations to the duplicated Paper Comic Book guidance.
src/content/templates/template books/Leveled Reader/ReadMe-en.md Assigns one shared localization identifier to the four identical “n/a” table cells.
DistFiles/localization/Digital Comic Book/ReadMe-en.xlf Adds the extracted English translation units corresponding to the newly annotated Digital Comic Book sections.
DistFiles/localization/Paper Comic Book/ReadMe-en.xlf Adds matching comic translation units and preserves the explicitly obsolete full-bleed unit.
DistFiles/localization/Leveled Reader/ReadMe-en.xlf Adds the English translation unit for the shared not-applicable table value.

Reviews (1): Last reviewed commit: "Also catch one i18n id shared by blocks ..." | Re-trigger Greptile

Comment thread src/BloomBrowserUI/scripts/check-readme-i18n.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant