Issue #3618523: Nothing checks that a shipped string is translated, so the French catalogue drifts
Adds a translations job to the validate stage that fails when a string the module ships has no French.
scripts/check-translations.php extracts with potx and compares against translations/yoyaku.fr.po. It writes nothing: what to do about a finding is a decision. Run it locally the same way CI does, from anywhere:
php scripts/check-translations.phptranslations/untranslated.txt holds what is deliberately English, one string per line with its reason: the two log messages (BookerRefusal, LockAnchors), and Home and Administration, which core already answers. Without that list the job is red on its first run and stops being read.
drupal/potx joins require-dev, pinned ^2.0.0-alpha2: 1.1.0 declares drush.services.yml: "^9", so Drush 13 will not expose it. composer install in the templates runs without --no-dev, so the job has it.
Three traps the script is built around, each of which has cost time before:
- An extraction that finds nothing is a crashed run, not a module without prose. It exits 1 saying so. A check that reports "0 missing" because it fell over is worse than no check.
- In CI the Drupal root is built inside the module's own directory. The walk skips any directory holding
core/includes/bootstrap.inc, or the job would extract the whole of core and every contributed module beside it. - A plural is one entry to potx and two to gettext. potx joins the two forms with a NUL; without splitting on it, all 55 plurals in this module read as missing however well they are translated. That was the first run's output.
Only Drupal's own YAML is fed in. mkdocs.yml carries a !!python/name: tag that the parser refuses outright.
Verified both ways. Against the tree as it stands: 1937 strings extracted, 2038 in the catalogue, 4 allowed, and nothing missing. Then with one entry (Contents) deleted from the catalogue: exit 1, naming that string. A check nobody has seen fail is not a check.
What it will not catch, documented in docs/translation.md rather than left to be discovered: a JavaScript call with a trailing comma after its last argument, Drupal.t('…',), which Prettier emits on every wrapped call and potx drops silently. Upstream, open since 2020. Strong over PHP and YAML, leaky over JavaScript.
docs/translation.md gains a section on all of this, under Keeping the shipped catalogue complete.