Hi guys,

I create a patch to make the translate feature of i18n working.

My patch depend of replicate & replicate_paragraph.

You can see it here:

Index: sites/all/modules/contrib/paragraphs/paragraphs.info
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- sites/all/modules/contrib/paragraphs/paragraphs.info	(revision 32de12b3ca2aa39f4fcc154352d66cbeb64e6b5e)
+++ sites/all/modules/contrib/paragraphs/paragraphs.info	(revision )
@@ -3,6 +3,8 @@
 core = 7.x
 
 dependencies[] = entity
+dependencies[] = replicate
+dependencies[] = replicate_paragraphs
 
 files[] = ParagraphsItemEntity.inc
 files[] = ParagraphsItemMetadataController.inc
Index: sites/all/modules/contrib/paragraphs/paragraphs.module
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- sites/all/modules/contrib/paragraphs/paragraphs.module	(revision 32de12b3ca2aa39f4fcc154352d66cbeb64e6b5e)
+++ sites/all/modules/contrib/paragraphs/paragraphs.module	(revision )
@@ -345,6 +345,12 @@
           $entity->setHostEntity($host_entity_type, $host_entity, $langcode, FALSE);
         }
 
+        if ($host_entity->nid == NULL) {
+            $new_entity = replicate_clone_entity('paragraphs_item', $entity);
+            $new_entity->setHostEntity($host_entity_type, $host_entity, $langcode, FALSE);
+            $entity = $new_entity;
+        }
+
         // If the host entity is saved as new revision, do the same for the item.
         if (!empty($host_entity->revision)) {
           $entity->revision = TRUE;
@@ -888,21 +894,5 @@
         }
       }
     }
-  }
-}
-
-/**
- * Implements hook_field_prepare_translation().
- *
- * @see field_attach_prepare_translation()
- */
-function paragraphs_field_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items, $source_entity, $source_langcode) {
-  list($id, , ) = entity_extract_ids($entity_type, $entity);
-
-  // field_attach_prepare_translation() copied the entity ids from the source,
-  // as we need a new entity for a new translation, we cannot reuse that.
-  // @todo clone existing paragraphs to new translation
-  if (empty($id)) {
-    $items = array();
   }
 }
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

killerpoke’s picture

FileSize
749 bytes

Hey!

Your patch works fine for attaching paragraphs only to nodes. However if you attach a paragraph field to any other entity (in my situation a paragraph field on a paragraph field) the field data gets lost on save. This is because of you only checking the nid of the host_entity but there are entities with another key.

To solve this, a wrote a little patch to patch your one.

xiaodoudou’s picture

Indeed that was an issue.

I will do more test to validate your solution then we could submit it to the repo.

Thanks anyway :)

xiaodoudou’s picture

Status: Active » Needs review

Status: Needs review » Needs work

The last submitted patch, 1: i18n_patch2.patch, failed testing.

xiaodoudou’s picture

Assigned: Unassigned » xiaodoudou
Status: Needs work » Needs review
FileSize
3.73 KB

Find in attachment another implementation as a sub module.

The new key feature of this implementation that now the nested paragraphs are also duplicated.

Status: Needs review » Needs work

The last submitted patch, 5: paragraph_i18n_v1.0.patch, failed testing.

xiaodoudou’s picture

FileSize
3.65 KB

Changed the patch return line format to unix style.

xiaodoudou’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 7: paragraph_i18n_v1.1.patch, failed testing.

xiaodoudou’s picture

Status: Needs work » Needs review
FileSize
3.37 KB

Change patch path.

Status: Needs review » Needs work

The last submitted patch, 10: paragraph_i18n_v1.2.patch, failed testing.

xiaodoudou’s picture

FileSize
3.27 KB

Path patch again... (Note to myself: Never use again phpstorm for creating patch :D)

xiaodoudou’s picture

Status: Needs work » Needs review
jeroen.b’s picture

Thanks for the patch, looks good!
Committed to dev, please test!

jeroen.b’s picture

Status: Needs review » Postponed (maintainer needs more info)
jeroen.b’s picture

Status: Postponed (maintainer needs more info) » Fixed
eigentor’s picture

This seems to work. I installed the last Dev version. Paragraphs attached to nodes get cloned correctly and can be translated. I did not test nested Paragraphs, though.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

ciss’s picture

Status: Closed (fixed) » Needs work

This patch has a major problem: hook_field_prepare_translation() gets invoked by translation_node_prepare() whenever the form for a new translation is displayed.
This means that a simple reload of the form page is enough to create additional detached paragraphs_item entities that will never be removed from the database.

ciss’s picture

Status: Needs work » Needs review
FileSize
1.56 KB

See attached patch for a fix. I also removed the unnecessary id check.

ciss’s picture

+++ b/modules/paragraphs_i18n/paragraphs_i18n.module
@@ -6,21 +6,11 @@
+      $paragraphs_item_copy->setHostEntity($entity_type, $source_entity, $langcode, FALSE);

I still have some issues with this line. Should we even set a host entity at this point?

ciss’s picture

FileSize
1.42 KB

The answer is no.

The last submitted patch, 21: paragraphs-i18n_duplicate-2331273-21.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 23: paragraphs-i18n_duplicate-2331273-23.patch, failed testing.

ciss’s picture

The test failures are unrelated to the patch: https://qa.drupal.org/pifr/test/668608

ciss’s picture

Status: Needs work » Needs review
FileSize
3.39 KB

OK, here we go. This patch should be as clean as it gets. We're now properly using replicate_paragraphs, and paragraphs_i18n only exists to provide a dependency to replicate_paragraphs. Tested for nested paragraphs items.

Expect the patch to fail, as the tests on the 7.x-1.x branch haven't been fixed yet.

ciss’s picture

Assigned: xiaodoudou » Unassigned
seanB’s picture

I already posted a comment to #2152931 but it seems to make sense to post it here as well.

In the field_collection module there was a similar problem, they fixed it without having to rely on the replicate module:
http://cgit.drupalcode.org/field_collection/commit/?id=1972527

I don't have time to test this now, but it might be worth checking if the paragraphs module can solve it in the same way.

recrit’s picture

The attached patch provides native support similar to field_collection's method using hook_field_insert to detect the host change. This eliminates the dependency for the replicate modules.

Changes:
* Function paragraphs_field_prepare_translation() is replaced with paragraphs_field_insert() similar to field_collection.
* Removed paragraphs_i18n_field_prepare_translation().

Future considerations:
* I kept the paragraphs_i18n module in case any installs have it as a dependency; however, it has been reduced to a stub module with no functions.
* Tests: A test similar to FieldCollectionContentTranslationTestCase could be created for paragraph items. The original paragraphs and paragraphs_i18n did not have a test so I did not add it to the patch in order to keep it simple. A separate issue could be created for this addition.

Petr Illek’s picture

Hi,
thanks for this effort, is really much appreciated.
I've tested the latest patch against 7.x-1.0-rc4 (as its the most recent release ATM).
And I've found one problem.
Basically there is synchronization between the "source" and "destination" language when adding the translation.

Step to reproduce:
* Have three languages enabled.
* Create new content in first language.
* Translate to second language (paragraphs are pre-filed with first language text –> great)
* Look at first language –> paragraph content is in second language
* Translate the first language to third language (paragraph is pre-filed with second language)
* Look at the first language –> paragraph content is in third language
* Look at the SECOND language –> paragraph content is in SECOND language (no synchronization –> great)
* Edit first language and rewrite it to first
* All paragraphs are now in correct languages and there is no more synchronization

If you need more information, I will do my best to provide them.

recrit’s picture

@Petr Illek
I cannot reproduce that issue which makes sense since the paragraphs_field_insert() creates a new paragraph item (not a revision of the original).
Can you provide a list of modules that you have enabled? i18n_sync, node clone, etc... Trying to eliminate any other module that could alter the field value.

seanB’s picture

Status: Needs review » Reviewed & tested by the community

Finally did a multilang project again. Patch in #30 worked perfectly. As stated before I think this is the way to go.
Marking as RTBC.

botelho’s picture

Hi, i've replicate_paragraphs because i need it for paragraphs_defaults, and its conflicting with this patch.

it gives me an error cant find "paragraphs_item_load_multiple" function.

When i turn paragraphs_defaults and replicate_paragraphs off everything work just fine.

Thanks

rv0’s picture

@botelho
That's a weird error, paragraphs_item_load_multiple is part of paragraphs.module and should always be available.
http://cgit.drupalcode.org/paragraphs/tree/paragraphs.module

bmx269’s picture

Thanks for this patch. What is needed to make it work on nested paragraphs, aka paragraphs inside paragraphs? Thanks

drupal_beast’s picture

Patch # 30 worked for me.

ngocketit’s picture

I have the same problem with field data synchronization of the source and the translation. This happens only when adding a new translation. The source field is updated with value of the translation.

ngocketit’s picture

This seems to happen only when the paragraph field is nested inside, for example, a field collection or another paragraph field.

ngocketit’s picture

So the issue is exactly the same as what @@Petr Illek has. It happens when a paragraph item is attached, for example, to another paragraph item or a field collection item. I believe in that case, we still need to keep the field_prepare_translation hook implementation.

ngocketit’s picture

So I managed to get it work, not with the patch #30 but #27. Like I said earlier, #30 works only if paragraph item is not attached to another paragraph item or a field collection. If it's attached to a paragraph item, #27 works well. In case it's attached to a field collection, this patch for field collection won't work, we need something similar to what's is done in replicate_paragraphs module:

 function field_collection_field_prepare_translation($entity_type, $entity, $field, $instance, $langcode, &$items, $source_entity, $source_langcode) {
  if(module_exists('replicate')) {
    replicate_field_collection_items($entity, $entity_type, $field['field_name'], $langcode);
    $items = $entity->{$field['field_name']}[$langcode];
  }
}

function replicate_field_collection_items(&$entity, $entity_type, $field_name, $language = LANGUAGE_NONE) {
  // Reset the field_language static.
  // If we don't, the language returned by field_language()
  // is FALSE, resulting in de metadata-wrapper (or field_get_items())
  // to get a FALSE / an empty array,
  // which means that the fields in it won't be cloned.
  drupal_static_reset('field_language');

  $entity_wrapper = entity_metadata_wrapper($entity_type, $entity);
  $old_items = $entity_wrapper->{$field_name}->value();
  if (is_null($old_items)) {
    $old_items = array();
  }
  elseif (!is_array($old_items)) {
    $old_items = array($old_items);
  }

  // Clean the previous entities from the field, so the new
  // can be saved instead.
  unset($entity->{$field_name}[$language]);

  foreach ($old_items as $old_item) {
    if (!empty($old_item)) {
      $old_item->item_id = NULL;
      $new_item = replicate_clone_entity('field_collection_item', $old_item);
      $new_item->setHostEntity($entity_type, $entity);
      // Don't save the new paragraphs,
      // it will be saved along with the host entity.
    }
  }
}
danilo_formagio’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
2.34 KB

I noticed that when adding a translation to a node without saving it, orphan paragraphs are generated and the field's table contains empty references to paragraphs items (in the field_***_value column).

When you click on "add a translation" in a node translate tab without saving it, all the paragraphs are persisted in the database and the field data, but the node is persisted only when clicking on save button.

Steps:
- Click to add a translation for a node that contains paragraphs.
- Don't click on save button.
- Close this tab on the browser or go to another page without saving this translation.
- Check in the database that there are paragraphs in the "paragraphs_item" table are not referenced in the paragraph field's table.

The attached patch fixes the issue above, the translation is working fine, including for nested paragraphs, also there is no synchronization issue between the "source" and "destination" that was commented on #31.

Basically the change was:

- Remove the code $current_entity->save(TRUE); from paragraphs_i18n_field_prepare_translation.
It was saving the paragraph when translating a node before click on save button, creating orphan paragraphs.

- Change the code

$news_items[] = array(
  'value' => $current_entity->item_id,
  'revision_id' => $current_entity->revision_id,
);

to

$news_items[] = array(
  'entity' => $current_entity,
);

It will replicate the paragraph to the new translated node.
Using the 'entity' key, the paragraph items are stored in memory instead of having to save them to the database and referencing them by its id. This solves the issue mentioned above.

The are other changes in the patch but they are related to coding standards.

Thanks @nbouhid for the help.

ciss’s picture

@danilo_formagio This issue already has two patches (#27, #30) that fix the behavior you describe. Is your patch an update to either of those? If not, please make sure to read the past comments before posting a completely new patch.

ciss’s picture

Due to a lack of feedback I'm assuming that #42 ignored the previous work done in this issue. Hiding #42 to avoid confusion.
Please review either the patch in #27 or #30 (the latter removes the dependency on replicate).

Current reviews:

There are other reviews that I could not associate with a particular patch. You may want to revisit those as well.

When reviewing or updating a patch please specify which patch you are referring to.

danilo_formagio’s picture

Sorry for the late reply.

#42 It is not an update for #27 or #30, it's a different way to solve it, it's a simple change, but it also has dependency with replicate module.

I tested the other patches with nested paragraphs:

#27 - It is working fine for me.
I would suggest just to check if $entity->{$field['field_name']} is set before use it, I saw some notices about undefined index "und" when translating a node with the paragraph field empty in another project, but testing with a clean Drupal I could not reproduce this message anymore.

#30 - I have the same problem with field data synchronization commented on #31.

@ciss feel free to proceed with patch #27.