TCA, DataHandler and FormEngine

The support for localization in the core of TYPO3 CMS is based around a scheme where a record in the default language (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:

  1. A field holding the reference to the system language (“sys_language” table) must be defined.
  2. A field holding the reference to the default language record must be defined
  3. 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.

[languageField]

The first field is defined by property “languageField” 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' => [
          'exclude' => 1,
          'label' => 'LLL:EXT:lang/locallang_general.xlf:LGL.language',
          'config' => [
                  'type' => 'select',
                  'renderType' => 'selectSingle',
                  'special' => 'languages',
                  'items' => [
                          [
                                  'LLL:EXT:lang/locallang_general.xlf:LGL.allLanguages',
                                  -1,
                                  'flags-multiple'
                          ],
                  ],
                  'default' => 0,
          ]
],

Notice the predefined entry for the “All” language.

Note

This field is traditionally named “sys_language_uid”, but any name can be used since it is registered with the “languageField” property.

[transOrigPointerField]

The first field is defined by property “transOrigPointerField” 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):

'l18n_parent' => [
          'exclude' => 1,
          'displayCond' => 'FIELD:sys_language_uid:>:0',
          'label' => 'LLL:EXT:lang/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 (i.e. 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\Frontend\Page\PageRepository::getRecordOverlay() which fetches translations of records for the frontend display (when config.sys_language_overlay = 1).

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:

Original content in the Form Engine

Original content shows up under the input fields when translating a record

[transOrigDiffSourceField]

There is one more field which can be used on translatable table, defined by property “languageField”. It is optional. It points to blob database field which will store the content of the default language record as it was when the translation was made. This is then 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:

Changes in original content

Changes in the original content are highlighted below the input field

This allows a translator to easily spot 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 (i.e. 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.

This setting is available since TYPO3 8.6.

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.