Skip to content

fix(l10n): the template shipped 38 catalogues the browser never reads - #186

Merged
rubenvdlinde merged 2 commits into
developmentfrom
fix/l10n-js-and-manifest-coverage
Aug 30, 2026
Merged

fix(l10n): the template shipped 38 catalogues the browser never reads#186
rubenvdlinde merged 2 commits into
developmentfrom
fix/l10n-js-and-manifest-coverage

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Nextcloud loads a locale catalogue in two formats and neither substitutes for the other:

  • l10n/<locale>.json is read server-side by PHP $l->t().
  • l10n/<locale>.js is an OC.L10N.register() call, and is the only one the browser ever sees.

This repo had 38 .json files and zero .js, so every translation in it was inert in the frontend. Every app scaffolded from this template started that way too.

That is the same defect reported on dossiq: an account set to Dutch still reading English. Measured across the fleet on development:

repo .js .json
openregister 37 38
opencatalogi 37 38
dossiq 38 39
petstore 38 38
nextcloud-app-template 0 38
thematiq 0 37

Also closes gate-102

manifest-l10n-coverage fails on development with 9 manifest string(s) have no l10n/nl.json key and will render English to a Dutch user. They are the example-app menu labels, widget titles and empty state: Examples, Example, Open examples, In progress, Closed, Recent examples, No examples yet, Close example, Features & roadmap. Added in the file's existing sentence-case style, appended rather than re-sorted so the diff is the 9 lines and nothing else.

The generator

scripts/build-l10n-js.js is petstore's, adopted unchanged rather than reimplemented, plus the l10n:build and check:l10n-js scripts that stop the two halves drifting again. Apps carrying check:l10n-js have measured zero drift; apps without it had accumulated between 142 and 1,090 unreachable entries.

Verification

  • All 9 strings reach l10n/nl.js with their Dutch values, checked individually rather than by count.
  • The register call names the right app id (apptemplate), read from appinfo/info.xml.
  • nl.js holds 49 keys; the manifest now has 0 user-visible strings missing from nl.json.
  • check:l10n-js exits 0.
  • All 38 generated files pass node --check and none is empty (smallest 1512 bytes) — an empty file passes node --check, so size was checked too.

thematiq needs the same fix and is not included here.

🤖 Generated with Claude Code

Nextcloud loads a locale catalogue in two formats and neither substitutes for
the other. l10n/<locale>.json is read server-side by PHP $l->t().
l10n/<locale>.js is an OC.L10N.register() call and is the only one the browser
ever sees. This repo had 38 .json files and zero .js, so every translation in
it was inert in the frontend, and every app scaffolded from this template
started that way too.

That is the shape of the defect a user reported on dossiq: an account set to
Dutch still reading English. Working fleet apps ship both halves (openregister
37/38, opencatalogi 37/38, dossiq 38/39, petstore 38/38). This repo and
thematiq shipped 0.

Also closes gate-102 (manifest-l10n-coverage), which failed on development with
9 manifest strings having no nl.json key. They are the example-app menu labels,
widget titles and empty state: Examples, Example, Open examples, In progress,
Closed, Recent examples, No examples yet, Close example, Features & roadmap.

The generator is petstore's scripts/build-l10n-js.js adopted unchanged rather
than reimplemented, with the l10n:build and check:l10n-js scripts that keep the
two halves from drifting again. Apps carrying check:l10n-js have measured zero
drift; apps without it had accumulated 142 to 1,090 unreachable entries.

Verified: all 9 strings reach l10n/nl.js with their Dutch values and the
register call names the right app id (apptemplate); nl.js holds 49 keys; the
manifest now has 0 user-visible strings missing from nl.json; check:l10n-js
exits 0; all 38 generated files pass node --check and none is empty.
@rubenvdlinde

Copy link
Copy Markdown
Contributor Author

Refining one line in the description, because the mechanism is worth stating precisely.

I wrote that the .js is "the only thing the browser ever sees". That is the generator script's wording and it is slightly too strong. What the code in these repos actually says:

  • Apps do call loadTranslations('<app>', …), which fetches l10n/<locale>.json at runtime.
  • But on many installs, including this fleet's standard dev container, Apache only lets the JS/CSS allowlist through and rewrites everything else to index.php. There is no route for /custom_apps/<app>/l10n/<locale>.json, so the fetch fails and loadTranslations rejects. src/main.js documents this and deliberately mounts anyway: "Strings just fall back to their English source on miss."
  • l10n/<locale>.js is an OC.L10N.register() call loaded as a <script>, so it rides the allowlist and works where the JSON does not.

So the accurate claim is: the JSON path is real but unreliable, the .js path is the one that survives, and shipping only .json is what produces a Dutch account reading English. The fix in this PR is unchanged.

@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/nextcloud-app-template @ 7812f48

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 737/737
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright 🚨 NO VERDICT — enabled but never ran
Hydra gates

Quality workflow — 2026-08-30 17:23 UTC

Download the full PDF report from the workflow artifacts.

The 38 l10n/*.js files this branch adds are emitted by
scripts/build-l10n-js.js with the Nextcloud l10n tooling's own four-space
shape, so prettier wants to rewrite all 38 and `npm run l10n:build` wants to
rewrite them back. Without the ignore the format check fails forever and the
two tools fight over the same files.

dossiq already carries this exact entry for the same reason; this matches it.

Verified load-bearing rather than assumed: with the entry removed `npm run
format` reports "Code style issues found in 38 files" and exits 1; with it
restored the check passes and exits 0.
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/nextcloud-app-template @ 49312a8

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-specs
check-manifest
format
composer ✅ 103/103
npm ✅ 737/737
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman
Playwright 🚨 NO VERDICT — enabled but never ran
Hydra gates

Quality workflow — 2026-08-30 18:45 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde
rubenvdlinde merged commit c5306f7 into development Aug 30, 2026
46 checks passed
@rubenvdlinde
rubenvdlinde deleted the fix/l10n-js-and-manifest-coverage branch August 30, 2026 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant