diff --git a/src/Controller/LingotekEntityController.php b/src/Controller/LingotekEntityController.php index 997f9f4..2c25131 100644 --- a/src/Controller/LingotekEntityController.php +++ b/src/Controller/LingotekEntityController.php @@ -30,7 +30,7 @@ class LingotekEntityController extends LingotekControllerBase { } } catch (LingotekApiException $exception) { - drupal_set_message(t('The check for @entity_type status failed. Please try again.', array('@entity_type' => $entity->getEntityTypeId(), '%title' => $entity->label())), 'error'); + drupal_set_message(t('The check for @entity_type %title status failed. Please try again.', array('@entity_type' => $entity->getEntityTypeId(), '%title' => $entity->label())), 'error'); } return $this->translationsPageRedirect($entity); diff --git a/src/LingotekContentTranslationService.php b/src/LingotekContentTranslationService.php index b8d6216..615eb4e 100644 --- a/src/LingotekContentTranslationService.php +++ b/src/LingotekContentTranslationService.php @@ -675,6 +675,13 @@ class LingotekContentTranslationService implements LingotekContentTranslationSer $langcode = $drupal_language->id(); try { $data = $this->lingotek->downloadDocument($document_id, $locale); + foreach ($data as &$item) { + for ($i = 0; $i < count($item); $i++) { + if (isset($item[$i]['value'])) { + $item[$i]['value'] = html_entity_decode($item[$i]['value']); + } + } + } } catch (LingotekApiException $exception) { // TODO: log issue diff --git a/tests/src/Functional/LingotekNodeMultivaluedFieldTest.php b/tests/src/Functional/LingotekNodeMultivaluedFieldTest.php index 0f62f48..d0f2a06 100644 --- a/tests/src/Functional/LingotekNodeMultivaluedFieldTest.php +++ b/tests/src/Functional/LingotekNodeMultivaluedFieldTest.php @@ -9,6 +9,8 @@ use Drupal\field\Entity\FieldStorageConfig; use Drupal\language\Entity\ConfigurableLanguage; use Drupal\language\Entity\ContentLanguageSettings; use Drupal\node\Entity\Node; +use Drupal\Component\Utility\Html; +use Drupal\Component\Utility\SafeMarkup; /** * Tests translating a node including multivalued fields. @@ -221,6 +223,140 @@ class LingotekNodeMultivaluedFieldTest extends LingotekTestBase { $this->assertText('Las llamas son muy chulas con distinto campo 4'); $this->assertText('Las llamas son muy chulas con distinto campo 5'); $this->assertText('Las llamas son muy chulas con distinto campo 6'); + } + /** + * Tests node translation with multivalued fields and quotation marks. + */ + public function testMultivaluedFieldsQuotations() { + // Login as admin. + $this->drupalLogin($this->rootUser); + + $this->drupalGet('node/add/article'); + + // Create a node. + $edit = []; + $edit['title[0][value]'] = '"Llamas are cool"'; + $edit['body[0][value]'] = '"Llamas are very cool"'; + $edit['foo[0][value]'] = '"Llamas are very cool field 1"'; + $edit['foo[1][value]'] = '"Llamas are very cool field 2"'; + $edit['foo[2][value]'] = '"Llamas are very cool field 3"'; + $edit['langcode[0][value]'] = 'en'; + + // Ensure we added the two new values in the form. + $this->submitForm([], 'Add another item'); + $this->submitForm([], 'Add another item'); + + $this->saveAndPublishNodeForm($edit, NULL); + + $this->node = Node::load(1); + + // Check that only the translatable fields have been uploaded. + $data = json_decode(\Drupal::state()->get('lingotek.uploaded_content', '[]'), TRUE); + $this->verbose(var_export($data, TRUE)); + + $this->assertIdentical($data['foo'][0]['value'], '"Llamas are very cool field 1"'); + $this->assertIdentical($data['foo'][1]['value'], '"Llamas are very cool field 2"'); + $this->assertIdentical($data['foo'][2]['value'], '"Llamas are very cool field 3"'); + + $this->goToContentBulkManagementForm(); + + // There is a link for checking status. + $this->clickLink('EN'); + $this->myassertText('The import for node "Llamas are cool" is complete.'); + + // Request the Spanish translation. + $this->clickLink('ES'); + $this->myassertText(Html::escape("Locale 'es_MX' was added as a translation target for node \"Llamas are cool\" .")); + $this->assertIdentical('es_MX', \Drupal::state()->get('lingotek.added_target_locale')); + + // Check status of the Spanish translation. + $this->clickLink('ES'); + $this->assertIdentical('es_MX', \Drupal::state()->get('lingotek.checked_target_locale')); + $this->myassertText('The es_MX translation for node "Llamas are cool" is ready for download.'); + + // This is a hack for avoiding writing different lingotek endpoint mocks. + \Drupal::state()->set('lingotek.uploaded_content_type', 'node+multivalue0'); + + // Download the Spanish translation. + $this->clickLink('ES'); + $this->myassertText('The translation of node "Llamas are cool" into es_MX has been downloaded.'); + + $this->clickLink('"Llamas are cool"'); + $this->clickLink('Translate'); + $this->clickLink('"las llamas son chulas"'); + + $this->assertNoText('"las llamas son muy chulas campo 1"'); + $this->assertNoText('"las llamas son muy chulas campo 2"'); + $this->assertNoText('"las llamas son muy chulas campo 3"'); + + // This is a hack for avoiding writing different lingotek endpoint mocks. + \Drupal::state()->set('lingotek.uploaded_content_type', 'node+multivalue1'); + + // We re-download, now with different values for the multivalued field. + $this->goToContentBulkManagementForm(); + + $edit = [ + 'table[1]' => TRUE, + 'operation' => 'download:es', + ]; + $this->drupalPostForm(NULL, $edit, t('Execute')); + $this->assertIdentical('es_MX', \Drupal::state()->get('lingotek.downloaded_locale')); + + $this->clickLink('"Llamas are cool"'); + $this->clickLink('Translate'); + $this->clickLink('"las llamas son chulas'); + $this->myassertText('"las llamas son muy chulas campo 1"'); + $this->myassertText('"las llamas son muy chulas campo 2"'); + $this->myassertText('"las llamas son muy chulas campo 3"'); + + // This is a hack for avoiding writing different lingotek endpoint mocks. + \Drupal::state()->set('lingotek.uploaded_content_type', 'node+multivalue2'); + + // We re-download, now with different values for the multivalued field. + $this->goToContentBulkManagementForm(); + + $edit = [ + 'table[1]' => TRUE, + 'operation' => 'download:es', + ]; + $this->drupalPostForm(NULL, $edit, t('Execute')); + $this->assertIdentical('es_MX', \Drupal::state()->get('lingotek.downloaded_locale')); + + $this->clickLink('"Llamas are cool"'); + $this->clickLink('Translate'); + $this->clickLink('"las llamas son chulas"'); + + $this->myassertText('"las llamas son muy chulas campo 1"'); + $this->myassertText('"las llamas son muy chulas con distinto campo 2"'); + $this->assertNoText('"las llamas son muy chulas campo 3"'); + + // This is a hack for avoiding writing different lingotek endpoint mocks. + \Drupal::state()->set('lingotek.uploaded_content_type', 'node+multivalue3'); + + // We re-download, now with different values for the multivalued field. + $this->goToContentBulkManagementForm(); + + $edit = [ + 'table[1]' => TRUE, + 'operation' => 'download:es', + ]; + $this->drupalPostForm(NULL, $edit, t('Execute')); + $this->assertIdentical('es_MX', \Drupal::state()->get('lingotek.downloaded_locale')); + + $this->clickLink('"Llamas are cool"'); + $this->clickLink('Translate'); + $this->clickLink('"las llamas son chulas"'); + + $this->myassertText('"las llamas son muy chulas campo 1"'); + $this->myassertText('"las llamas son muy chulas con distinto campo 2"'); + $this->myassertText('"las llamas son muy chulas con distinto campo 3"'); + $this->myassertText('"las llamas son muy chulas con distinto campo 4"'); + $this->myassertText('"las llamas son muy chulas con distinto campo 5"'); + $this->myassertText('"las llamas son muy chulas con distinto campo 6"'); } -} + protected function myassertText($text, $message = "%s", $group = 'Other') { + $text = Html::escape($text); + return parent::assertText($text, $message, $group); + } +} \ No newline at end of file