MessageId: build the translation-key completeness check the type's own docstring promises #44
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
iterative-works/support#44
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
MessageId's own header has declared this intent since the type was written, and no project has ever collected on it:Why now
Found in MEDECA-407 (medeca-modul-poptavky), recorded as lesson L8. Three
MessageIds reachable from the Žádost workflow engine had no entry in either catalogue, so a user who hit them saw the raw key:error.unhandled.command— the message of everyUnhandledCommand, i.e. the wholeapplicableWhenrejection path.UnhandledCommand.userMessage(AggregateError.scala:20-21) isUserMessage("error.unhandled.command", command.toString(), state.toString()), so the untranslated case was also rendering the entire aggregate into a user-facing string.error.zadost.ukoncena— a terminal-state refusal.error.document_matrix.missing— four payload-guard sites.error.unhandled.effectwas Czech-only, a fourth gap in the same family. All four were fixed in that project. The gap that produced them was not.Why it was invisible:
-Werrorcannot see a missing catalogue entry, and the project had only narrow per-bundle parity specs, none covering guard messages. Nothing iniw-supportoriw-project-supportoffers a general check — I searched both.What is asked for
A reusable completeness check: every
MessageIda project can emit resolves in every catalogue the project ships.MessageCatalogue.get(id): Option[String](MessageCatalogue.scala:29) is the single resolution point, withJsonMessageCatalogue(ScalaJS) andInMemoryMessageCatalogue(JVM) as implementations. So the check needs one input the library does not have today: the set of all keys.The obstacle, stated plainly
MessageIdis an opaque type overStringand carriesgiven Conversion[String, MessageId](MessageId.scala:22-24). A bare string literal therefore becomes aMessageIdwith no syntactic marker at the call site. You cannot find the keys by searching forMessageId(...).Four ways to get the key set, ranked
MessageId.applythat writes each key to a resource at compile time. Complete and robust, but it misses the implicit-conversion path unless that becomes a macro too..semanticdbfiles the build already emits. These index call sites and their literal arguments, including conversions, with no source parsing. The data exists in every build today. Suggested first step.UserMessage/MessageIdpositions. Simple and brittle — what the original comment imagined.Suggested shape
iw-project-supportas an SBT task (it has no i18n tooling today), or iniw-supportas a test-time utility.MessageCatalogueCompletenessSpec(catalogues, keys), so a project adds coverage in one line rather than writing its own parity spec per bundle — the pattern MEDECA-407 found four narrow copies of.