Internationalization
Every text the SDK shows a person comes in that person's language: the rail and the Launchpad, the titles of abilities, roles and settings in the admin apps, the rows of a Customizing catalog, the messages an action answers with, and the names of your own records. You write each text once per language; the SDK decides which one a request gets.
Three places a text lives
Where a text lives depends on who brings the vocabulary.
| Module bundles | Synced texts | Master data | |
|---|---|---|---|
| For | everything your module declares in code: app titles, navigation, Weave labels, ability, role and setting texts, messages | the same declared texts, read on the server: Customizing rows, abilities, roles, settings, artifacts | what the people using the app write: an item's name, a product's description |
| Written by | you, and your translators (i18n_<lang>.properties) | ui5:sync, from the bundles | your app, through an action |
| Stored in | the module's i18n.properties and its locale files | sdk_texts | the model's own column (base language) and sdk_translations (further languages) |
| Read | by the browser and by the server, from the bundle | by SQL: filter, sort and search run on the translated text | by SQL, the same way |
The middle column is not a second source. The bundle stays the one place you write a declared text; the sync copies it into a table so that OData and the server can read it where a bundle is out of reach, inside a query.
The request's language
Core's ResolveRequestLanguage middleware sets the language of every request: sap-language if the app wrote one into its service URL, else the first entry of Accept-Language, which UI5 sends on every request. It is a language, not a locale: de-AT becomes de. See the request language in Core.
On an SDK host it belongs in ui5.middleware, ahead of ResolveUi5Context. A host that overrides middleware without it serves the base bundle to everyone (troubleshooting).
The fallback chain
A declared text resolves like UI5's own ResourceBundle: the requested language, then English, then the base bundle. de reads i18n_de.properties; a language no bundle offers reads i18n_en.properties; a key that no locale file carries reads i18n.properties. Shell and server follow the same chain, so one screen never mixes two languages.
Master data is different: a missing translation falls back to the base column, the company's own language, never to English. A company in Vienna that has not translated an item's name shows it in German, not in an English it never wrote.
What is not here
- Code lists (countries, currencies, units) come with their own package and texts; their mechanism is settled with the ERP Foundation, not in the SDK.
- Help pages are documents, not texts: one Markdown file per topic and locale. See Help authoring.
The pages of this group
- Module Bundles: the keys every module carries, and what stops when one is missing
- Synced Texts:
sdk_texts, and how OData reads in the user's language - Translatable Master Data:
#[Translatable]andHasTranslations - Customizing: the texts of a catalog's rows
- LeanShell: the rail, Weave menus and the shell's own texts
- Actions & Messages:
MessageText, and in whose bundle a message is looked up