Language support for entity fields

Last updated on
22 July 2017

Drupal 7 will no longer be supported after January 5, 2025. Learn more and find resources for Drupal 7 sites

About multilingual fields

Entity fields natively implement multilingual support. The language associated with a field depends on a number of factors including if translation is enabled and the chosen translation method (e.g. for node entities, either node translation or field translation).

Before looking at the specific field language support, it is important to know the different possible entity configurations. For node entities, content types can be configured as follows:

  • Locale module is disabled
    • No language assignment
    • No translation
  • Locale module enabled
    • Language assignment
    • No translation
  • Locale and Content translation modules enabled
    • Language assignment
    • Translation via node translation method (multiple nodes)
  • Locale and Entity translation modules enabled
    • Language assignment
    • Translation via field translation method (one node)

To learn more about the two translation methods, check out the documentation on translating content into different languages. Note that the Content translation module only handles node entities, so other core entities must use the Entity translation module for translation.

As we will see, the entity configuration will affect what languages can be assigned to fields and also what the ubiquitous LANGUAGE_NONE (und) means for each case.

Handling of multilingual fields

Fields implement multilingual support by holding multiple values in the field array. All fields use the following structure:

$entity->{$field_name}[$langcode][$delta][$column_name]

Here are some examples:

$entity->body[und][0][value];
$entity->image[und][0][value];
$entity->description[en][0][value];
$entity->description[fr][0][value];
$entity->history[en][0][value];
$entity->history[fr][0][value];

When dealing with entities, it is important to understand what entity languages and field languages are appropriate for each of the entity configurations. For node entities, the following figure provides a high-level overview of the possible language values and the different uses of LANGUAGE_NONE (und).

Another way to think about a node field's language is illustrated in the following flowchart.

These scenarios are described in more detail below.

Locale module is disabled

By default a single-language site in English without the Locale module enabled uses LANGUAGE_NONE as the $langcode, and there is always only one language variant for each field.

$entity->body[und][0][value];
$langcode = entity_language('entity_type', $entity);
$langcode == 'und'

Locale and Content translation modules enabled

With the core Locale and Content translation modules enabled, fields will not have their own language information, and LANGUAGE_NONE is used to signify that we don't have a field language specified. The whole entity with all its properties and fields is assumed to have the entity language code assigned (conceptually).

$entity->body[und][0][value];
$langcode = entity_language('entity_type', $entity);
$langcode == 'en'

Locale and Entity translation modules enabled

Field translation is pluggable, but the only known implementation is the contributed Entity translation module that provides a user interface to enable field translation for entities and to change the translatability on fields.

Shared fields

When we enable field translation, a field that does not have translation enabled will always use LANGUAGE_NONE, and no other language values will be present. The meaning of this is different from the above. It means that the field will have the same value across all translations. This is also called a shared field. The $entity->langcode value will persist to represent the language of the properties of the entity, such as the author and status, as well as signify the original language that the entity was saved with. That information can be useful for permission and workflow purposes.

$entity->body[und][0][value]; // not translatable (shared)
$langcode = entity_language('entity_type', $entity);
$langcode == 'en' // applies to properties of the entity

Translatable fields

For a field with translation enabled, multiple variants of the value may be available in any of the enabled languages.

$entity->body[en][0][value];
$entity->body[de][0][value];
$langcode = entity_language('entity_type', $entity);
$langcode == 'en' // applies to properties of the entity

(Translatable fields should not have a variant keyed with LANGUAGE_NONE. If that is there, it is a bug in one of the modules handling the data.)

Multilingual field API

The available languages for a particular field are returned by field_available_languages(), which abstracts the above logic.

Whether a field is translatable can be determined by calling field_is_translatable() directly.

If you are interested in looking up whether an entity type has field translation support implemented by one of the enabled modules (in the most common use case that entity_translation module is enabled and this entity type is configured with it to support field translation), use field_has_translation_handler() on the entity type.

Given that the entity structure contains all the different language versions of fields when field translation is used, we need to pick from them for display. The field_language() function can be used to determine the display language for the fields attached to the given entity. That handles the fallback logic defined by handlers to pick the right language of each field for display. The field_get_items() function can be used to return field values in that language.

When acting on fields, by default, _field_invoke() and _field_invoke_multiple() process fields in all available languages. They allow to limit the operation to a specific language or a set of languages.

The entity_language() function can be used to retrieve an entity's language in a generic fashion. The value returned by entity_language() is the recommended value to be passed as $langcode parameter of the field_attach_form() function, when the logic being implemented does not explicitly dictate a different one.

Help improve this page

Page status: No known problems

You can: