🐛 Keep buttons intact under gettext translation#270
Merged
Conversation
0a1ccad to
f8792ba
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #270 +/- ##
==========================================
+ Coverage 88.08% 88.39% +0.31%
==========================================
Files 11 11
Lines 1041 1043 +2
==========================================
+ Hits 917 922 +5
+ Misses 124 121 -3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Builds on the approach from #264: gettext targets only the button text via a translatable inline, so translated button-link/button-ref keep their classes and links (closes #96, #44, #263). Additional hardening and coverage on top of #264: - wrap the translatable placeholder inline in a plain inline, so the reference always retains an element child after sphinx unwraps the placeholder (an unresolved button-ref otherwise crashed the build during reference resolution in translated projects) - this also restores the pre-existing doctree shape (inline wrapper), keeping HTML output identical to previous releases - add gettext extraction regression (pot) and a translated-build round-trip test proving classes/links/refs survive with translated text, for both button types, plus a badge control - align the rst button-link snippet with the myst one (both feed the same regression files) - note: button-ref text is still missing from pot extraction because std-domain xref resolution flattens explicit-title content before the gettext builder extracts; translation itself works (documented in the test, follow-up tracked on the roadmap)
- add 'translatable'/'translated' to the boolean-attribute normalization list, so regressions are stable across docutils 0.22 (1/0) and earlier (True/False) serializations - define an 'issue' extlink for changelog references
f8792ba to
d3bbb47
Compare
This was referenced Jul 12, 2026
chrisjsewell
added a commit
that referenced
this pull request
Jul 14, 2026
Two `button-ref` bugs, plus a parity improvement: ## Changes - **#110 — targets no longer whitespace-stripped**: both button directives ran their argument through `directives.uri`, which deletes all whitespace — correct for `button-link` URLs, but it turned multi-word ref targets (exactly what `autosectionlabel` generates, e.g. `my article section`) into `myarticlesection` → `undefined label`. Each directive now normalizes its own argument: `button-link` keeps `directives.uri`; `button-ref` collapses whitespace runs like Sphinx's `XRefRole` does. Additionally, `ref-type: ref` targets are lowercased to match the `:ref:` role (`XRefRole(lowercase=True)` — std labels are stored lowercased), so the visible Title-Case heading text can be pasted verbatim; `doc`/`myst` targets stay case-sensitive. - **#228 — rich content preserved through resolution**: the std-domain resolvers rebuild explicit-title refs from `astext()`, flattening nested inline markup (emphasis, icons rendered as escaped text). Fixed with a stash/graft pair of post-transforms using only stable APIs: content is stashed and the `pending_xref` tagged with a transient marker class before any resolver runs (priority 8 — below myst-parser's resolver at 9 and the built-in at 10), then grafted back onto the resolved reference (priority 11). Buttons whose content itself contains a cross-reference role are deliberately left on the old flatten path — regrafting would re-insert an unresolved `pending_xref` and crash the writer (and a link inside a button link is invalid HTML anyway). - Content-less `button-ref`s keep the resolver-generated section title (guarded by `refexplicit`). - Unresolved `button-ref`s degrade to a standard `undefined label` warning with unlinked content — no traceback (locking in the hardening from #270). Docs updated: the "bold text will be rendered without bold" caveat is gone (it now renders), and targets may contain spaces. ## Verification - New `tests/test_buttons.py` (11 tests, rst + myst): multi-word target resolution (verified red on the old code: `undefined label: 'myarticlesection'`), Title-Case + `ref-type: ref`, nested-content parity with `button-link`, nested-xref-in-content build safety (verified red — reproduced the writer crash pre-fix), content-less title rendering, unresolved warning path, and marker-leak assertions (HTML + doctree) on every path. - Independent adversarial review: marker-leak sweep across HTML/latex/text/xml/gettext outputs *and* pickled doctrees/env (clean, including incremental rebuilds), resolver-path matrix (std ref/doc, any, myst resolving + failing, missing-ref), `sd-btn` class output byte-identical to main outside the intended fixes, nitpicky-mode parity. - Full suite green on pinned Sphinx 7.2.6 / 7.4.7 / 8.2.3 (145 passed each, versions verified in-venv) and the standard matrix on 9.0.4. An earlier draft used a private resolver API that doesn't exist before Sphinx 8.2 — the final design deliberately uses only stable public mechanics. Closes #110 Closes #228
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Carries #264 by @sneakers-the-rat (commit preserved) with hardening and test coverage on top. Closes #96, closes #44, closes #263.
From #264 (the core fix): gettext now targets only the button text via a translatable inline (
translatable=True) instead of the whole directive paragraph (translatable=False), so translation no longer replaces the styled button with plain text.Added on top:
RemoveTranslatableInlinetransform unwraps the translatable placeholder, leaving a bareTextas the reference/xref child — an unresolvedbutton-refin a translated project then crashed the build (Losing "classes" attributeassertion during reference resolution). The placeholder is now nested inside a plain inline wrapper, so an element child always remains. This also restores the pre-existing doctree shape, keeping HTML output identical to released behaviour..potextraction regression; a translated-build round-trip (compiled.mo,language="de") asserting both button types keep classes and links and resolve refs with translated text, plus a badge control; rst snippet aligned with the myst one (they share regression files)..gitignoreexception for the new pot regression dir; changelog entry.Known gap, deliberately out of scope:
button-reftext is absent from.potextraction because the gettext builder extracts from the resolved doctree, and std-domain xref resolution flattens explicit-title content (rebuilds it as a plainstd std-refinline), discarding the translatable marker. Translation itself works for both button types since the Locale transform runs before resolution. Documented in the test docstring; follow-up tracked in #265.Validation:
tox -e py311(113 passed),py311-no-myst,mypy,ruff— all green.