Synced Texts
A bundle is read by key, one text at a time. That is enough for a label, and not enough for a list: a table of document types sorted by name has to sort by the name in the user's language, inside the query. So ui5:sync copies every declared text it syncs into a table, sdk_texts, and the models read their translated columns from there.
What the sync writes
For each row it syncs, the worker that owns the row writes the row's texts, in the same run, in every language of the declaring module's bundle (default is the base bundle):
| Family | Rows | Columns |
|---|---|---|
| Customizing | each catalog's rows | the columns the entry lists in translatable() |
| Ability | sdk_abilities | title, description |
| Role | sdk_roles | title, description |
| Setting | sdk_settings | title, description |
| Artifact | sdk_artifacts | title, description |
The texts are code-owned like the rows: a text the bundle no longer carries is removed, and a row declared away takes its texts with it. Never write to sdk_texts; change the bundle and sync.
How a model reads them
A model you name under ui5.i18n gets a global scope that joins sdk_texts and replaces each translated column by its text in the request's language. Where a row has no text, the column shows its literal. Because the column itself carries the text, everything that reads the column follows:
- an OData entity set behind
discoverModelanswers in the user's language; $filter,$orderbyand$searchrun on the text:name eq 'Rechnung'finds the invoice under German, and a list sorted bynamesorts in German.
The read costs one LEFT JOIN per translated column at one effective language, asked once per request. There is no subquery per row.
The configuration
// config/ui5.php
'i18n' => [
'customizing' => [
\App\Models\DocumentType::class => \App\Customizing\DocumentType::class,
],
'models' => [
// a model of yours => its LocalizedTableInterface adapter
],
],customizingmaps the Eloquent model of a catalog to the Customizing entry class that declares its rows. This is the line you add for a catalog of your own (Customizing).modelsmaps any other model to an adapter that says which family and catalog its rows belong to. The SDK's own models are wired here already: artifacts, abilities, roles.
Both are maps and merge key by key with the SDK's defaults: a host adds its own models and keeps the SDK's.
Reading past the model
A query that does not go through the model, DB::table(), reads the literals. A raw-SQL entity set that joins a translated table asks LocalizedTexts for the column:
use LaravelUi5\Sdk\I18n\Adapters\CustomizingLocalizedTable;
use LaravelUi5\Sdk\I18n\LocalizedTexts;
$query = DB::table('documents as d')->join('document_types as t', 't.id', '=', 'd.type_id');
$name = app(LocalizedTexts::class)->column(
$query, new CustomizingLocalizedTable(DocumentTypeEntry::class), 'name', request()->getLocale(), 't', 'type_name',
);
$query->select(['d.id', $name]);See also
- Database Schema: the shape of
sdk_texts - Sync Pipeline: the workers and their order