diff --git a/core/modules/content_translation/content_translation.module b/core/modules/content_translation/content_translation.module
index 661aac9..02e395e 100644
--- a/core/modules/content_translation/content_translation.module
+++ b/core/modules/content_translation/content_translation.module
@@ -154,6 +154,63 @@ function content_translation_entity_field_info_alter(&$info, $entity_type) {
}
/**
+ * Implements hook_entity_field_info().
+ */
+function content_translation_entity_field_info($entity_type) {
+ if (content_translation_enabled($entity_type)) {
+ $info = array();
+
+ $info['definitions']['translation_source'] = array(
+ 'label' => t('Translation source'),
+ 'description' => t('The source language from which this translation was created.'),
+ 'type' => 'field_item:language',
+ );
+
+ $info['definitions']['translation_outdated'] = array(
+ 'label' => t('Translation outdated'),
+ 'description' => t('A boolean indicating whether this translation needs to be updated.'),
+ 'type' => 'field_item:boolean',
+ );
+
+ $info['definitions']['translation_uid'] = array(
+ 'label' => t('Translation author id'),
+ 'description' => t('The author of this translation.'),
+ 'type' => 'field_item:entity_reference',
+ 'settings' => array(
+ 'target_type' => 'user',
+ 'default_value' => 0,
+ ),
+ );
+
+ $info['definitions']['translation_status'] = array(
+ 'label' => t('Translation status'),
+ 'description' => t('Boolean indicating whether the translation is visible to non-translators.'),
+ 'type' => 'field_item:boolean',
+ 'settings' => array(
+ 'default_value' => 1,
+ ),
+ );
+
+ $info['definitions']['translation_created'] = array(
+ 'label' => t('Translation created time'),
+ 'description' => t('The Unix timestamp when the translation was created.'),
+ 'type' => 'field_item:integer',
+ );
+
+ $info['definitions']['translation_changed'] = array(
+ 'label' => t('Translation changed time'),
+ 'description' => t('The Unix timestamp when the translation was most recently saved.'),
+ 'type' => 'field_item:integer',
+ 'property_constraints' => array(
+ 'value' => array('EntityChanged' => array()),
+ ),
+ );
+
+ return $info;
+ }
+}
+
+/**
* Implements hook_menu().
*/
function content_translation_menu() {
@@ -313,7 +370,7 @@ function content_translation_translate_access(EntityInterface $entity) {
*/
function content_translation_view_access(EntityInterface $entity, $langcode, AccountInterface $account = NULL) {
$entity_type = $entity->entityType();
- return !empty($entity->translation[$langcode]['status']) || user_access('translate any entity', $account) || user_access("translate $entity_type entities", $account);
+ return !empty($entity->getTranslation($langcode)->translation_status->value) || user_access('translate any entity', $account) || user_access("translate $entity_type entities", $account);
}
/**
@@ -648,13 +705,13 @@ function content_translation_field_language_alter(&$display_language, $context)
$entity = $context['entity'];
$entity_type = $entity->entityType();
- if ($entity instanceof ContentEntityInterface && isset($entity->translation[$context['langcode']]) && $entity->isTranslatable() && !content_translation_view_access($entity, $context['langcode'])) {
+ if ($entity instanceof ContentEntityInterface && $entity->isTranslatable() && !content_translation_view_access($entity, $context['langcode'])) {
$instances = field_info_instances($entity_type, $entity->bundle());
// Avoid altering the real entity.
$entity = clone($entity);
$entity_langcode = $entity->getUntranslated()->language()->id;
- foreach ($entity->translation as $langcode => $translation) {
+ foreach ($entity->getTranslationLanguages() as $langcode => $language) {
if ($langcode == $context['langcode'] || !content_translation_view_access($entity, $langcode)) {
$entity->removeTranslation($langcode);
}
@@ -696,16 +753,23 @@ function content_translation_load_translation_metadata(array $entities, $entity_
$query = 'SELECT * FROM {content_translation} te WHERE te.entity_type = :entity_type AND te.entity_id IN (:entity_id)';
$result = db_query($query, array(':entity_type' => $entity_type, ':entity_id' => array_keys($entities)));
$exclude = array('entity_type', 'entity_id', 'langcode');
+
foreach ($result as $record) {
$entity = $entities[$record->entity_id];
- // @todo Declare these as entity (translation?) properties.
- foreach ($record as $field_name => $value) {
- if (!in_array($field_name, $exclude)) {
+ foreach ($record as $key => $value) {
+ if (!in_array($key, $exclude)) {
$langcode = $record->langcode;
- $entity->translation[$langcode][$field_name] = $value;
if (!$entity->hasTranslation($langcode)) {
$entity->initTranslation($langcode);
}
+ $name = 'translation_' . $key;
+ $item = $entity->getTranslation($langcode)->get($name);
+ if ($key != 'uid') {
+ $item->value = $value;
+ }
+ else {
+ $item->target_id = $value;
+ }
}
}
}
@@ -724,9 +788,19 @@ function content_translation_entity_insert(EntityInterface $entity) {
$query = db_insert('content_translation')->fields($fields);
foreach ($entity->getTranslationLanguages() as $langcode => $language) {
- $translation = isset($entity->translation[$langcode]) ? $entity->translation[$langcode] : array();
+ $translation = $entity->getTranslation($langcode);
+ $definitions = $entity->getPropertyDefinitions();
- $translation += array(
+ $values = array();
+ foreach ($fields as $key) {
+ $name = 'translation_' . $key;
+ if (isset($definitions[$name])) {
+ $item = $translation->get($name);
+ $values[$key] = $key != 'uid' ? $item->value : $item->target_id;
+ }
+ }
+
+ $values += array(
'source' => '',
'uid' => $GLOBALS['user']->id(),
'outdated' => FALSE,
@@ -735,17 +809,16 @@ function content_translation_entity_insert(EntityInterface $entity) {
'changed' => REQUEST_TIME,
);
- $translation['entity_type'] = $entity->entityType();
- $translation['entity_id'] = $entity->id();
- $translation['langcode'] = $langcode;
+ $values['entity_type'] = $entity->entityType();
+ $values['entity_id'] = $entity->id();
+ $values['langcode'] = $langcode;
// Reorder values to match the schema.
- $values = array();
- foreach ($fields as $field_name) {
- $value = is_bool($translation[$field_name]) ? intval($translation[$field_name]) : $translation[$field_name];
- $values[$field_name] = $value;
+ $record = array();
+ foreach ($fields as $key) {
+ $record[$key] = is_bool($values[$name]) ? intval($values[$name]) : $values[$name];
}
- $query->values($values);
+ $query->values($record);
}
$query->execute();
diff --git a/core/modules/content_translation/content_translation.pages.inc b/core/modules/content_translation/content_translation.pages.inc
index f64599f..e7bf9ba 100644
--- a/core/modules/content_translation/content_translation.pages.inc
+++ b/core/modules/content_translation/content_translation.pages.inc
@@ -66,7 +66,8 @@ function content_translation_overview(EntityInterface $entity) {
if (isset($translations[$langcode])) {
// Existing translation in the translation set: display status.
- $source = isset($entity->translation[$langcode]['source']) ? $entity->translation[$langcode]['source'] : '';
+ $translation = $entity->getTranslation($langcode);
+ $source = isset($translation->translation_source) ? $translation->translation_source->value : '';
$is_original = $langcode == $original;
$label = $entity->getTranslation($langcode)->label();
$link = isset($links->links[$langcode]['href']) ? $links->links[$langcode] : array('href' => $path, 'language' => $language);
@@ -90,10 +91,9 @@ function content_translation_overview(EntityInterface $entity) {
$links['edit']['title'] = t('Edit');
}
- $translation = $entity->translation[$langcode];
- $status = !empty($translation['status']) ? t('Published') : t('Not published');
+ $status = !empty($translation->translation_status->value) ? t('Published') : t('Not published');
// @todo Add a theming function here.
- $status = '' . $status . '' . (!empty($translation['outdated']) ? ' ' . t('outdated') . '' : '');
+ $status = '' . $status . '' . (!empty($translation->translation_outdated->value) ? ' ' . t('outdated') . '' : '');
if ($is_original) {
$language_name = t('@language_name (Original language)', array('@language_name' => $language_name));
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php
index c499806..ec4ad21 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationController.php
@@ -49,7 +49,7 @@ public function retranslate(EntityInterface $entity, $langcode = NULL) {
$updated_langcode = !empty($langcode) ? $langcode : $entity->language()->id;
$translations = $entity->getTranslationLanguages();
foreach ($translations as $langcode => $language) {
- $entity->translation[$langcode]['outdated'] = $langcode != $updated_langcode;
+ $entity->getTranslation($langcode)->translation_outdated->value = $langcode != $updated_langcode;
}
}
@@ -212,7 +212,7 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac
);
// A new translation is enabled by default.
- $status = $new_translation || $entity->translation[$form_langcode]['status'];
+ $status = $new_translation || $entity->translation_status->value;
// If there is only one published translation we cannot unpublish it,
// since there would be nothing left to display.
$enabled = TRUE;
@@ -220,8 +220,8 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac
// A new translation is not available in the translation metadata, hence
// it should count as one more.
$published = $new_translation;
- foreach ($entity->translation as $translation) {
- $published += $translation['status'];
+ foreach ($entity->getTranslationLanguages() as $langcode => $language) {
+ $published += $entity->getTranslation($langcode)->translation_status->value;
}
$enabled = $published > 1;
}
@@ -237,7 +237,7 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac
'#disabled' => !$enabled,
);
- $translate = !$new_translation && $entity->translation[$form_langcode]['outdated'];
+ $translate = !$new_translation && $entity->translation_outdated->value;
if (!$translate) {
$form['content_translation']['retranslate'] = array(
'#type' => 'checkbox',
@@ -255,7 +255,7 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac
);
}
- $name = $new_translation ? $GLOBALS['user']->getUsername() : user_load($entity->translation[$form_langcode]['uid'])->getUsername();
+ $name = $new_translation ? $GLOBALS['user']->getUsername() : $entity->translation_uid->entity->getUsername();
$form['content_translation']['name'] = array(
'#type' => 'textfield',
'#title' => t('Authored by'),
@@ -265,7 +265,7 @@ public function entityFormAlter(array &$form, array &$form_state, EntityInterfac
'#description' => t('Leave blank for %anonymous.', array('%anonymous' => \Drupal::config('user.settings')->get('anonymous'))),
);
- $date = $new_translation ? REQUEST_TIME : $entity->translation[$form_langcode]['created'];
+ $date = $new_translation ? REQUEST_TIME : $entity->translation_created->value;
$form['content_translation']['created'] = array(
'#type' => 'textfield',
'#title' => t('Authored on'),
@@ -387,30 +387,24 @@ protected function addTranslatabilityClue(&$element) {
public function entityFormEntityBuild($entity_type, EntityInterface $entity, array $form, array &$form_state) {
$form_controller = content_translation_form_controller($form_state);
$form_langcode = $form_controller->getFormLangcode($form_state);
-
- if (!isset($entity->translation[$form_langcode])) {
- $entity->translation[$form_langcode] = array();
- }
$values = isset($form_state['values']['content_translation']) ? $form_state['values']['content_translation'] : array();
- $translation = &$entity->translation[$form_langcode];
- // @todo Use the entity setter when all entities support multilingual
- // properties.
- $translation['uid'] = !empty($values['name']) && ($account = user_load_by_name($values['name'])) ? $account->id() : 0;
- $translation['status'] = !empty($values['status']);
- $translation['created'] = !empty($values['created']) ? strtotime($values['created']) : REQUEST_TIME;
- $translation['changed'] = REQUEST_TIME;
+ $entity->translation_uid->target_id = !empty($values['name']) && ($account = user_load_by_name($values['name'])) ? $account->id() : 0;
+ $entity->translation_status->value = !empty($values['status']);
+ $entity->translation_created->value = !empty($values['created']) ? strtotime($values['created']) : REQUEST_TIME;
+ $entity->translation_changed->value = REQUEST_TIME;
$source_langcode = $this->getSourceLangcode($form_state);
if ($source_langcode) {
- $translation['source'] = $source_langcode;
+ $entity->translation_source->value = $source_langcode;
}
- $translation['outdated'] = !empty($values['outdated']);
+ $entity->translation_outdated->value = !empty($values['outdated']);
if (!empty($values['retranslate'])) {
$this->retranslate($entity, $form_langcode);
}
+ // TODO
// Set contextual information that can be reused during the storage phase.
// @todo Remove this once translation metadata are converted to regular
// fields.
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
index 21c8465..1b532de 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationUITest.php
@@ -142,7 +142,7 @@ protected function assertOutdatedStatus() {
$this->drupalGet($path);
$this->assertFieldByXPath('//input[@name="content_translation[retranslate]"]', FALSE, 'The retranslate flag is now shown.');
$entity = entity_load($this->entityType, $this->entityId, TRUE);
- $this->assertFalse($entity->translation[$enabled_langcode]['outdated'], 'The "outdated" status has been correctly stored.');
+ $this->assertFalse($entity->getTranslation($enabled_langcode)->translation_outdated->value, 'The "outdated" status has been correctly stored.');
}
}
}
@@ -160,7 +160,7 @@ protected function assertPublishedStatus() {
$edit = array('content_translation[status]' => FALSE);
$this->drupalPostForm($langcode . '/' . $path, $edit, $this->getFormSubmitAction($entity));
$entity = entity_load($this->entityType, $this->entityId, TRUE);
- $this->assertFalse($entity->translation[$langcode]['status'], 'The translation has been correctly unpublished.');
+ $this->assertFalse($entity->getTranslation($langcode)->translation_status->value, 'The translation has been correctly unpublished.');
}
}
@@ -194,8 +194,9 @@ protected function assertAuthoringInfo() {
$entity = entity_load($this->entityType, $this->entityId, TRUE);
foreach ($this->langcodes as $langcode) {
- $this->assertEqual($entity->translation[$langcode]['uid'] == $values[$langcode]['uid'], 'Translation author correctly stored.');
- $this->assertEqual($entity->translation[$langcode]['created'] == $values[$langcode]['created'], 'Translation date correctly stored.');
+ $translation = $entity->getTranslation($langcode);
+ $this->assertEqual($translation->translation_uid->target_id == $values[$langcode]['uid'], 'Translation author correctly stored.');
+ $this->assertEqual($translation->translation_created->value == $values[$langcode]['created'], 'Translation date correctly stored.');
}
// Try to post non valid values and check that they are rejected.
@@ -207,8 +208,9 @@ protected function assertAuthoringInfo() {
);
$this->drupalPostForm($path, $edit, $this->getFormSubmitAction($entity));
$this->assertTrue($this->xpath('//div[contains(@class, "error")]//ul'), 'Invalid values generate a list of form errors.');
- $this->assertEqual($entity->translation[$langcode]['uid'] == $values[$langcode]['uid'], 'Translation author correctly kept.');
- $this->assertEqual($entity->translation[$langcode]['created'] == $values[$langcode]['created'], 'Translation date correctly kept.');
+ $translation = $entity->getTranslation($langcode);
+ $this->assertEqual($translation->translation_uid->target_id == $values[$langcode]['uid'], 'Translation author correctly kept.');
+ $this->assertEqual($translation->translation_created->value == $values[$langcode]['created'], 'Translation date correctly kept.');
}
/**
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
index 6a2608c..31915cc 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTranslationUITest.php
@@ -96,7 +96,7 @@ protected function assertPublishedStatus() {
// The node is created as unpulished thus we switch to the published
// status first.
$status = !$index;
- $this->assertEqual($status, $entity->translation[$langcode]['status'], 'The translation has been correctly unpublished.');
+ $this->assertEqual($status, $entity->getTranslation($langcode)->translation_status->value, 'The translation has been correctly unpublished.');
}
}
}
@@ -127,8 +127,9 @@ protected function assertAuthoringInfo() {
$entity = entity_load($this->entityType, $this->entityId, TRUE);
foreach ($this->langcodes as $langcode) {
- $this->assertEqual($entity->translation[$langcode]['uid'] == $values[$langcode]['uid'], 'Translation author correctly stored.');
- $this->assertEqual($entity->translation[$langcode]['created'] == $values[$langcode]['created'], 'Translation date correctly stored.');
+ $translation = $entity->getTranslation($langcode);
+ $this->assertEqual($translation->translation_uid->target_id == $values[$langcode]['uid'], 'Translation author correctly stored.');
+ $this->assertEqual($translation->translation_created->value == $values[$langcode]['created'], 'Translation date correctly stored.');
}
}