For example, a string missing a placeholder in Android will trigger the warning when submitting, but then the string is stored as translated (cc @parker, since these errors can lead to build failures for all locales).
Leaving this here in case it's of any use
The warning is computed but silently discarded
run_custom_checks puts every warning it produces into the pndbWarnings key (pontoon/checks/libraries/custom.py:174). That prefix means "pontoon non-db" — and get_failed_checks_db_objects drops it:
# pontoon/checks/utils.py:53-56
library = check_group.replace("Warnings", "").replace("Errors", "")
if library not in DB_LIBRARIES: # ("p", "cl")
continue
"pndb" is in neither. Verified:
pndbWarnings -> ([], [])
clWarnings -> ([[Warning] compare-locales: Placeholder %1$s not found in translation], [])
So the translator sees the warning in the submit dialog, clicks through, and no Warning row is created — the string is indistinguishable from a clean one afterwards.
Where it broke
Before #3790, pndbWarnings had exactly one producer — pontoon_non_db.py, which only ever emitted "Empty translation", deliberately not stored. The Android placeholder warning came from compare-locales as clWarnings → library "cl" → persisted, filterable, visible in the sidebar.
#3790 merged pontoon_db.py + pontoon_non_db.py into custom.py and inlined the Android checks, but routed all warnings through the single pndbWarnings bucket. The placeholder/element warnings inherited the non-persisted behavior by accident.
Affected: Placeholder X not found in translation, Element not found in translation, and Source parse error — for android, xcode, xliff, and gettext.
For example, a string missing a placeholder in Android will trigger the warning when submitting, but then the string is stored as translated (cc @parker, since these errors can lead to build failures for all locales).
Leaving this here in case it's of any use
The warning is computed but silently discarded
run_custom_checksputs every warning it produces into thepndbWarningskey (pontoon/checks/libraries/custom.py:174). That prefix means "pontoon non-db" — andget_failed_checks_db_objectsdrops it:"pndb" is in neither. Verified:
So the translator sees the warning in the submit dialog, clicks through, and no Warning row is created — the string is indistinguishable from a clean one afterwards.
Where it broke
Before #3790,
pndbWarningshad exactly one producer —pontoon_non_db.py, which only ever emitted "Empty translation", deliberately not stored. The Android placeholder warning came from compare-locales asclWarnings→ library "cl" → persisted, filterable, visible in the sidebar.#3790 merged pontoon_db.py + pontoon_non_db.py into custom.py and inlined the Android checks, but routed all warnings through the single pndbWarnings bucket. The placeholder/element warnings inherited the non-persisted behavior by accident.
Affected: Placeholder X not found in translation, Element not found in translation, and Source parse error — for android, xcode, xliff, and gettext.