Problem/Motivation

In #2431329: Make (content) translation language available as a field definition we introduced a translated default_langcode field, but we prevented it from being altered as it should be considered read-only. We did not use a standard method to implement this as read-only constraints were not working at the time. Moreover until #2137801: Refactor entity storage to load field values before instantiating entity objects is fixed, the field is actually populated so it cannot be read-only. However we should switch to a standard method as soon as possible.

Proposed resolution

TBD

Remaining tasks

  • Figure out a solution
  • Write a patch
  • Review it

User interface changes

None

API changes

None

Issue fork drupal-2443991

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

plach’s picture

Issue summary: View changes
hchonov’s picture

Why is the default_langcode considered as read-only?
Consider the following use case:

  1. Create an entity with default language german.
  2. Add an english translation.
  3. At some point decide that the german translation is not needed anymore.
  4. Switch the default language to english and remove the german translation, so that it is not carried through all the further revisions of the entity as it is not needed and it will stay there only as a garbage.

At the moment we are not able to do this.

mkalkbrenner’s picture

I second hchonov's use-case described in #2. He demonstrated it to me by simply removing the Exception that is thrown when you modify the default language field.
I'm now of the opinion that it should be allowed to modify the default language. But additionally we need constraints that ensure that there is always a valid default language.

plach’s picture

Status: Postponed » Active

This is an interesting point and may help with solving #2485499: Allow source translations to be removed. However, I think we still need to ensure that only one single translation is marked as default and, if we change it, the previous default is marked as non-default.

Anyway, I'm pretty sure just changing the default_langcode field value is not enough, unless the entity is reloaded, because the internal data structures need to be adjusted to take the new default langcode into account.

plach’s picture

Title: Use constraints to ensure default_langcode has always a valid value » Allow default_langcode field value to be changed
plach’s picture

Priority: Normal » Major
Issue tags: +Entity Field API
berdir’s picture

This might also resolve bugs in the serializer when you have multiple translations, because it currently explodes on the default_langcode field, as it tries to explicitly set the value to 0/1 for different translations.

mkalkbrenner’s picture

Anyway, I'm pretty sure just changing the default_langcode field value is not enough, unless the entity is reloaded, because the internal data structures need to be adjusted to take the new default langcode into account.

@plach: Could you explain, why a change of this field has to be handled differently from a change of any other field?

plach’s picture

Because many internal data structures of a content entity are keyed by language, so if we change the default language we must adjust them. For instance the field values of the default translation are keyed by LanguageInterface::LANGCODE_DEFAULT to make it easy to change the entity's default language from the UI (usually keeping its values untouched). If instead we switch the default language, we need to adjust that.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

mikeryan’s picture

Last comment here was one year ago today - time for a bump!

Migration needs this - we can't guarantee the default language node (the one referenced by tnid in the legacy installation) will be the first one migrated, so want to be able to change it when that node is migrated in.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

beltofte’s picture

Any updates to this issue?

Anyone patched Drupal core to get this working or implemented a custom solution?

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

acontia’s picture

What's the current status of this? Did anyone manage to get this working?

berdir’s picture

My use case was to remove DE translation and just keep EN, but DE was the default, what I did is take the EN values, delete the EN translation, then change DE to EN and add all the translatable fields back again and save again. The double save is necessary because the language can't be changed if you still have a en language, even if deleted.


if ($node->language()->getId() == 'de' && $node->hasTranslation('en')) {
      $en_values = $node->getTranslation('en')->toArray();
      $node->removeTranslation('en');
      // The removed translation needs to be saved or we can not change the
      // the language to that.
      $node->save();
      $node->set('langcode', 'en');
      foreach ($en_values as $field_name => $en_field_values) {
        if ($node->getFieldDefinition($field_name)->isTranslatable() && !in_array($field_name, ['default_langcode'])) {
          $node->set($field_name, $en_field_values);
        }
      }
      $node->save();
}

Note that if you use paragraphs, you'll need to, possibly recursively, update them too and do that first, as removing the translation on the node will also automatically remove it on all referenced paragraphs.

acontia’s picture

Following Berdir's recommendations I have written this function, that seems to work for me:

function mymodule_change_entity_langcode($entity, $langcode_to_remove, $langcode_to_keep) {
  // Check that the entity langcode is correct.
  if ($entity->language()->getId() != $langcode_to_remove) {
    return false;
  }

  // Check that the translation exist.
  if (!$entity->hasTranslation($langcode_to_keep)) {
    return false;
  }

  // Extract values of translation to keep.
  $values_to_keep = $entity->getTranslation($langcode_to_keep)->toArray();

  // Update paragraph fields recursively.
  $field_definitions = $entity->getFieldDefinitions();
  foreach ($field_definitions as $field_name => $field_definition) {
      if ($field_definition->getSetting('handler') == 'default:paragraph') {
        foreach ($values_to_keep[$field_name] as $paragraph_reference) {
          $paragraph = \Drupal::entityTypeManager()->getStorage('paragraph')->loadRevision($paragraph_reference['target_revision_id']);
          mymodule_change_entity_langcode($paragraph, $langcode_to_remove, $langcode_to_keep);
        }
      }
  }

  // The removed translation needs to be saved or we can not change the
  // the language to that.
  $entity->removeTranslation($langcode_to_keep);
  $entity->save();

  // Set new langcode.
  $entity->set('langcode', $langcode_to_keep);

  // Copy translatable field values.
  foreach ($values_to_keep as $field_name => $field_values) {
    if ($entity->getFieldDefinition($field_name)->isTranslatable() && !in_array($field_name, ['default_langcode'])) {
      $entity->set($field_name, $field_values);
    }
  }

  // Save entity again.
  $entity->save();
}

I am using it to remove the English version of my nodes (which was the source language) and set Italian as source language of all the nodes in my site:

$nids = \Drupal::entityQuery('node')->condition('langcode','en')->execute();

foreach ($nids as $nid) {
  $node = Node::load($nid);
  mymodule_change_entity_langcode($node, 'en', 'it');
}

A few caveats/questions:
1) My nodes have Content Moderation enabled. To avoid possible issues in the future I have removed all the past revisions from all nodes (my particular case allowed me to do it). Is this needed or should it work without doing it?
2) Do we need to follow the same logic that we follow with paragraph fields in other fields of type "Entity Reference Revision" or "Entity Reference"?

acontia’s picture

After a few months of running this in production I can confirm that works without issues.

Regarding Content Modreation, it can be left enabled and there is no need of removing old revisions of nodes

The code doesn't go recursively into other referenced entities like Media items, so as result they will still have Italian as source language. This is not causing any issues for me. I think it should be easy to adapt the code to go recursively into Media items, similarly to what I did for Paragraph fields.

ytsurk’s picture

Thanks for sharing code!

ytsurk’s picture

geek-merlin’s picture

The issue referenced in the IS is fixed for quite some time now. I think the IS should be updated for that.

hchonov’s picture

I don't think that the issue is fixed. We need a proper method for making it possible to switch the default translation. It should account for existing untranslatable field instances linked by the entity which point to the old default entity translation object but after the change they should point to the new one.

omessaoudi’s picture

Thank you @acontia @Berdir for sharing your scripts. It was really helpful for me and saved lot of my time :-)

I adjusted this one to make it working also for terms, media and content_blocks.

Also changed to switch default language to target one even by keeping original language values (was necessary in my case).

You can use it as a script to run by drush (eg : drush scr switch-default-language.php)

//  switch-default-language.php

// Get drush scr param.
if (empty($extra[0]) || !in_array($extra[0], ['node', 'term', 'media', 'block'])) {
  echo "\n Please enter a valid entity type: node, term, media, block";
  return false;
}

switch ($extra[0]) {
  case 'node':
    $table = 'node';
    $id = 'nid';
    $entityLoder = '\Drupal\node\Entity\Node';
    break;
  case 'term':
    $table = 'taxonomy_term_data';
    $id = 'tid';
    $entityLoder = '\Drupal\taxonomy\Entity\Term';
    break;
  case 'media':
    $table = 'media';
    $id = 'mid';
    $entityLoder = '\Drupal\media\Entity\Media';
    break;
  case 'block':
    $table = 'block_content';
    $id = 'id';
    $entityLoder = '\Drupal\block_content\Entity\BlockContent';
    break;
}

// Target language settings.
$langcode_to_remove = 'fr';
$langcode_to_keep = 'en';

// Migrate nodes
$rows = db_query("SELECT $id FROM $table WHERE langcode = :langcode", [':langcode' => $langcode_to_remove])->fetchCol();
$items = $entityLoder::loadMultiple($rows);
foreach ($items as $item) {
  _change_entity_langcode($item, $langcode_to_remove, $langcode_to_keep);
}

function _change_entity_langcode($entity, $langcode_to_remove, $langcode_to_keep) {
  // Check that the entity langcode is correct.
  if ($entity->language()->getId() != $langcode_to_remove) {
    return false;
  }
  $field_definitions = $entity->getFieldDefinitions();

  // Check that the translation exist.
  if (!$entity->hasTranslation($langcode_to_keep)) {
    $values_to_keep = $entity->toArray();
    foreach ($field_definitions as $field_name => $field_definition) {
      if ($field_definition->getSetting('handler') == 'default:paragraph') {
        foreach ($values_to_keep[$field_name] as $paragraph_reference) {
          $paragraph = \Drupal::entityTypeManager()->getStorage('paragraph')->loadRevision($paragraph_reference['target_revision_id']);
          _change_entity_langcode($paragraph, $langcode_to_remove, $langcode_to_keep);
        }
      }
    }
    $entity->set('langcode', $langcode_to_keep);
    echo "\n Entity type  \"" . $entity->bundle() . '" #' . $entity->id() . ' "' . $entity->label()  . '" default language was set to "' . $langcode_to_keep . '" by keeping "' . $langcode_to_remove . '" field values because no "' . $langcode_to_keep . '" translation was found. ';
    return $entity->save();
  }

  // Extract values of translation to keep.
  $values_to_keep = $entity->getTranslation($langcode_to_keep)->toArray();

  // Update paragraph fields recursively.
  foreach ($field_definitions as $field_name => $field_definition) {
    if ($field_definition->getSetting('handler') == 'default:paragraph') {
      foreach ($values_to_keep[$field_name] as $paragraph_reference) {
        $paragraph = \Drupal::entityTypeManager()->getStorage('paragraph')->loadRevision($paragraph_reference['target_revision_id']);
        _change_entity_langcode($paragraph, $langcode_to_remove, $langcode_to_keep);
      }
    }
  }

  // The removed translation needs to be saved or we can not change the
  // the language to that.
  $entity->removeTranslation($langcode_to_keep);
  $entity->save();

  // Set new langcode.
  $entity->set('langcode', $langcode_to_keep);

  // Copy translatable field values.
  foreach ($values_to_keep as $field_name => $field_values) {
    if ($entity->getFieldDefinition($field_name)->isTranslatable() && !in_array($field_name, ['default_langcode'])) {
      $entity->set($field_name, $field_values);
    }
  }

  // Save entity again.
  $entity->save();
  echo "\n Entity type  \"" . $entity->bundle() . '" #' . $entity->id() . ' "' . $entity->label()  . '" default language was set to "' . $langcode_to_keep . '"';
}
Deno’s picture

Current implementation at D8.8 allows changing of a language for "default translation" entity from lang A to lang B as long as the translation in Lang B doesn't exist. This has hit me as we are using automated translation to several languages and some people have posted the entries with wrong default language flag.

Ideally, the "default translation" would be merely a boolean that can be set and unset at will and the code in the background would simply unset the "default translation?" field in all other languages when it's set in one. Or a feature of an extra lookup table that's linking all translations together - entity reference pointing to default translation.

Which would also mean that there needs to exist an entity for each translation (including the default one) somewhere, containing the data for all the translateable fields. I'm not sure how this is implemented, but if additional entities only exist for "translations" and only contain translateable fields, whereas the original node entity is used for the default language. then switching the default language is much more difficult. This would also be error prone, since actuall content would have to switch between two entities.

vuil’s picture

Version: 8.6.x-dev » 8.7.x-dev

Version: 8.7.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Branches prior to 8.8.x are not supported, and Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

wim leers’s picture

Issue tags: +migrate-d7-d8

Per #11.

proweb.ua’s picture

#26
Error: Call to undefined function db_query() in include() (line 38.. switch-default-language.php
Drupal 9
php 8

bessonweb’s picture

I have a website with 3 languages (FR/EN/DE) and I would like to remove English and Deutsh to remove the multilingual feature.

I have adapted the #26 code to Drupal 9 (I'm not developer but I do what I can...) and it seem to work, but it removed the FR translation instead of english.

The code :

<?php
//  switch-default-language.php

// Get drush scr param.
if (empty($extra[0]) || !in_array($extra[0], ['node', 'term', 'media', 'block'])) {
  echo "\n Please enter a valid entity type: node, term, media, block";
  return false;
}

switch ($extra[0]) {
  case 'node':
    $table = 'node';
    $id = 'nid';
    $entityLoder = '\Drupal\node\Entity\Node';
    break;
  case 'term':
    $table = 'taxonomy_term_data';
    $id = 'tid';
    $entityLoder = '\Drupal\taxonomy\Entity\Term';
    break;
  case 'media':
    $table = 'media';
    $id = 'mid';
    $entityLoder = '\Drupal\media\Entity\Media';
    break;
  case 'block':
    $table = 'block_content';
    $id = 'id';
    $entityLoder = '\Drupal\block_content\Entity\BlockContent';
    break;
}

// Target language settings.
$langcode_to_remove = 'fr';
$langcode_to_keep = 'en';

// Migrate nodes
$database = \Drupal::database();
$rows = $database->query("SELECT $id FROM $table WHERE langcode = :langcode", [':langcode' => $langcode_to_remove])->fetchCol();
$items = $entityLoder::loadMultiple($rows);
foreach ($items as $item) {
  _change_entity_langcode($item, $langcode_to_remove, $langcode_to_keep);
}

function _change_entity_langcode($entity, $langcode_to_remove, $langcode_to_keep) {
  // Check that the entity langcode is correct.
  if ($entity->language()->getId() != $langcode_to_remove) {
    return false;
  }
  $field_definitions = $entity->getFieldDefinitions();

  // Check that the translation exist.
  if (!$entity->hasTranslation($langcode_to_keep)) {
    $values_to_keep = $entity->toArray();
    foreach ($field_definitions as $field_name => $field_definition) {
      if ($field_definition->getSetting('handler') == 'default:paragraph') {
        foreach ($values_to_keep[$field_name] as $paragraph_reference) {
          $paragraph = \Drupal::entityTypeManager()->getStorage('paragraph')->loadRevision($paragraph_reference['target_revision_id']);
          _change_entity_langcode($paragraph, $langcode_to_remove, $langcode_to_keep);
        }
      }
    }
    $entity->set('langcode', $langcode_to_keep);
    echo "\n Entity type  \"" . $entity->bundle() . '" #' . $entity->id() . ' "' . $entity->label()  . '" default language was set to "' . $langcode_to_keep . '" by keeping "' . $langcode_to_remove . '" field values because no "' . $langcode_to_keep . '" translation was found. ';
    return $entity->save();
  }

  // Extract values of translation to keep.
  $values_to_keep = $entity->getTranslation($langcode_to_keep)->toArray();

  // Update paragraph fields recursively.
  foreach ($field_definitions as $field_name => $field_definition) {
    if ($field_definition->getSetting('handler') == 'default:paragraph') {
      foreach ($values_to_keep[$field_name] as $paragraph_reference) {
        $paragraph = \Drupal::entityTypeManager()->getStorage('paragraph')->loadRevision($paragraph_reference['target_revision_id']);
        _change_entity_langcode($paragraph, $langcode_to_remove, $langcode_to_keep);
      }
    }
  }

  // The removed translation needs to be saved or we can not change the
  // the language to that.
  $entity->removeTranslation($langcode_to_keep);
  $entity->save();

  // Set new langcode.
  $entity->set('langcode', $langcode_to_keep);

  // Copy translatable field values.
  foreach ($values_to_keep as $field_name => $field_values) {
    if ($entity->getFieldDefinition($field_name)->isTranslatable() && !in_array($field_name, ['default_langcode'])) {
      $entity->set($field_name, $field_values);
    }
  }

  // Save entity again.
  $entity->save();
  echo "\n Entity type  \"" . $entity->bundle() . '" #' . $entity->id() . ' "' . $entity->label()  . '" default language was set to "' . $langcode_to_keep . '"';
}

Somebody have an explanation?

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

ludostation’s picture

#33

Your code is asking to remove "French" and to keep "English".

// Target language settings.
$langcode_to_remove = 'fr';
$langcode_to_keep = 'en';

That's why!
You need to process this twice, on to remove 'en' and one to remove 'de', but keep in mind to leave 'fr' as langcode to keep.

bessonweb’s picture

Oh ! Sorry, it's possible I forgot to change this!

Thanks!

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

sascha_meissner’s picture

In case anyone might find this useful, this code will remove the edit-langcode element from ContentEntityForms if there are already translations created to prevent the error "Can't change the default langauge"

/**
 * Implements hook_form_alter().
 */
function yourmodule_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  $form_object = $form_state->getFormObject();
  if ($form_object instanceof ContentEntityFormInterface) {
    // Prevent switching languages on already translated content.
    // @see \Drupal\content_translation\ContentTranslationHandler::entityFormAlter.
    $entity = $form_object->getEntity();
    if ($entity->isTranslatable() && count($entity->getTranslationLanguages()) > 1) {
      // Translations exist, prevent language switching.
      $langcode_key = $entity->getEntityType()->getKey('langcode');
      $form[$langcode_key]['widget']['#access'] = FALSE;
    }
  }
}
wim leers’s picture

Title: Allow default_langcode field value to be changed » [PP-1] Allow default_langcode field value to be changed
Version: 9.5.x-dev » 11.x-dev
Status: Active » Postponed
Related issues: +#3373653: Add a `langcode` data type to config schema

But additionally we need constraints that ensure that there is always a valid default language.

— @mkalkbrenner in #3, >8 years ago.

This is now within reach: #3373653: Add a `langcode` data type to config schema is RTBC, and then we'll still need to do the work here to actually run validation constraints 😊

berdir’s picture

@Wim: This is about content entities and the boolean default_langcode flag. (ensuring that exactly one translation has this flag). That has nothing to do with langcode validation in config entities.

wim leers’s picture

Title: [PP-1] Allow default_langcode field value to be changed » Allow default_langcode field value to be changed
Status: Postponed » Active

Mea culpa — I thought it was about a default_langcode setting in some Field(Storage)Config. 🙈

That being said … exactly the same validation approach will be usable here AFAICT? 😊 That'd be:

constraints:
  NotNull: []
  Choice:
    callback: 'Drupal\Core\TypedData\Plugin\DataType\LanguageReference::getAllValidLangcodes'

That's also why I didn't dig very deep into this issue, because that alone landing in core in another issue would be sufficient to make this issue more actionable?

wim leers’s picture

#3373653: Add a `langcode` data type to config schema landed. Per #43, AFAICT that should still help this issue! 😊

Taran2L made their first commit to this issue’s fork.

ressa’s picture

EDIT: After using Drupal with an updated default language, I found some issues, where language is set to und ... so, it's still not a great idea to change default language -- at least with this method :)

It's a bit of an edge case, but I'll share it here, since this issue pops up when searching for changing default language.

I have originally started my web site in the standard English language, but now want to change to Danish as the default language, because I want to translate block titles and other user interface elements, with a base in Danish. What makes this case special, is that all content is migrated into Drupal from JSON-files, so there is no existing content to change language for, only configuration.

I updated and renamed these configuration files, to change from English to Danish:

sed -i "s|langcode: en|langcode: da|g" *.yml
sed -i "s|en: ''|da: ''|g" language.negotiation.yml
mv language.entity.en.yml language.entity.da.yml
sed -i "s|id: en|id: da|g" language.entity.da.yml 
sed -i "s|label: English|label: Dansk|g" language.entity.da.yml

I then installed a fresh instance of Drupal in Danish, importing the config:

drush site:install minimal --config-dir=../assets/config --locale=da -y

I installed the language modules, to allow adding English language, as an additional language:

drush install content_translation locale config_translation

Before finding this method, I tried to create Danish language, set it as default, and delete English. But in the exported config files, there were still many lingering langcode: en strings in the config files (maybe ~50?), so I thought it better to switch all instances manually. It seems to work well, so far ...

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

namisha jadhav’s picture

StatusFileSize
new1.36 KB

The below patch worked for me.

namisha jadhav’s picture

StatusFileSize
new1.63 KB

Please ignore the above patch and check this patch as this patch also covers the translations addition issue.

namisha jadhav’s picture

kumudb made their first commit to this issue’s fork.

kumudb’s picture

Uploading updated fix. Removed the LogicException entirely and syncing
the value silently, which aligns with the original @todo intent now that
#2137801 is resolved. Issue fork: drupal-2443991, MR: !7331.

The `composer validate` failure is a pre-existing issue on Drupal core's
main branch caused by the "main-dev" version string in the internal
metapackage generator. This is not related to the patch in this MR.

Reference: This same failure can be seen on the main branch pipelines.
The code change in ContentEntityBase.php is correct and ready for review.