When a ResKey field in an I18NConstants class is pre-initialized with a custom key via ResKey.internalCreate(), the TLDoclet generates the messages_en.properties entry under the normative key(class.pkg.ClassName.FIELD_NAME) instead of the custom key. At runtime, the field holds the custom key, so the localized string from JavaDoc is never found.
Example
{{{#!java /**
- @en Play audio */
public static ResKey JS_AUDIO_PLAYER_PLAY = ResKey.internalCreate("js.audioPlayer.play"); }}}
- TLDoclet generates: class.com.top_logic.layout.react.I18NConstants.JS_AUDIO_PLAYER_PLAY = Play audio (in META-INF/messages_en.properties)
- Runtime looks up: js.audioPlayer.play (the custom key from internalCreate)
- Result: English text is never found under the runtime key
This forces developers to manually duplicate the translations in a separate WEB-INF/conf/resources/*.messages_en.properties file.
Proposed Fix
Add a @CustomKey annotation that can be placed on ResKey fields in I18NConstants classes. Both the doclet and the runtime initializer read this annotation to derive the correct key.
Before (broken JavaDoc generation): {{{#!java public static ResKey JS_AUDIO_PLAYER_PLAY = ResKey.internalCreate("js.audioPlayer.play"); }}}
After (JavaDoc generation works correctly): {{{#!java @CustomKey("js.audioPlayer.play") public static ResKey JS_AUDIO_PLAYER_PLAY; }}}
Changes needed:
- New annotation @CustomKey in com.top_logic.basic.i18n(@Target(FIELD), @Retention(RUNTIME))
- I18NConstantsBase.initField(): check for @CustomKey annotation, use its value instead of normative key
- TLDoclet.collectI18NConstantDoc(): check for @CustomKey annotation, use its value instead of normative key
- Migrate existing ResKey.internalCreate() usages to I18NConstants classes
Code migration
legacyKey() calls replaced by @CustomKey annotation
All ResKey fields in I18NConstants classes that used legacyKey(), legacyKey1(), legacyKey2(), etc. to assign a custom resource key must now use the @CustomKey annotation instead.
Before:{{{#!java public static ResKey MY_KEY = legacyKey("my.custom.key"); public static ResKey1 MY_KEY_1 = legacyKey1("my.custom.key"); }}}
After:{{{#!java @CustomKey("my.custom.key") public static ResKey MY_KEY;
@CustomKey("my.custom.key") public static ResKey1 MY_KEY_1; }}}
The field must not be initialized - initConstants() handles it using the custom key from the annotation.
This ensures that both the runtime (I18NConstantsBase) and the build-time doclet (TLDoclet) use the same custom key, so that @en JavaDoc translations are correctly written to messages_en.properties under the custom key.
Migrating WEB-INF resource properties to JavaDoc
A migration tool MigrateResourcesToJavaDoc is available in com.top_logic.layout.tools.cleanup to automatically move English translations from WEB-INF/conf/resources/*_en.properties files into @en JavaDoc tags on the corresponding ResKey fields. The tool respects @CustomKey annotations when matching keys to fields. After migration, the entries are removed from the properties files.