|
| 1 | +--- |
| 2 | +'@objectstack/lint': patch |
| 3 | +--- |
| 4 | + |
| 5 | +lint: warn when a form section declares a `label` but no `name` — the heading no translation key can ever address |
| 6 | + |
| 7 | +`_sections` is keyed by the section's `name`, and every renderer that draws a |
| 8 | +section heading resolves it that way (`sectionLabel(objectName, section.name, |
| 9 | +authored)` — `plugin-form`'s `ObjectForm`/`ModalForm`, `plugin-detail`'s |
| 10 | +`record:details`), falling back to the authored label when there is no name. |
| 11 | +So a section authored with a `label` and no `name` is untranslatable **by |
| 12 | +construction**, and every gate we own was structurally blind to it: |
| 13 | + |
| 14 | +- the reference validator reports keys a bundle carries that nothing declares — |
| 15 | + a nameless section produces no key, so there is no orphan to report; |
| 16 | +- the i18n coverage walk (#5405) emits one expected key per `sections[].name` — |
| 17 | + a section with no name contributes nothing to demand, so the report reads |
| 18 | + 100% while the heading renders in the source locale in every locale. |
| 19 | + |
| 20 | +Measured on HotCRM: **70 of 70** form-view sections across all 14 view files are |
| 21 | +in exactly that state, with four locales at full declared coverage and zero |
| 22 | +warnings anywhere. It is also the real cause of the reported `Case / SLA / |
| 23 | +Resolution` English strip — that object's *detail page* sections carry names and |
| 24 | +translate, while its *form view* sections carry none. |
| 25 | + |
| 26 | +`validateTranslatableSections` (rule id `translation-section-name-missing`) joins |
| 27 | +the reference-integrity suite, so it runs on `os validate`, `os lint` and |
| 28 | +`os compile` at once. It reads exactly the anchors the two landed halves already |
| 29 | +agree on: a view container's `sections`, its **default** `form.sections`, every |
| 30 | +`listViews.*` / `formViews.*` sub-container, the same three on views embedded in |
| 31 | +an object, and `record:details` sections nested anywhere in a page's component |
| 32 | +tree. `fieldGroups`-derived sections are out of range by construction — their |
| 33 | +heading is keyed by `fieldGroups[].key`, so they always have a name. |
| 34 | + |
| 35 | +**Warning, and opt-in.** Nothing crashes and nothing is dead — one heading stays |
| 36 | +in the source locale — so the severity matches its sibling rules (ADR-0072 D1) |
| 37 | +and nothing that passed before starts failing. `os validate` over |
| 38 | +`examples/app-showcase` now reports 14 of these (6 from form views, 8 from |
| 39 | +`record:details` pages) and still exits 0. A section warns only when the |
| 40 | +object it renders under carries some translation of its own, which keeps the |
| 41 | +monolingual case silent exactly as the coverage gate already does. |
| 42 | + |
| 43 | +The fix is a diagnostic at the **producer**, deliberately not tolerance at the |
| 44 | +consumer: deriving a lookup key by slugifying the label would fossilize a second |
| 45 | +de-facto contract next to the declared one, and would move the day anyone edits |
| 46 | +the heading text. The `name` the hint suggests is a suggestion for the author to |
| 47 | +write down, never a key anything resolves. |
0 commit comments