Use Case:
As a content producer I would like to be able to schedule moderation state changes for translations so that I can update translations automatically without impacting the original node or other translations.

Issue:
After a fresh install and configuration of the translation modules with one language, I am unable to schedule different update times for the various translations. Once I schedule an update for the original english version, it is inherited by the translation. If I edit the scheduled update date/time on the translation, it updates the date/time in the original english node.

It does not appear that the scheduler fields on a content type are translatable.

Steps to Reproduce:
- Fresh install of 8.x-2.03
- Enable translation related modules
- Add Spanish Language
- Configure translations for all fields in Content -> Basic Page
- Create new basic page in English
- Save as Draft
- Translate page into Spanish
- Save Draft
- Edit english to schedule update
- Save Draft
- Edit Spanish version
- Schedule update is already populated with English version settings (ISSUE)
- Edit update date/time to something else
- Save Draft
- Edit English version
- Schedule information is now changed to mirror Spanish translation (ISSUE)

Members fund testing for the Drupal project. Drupal Association Learn more

Comments

tedbow created an issue. See original summary.

bonus’s picture

Priority: Normal » Major
vegantriathlete’s picture

In one environment in which I run multilingual I am noticing that translated pieces of content (which have scheduled update fields) are not creating a separate entry in the node__ table; everything is recorded against the default site langcode. However, in a different environment I am seeing that there are different langcode entries in the table. I have not checked into the difference in the configuration in the two environments.

In the environment in which it appears to be broken, what I've done is to create a Scheduled Update Type that is targeting a specific bundle for a content entity. I'm using the Embedded Runner and haven't changed the Advanced Runner Options.
I create a piece of content and assign it a date.
Then I translate that piece of content.
I expect to see two different entries in the node__ table; I see only one.

vegantriathlete’s picture

I'm not sure if this should be considered related to or a duplicate of #2854988: Schedule Moderation State Updates for Translations. I'll mark it as related for the time being.

Since this one is older, I would think it should stay and the other should be marked as a duplicate. I'll mark the other one as related to this one as well.

vegantriathlete’s picture

I notice that in the Entity definition for scheduled_update it does not use the langcode entity_keys entry nor does it use $fields = parent::baseFieldDefinition($entity_type); inside of the baseFieldDefinitions method. Would it be a good step in the right direction to make those changes to the entity? I'm suggesting that we let ContentEntityBase take care of id, uuid and langcode.

balsama’s picture

We dug into this over in #2854988: Schedule Moderation State Updates for Translations (which I closed as a duplicate). Here is what we found - some if it specific to Lightning's implementation:

Scheduled Updates

  1. Would need a new update runner plugin, or probably better, an update to the existing UpdateRunnerBase that took into consideration the language of the update and loaded the appropriate translation of the given entity.
  2. Allow update entities to be translatable. Right now, translation is specifically set to false.

And the from the configuration (Lightning) side:

Configuration (Lightning)

There are two types of Updates:

  1. Updates that are created within the context of an entity where the entity contains a reference to the update
  2. Updates that are created independently which have references to entities to update

For the former, the update field would need to be translatable. Lightning couldn't ship with a translatable field since it doesn't have Content Translation enabled out of the box. But it should be (?) fairly intuitive to the user once the translation->false is removed from Scheduled Updates (would be just like any other field)

For the latter, the update itself would either need to be translated (likely) or the reference to the entity would need to reference a specific language (which I don't think is currently possible).

Entity Reference

It looks like Entity Reference doesn't currently support referencing a specific language. That should be fine, but it causes some weirdness when trying to reference something that is translated. E.g. autocomplete works when typing reference in Language A, but Language B shows up as option.

Considerations

What about users who want to schedule a transition to all languages at once? The update runner would likely need to take that into account (that is, if an untranslated update references a translated entity that == update all languages)

Summary

This is a fair amount of work. There is no current workaround for users who need this functionality and I'm honestly a little surprised that it hasn't come up before. But that fact that it hasn't makes me wonder how much of our limited resources we should throw at it.

vegantriathlete’s picture

Issue summary: View changes

Copy issue summary from 2854988

vbouchet’s picture

Hi,

I initially started to work on https://www.drupal.org/node/2854988 about 3 months ago. As always, I thought I would have time to dive more in the issue but it never happened so I think it is better to take time to share my findings and my work.

First, I added the translation support to the scheduled update entity type.
Then I edited the getEmbeddedUpdates() method to properly store the scheduled update language in the queue item. Previously, it was only storing the entity_id which makes impossible in the queue worker to update the appropriate translation of the given entity.
Finally, I tried to update the BaseUpdateRunner::runUpdate() method to use the language stored in the queue item.

This is where I am stucked. Given a translated entity with a different schedule update for each translation, the proper information are stored in the queue. However, the queue worker is not properly dealing with the data and only one of translation's update is performed, the second one remain in the queue.

Please find a patch with this work. Hope I went in the good direction and it will help solving the issue.

suresh kumara’s picture

I tried #9 but scheduled update is not listing in content translation page.

I reverted the patch and added

 * @ContentEntityType(
  *   id = "scheduled_update",
  *   label = @Translation("Scheduled update"),
+ *   translatable = TRUE,
  *   handlers = {
  *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
  *     "list_builder" = "Drupal\scheduled_updates\ScheduledUpdateListBuilder",
@@ -44,6 +45,7 @@ use Drupal\user\UserInterface;
  *     "id" = "id",
  *     "bundle" = "type",
  *     "label" = "update_timestamp",
+ *     "langcode" = "langcode",
  *     "uuid" = "uuid"
  *   },
  *   links = {
@@ -155,6 +157,7 @@ class ScheduledUpdate extends ContentEntityBase implements ScheduledUpdateInterf
     // @todo Change this field to list_integer so that Views can easily filter by label.
     $fields['status'] = BaseFieldDefinition::create('list_integer')
       ->setLabel(t('Status'))
+      ->setTranslatable(TRUE)
       ->setDescription(t('The status of the update.'))
       ->setDefaultValue(ScheduledUpdateInterface::STATUS_UNRUN)
       ->setDisplayConfigurable('view', TRUE)
@@ -168,6 +171,7 @@ class ScheduledUpdate extends ContentEntityBase implements ScheduledUpdateInterf
 
     $fields['user_id'] = BaseFieldDefinition::create('entity_reference')
       ->setLabel(t('Created by'))
+      ->setTranslatable(TRUE)
       ->setDescription(t('The user ID of author of the Scheduled update entity.'))
       ->setRevisionable(TRUE)
       ->setSetting('target_type', 'user')
@@ -184,14 +188,17 @@ class ScheduledUpdate extends ContentEntityBase implements ScheduledUpdateInterf
 
     $fields['langcode'] = BaseFieldDefinition::create('language')
       ->setLabel(t('Language code'))
+      ->setTranslatable(TRUE)
       ->setDescription(t('The language code for the Scheduled update entity.'));
 
     $fields['created'] = BaseFieldDefinition::create('created')
       ->setLabel(t('Created'))
+      ->setTranslatable(TRUE)
       ->setDescription(t('The time that the entity was created.'));
 
     $fields['changed'] = BaseFieldDefinition::create('changed')
       ->setLabel(t('Changed'))
+      ->setTranslatable(TRUE)
       ->setDescription(t('The time that the entity was last edited.'));
 
     $fields['update_timestamp'] = BaseFieldDefinition::create('timestamp')
@@ -214,6 +221,7 @@ class ScheduledUpdate extends ContentEntityBase implements ScheduledUpdateInterf
 
     $fields['entity_ids'] = BaseFieldDefinition::create('entity_reference')
       ->setLabel(t('Entities to Update'))
+      ->setTranslatable(TRUE)
       ->setDescription(t('The entities that will be updated.'))
       ->setRequired(TRUE)
       ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)

scheduled update listed and content translation enabled successufully.

I made few observation.

1. suppose if we edit german node by default german scheduled update inlined add/edit form should be loaded, but if we have created scheduled update for english content then only german node is showing scheduled update in english, german node supposed to show german scheduled update only.

2. If we try to run scheduled update then below error is occured. Basically we need to change all the queries to get entity and revisions with respect to languauge.

The website encountered an unexpected error. Please try again later.

Drupal\Core\Entity\Query\QueryException: 'update_timestamp' not found in Drupal\Core\Entity\Query\Sql\Tables->ensureEntityTable() (line 316 of core/lib/Drupal/Core/Entity/Query/Sql/Tables.php).

Drupal\Core\Entity\Query\Sql\Tables->addField('update_timestamp', 'INNER', NULL) (Line: 44)
Drupal\Core\Entity\Query\Sql\Condition->compile(Object) (Line: 155)
Drupal\Core\Entity\Query\Sql\Query->compile() (Line: 74)
Drupal\Core\Entity\Query\Sql\Query->execute() (Line: 580)
Drupal\scheduled_updates\Plugin\BaseUpdateRunner->getReadyUpdateIds() (Line: 46)
Drupal\scheduled_updates\Plugin\UpdateRunner\LatestRevisionUpdateRunner->getEntityIdsReferencingReadyUpdates() (Line: 37)
Drupal\scheduled_updates\Plugin\UpdateRunner\EmbeddedUpdateRunner->getEmbeddedUpdates() (Line: 79)
Drupal\scheduled_updates\Plugin\UpdateRunner\EmbeddedUpdateRunner->getAllUpdates() (Line: 125)
Drupal\scheduled_updates\Plugin\BaseUpdateRunner->addUpdatesToQueue() (Line: 131)
Drupal\scheduled_updates\UpdateRunnerUtils->runAllUpdates() (Line: 65)
Drupal\scheduled_updates\Form\UpdateRunnerForm->submitForm(Array, Object)
call_user_func_array(Array, Array) (Line: 111)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array, Object) (Line: 51)
Drupal\Core\Form\FormSubmitter->doSubmitForm(Array, Object) (Line: 585)
Drupal\Core\Form\FormBuilder->processForm('update_runner_form', Array, Object) (Line: 314)
Drupal\Core\Form\FormBuilder->buildForm('update_runner_form', Object) (Line: 74)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 574)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
call_user_func_array(Object, Array) (Line: 144)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 64)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 50)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 656)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)