Repository navigation
i18n audit: count plural entries as translated in the coverage summary - #1616
Merged
Merged
Conversation
The human-readable coverage summary read localizations[lang].stringUnit.state directly. A pluralised entry keeps its units under variations.plural.<category>.stringUnit, so that flat lookup returned None and scored a fully-translated plural as a gap. It reported de/es/fr/pt-PT missing=4 and pl missing=5 on the Strand catalog when every one of those entries was translated in every plural form - "%lld days" is "%lld Tage", "%lld días", "%lld jours", "%lld dias", "%lld dnia". Worse than a wrong number: it sent a reader off to re-translate strings that were already done, and it made Polish look like the worst-covered shipped language precisely BECAUSE it correctly carries one/few/many/other where the others need only a flat unit. `_string_units` and `_is_translated` were written for exactly this - the former's docstring says "Reading only the FIRST shape makes every pluralised entry look untranslated to this gate". The GATE was fixed then (#844); this summary was the one caller still doing the naive read. It now goes through `_is_translated`, which also keeps a partially-translated plural counting as a gap. Separately, and NOT caused by the above: the ratchet in i18n_extra_locale_baseline.txt was stale by two on four targets (it 181->179, ru 158->156, zh-Hans 131->129, zh-Hant 181->179). The gate already computed the lower numbers on unmodified main and asked for the file to be lowered on every run, because real translations had landed since it was last written. Lowered to match, down only, as the file requires. The genuine drift is unchanged in substance: it/ru/zh remain the untranslated locales. Five tests pin the summary itself rather than only the shared helper, since a revert would restore the flat read and leave the helper's own tests green.
ryanbr
force-pushed
the
fix/i18n-audit-plural-coverage
branch
from
August 25, 2026 06:42
db7f800 to
8cf5c72
Compare
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.
The audit's human-readable coverage summary reported gaps that do not exist:
Every one of those 21 entries is translated, in every plural form.
%lld daysis%lld Tage,%lld días,%lld jours,%lld dias,%lld dnia.Syncing strap history, %lld chunksis"Synchronisation de l'historique du bracelet, %lld blocs".The bug
catalog_summaryread the state directly:A pluralised entry has no
stringUnitat that level — its units live undervariations.plural.<category>.stringUnit. So the lookup returnsNone,None != "translated", and a fully-translated plural scores as a gap.This is worse than a wrong number in two ways.
It sends you to do work that is already done. I went looking for these 21 strings to translate them and found them already translated — that is the only reason the bug surfaced.
And it defames Polish specifically.
%lld markerscounts as missing forplalone, because Polish carriesone/few/many/otherwhere de/es/fr/pt-PT need only a flat unit. The language with the most correct pluralisation scored worst.The fix
_string_unitsand_is_translatedalready exist for exactly this. The former's docstring:The gate was fixed then. This summary was the one caller left doing the naive read, which is a familiar shape: #844's own comment notes that showing only
LANGShere is "very likely WHY the drift went unnoticed for so long". That pass fixed the locale blind spot and left a structural one behind it.Routed through
_is_translated, which also preserves the strict direction — a plural with one category stillnewremains a gap.After
A second, unrelated change in this PR — and a correction
i18n_extra_locale_baseline.txtis lowered on four targets:it181→179,ru158→156,zh-Hans131→129,zh-Hant181→179.My first version of this description claimed those improvements came from the plural fix. They do not. I checked against a clean checkout of
main, and the gate already reports exactly those fourIMPROVEDlines with the audit untouched — the gate has been plural-aware since #844, and only the summary was naive. The ratchet was simply stale by two on each, because real translations landed after it was last written, and the tool asks for it to be lowered on every run.So it is a genuine tidy-up that this PR happens to carry, not a consequence of the fix. Down only, as the file requires; every change verified to decrease. Split it out if you would rather keep the diff to one concern.
The real drift is unchanged in substance:
it,ruandzh-*remain the genuinely untranslated locales, and that is separate work.A sibling blind spot, found in review and deliberately not fixed here
_ios_echoed_counts(the detector for translations that are verbatim English) does the same flatunit.get("stringUnit")read, so it cannot see plural forms either.I measured it before deciding: zero plural echoes are currently hidden by it. The blind spot is real but costs nothing today, and fixing it would touch the echo baseline for no present gain. Recording it here so it is not rediscovered from scratch.
Tests
Five, and they pin the summary rather than only the shared helper — a revert would restore the flat read while
_is_translated's own coverage stayed green:one/few/many/otheris not penalised for having more categoriesstringUnitentries still count exactly as beforeshouldTranslate: falseis still skippedVerification
python3 -m unittest discoveroverTools/— all green, which is whattools-python.ymlrunsi18n_audit.py --cipasses, and--fullshows the corrected table above