WeblateOrg / WeblateOrg/weblate
Arabic "many" plural form is never filled by autotranslate, regardless of engine
- Dominant language
- Python
- Stars
- 6.1k
- Forks
- 1.4k
- Avg merge
- 9h 53m
- Merged PRs (30d)
- 395
Description
### Describe the issue
Autotranslating a plural string from English into Arabic (6 plural forms: zero/one/two/few/many/other) consistently leaves the CLDR **"many"** form (index 4, used for counts like 11, 25, 100) empty — across three unrelated engines tested (a classical NMT engine and two different LLMs), all producing byte-identical coverage: 5 of 6 forms filled, index 4 always `''`.
The fact that three architecturally unrelated engines fail on exactly the same form pointed at the cause being in Weblate's own source→target plural mapping rather than in any engine — confirmed via the Django shell:
```python
>>> from weblate.lang.models import Language, PluralMapper
>>> en, ar = Language.objects.get(code='en'), Language.objects.get(code='ar')
>>> en.plural.examples
{1: ['0', '2', '3', '4', '5', '6', '7', '8', '9', '10', '…'], 0: ['1']}
>>> ar.plural.examples
{0: ['0'], 1: ['1'], 2: ['2'], 3: ['3', '4', ..., '10', '103', '104', '…'], 4: ['11', '12', ..., '19', '20', '…'], 5: ['100', '101', '102', '200', '201', '202', '300', '301', '302', '400', '…']}
>>> PluralMapper(en.plural, ar.plural).target_map
index 0 -> (1, 0)
index 1 -> (0, None)
index 2 -> (1, 2)
index 3 -> (1, None)
index 4 -> (None, None) # Arabic 'many' — no source example set overlaps it
index 5 -> (-1, None)
```
English `other` = index 1, cached examples `0, 2–10`; Arabic `many` = index 4, cached examples `11–20`. The two windows never intersect. `Plural.examples` caches only ten numeric examples per plural form, so `PluralMapper.target_map` can't establish a mapping for that form and emits `(None, None)` at index 4. That maps to an empty string, and machinery skips empty source text **before any translation engine is ever invoked** — which is exactly why every engine showed the identical gap: none of them ever received the string for that form.
### I already tried
- [x] I've read and searched the documentation.
- [x] I've searched for similar filed issues in this repository.
(Related: Discussion #15602 covers incomplete automatic plural translation generally, and merged PR #16213 explicitly attempted to prevent blank target plural forms — its discussion states blank plurals break applications and an imperfect translation is preferable to an empty one, which is directly relevant to why this specific gap is worth closing.)
### Steps to reproduce the behavior
1. Create a component with a source plural string in English using `_one`/`_other` forms (e.g. `cart_one` / `cart_other`).
2. Add Arabic as a target language (6 plural forms).
3. Run autotranslate with `mode=translate`.
4. Observe 5 of 6 forms filled; index 4 (Arabic "many") is always empty, regardless of which machinery engine is configured.
5. Confirm via Django shell: `PluralMapper(Language.objects.get(code='en').plural, Language.objects.get(code='ar').plural).target_map` — index 4 is `(None, None)`.
Note when reproducing: Arabic `100` is actually the `other` form, not `many` — use `11`, `25`, `99`, or `111` as example counts that genuinely land in the `many` category, to avoid confusion when verifying.
### Expected behavior
The plural target-mapping logic should compute the mapping from the actual plural functions/rules over a domain wide enough to establish every form pairing, rather than relying on the ten cached display examples per side — so that a form like Arabic "many" (which requires seeing a number ≥ 11 in the *source* language's example set, not just the target's) isn't left permanently unmappable purely because of a display-cache size limit unrelated to the actual plural rule.
### Screenshots
N/A
### Exception traceback
N/A — no exception; the string is silently treated as empty and skipped before reaching any engine.
### How do you run Weblate?
Docker container
### Weblate version
2026.7.1 (confirmed against the current `latest` Docker tag as well)
### Weblate deploy checks
N/A — reproduced on a minimal, disposable single-node instance for isolation.
### Additional context
Secondary, smaller point worth noting in the same report: `autotranslate` returns `"1 string was updated"` for a plural unit left with 5 of 6 forms filled — technically accurate (a unit *was* updated) but gives no signal that the update is incomplete. Not requesting a separate report for this; flagging in case a partial-completeness indicator is a natural byproduct of fixing the mapping itself.
Contributor guide
Research direction
Start with the PluralMapper entry point and inspect how target_map uses the cached plural examples exposed by Language.plural. Reproduce the Django shell mapping for English to Arabic, then add coverage for the Arabic “many” form and verify that autotranslate no longer leaves that form empty while preserving the other plural mappings.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- django, python
- Domain
- internationalization, localization
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100