As a developer moving from key-user (RTA) extensibility to an Adaptation Project,
I want to keep and continue authoring annotation-based changes (e.g. label renames) with their translations,
so that I don't have to redo my key-user work and can rename labels in the editor the same way I did in RTA.
Description
Key users can now make annotation-based changes (e.g. renameLabel / annotationRename, text-arrangement) in RTA without writing XML. When a customer switches to developer extensibility via an Adaptation Project, ADP tooling must support these changes in two places:
- Take-over (project generation): annotation-based key-user changes carried into a new ADP must render their translated text correctly.
- Live authoring (adaptation editor): annotation-based renames authored in the editor must be captured, their text extracted for translation, and the change stored as a binding.
The load-bearing detail is the resource model: annotation-based changes resolve their translatable text against the @i18n model, not the plain i18n model. The UI5 annotation processor only resolves @i18n, and Fiori Elements V2 rebuilds the plain i18n model per template view (shadowing ADP-added keys — the failure behind the reverted #4858). Today the take-over pipeline writes {i18n>...} bindings and never registers an @i18n model, so carried-over annotation labels do not resolve; annotation-change authoring is also disabled in the editor.
This feature makes annotation-based changes work end to end by (a) binding translatable text against @i18n, (b) registering the @i18n model once per project (reusing the existing i18n/i18n.properties file — a single file backing both i18n and @i18n model IDs), and (c) reading/authoring .annotation_change files in the preview.
Technical Design
What modules need to be created or enhanced?
@sap-ux/preview-middleware — read .annotation_change files (extend the change glob in base/flex.ts readChanges); intercept writeChange to extract translatable text from incoming annotationRename / renameLabel / rename / renameField changes, rewrite the value to {@i18n>...}, append the string to i18n/i18n.properties, and ensure the @i18n model is registered once (idempotent).
@sap-ux/adp-tooling — bake the @i18n model into the generator scaffold (writer/manifest/descriptor-content.ts getManifestContent) so every new project already contains it; correct the take-over translation writer (writer/i18n/key-user-translations.ts) to emit {@i18n>...}; add an idempotent descriptor helper (new writer/manifest/ensure-annotation-i18n-model.ts, wired into writeKeyUserChanges) as a runtime safety net for projects created before the scaffold change; add backend capability gating.
@sap-ux/preview-middleware-client — enable annotation-change authoring (isAnnotationChangeEnabled) in WorkspaceConnector once the server side is in place.
How would the functionality be exposed and how can it be consumed?
Transparently through the existing flows: the ADP generator carries over changes when the user opts to import key-user changes; the adaptation editor exposes label rename on supported controls. Text lives under the change's top-level texts.<textId>.value (e.g. annotationText, newText, fieldLabel). The @i18n model reuses the project's existing i18n/i18n.properties (single file, two model IDs).
Backend dependency: registering a bare (non-customer.-prefixed) @i18n model on the CUSTOMER_BASE layer, and the createIfMissing: true option, require the new merger capability (Cloud 2602 / ABAP Platform OP 2027). Where the base app already declares @i18n, registration is an enhancement and works on current backends; where it does not, the deployable path is blocked on that backend feature. The adaptation editor preview path and the generator's file output can be built and tested without the backend feature.
Acceptance Criteria
GivenWhenThen format (https://martinfowler.com/bliki/GivenWhenThen.html)
Given an app with annotation-based key-user changes,
when I create an Adaptation Project and import the key-user changes,
then the annotation changes are carried over, bound against @i18n, and their translated labels render in the adaptation editor (including FEV2 List Report / Object Page apps).
Given an Adaptation Project open in the adaptation editor,
when I rename a label,
then the text is stored for translation, the change references it via an {@i18n>...} binding, and the @i18n model is registered exactly once regardless of how many renames I make.
Notes
Related BLIs: FIORITECHP1-30714 (take-over), FIORITECHP1-34192 (Flex-area). ADR: ui5-flexibility/architecture#108. Supersedes the reverted approach in #4858 (which kept {i18n>...} bindings and proxied i18n.properties at the HTTP layer; this instead keeps bindings on the FEV2-safe @i18n model). Out of scope: the separate flex-bundle loading change, the ABAP merger itself, and deployment/app-index support for .annotation_change — all owned by adjacent teams.
Tasks
As a developer moving from key-user (RTA) extensibility to an Adaptation Project,
I want to keep and continue authoring annotation-based changes (e.g. label renames) with their translations,
so that I don't have to redo my key-user work and can rename labels in the editor the same way I did in RTA.
Description
Key users can now make annotation-based changes (e.g.
renameLabel/annotationRename, text-arrangement) in RTA without writing XML. When a customer switches to developer extensibility via an Adaptation Project, ADP tooling must support these changes in two places:The load-bearing detail is the resource model: annotation-based changes resolve their translatable text against the
@i18nmodel, not the plaini18nmodel. The UI5 annotation processor only resolves@i18n, and Fiori Elements V2 rebuilds the plaini18nmodel per template view (shadowing ADP-added keys — the failure behind the reverted #4858). Today the take-over pipeline writes{i18n>...}bindings and never registers an@i18nmodel, so carried-over annotation labels do not resolve; annotation-change authoring is also disabled in the editor.This feature makes annotation-based changes work end to end by (a) binding translatable text against
@i18n, (b) registering the@i18nmodel once per project (reusing the existingi18n/i18n.propertiesfile — a single file backing bothi18nand@i18nmodel IDs), and (c) reading/authoring.annotation_changefiles in the preview.Technical Design
What modules need to be created or enhanced?
@sap-ux/preview-middleware— read.annotation_changefiles (extend the change glob inbase/flex.tsreadChanges); interceptwriteChangeto extract translatable text from incomingannotationRename/renameLabel/rename/renameFieldchanges, rewrite the value to{@i18n>...}, append the string toi18n/i18n.properties, and ensure the@i18nmodel is registered once (idempotent).@sap-ux/adp-tooling— bake the@i18nmodel into the generator scaffold (writer/manifest/descriptor-content.tsgetManifestContent) so every new project already contains it; correct the take-over translation writer (writer/i18n/key-user-translations.ts) to emit{@i18n>...}; add an idempotent descriptor helper (newwriter/manifest/ensure-annotation-i18n-model.ts, wired intowriteKeyUserChanges) as a runtime safety net for projects created before the scaffold change; add backend capability gating.@sap-ux/preview-middleware-client— enable annotation-change authoring (isAnnotationChangeEnabled) inWorkspaceConnectoronce the server side is in place.How would the functionality be exposed and how can it be consumed?
Transparently through the existing flows: the ADP generator carries over changes when the user opts to import key-user changes; the adaptation editor exposes label rename on supported controls. Text lives under the change's top-level
texts.<textId>.value(e.g.annotationText,newText,fieldLabel). The@i18nmodel reuses the project's existingi18n/i18n.properties(single file, two model IDs).Backend dependency: registering a bare (non-
customer.-prefixed)@i18nmodel on theCUSTOMER_BASElayer, and thecreateIfMissing: trueoption, require the new merger capability (Cloud 2602 / ABAP Platform OP 2027). Where the base app already declares@i18n, registration is an enhancement and works on current backends; where it does not, the deployable path is blocked on that backend feature. The adaptation editor preview path and the generator's file output can be built and tested without the backend feature.Acceptance Criteria
GivenWhenThen format (https://martinfowler.com/bliki/GivenWhenThen.html)
Given an app with annotation-based key-user changes,
when I create an Adaptation Project and import the key-user changes,
then the annotation changes are carried over, bound against
@i18n, and their translated labels render in the adaptation editor (including FEV2 List Report / Object Page apps).Given an Adaptation Project open in the adaptation editor,
when I rename a label,
then the text is stored for translation, the change references it via an
{@i18n>...}binding, and the@i18nmodel is registered exactly once regardless of how many renames I make.Notes
Related BLIs: FIORITECHP1-30714 (take-over), FIORITECHP1-34192 (Flex-area). ADR:
ui5-flexibility/architecture#108. Supersedes the reverted approach in #4858 (which kept{i18n>...}bindings and proxiedi18n.propertiesat the HTTP layer; this instead keeps bindings on the FEV2-safe@i18nmodel). Out of scope: the separate flex-bundle loading change, the ABAP merger itself, and deployment/app-index support for.annotation_change— all owned by adjacent teams.Tasks
annotation_changeto the preview change-reader glob{@i18n>...}bindings@i18nmodel into the generator scaffold so new projects contain it by default (if the base app already declares@i18n, addcreateIfMissingto that entry instead of a duplicate)@i18nmodel registration helper for pre-existing projects (enhance existing entry if present, add if absent — never duplicate)writeChange(extract text, rewrite binding, register model)