Conversation
…o opinion - detect_language() returns empty both for "text too short to judge" and "not a language we handle"; the gate treated both as "translate". Fall back to the field-office language only in the first case, so short captions stop reaching the platform while T3339 stays fixed. - same correction in _can_auto_send(), which 2b82fb2 changed alongside the gate.
|
- langdetect samples randomly and runs unseeded; the English test text misses the confidence threshold in ~0.1% of runs, which would fail CI without a product regression. Pin the seed in setUp and restore it on cleanup.
- pre-commit runs ruff-format as well as ruff check; only the latter was run locally.
Danielgergely
approved these changes
Sep 17, 2026
Danielgergely
left a comment
Member
There was a problem hiding this comment.
@NoeBerdoz The changes look sound and valid. 👍 Thanks for investigating and correcting the issue!
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.
[T3371] FIX: don't queue B2S letters when the language detector has no opinion
Problem
Letters that need no translation are landing on the translation platform — reported for
TH / UG / PH / GH / KE / TG / BF, including letters queued to be "translated" from a
language into that same language.
Root cause
T3339 fixed a real bug: field offices were labelling letters as already-translated when
they were not, Odoo trusted the label, and untranslated letters reached sponsors.
2b82fb24fixed it by making content detection the deciding input.The problem is that
detect_language()returns an empty recordset for four differentreasons:
en/de/fr/it/esprocess_letter()could not tell them apart and read all four as "the sponsor cannotread this → translate". Only the second justifies that.
The short-text case dominates. Most B2S letters below the floor are photo captions and
gift acknowledgements that the field office already writes in the sponsor's language —
there is nothing to translate, and no amount of detection will ever say so, because
there is not enough text to detect.
The fix
_letter_language_verdict()reports whether we have an opinion at all._sponsor_can_read_letter()then decides:Both gates call the shared predicate, so they cannot drift apart.
Does this reopen T3339?
No. Letters long enough to judge are still decided by their content — including letters
whose label claims the sponsor can read them but whose content disagrees. That is
exactly the population T3339 was about, and the fallback never touches it. Before
T3339, every letter was decided by the label; after this change, only letters too
short to detect are.
Residual gap: a letter that is both untranslated and below the length floor falls
back to the label, which could be wrong. Detection cannot close this — there is nothing
to detect.
_can_auto_send()took the same change in2b82fb24, and it decides whether a letter isemailed to the sponsor without human validation. T3339 sharply reduced automatic
sending as an untracked side effect; this change restores it.
Coordinate the deploy with whoever runs the communication queue.
Fixing only the translation gate would release short letters from the translation queue
and strand them at the auto-send check — moving the backlog rather than clearing it.
That is why both gates are in scope.
Changes
advanced_translation/models/langdetect.pymin_lengthinstead of a magic numbersbc_compassion/models/correspondence.py_letter_language_verdict()and_sponsor_can_read_letter(); extract_clean_letter_text(); drop the now-unused_detect_letter_language()sbc_translation/models/correspondence.pyprocess_letter()calls the shared predicatepartner_communication_compassion/models/correspondence.py_can_auto_send()calls the same predicatesbc_compassion/tests/test_letter_language_verdict.pyTesting
3 tests in
sbc_compassion/tests/test_letter_language_verdict.py, passing._sponsor_can_read_letter()itself has no unit coverage. It needs a persisted letter,because
supporter_languages_idsis related topartner_id.spoken_lang_idsand comesback NewId-wrapped on an in-memory record. Building one requires
BaseSponsorshipTest,whose
setUpClassis currently broken for all 13 test classes that use it across 9modules — pre-existing and out of scope here, but worth knowing.
Behaviour was instead validated by replaying the pre-T3339, current and new predicates
over the full B2S corpus on a database copy, and by checking the gate against an
independent reimplementation through
odoo shell. Both agree.sbc_translationships notests/directory at all, which is whyprocess_letter()could invert its failure mode between T3339 and T3371 without anything catching it.
Known issues (pre-existing, not introduced here)
langdetectis used without settingDetectorFactory.seed, so a letter near the confidence threshold can be queued on onerun and published on the next. T3339's code has the same property.
them, because below-threshold counts as an opinion. Deliberate — it is the safe
direction for T3339.
filtering to the five languages, so a single surviving candidate always scores 1.0.
Odoo 18 — companion PR
T3339 was ported to v18 in
ba4ba7e6, so v18 has the same defect this PR fixes. Thev18 change is the same patch:
_detect_letter_language()and_can_auto_send()thereare byte-identical to v14 before this change, so the port is a straight copy rather than
a rewrite.
Out of scope
search_iso639()resolves duplicates by id order —ilike+limit=1with no_orderon the model, so it always returns the lowest id, and Spanish exists threetimes. Measured impact on this ticket: none. Its own data-hygiene ticket at most.
label-trusting bypass into the publish path, and the affected letters are data defects
rather than detection failures.