enhancement
major
minor
major
minor
major
#29623
Build: the translate goal re-translates committed German messages after a pull or branch switch when the doclet did not run in the same build
Problem
The German resource bundles (src/main/java/META-INF/messages_de.properties) are hand-maintained; the build is supposed to seed new keys via DeepL and never touch an existing entry whose English text did not change. Sometimes a local build nevertheless replaces existing German entries with fresh machine translations, in whole modules at once - hand-polished texts like Läuft for the running job status turn into Laufen.
Cause
The TLDoclet regenerates messages_en.properties and keeps the previous file as messages_en.properties~. The translate goal of the tl-maven-plugin (execution translate-system-messages in tl-parent-build, phase prepare-package) uses that tilde file as referencePath: every key whose English text differs between the reference and the current messages_en.properties is translated again (ResourceTranslator.isKeyToUpdate).
The tilde file is an untracked, per-worktree artifact: it records the English texts as they were the last time the doclet ran //in this worktree//. After a pull or branch switch the committed messages_en.properties carries the English texts of other people's changes, while the reference still describes the old state. If the doclet then does not run to completion - a build without a JDK, where the javadoc plugin fails with Unable to find javadoc command but failOnError=false keeps the build going; or a doclet run that aborts on unresolvable dependencies - neither file is refreshed, the translate goal still runs, and it re-translates every key that changed on the branch since the last local doclet run, replacing the German the author of that change had already committed.
Evidence from a worktree that pulled master (9d4d5c2d8c → 91ad0edc58) and then ran rebuild-stale.sh without a JDK:
| = module = | = English lines changed by the pull = | = lines DeepL translated = |
| com.top_logic | 16 | 16 |
| com.top_logic.element | 1 | 1 |
| com.top_logic.layout.react | 41 | 41 |
| com.top_logic.layout.view | 190 | 190 |
A build that does run the doclet is not affected: the doclet moves the committed English file to the tilde reference and regenerates the English from the sources, so the reference matches the committed state and only genuinely changed texts differ.
Lösung
The translate goal runs only when the doclet generated the English bundle it sees in the same build, because only then is the tilde reference the state the English texts had before this build regenerated them.
- TLDoclet marks a completed run: after writing messages_en.properties (and its tilde backup) it writes a marker file target/messages-generated.marker (option -messagesMarker, one property messagesMarker in tl-parent-build) holding the SHA-256 digest of the bundle it generated. The marker is module-local and removed by mvn clean; it does not depend on the shared javadocOutput of the framework modules.
- The translate goal takes the marker as parameter generationMarker (configured next to referencePath). It consumes the marker first thing - deletes it, also when the translation is skipped by tl.javadoc.skipTranslate - so no marker outlives the build that wrote it. Without a marker it logs that the doclet did not run and skips. With a marker whose digest differs from the current messages_en.properties - a marker left by a build that died between the javadoc and the translate goal, followed by a pull - it logs that the bundle changed since the doclet generated it and skips. Only a marker matching the bundle lets the translation run.
- Invocations of the goal without the parameter behave as before.
Test
- Build a module with a JDK: the doclet runs, new keys are translated as before, existing entries with unchanged English are untouched, the marker is gone after the build.
- Replace the tilde reference of a module by an older English state and build with -Dmaven.javadoc.skip=true: the build logs that the translation is skipped and messages_de.properties stays as committed.
- Build with -Dtl.javadoc.skipTranslate=true: the marker is consumed nonetheless.
- Write a marker with the digest of the current bundle, replace the bundle by an older state, build with -Dmaven.javadoc.skip=true: the build logs that the bundle changed since it was generated and skips; with the bundle unchanged, the translation runs.
- tl-maven-plugin has no unit-test infrastructure; the decision is verified through these builds.