My module creates and manages some config_entities programmatically (ie. not through an EntityForm) in response to associated content entities being saved.

In order to handle multi-language content entities, I see two options:

  • create one config entity and add translations for it
  • create a unique config entity for each translation

The first seems cleaner - however, I don't see how to actually transparently manage translations for config entities. Translating an entity with the config_translation module appears to create a new entry in the config table with collection = language.xx, but I don't see how to access a translated entity explicitly (rather than it being automatically mapped by the site's interface language). Is this even possible?

3 Answers 3


The answer from @Smartsheet eng is correct if you want to load and read a specific translation as a config entity, see also How to progragrammatically get NodeType translated value in D8?.

However, changing them is different, because the config entity can't be saved like that, it doesn't understand what is a translation and what's not. It will just overwrite your default language with that data. See also https://www.drupal.org/project/drupal/issues/2910353.

To actually manage a translation of a config entity, you have to directly interact with the config system, you can see how in \Drupal\config_translation\Form\ConfigTranslationFormBase::submitForm():

$config_translation = \Drupal::languageManager()->getLanguageConfigOverride($langcode, $config_name);

// Write the keys you want to translate on the config object.
  • 1
    Note: $config_translation->setData($config_entity->toArray()); is how you get from config entity to config object. Commented Sep 28, 2018 at 6:26
  • 3
    That doesn't work for any entity type (field storages) and then you'd have everything in there, you must only add the translatable keys.
    – Berdir
    Commented Sep 28, 2018 at 6:56

As far as I can see -- yes, this is possible but it's not as pretty as $contentEntity->getTranslation($langcode);. The full enchillada would be:

protected function getTranslatedConfigEntity(ConfigEntityInterface $configEntity, LanguageInterface $language) {
  $langcode = $language->id():
  /** @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface $configEntityType */
  $configEntityType = $configEntity->getEntityType();
  $name = $configEntityType->getConfigPrefix() . '.' . $configEntity->id();
  $translatedConfig = $this->languageManager->getLanguageConfigOverride($langcode, $name);
  $translatedConfig[$configEntity->getKeys('langcode')] = $langcode;
  $class = $configEntityType->getClass();
  return new $class($translatedConfig->get(), $configEntityType->id());

An alternative would be:

public function getTranslatedConfigEntity(ConfigEntityInterface $configEntity, LanguageInterface $language) {
  $currentLanguage = $this->languageManager->getConfigOverrideLanguage();
  $translatedConfigEntity = $this->entityTypeManager
  return $translatedConfigEntity;
  • 1
    Just to mention, not all config entities can be translated with this approach. For example, webform entity defines its own translation logic.
    – Leksat
    Commented May 17, 2019 at 9:36
  • My config is ImmutableConfig; how do i t get a specific translation of that?
    – liquidcms
    Commented Nov 26, 2021 at 18:40

Adding translation from code (in my case update hook) should look something like:

$my_field_translation = \Drupal::languageManager()->getLanguageConfigOverride('de', 'field.field.node.my_conent_type.my_field_name');
$my_field_translation->set('label', 'German Label');

To get exact name of config file ('field.field.node.my_conent_type.my_field_name') I added translation manually for field, exported config ("drush cex") and saw what config file was changed...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.