diff --git a/README.txt b/README.txt
index 562ce31..209b4e5 100644
--- a/README.txt
+++ b/README.txt
@@ -4,8 +4,44 @@ README.txt
Paragraph is a module to create paragraphs in your content.
You can create types(with own display and fields) as paragraph types.
-When you use the Entity Reference Paragraphs widget + Entity Reference selection type on your node/entity, you can select the allowed types, and when using the widget, you can select a paragraph type from the allowed types to use different fields/display per paragraph.
+When you use the Entity Reference Paragraphs widget + Entity Reference selection
+type on your node/entity, you can select the allowed types, and when using the
+widget, you can select a paragraph type from the allowed types to use
+different fields/display per paragraph.
* Different fields per paragraph type
* Using different paragraph types in a single paragraph field
* Displays per paragraph type
+
+CONFIGURATION
+-------------
+ * Enable the Paragraph module.
+
+ * Add new languages for the translation in Configuration » Languages.
+
+ * Enable any custom content type with a paragraph field to be translatable in
+ Configuration » Content language
+ and translation:
+
+ - Under Custom language settings check Content.
+
+ - Under Content check the content type with a paragraph field.
+
+ - Make sure that the content type with a paragraph field is set to NOT
+ translatable.
+
+ - Set the fields of each paragraph type to translatable as required.
+
+ * Check Paragraphs as the embedded reference in Configuration » Translation
+ Management settings.
+
+ * Create a new content - Paragraphed article and translate it.
+
+
+LIMITATION
+-------------
+For now, this module does not support switching entity reference revision field
+of the paragraph itself into multilingual mode. This would raise complexity
+significantly.
+Check #2461695: Support translatable paragraph entity reference revision field
+(https://www.drupal.org/node/2461695).
diff --git a/modules/paragraphs_demo/config/install/core.entity_form_display.node.paragraphed_content_demo.default.yml b/modules/paragraphs_demo/config/install/core.entity_form_display.node.paragraphed_content_demo.default.yml
index 315b72d..dc94f0c 100644
--- a/modules/paragraphs_demo/config/install/core.entity_form_display.node.paragraphed_content_demo.default.yml
+++ b/modules/paragraphs_demo/config/install/core.entity_form_display.node.paragraphed_content_demo.default.yml
@@ -6,7 +6,6 @@ dependencies:
- node.type.paragraphed_content_demo
module:
- paragraphs
- - path
id: node.paragraphed_content_demo.default
targetEntityType: node
bundle: paragraphed_content_demo
@@ -35,11 +34,6 @@ content:
add_mode: dropdown
form_display_mode: default
third_party_settings: { }
- path:
- type: path
- weight: 30
- settings: { }
- third_party_settings: { }
promote:
type: boolean_checkbox
weight: 15
diff --git a/modules/paragraphs_demo/config/install/node.type.paragraphed_content_demo.yml b/modules/paragraphs_demo/config/install/node.type.paragraphed_content_demo.yml
index 73462f0..2a71756 100644
--- a/modules/paragraphs_demo/config/install/node.type.paragraphed_content_demo.yml
+++ b/modules/paragraphs_demo/config/install/node.type.paragraphed_content_demo.yml
@@ -1,13 +1,7 @@
langcode: en
status: true
-dependencies:
- module:
- - menu_ui
-third_party_settings:
- menu_ui:
- available_menus:
- - main
- parent: 'main:'
+dependencies: { }
+third_party_settings: { }
name: 'Paragraphed article'
type: paragraphed_content_demo
description: 'Article with paragraphs.'
diff --git a/modules/paragraphs_demo/paragraphs_demo.info.yml b/modules/paragraphs_demo/paragraphs_demo.info.yml
index d3c907d..5282294 100644
--- a/modules/paragraphs_demo/paragraphs_demo.info.yml
+++ b/modules/paragraphs_demo/paragraphs_demo.info.yml
@@ -2,6 +2,11 @@ description: Demo module for paragraphs.
core: 8.x
dependencies:
- paragraphs
+ - field
+ - image
+ - field_ui
+ - entity_reference
+ - block
hidden: false
name: Paragraphs demo
package: paragraphs
diff --git a/paragraphs.routing.yml b/paragraphs.routing.yml
index e255d5e..e892a22 100644
--- a/paragraphs.routing.yml
+++ b/paragraphs.routing.yml
@@ -28,4 +28,4 @@ entity.paragraphs_type.delete_form:
_entity_form: 'paragraphs_type.delete'
_title: 'Delete'
requirements:
- _permission: 'administer paragraphs types'
\ No newline at end of file
+ _permission: 'administer paragraphs types'
diff --git a/src/Entity/Paragraph.php b/src/Entity/Paragraph.php
index 7be72a5..a463ed0 100644
--- a/src/Entity/Paragraph.php
+++ b/src/Entity/Paragraph.php
@@ -47,6 +47,7 @@ use Drupal\user\UserInterface;
* bundle_entity_type = "paragraphs_type",
* field_ui_base_route = "entity.paragraphs_type.edit_form",
* common_reference_revisions_target = TRUE,
+ * content_translation_ui_skip = TRUE,
* default_reference_revision_settings = {
* "field_storage_config" = {
* "cardinality" = -1,
diff --git a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
index 7debd12..f935440 100644
--- a/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
+++ b/src/Plugin/Field/FieldWidget/InlineParagraphsWidget.php
@@ -201,6 +201,10 @@ class InlineParagraphsWidget extends WidgetBase {
}
if ($paragraphs_entity) {
+
+ // Initiate the paragraph with the correct translation.
+ $paragraphs_entity = $paragraphs_entity->getTranslation($this->getCurrentLangcode($form_state, $items));
+
$element_parents = $parents;
$element_parents[] = $field_name;
$element_parents[] = $delta;
@@ -275,6 +279,7 @@ class InlineParagraphsWidget extends WidgetBase {
);
}
+ $button_access = $paragraphs_entity->access('delete') && $paragraphs_entity->language()->getId() == $paragraphs_entity->getUntranslated()->language()->getId();
$links['remove_button'] = array(
'#type' => 'submit',
'#value' => t('Remove'),
@@ -288,7 +293,7 @@ class InlineParagraphsWidget extends WidgetBase {
'wrapper' => $widget_state['ajax_wrapper_id'],
'effect' => 'fade',
),
- '#access' => $paragraphs_entity->access('delete'),
+ '#access' => $button_access,
'#prefix' => '
',
'#suffix' => '',
);
@@ -711,9 +716,11 @@ class InlineParagraphsWidget extends WidgetBase {
// Add 'add more' button, if not working with a programmed form.
if (($real_item_count < $cardinality || $cardinality == FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED) && !$form_state->isProgrammed()) {
+ $add_more_access = $this->getCurrentLangcode($form_state, $items) == $items->getEntity()->getUntranslated()->language()->getId();
$elements['add_more'] = array(
'#type' => 'container',
'#theme_wrappers' => array('paragraphs_dropbutton_wrapper'),
+ '#access' => $add_more_access,
);
if (count($access_options)) {
@@ -816,6 +823,21 @@ class InlineParagraphsWidget extends WidgetBase {
}
/**
+ * Gets current language code from the form state or item.
+ *
+ * Since the paragraph field is not set as translatable, the item language
+ * code is set to the source language. The intended translation language
+ * is only accessibly through the form state.
+ *
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * @param \Drupal\Core\Field\FieldItemListInterface $items
+ * @return string
+ */
+ protected function getCurrentLangcode(FormStateInterface $form_state, FieldItemListInterface $items) {
+ return $form_state->get('langcode') ?: $items->getEntity()->language()->getId();
+ }
+
+ /**
* {@inheritdoc}
*/
public static function addMoreAjax(array $form, FormStateInterface $form_state) {
diff --git a/src/Tests/ParagraphsTranslationTest.php b/src/Tests/ParagraphsTranslationTest.php
new file mode 100644
index 0000000..4448a79
--- /dev/null
+++ b/src/Tests/ParagraphsTranslationTest.php
@@ -0,0 +1,156 @@
+save();
+ $language = ConfigurableLanguage::createFromLangcode('fr');
+ $language->save();
+ }
+
+ /**
+ * Tests the paragraph translation.
+ */
+ public function testParagraphTranslation() {
+ $admin_user = $this->drupalCreateUser(array(
+ 'administer site configuration',
+ 'administer nodes',
+ 'create paragraphed_content_demo content',
+ 'edit any paragraphed_content_demo content',
+ 'delete any paragraphed_content_demo content',
+ 'administer content translation',
+ 'translate any entity',
+ 'create content translations',
+ 'administer languages',
+ ));
+
+ $this->drupalLogin($admin_user);
+
+ $this->drupalGet('admin/config/regional/content-language');
+
+ // Enable translation for paragraphs and it's bundles.
+ $edit = array(
+ 'entity_types[node]' => TRUE,
+ 'entity_types[paragraph]' => TRUE,
+ 'settings[paragraph][images][translatable]' => TRUE,
+ 'settings[paragraph][image_text][translatable]' => TRUE,
+ 'settings[node][paragraphed_content_demo][settings][language][language_alterable]' => TRUE,
+ 'settings[paragraph][user][translatable]' => TRUE,
+ 'settings[paragraph][text_image][translatable]' => TRUE,
+ 'settings[paragraph][text_image][fields][field_text_demo]' => TRUE,
+ 'settings[node][paragraphed_content_demo][translatable]' => TRUE,
+ 'settings[node][paragraphed_content_demo][fields][title]' => TRUE,
+ 'settings[node][paragraphed_content_demo][fields][uid]' => TRUE,
+ 'settings[node][paragraphed_content_demo][fields][status]' => TRUE,
+ 'settings[node][paragraphed_content_demo][fields][created]' => TRUE,
+ 'settings[node][paragraphed_content_demo][fields][changed]' => TRUE,
+ 'settings[node][paragraphed_content_demo][fields][promote]' => TRUE,
+ 'settings[node][paragraphed_content_demo][fields][sticky]' => TRUE,
+ 'settings[node][paragraphed_content_demo][fields][revision_log]' => TRUE,
+ );
+ $this->drupalPostForm(NULL, $edit, t('Save configuration'));
+
+ // Clear cached bundles refer 2450251.
+ \Drupal::entityManager()->clearCachedBundles();
+
+ // Check the settings are saved correctly.
+ // @todo Uncomment these lines once core is fixed https://www.drupal.org/node/2449457
+ // https://www.drupal.org/node/2473721
+ // $this->assertFieldChecked('edit-entity-types-paragraph');
+ $this->assertFieldChecked('edit-settings-node-paragraphed-content-demo-translatable');
+ // $this->assertFieldChecked('edit-settings-paragraph-text-image-translatable');
+
+ // Add paragraphed content.
+ $this->drupalGet('node/add/paragraphed_content_demo');
+ $this->drupalPostForm(NULL, NULL, t('Add Text + Image'));
+ $edit = array(
+ 'title[0][value]' => 'Title in english',
+ 'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Text in english',
+ );
+ // The button to remove a paragraph is present.
+ $this->assertRaw(t('Remove'));
+ $this->drupalPostForm(NULL, $edit, t('Save and publish'));
+ $node = $this->drupalGetNodeByTitle('Title in english');
+ // The text is present when editing again.
+ $this->clickLink(t('Edit'));
+ $this->assertText('Title in english');
+ $this->assertText('Text in english');
+
+ // Add french translation.
+ $this->clickLink(t('Translate'));
+ $this->clickLink(t('Add'));
+ // Make sure the Add / Remove paragraph buttons are hidden.
+ $this->assertNoRaw(t('Remove'));
+ $this->assertNoRaw(t('Add Text + Image'));
+ $edit = array(
+ 'title[0][value]' => 'Title in french',
+ 'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'Text in french',
+ );
+ $this->drupalPostForm(NULL, $edit, t('Save and keep published (this translation)'));
+
+ // Check the english translation.
+ $this->drupalGet('node/' . $node->id());
+ $this->assertText('Title in english');
+ $this->assertText('Text in english');
+ $this->assertNoText('Title in french');
+ $this->assertNoText('Text in french');
+
+ // Check the french translation.
+ $this->drupalGet('fr/node/' . $node->id());
+ $this->assertText('Title in french');
+ $this->assertText('Text in french');
+ $this->assertNoText('Title in english');
+ // The translation is still present when editing again.
+ $this->clickLink(t('Edit'));
+ $this->assertText('Title in french');
+ $this->assertText('Text in french');
+ $edit = array(
+ 'field_paragraphs_demo[0][subform][field_text_demo][0][value]' => 'New text in french',
+ );
+ $this->drupalPostForm(NULL, $edit, t('Save and keep published (this translation)'));
+ $this->assertText('Title in french');
+ $this->assertText('New text in french');
+
+ // Back to the source language.
+ $this->drupalGet('node/' . $node->id());
+ $this->clickLink(t('Edit'));
+ $this->assertText('Title in english');
+ $this->assertText('Text in english');
+ }
+}