Skip to content

The composed sentence speaks its language; the box meets the text (0.1.1) - #2

Merged
rameerez merged 3 commits into
mainfrom
composed-sentence-quality
Aug 19, 2026
Merged

The composed sentence speaks its language; the box meets the text (0.1.1)#2
rameerez merged 3 commits into
mainfrom
composed-sentence-quality

Conversation

@rameerez

Copy link
Copy Markdown
Owner

The one-line signup rendered broken Spanish — "Acepto Términos y Condiciones y He recibido Política de Privacidad." — missing both articles and carrying a capital H mid-sentence. And the checkbox read as floating high against the sentence in every host.

Per-key sentence fragments

Spanish (and most declining languages) cannot say "acepto %{documents}" for every document — the article agrees with the noun. The composer now resolves clickwrap.sentence.fragments.<kind>.<key> before falling back to the per-kind template, and es.yml ships defaults for the gem's standard keys: agreement.terms: "acepto los %{documents}", acknowledgment.privacy_notice: "he recibido la %{documents}". Apps add fragments for their own keys in their locale files — no DSL change — and untranslated keys still compose with the neutral generic ("he recibido X" is gender-safe).

One opening capital

Fragment templates are now written lowercase, for the middle of a sentence — because every fragment but the first sits there. The composer capitalizes exactly one letter, once, at build time, so the manifest-signed sentence and the rendered HTML derive from the same fragment. English is untouched (its fragments start with "I").

Before: Acepto Términos y Condiciones y He recibido Política de Privacidad.
After: Acepto los Términos y Condiciones y he recibido la Política de Privacidad.

Checkbox optical alignment

calc((1lh - 1em) / 2) centres the box on the first line mathematically — measured: box centre == line centre to the pixel — and it still reads as floating high, because Latin text carries its visual mass between cap-height and baseline, below the line box's midpoint. The offset gains an optical 0.125em, calibrated against rendered screenshots of the live control at 400% across +0/+1/+2/+3px candidates.

Verification

New Spanish golden test (sentence + per-fragment prefixes prove per-key lookup and single capitalization), a per-key app-override test, and the old test that had pinned the broken wording corrected. 789 runs, 0 failures; rubocop clean across 169 files.

🤖 Generated with Claude Code

https://claude.ai/code/session_013A6ZmfmFuQ2z3GyvQCuECA

rameerez and others added 3 commits August 19, 2026 04:37
…1.1)

"Acepto Términos y Condiciones y He recibido Política de Privacidad."
is broken Spanish twice over — the missing articles and the capital H
mid-sentence — and it shipped as the one-line signup every Spanish host
renders. Three fixes, all first-class:

- Per-key fragment templates: the composer looks up
  clickwrap.sentence.fragments.<kind>.<key> before the per-kind
  fallback, and es.yml ships defaults for the standard keys with the
  article each document needs ("acepto los %{documents}", "he recibido
  la %{documents}"). Applications add their own keys in their locale
  files; no DSL change, and a key nobody translated still composes with
  the neutral generic.
- Templates are written lowercase for the middle of the sentence, and
  the composer capitalizes exactly one letter — the first — once, at
  build time, so the signed manifest text and the rendered HTML derive
  from the same fragment and can never disagree about the capital.
- The checkbox's lh-math centred it on the first line and it still read
  as floating high: text mass sits between cap-height and baseline,
  below the line box's midpoint. The offset gains an optical 0.125em,
  calibrated against rendered screenshots at 400%.

Spanish golden: "Acepto los Términos de Servicio y he recibido la
Política de Privacidad." — pinned, with the per-key override path
tested and the old broken wording's test corrected. 789 runs, 0
failures; rubocop clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013A6ZmfmFuQ2z3GyvQCuECA
"…y doy por recibida la Política de Privacidad." — the same words the
itemized default uses: the same act must read the same way composed or
detailed, and it is better register than "he recibido". The owner
floated "he leído"; es.yml's own header rule stands — "'He leído...' is
deliberately absent" — the evidence records an affirmative act on an
offered notice, never that anyone read it. An application that wants a
read-declaration owns that wording via its per-key fragment override.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013A6ZmfmFuQ2z3GyvQCuECA
The engine appended its locale files to app.config.i18n.load_path on
top of Rails::Engine's automatic :add_locales. Railties paths are
unshifted ahead of that list, so the appended copy landed AFTER the
host application's own locale files — and every host override of a gem
key silently lost to the gem's default, the exact opposite of what the
initializer's comment promised. Discovered live: a host's "He leído la
Política de Privacidad." kept rendering as the gem's "Doy por
recibida...".

The manual append is deleted; Rails's own ordering (gem first, host
last) is the whole contract. The dummy app now ships a real override of
a real gem key, and two tests pin both the outcome and the load-path
ordering that produces it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013A6ZmfmFuQ2z3GyvQCuECA
@rameerez
rameerez merged commit 23f0044 into main Aug 19, 2026
23 checks passed
@rameerez
rameerez deleted the composed-sentence-quality branch August 19, 2026 04:01
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