Can't add translation to locked language

Created on 28 April 2022, over 2 years ago
Updated 9 November 2023, 11 months ago

Problem/Motivation

When we have an entity that has the "fr" langcode on the server website and the "und" langcode on the client website, the sync fails with this error:

InvalidArgumentException : The entity cannot be translated since it is language neutral (und). dans Drupal\Core\Entity\ContentEntityBase->addTranslation()

This happens because ImportService::getProcessedEntity() sees that the entity does not already have a French translation so it calls addTranslation() on it, but this is not allowed for entities with a locked language.

Steps to reproduce

  1. Create a media with the "und" language and synchronize it to another website.
  2. Change the language to "fr" and synchronize it again.

Proposed resolution

ImportService::getProcessedEntity() should not add a translation when the existing entity has a locked language, it should instead change its language.

🐛 Bug report
Status

Fixed

Version

3.0

Component

Code

Created by

🇫🇷France prudloff Lille

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • First commit to issue fork.
  • Assigned to Grimreaper
  • 🇫🇷France Grimreaper France 🇫🇷
  • Status changed to Needs work over 1 year ago
  • 🇫🇷France Grimreaper France 🇫🇷

    Hi,

    Thanks I reproduce the problem. Having entities in a locked language is not something frequent.

    So I made some test and ok, if an entity is in language und, it can't have translation so no risk to have imported it previously in another language.

    The problem may also happen is the following scenario:

    Site 1:
    - Entity A und

    Site 2:
    import entity
    - Entity A und

    Site 1:
    - change default language
    - Entity A en
    - add translation
    - Entity A fr

    Site 2:
    - try to import Entity A fr (which is not the default language on Site 1)

    In this case, with the currently proposed solution, this will change the default langcode of the imported entity to the langcode of the translation being imported which this may not be what we want.

    In DefaultDataProcessor.php, the default_langcode attribute is removed, but I think we still have access to the content_translation_source attribute which value is und in the case of the default translation and the source translation code if not.

    I will try to poc something around that.

  • 🇫🇷France Grimreaper France 🇫🇷

    I tried something like the following code.

    And the problem is in the last else statement. So I guess that when having content switching from locked language to normal languages, this may not be a problem that the imported entity in language und, is overridden with new data set as default translation. In most cases I guess that the next import will be to update the default langcode.

          // If the existing entity is in an untranslatable language like 'und':
          // - if the imported translation is still the default language, update
          //   the entity default language.
          // - if the imported translation is for a different language than the
          //   new default language on the remote, detect remote new default
          //   language using content_translation_source attribute and set it. Then
          //   create a new translation has usual.
          if ($existing_entity->language()->isLocked()) {
            $content_translation_source_public_name = FALSE;
            if (isset($field_mappings[$entity_type_id][$entity_bundle]['content_translation_source'])) {
              $content_translation_source_public_name = $field_mappings[$entity_type_id][$entity_bundle]['content_translation_source'];
            }
            $content_translation_source = FALSE;
            if ($content_translation_source_public_name && !empty($entity_data['attributes'][$content_translation_source_public_name])) {
              $content_translation_source = $entity_data['attributes'][$content_translation_source_public_name];
            }
    
            // @todo Add check in Default data processor that content translation source is present.
            // We are still dealing with the default language.
            if ($content_translation_source == LanguageInterface::LANGCODE_NOT_SPECIFIED) {
              $existing_entity->set('langcode', $data_langcode);
            }
            else {
              // The problem is that we would have to check that the content translation source
              // is referencing a language that exists on this website. And if not skip the entity and
              // log an error.
              $existing_entity->set('langcode', $content_translation_source);
            }
          }
    

    So the issue "only" needs tests.

    • Grimreaper committed b4859113 on 8.x-3.x
      Issue #3277731 by Grimreaper: Can't add translation to locked language:...
  • Issue was unassigned.
  • Status changed to Fixed over 1 year ago
  • 🇫🇷France Grimreaper France 🇫🇷
  • Automatically closed - issue fixed for 2 weeks with no activity.

  • Status changed to Fixed 11 months ago
  • 🇨🇳China lawxen

    I still got error when syncing a node again
    InvalidArgumentException: Invalid translation language (und) specified. in Drupal\Core\Entity\ContentEntityBase->addTranslation() (line 952 of /var/www/html/docroot/core/lib/Drupal/Core/Entity/ContentEntityBase.php) [d96fafe1-837e-42f9-ad09-cb688adda8fc].

  • 🇨🇳China lawxen

    Continue:
    On ther sever side, I use jsonapi_extra hide the language field, then the client side will use the default languge to create the node, then sync again, error comes.

Production build 0.71.5 2024