Summary
When an entity:
- is translatable
- is under content moderation
- contains a paragraph field
when that entity is translated, the translated paragraph entity will have a content_translation_source value of und
.
This is the same issue that was looked at in
#2597201 Translation source language is not set β
, but it currently only manifests when the parent entity is under content moderation.
Analysis
In
#2597201 β
, code was added that set the correct translation source language on paragraph translations: Initialise the translation with source language values.
This code was later also included in the 'Experimental' ParagraphsWidget.php. This is the code that sets translation source in ParagraphsWidget.php.
However, this only applies if the paragraph translation doesn't already exist, according to this code. If the paragraph translation already exists, the source is not set on the paragraph translation.
When Content Moderation is enabled, its entityPrepareForm
call clones the parent entity, including the referenced paragraphs. When this happens, the newly created translation of the paragraph has a source language of und
rather than the true source language.
Then, when the processing of the form element happens, as linked above, the content_translation_source is not corrected, because the translation already exists. This leads to failures like the ones identified in #2597201.
I would note that I only observe this when I create a translation via the content_translation_add
form. If I create a translation via code, for example via TMGMT, the resulting translation's paragraphs have the correct content_translation_source values even if the parent is subject to moderation.
Potential solutions
My naive solution would be to set content_translation_source on the $paragraph_entity
translation, regardless of whether the translation already existed or not. However, this may have consequences I don't foresee.
Setup to repro
1. Set up Drupal with the following packages
"drupal/core": "^8.6.0",
"drupal/paragraphs": "1.9"
with a clean standard site install.
2. Enable:
- Content translation
- Content moderation
- Paragraphs
3. Add any two languages. I used Spanish & Swedish, but it doesn't matter.
4. Create two simple paragraphs, called textpara
and imagepara
, each with a single field:
- One with a short plaintext field
- One with an image field
5. Make each of these two paragraph entities translatable, keeping default settings for the fields (in particular, for the image field, File is not translatable, Alt & Title are translatable).
6. Create two node types, moderated_node
and not_moderated_node
. They can be simple, but they should each have a paragraph field that can accept both of the paragraphs types created in 5. They should be translatable, and the language selector should be visible.
7. Create a Content Moderation workflow if necessary, and then apply it to the moderated_node
entity type. Do not apply to the not_moderated_node
type.
Steps to reproduce
Unmoderated node, text paragraph (working case)
- Create a default language
not_moderated_node
with a textpara
paragraph. Save.
- Click translate; add a translation to another language (es), and save.
Expected behavior
- The translation should save successfully.
- If you examine the database, in table paragraphs_item_field_data, you should see two instances of
textpara
, with the following langcode
/content_translation_source
pairs:
Actual behavior
Matches expected behavior.
Unmoderated node, image paragraph (working case)
- Create a default language
not_moderated_node
with a imagepara
paragraph. Save.
- Click translate; add a translation to another language (es), and save.
Expected behavior
- The translation should save successfully.
- If you examine the database, in table paragraphs_item_field_data, you should see two instances of
imagepara
, with the following langcode
/content_translation_source
pairs:
Actual behavior
Matches expected behavior.
Moderated node, text paragraph (failing case)
- Create a default language
moderated_node
with a textpara
paragraph. Save.
- Click translate; add a translation to another language (es), and save.
Expected behavior
- The translation should save successfully.
- If you examine the database, in table paragraphs_item_field_data, you should see two instances of
textpara
, with the following langcode
/content_translation_source
pairs:
Actual behavior
- The translation does save successfully.
- If you examine the database, in table paragraphs_item_field_data, you will see two instances of
textpara
, with the following langcode
/content_translation_source
pairs:
- en / und
- es / und (incorrect)
Moderated node, image paragraph (failing case)
- Create a default language
moderated_node
with a imagepara
paragraph. Save.
- Click translate; add a translation to another language (es), and save.
Expected behavior
- The translation should save successfully.
- If you examine the database, in table paragraphs_item_field_data, you should see two instances of
imagepara
, with the following langcode
/content_translation_source
pairs:
Actual behavior
- Attempting to save throws a fatal error with the "Invalid translation language (und) specified" error.
- No paragraph is created.
Moderated node, text paragraph, non-default source language (failing case)
- Create a non-default
moderated_node
(es) with a textpara
paragraph. Save.
- Click translate; add a translation to another language (sv), and save.
Expected behavior
- The translation should save successfully.
- If you examine the database, in table paragraphs_item_field_data, you should see two instances of
textpara
, with the following langcode
/content_translation_source
pairs:
Actual behavior
- The translation does save successfully.
- If you examine the database, in table paragraphs_item_field_data, you will see two instances of
textpara
, with the following langcode
/content_translation_source
pairs:
- es / und
- sv / und (incorrect)