TCA, DataHandler and FormEngine¶
The support for localization in the Core of TYPO3 is based around a scheme where a record in the default language (id "0") can have other records pointing to it, offering a translation of its content. This implies some requirements for the structure of any database tables which we want to be available for translation:
- A field holding the reference to the language defined in the site configuration must be defined.
- A field holding the reference to the default language record must be defined.
- Optionally, a field holding the reference to the record it was translated from can be defined.
These fields are declared in the "[ctrl]" section of the TCA for the table.
Content
[languageField]¶
The first field is defined by the "languageField" property and contains a reference to the language the record is in.
Here is how such a field is configured (example from the tt_content
table):
'sys_language_uid' => [
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.language',
'config' => [
'type' => 'language'
]
]
The entry for the [All] language gets automatically added with the TCA type language.
Note
This field is traditionally named sys_language_uid
, but any name can
be used since it is registered with the languageField
property in the
ctrl section.
Deprecated since version 11.2
This field can only be used with the TCA type "language". All other field types will be automatically migrated on-the-fly possibly losing configurations. See Migration to the language type.
[transOrigPointerField]¶
The second field is defined by the "transOrigPointerField" property and contains a reference to the record in the default language.
Here is how such a field is configured (example from the tt_content
table):
'l10n_parent' => [
'displayCond' => 'FIELD:sys_language_uid:>:0',
'label' => 'LLL:EXT:core/Resources/Private/Language/locallang_general.xlf:LGL.l18n_parent',
'config' => [
'type' => 'select',
'renderType' => 'selectSingle',
'items' => [
['', 0]
],
'foreign_table' => 'tt_content',
'foreign_table_where' => 'AND {#tt_content}.{#pid}=###CURRENT_PID### AND {#tt_content}.{#sys_language_uid} IN (-1,0)',
'default' => 0,
],
],
Note
This field is traditionally named l10n_parent
, but any name can be
used since it is registered with the transOrigPointerField
property.
The l18n_parent
name used in table tt_content
is a historical
mistake.
Obviously, the table name has to be adapted in properties foreign_table
and foreign_table_where
for each table.
Notice the display condition set on the field, which will check the value of
the sys_language_uid
and display the l18n_parent
field only when
it is greater than zero (that means, it is a translation).
Another interesting point is that it will only look for a default language
record in the current pid. This means that a
default language record and all its translations must be on the same page!
This principle is also respected by the API function
\TYPO3\CMS\Core\Domain\Repository\PageRepository::getLanguageOverlay()
which fetches translations of records for the frontend display.
When the transOrigPointerField
and languageField
are defined for a
table you will see references to the content of the default language
record when editing the translation:
Warning
The configured $GLOBALS['TCA'][$table]['ctrl']['transOrigPointerField']
cannot be excluded as this leads to inconsistent data stored in the database.
This happens when a non-admin user creates a localization while not having
the permission to edit the transOrigPointerField
. Remove
exclude => true
from TCA, if set.
[transOrigDiffSourceField]¶
There is one more field which can be used on a translatable table, defined by
the property "languageField".
It is optional. It points to a blob database field which will store the content
of the default language record as it was when the translation was made. Then
this is used to display any changes that have occurred in the default record
since translation happened. For example, in the tt_content
table, it may
look like this for the header field:
This allows a translator to spot easily what has changed in order to adjust the translation accordingly.
[translationSource]¶
The "translationSource" property
defines a name of the field used by translations to point back to the original
record (that means, the record in any language of which they are a translation).
This property is often set to l10n_source
in Core tables.
This property is similar to
transOrigPointerField.
In connected mode, while transOrigPointerField
always contains the uid of the default language record, this field contains the
uid of the record the translation was created from.
For example, if a tt_content
record in default language (English) with
uid 13 exists, this record is translated to French with uid 17, and the Danish
translation is later created based on the French translation, then the Danish
translation has uid 13 set as l10n_parent
and 17 as l10n_source
.
DataHandler commands for localization¶
Localizing a record can be done by the "localize" command of the DataHandler. This is the command that is sent when you press the translate buttons in Web > List or Web > Page for an element.
When this command is issued an ordinary copy is made but the fields languageField and transOrigPointerField are updated accordingly.
You can only localize a record which is not already localized and which is in "default" or "All" language (a record in "All" language is supposed to be somehow valid for any language, but can still be translated if needed).
It is possible to manually create two or more translations of the same record but this is considered an error in the system, although not fatal, yet producing unpredictable results.
Localization command options per field¶
Each field may contain special instructions which will affect the "localize" command. Most important is the "l10n_mode" field with which, for example, a field can be entirely excluded from the translation process.