Skip to content

Commit e712bab

Browse files
authored
Merge pull request #3475 from ConductionNL/fix/l10n-dynamic-keys-manifest
docs(l10n): correct what collectDynamicKeys says about page titles
2 parents 74fbf55 + fd033e8 commit e712bab

1 file changed

Lines changed: 48 additions & 10 deletions

File tree

scripts/l10n/lib.js

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -488,13 +488,38 @@ const DYNAMIC_KEYS = [
488488
* Every key reached dynamically: DYNAMIC_KEYS plus the src/manifest.json fields
489489
* that MainMenu.translate(key) passes straight to t().
490490
*
491-
* Only the fields CnAppNav actually resolves through its `translate` prop count:
492-
* `menu[].label` (recursively through `children`) and the two nav label
493-
* overrides. Anything else in the manifest is data, not UI copy — notably
494-
* `observability.metrics[].name` (Prometheus metric identifiers) and
495-
* `pages[].title`, which CnPageRenderer forwards to the page component as a raw
496-
* prop without translating it. Harvesting those made metric names look like
497-
* catalogue keys and would have put them in front of translators.
491+
* Only fields that are actually resolved through a `translate` prop count.
492+
* Anything else in the manifest is data, not UI copy — notably
493+
* `observability.metrics[].name` (Prometheus metric identifiers), which made
494+
* metric names look like catalogue keys and would have put them in front of
495+
* translators.
496+
*
497+
* WHAT COUNTS, AND HOW IT WAS ESTABLISHED
498+
* ---------------------------------------
499+
* This function used to exclude `pages[].title` on the stated grounds that
500+
* CnPageRenderer "forwards [it] to the page component as a raw prop without
501+
* translating it". That is no longer true. Measured 2026-09-06 on integriq,
502+
* which wires `<CnAppRoot :translate="translateForApp">` exactly as
503+
* `src/App.vue` does here, against a Nextcloud 34 instance with the user set
504+
* to `nl` and the app's `l10n/` deployed:
505+
*
506+
* - `menu[].label` renders translated (Sources became "Bronnen").
507+
* - `pages[].title` renders translated: the page heading was
508+
* "StUF-berichten", not "StUF messages".
509+
* - report `cards[].label` / `cards[].description` render translated;
510+
* CnReportsPage builds `resolvedCards` with `this.tr(card.label)`.
511+
*
512+
* The cost of the stale exclusion is not cosmetic: live keys get reported
513+
* UNUSED, and clean-l10n proposes deleting exactly what this function fails to
514+
* claim. Deleting a translated page title removes the localised string and
515+
* leaves the English source rendering correctly, so nothing fails and nobody
516+
* notices.
517+
*
518+
* Adding a field here can only make the cleaner more conservative, never less.
519+
* Verify a new one against the DOM rather than the source: the template renders
520+
* `{{ card.label }}` and only `resolvedCards` shows the translation, so reading
521+
* the component alone reproduces the wrong conclusion. The measurement also
522+
* needs the app's `l10n/` deployed, which the built bundle does not carry.
498523
*
499524
* @param {string} repoRoot Absolute path to the app root.
500525
* @return {Set<string>} Keys that must count as used.
@@ -509,17 +534,30 @@ function collectDynamicKeys(repoRoot) {
509534
} catch {
510535
return out
511536
}
537+
const add = (value) => {
538+
if (typeof value === 'string' && value.trim() !== '') out.add(value)
539+
}
512540
;(function collectMenu(items) {
513541
if (!Array.isArray(items)) return
514542
for (const item of items) {
515543
if (!item || typeof item !== 'object') continue
516-
if (typeof item.label === 'string') out.add(item.label)
544+
add(item.label)
517545
collectMenu(item.children)
518546
}
519547
})(manifest.menu)
520548
for (const field of ['roadmapLabel', 'documentationLabel']) {
521-
const v = manifest.nav?.[field]
522-
if (typeof v === 'string') out.add(v)
549+
add(manifest.nav?.[field])
550+
}
551+
if (Array.isArray(manifest.pages)) {
552+
for (const page of manifest.pages) {
553+
if (!page || typeof page !== 'object') continue
554+
add(page.title)
555+
for (const card of page.config?.cards ?? []) {
556+
if (!card || typeof card !== 'object') continue
557+
add(card.label)
558+
add(card.description)
559+
}
560+
}
523561
}
524562
return out
525563
}

0 commit comments

Comments
 (0)