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
| Comment | File | Size | Author |
|---|---|---|---|
| #50 | fix-default-langcode-throw-2443991_2.patch | 1.63 KB | namisha jadhav |
Issue fork drupal-2443991
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
Comment #1
plachComment #2
hchonovWhy is the default_langcode considered as read-only?
Consider the following use case:
At the moment we are not able to do this.
Comment #3
mkalkbrennerI 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.
Comment #4
plachThis 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_langcodefield 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.Comment #5
plachComment #6
plachComment #7
berdirThis 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.
Comment #8
mkalkbrenner@plach: Could you explain, why a change of this field has to be handled differently from a change of any other field?
Comment #9
plachBecause 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_DEFAULTto 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.Comment #11
mikeryanLast 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.
Comment #15
beltofteAny updates to this issue?
Anyone patched Drupal core to get this working or implemented a custom solution?
Comment #18
acontia commentedWhat's the current status of this? Did anyone manage to get this working?
Comment #19
berdirMy 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.
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.
Comment #20
acontia commentedFollowing Berdir's recommendations I have written this function, that seems to work for me:
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:
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"?
Comment #21
acontia commentedAfter 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.
Comment #22
ytsurkThanks for sharing code!
Comment #23
ytsurkComment #24
geek-merlinThe issue referenced in the IS is fixed for quite some time now. I think the IS should be updated for that.
Comment #25
hchonovI 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.
Comment #26
omessaoudi commentedThank 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)
Comment #27
Deno commentedCurrent 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.
Comment #28
vuilComment #29
matsbla commentedOne related issue:
#3005641: Exception is thrown on changing "Site language" setting of a user if user account is translated
Comment #31
wim leersPer #11.
Comment #32
proweb.ua commented#26
Error: Call to undefined function db_query() in include() (line 38.. switch-default-language.php
Drupal 9
php 8
Comment #33
bessonweb commentedI 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 :
Somebody have an explanation?
Comment #35
ludostation commented#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.
Comment #36
bessonweb commentedOh ! Sorry, it's possible I forgot to change this!
Thanks!
Comment #40
sascha_meissnerIn 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"
Comment #41
wim leers— @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 😊
Comment #42
berdir@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.
Comment #43
wim leersMea culpa — I thought it was about a
default_langcodesetting in someField(Storage)Config. 🙈That being said … exactly the same validation approach will be usable here AFAICT? 😊 That'd be:
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?
Comment #44
wim leers#3373653: Add a `langcode` data type to config schema landed. Per #43, AFAICT that should still help this issue! 😊
Comment #47
ressaEDIT: 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:
I then installed a fresh instance of Drupal in Danish, importing the config:
drush site:install minimal --config-dir=../assets/config --locale=da -yI installed the language modules, to allow adding English language, as an additional language:
drush install content_translation locale config_translationBefore 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: enstrings in the config files (maybe ~50?), so I thought it better to switch all instances manually. It seems to work well, so far ...Comment #49
namisha jadhav commentedThe below patch worked for me.
Comment #50
namisha jadhav commentedPlease ignore the above patch and check this patch as this patch also covers the translations addition issue.
Comment #51
namisha jadhav commentedComment #53
kumudbUploading 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.