Found while rolling the generated browser catalogue across the fleet (#553, #556, #557 and the nine app PRs).
The nine apps that were fixed
They had no l10n/*.js at all. Nextcloud serves only the .js to a browser, so 8,137 Dutch translations never reached a user. Generating the .js from the .json was safe there: there was nothing to lose.
These eight are different, and must NOT be regenerated
Both halves exist and each holds keys the other does not:
| app |
keys only in .js |
keys missing from .js |
stale values |
| opencatalogi |
21,958 |
4,216 |
32 |
| openconnector |
5,240 |
18,463 |
183 |
| procest / dossiq |
631 |
54,646 |
4,248 |
| launchpad |
962 |
0 |
8,106 |
| openregister |
15 |
44,194 |
16,874 |
| softwarecatalog / stackiq |
4 |
2,046 |
0 |
| docudesk / filinq |
0 |
1,689 |
15 |
| pipelinq |
0 |
2,128 |
1,665 |
(measured 2026-08-23 across every locale pair in each repo)
Running build-l10n-js.js in these repos would delete every key in the first column — 21,958 of them in opencatalogi. I deliberately did not roll the generator into them, and removed the copies made while measuring.
Why this is not mechanically fixable
None of the eight has a .tx/config or a translation workflow, so the .js-only keys are not Transifex output that could simply be re-pulled — they are translations someone produced that the .json never received. Which half is authoritative is a per-app judgement, and getting it wrong silently deletes work.
Suggested disposition, per app
- Decide which half is authoritative (probably: union them,
.json wins on conflict, since .json is what PHP $l->t() reads).
- Merge into the
.json.
- Then adopt
scripts/build-l10n-js.js + check:l10n-js as the nine did, so the pair cannot drift again.
Step 1 is the part that needs a human. Steps 2–3 are mechanical and already proven.
Related
- Generator +
check:l10n-js, shipped to 9 apps
check:schema-l10n ratchet, shipped to 18 apps — 30,459 untranslated schema strings measured and frozen
- Per-app e2e
l10n-browser-catalogue.spec.ts — asserts from the browser that the catalogue is served and t() resolves through it
Found while rolling the generated browser catalogue across the fleet (#553, #556, #557 and the nine app PRs).
The nine apps that were fixed
They had no
l10n/*.jsat all. Nextcloud serves only the.jsto a browser, so 8,137 Dutch translations never reached a user. Generating the.jsfrom the.jsonwas safe there: there was nothing to lose.These eight are different, and must NOT be regenerated
Both halves exist and each holds keys the other does not:
.js.js(measured 2026-08-23 across every locale pair in each repo)
Running
build-l10n-js.jsin these repos would delete every key in the first column — 21,958 of them in opencatalogi. I deliberately did not roll the generator into them, and removed the copies made while measuring.Why this is not mechanically fixable
None of the eight has a
.tx/configor a translation workflow, so the.js-only keys are not Transifex output that could simply be re-pulled — they are translations someone produced that the.jsonnever received. Which half is authoritative is a per-app judgement, and getting it wrong silently deletes work.Suggested disposition, per app
.jsonwins on conflict, since.jsonis what PHP$l->t()reads)..json.scripts/build-l10n-js.js+check:l10n-jsas the nine did, so the pair cannot drift again.Step 1 is the part that needs a human. Steps 2–3 are mechanical and already proven.
Related
check:l10n-js, shipped to 9 appscheck:schema-l10nratchet, shipped to 18 apps — 30,459 untranslated schema strings measured and frozenl10n-browser-catalogue.spec.ts— asserts from the browser that the catalogue is served andt()resolves through it