Translatable fields

With translatable fields the record exists once in the database, and a translatable column holds a value for every language. Add the locale parameter to every field you want to translate. Localization has to be enabled.
app/Models/Category.php
The column stores a JSON object keyed by the language slug:
A translated field gets a json column. type:text and encrypted fields keep a text column holding the same JSON object.
Do not combine locale with belongsTo or belongsToMany. Relation values are not translatable.

Reading translated values

Reading the attribute returns the value of the current language. When the translation is empty, the value of the default (first) language is returned, and when it is missing too, the first filled translation.
Assign an array (or a JSON object string) to store all translations at once. Empty (null) translations are not stored.

Arrays and API responses

toArray() and toJson() return all translations by default, which is what the administration needs. In your API, return only the value of the requested language:
The Admin\Helpers\SetApiResponse middleware does this for you, and switches the language by the app-locale request header.
routes/api.php
An empty translatable value is returned as null.

Validation

Rules are applied per language. required (and every required_* rule) is checked only for the default language, other languages may stay empty. All other rules, e.g. max, are checked for every language.
Use unique_json to check that a translation is unique within its own language.

Field types

  • file – a file is uploaded for every language, multiple uploads a list of files per language. A required file is required only for the default language, and only when the default language has no file yet.
  • checkbox – stores 0 or 1 for every language.
  • select with static options, including multiple – the selected options are stored per language.
  • date (also multiple) and editor – stored and cast per language.
In the administration table the value of the default language is shown, and the search matches words in any language.

Default values

default only prefills the input of the current language in the form. JSON columns have no database default.

Translating an existing column

When you add locale to a field which already has data, php artisan admin:migrate lists the values and asks whether to wrap them into the first language:
If you refuse, the column can not be changed to JSON and the migration fails.
Translated slugs are described in Pretty URLs, translated field labels in labels and help texts.