diff --git a/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/core/lib/Drupal/Core/Entity/ContentEntityBase.php index 177a495..ce01f24 100644 --- a/core/lib/Drupal/Core/Entity/ContentEntityBase.php +++ b/core/lib/Drupal/Core/Entity/ContentEntityBase.php @@ -154,10 +154,10 @@ public function __construct(array $values, $entity_type, $bundle = FALSE, $trans // original language. $data = array('status' => static::TRANSLATION_EXISTING); $this->translations[Language::LANGCODE_DEFAULT] = $data; + $this->initializeDefaultLanguage(); if ($translations) { - $default_langcode = $this->language()->id; foreach ($translations as $langcode) { - if ($langcode != $default_langcode && $langcode != Language::LANGCODE_DEFAULT) { + if ($langcode != $this->language->id && $langcode != Language::LANGCODE_DEFAULT) { $this->translations[$langcode] = $data; } } @@ -399,7 +399,8 @@ protected function getTranslatedField($property_name, $langcode) { } // Non-translatable fields are always stored with // Language::LANGCODE_DEFAULT as key. - if ($langcode != Language::LANGCODE_DEFAULT && empty($definition['translatable'])) { + $default = $langcode == Language::LANGCODE_DEFAULT; + if (!$default && empty($definition['translatable'])) { if (!isset($this->fields[$property_name][Language::LANGCODE_DEFAULT])) { $this->fields[$property_name][Language::LANGCODE_DEFAULT] = $this->getTranslatedField($property_name, Language::LANGCODE_DEFAULT); } @@ -411,7 +412,14 @@ protected function getTranslatedField($property_name, $langcode) { $value = $this->values[$property_name][$langcode]; } $field = \Drupal::typedData()->getPropertyInstance($this, $property_name, $value); - $field->setLangcode($langcode); + if (!$default) { + $field->setLangcode($langcode); + } + // If we are initializing the default language cache, the variable is + // not populated, thus we have no valid value to set. + elseif (isset($this->language)) { + $field->setLangcode($this->language->id); + } $this->fields[$property_name][$langcode] = $field; } } @@ -531,17 +539,17 @@ public function language() { return $this->languages[$this->activeLangcode]; } else { - return $this->language ?: $this->getDefaultLanguage(); + return $this->language; } } /** - * Returns the entity original language. + * Initializes the entity original language local cache. * * @return \Drupal\Core\Language\Language * A language object. */ - protected function getDefaultLanguage() { + protected function initializeDefaultLanguage() { // Keep a local cache of the language object and clear it if the langcode // gets changed, see ContentEntityBase::onChange(). if (!isset($this->language)) { @@ -565,6 +573,7 @@ public function onChange($property_name) { // Avoid using unset as this unnecessarily triggers magic methods later // on. $this->language = NULL; + $this->initializeDefaultLanguage(); } } @@ -576,11 +585,8 @@ public function onChange($property_name) { public function getTranslation($langcode) { // Ensure we always use the default language code when dealing with the // original entity language. - if ($langcode != Language::LANGCODE_DEFAULT) { - $default_language = $this->language ?: $this->getDefaultLanguage(); - if ($langcode == $default_language->id) { - $langcode = Language::LANGCODE_DEFAULT; - } + if ($langcode != Language::LANGCODE_DEFAULT && $langcode == $this->language->id) { + $langcode = Language::LANGCODE_DEFAULT; } // Populate entity translation object cache so it will be available for all @@ -607,7 +613,7 @@ public function getTranslation($langcode) { // If the entity or the requested language is not a configured // language, we fall back to the entity itself, since in this case it // cannot have translations. - $translation = empty($this->getDefaultLanguage()->locked) && empty($languages[$langcode]->locked) ? $this->addTranslation($langcode) : $this; + $translation = empty($this->language->locked) && empty($languages[$langcode]->locked) ? $this->addTranslation($langcode) : $this; } } } @@ -667,8 +673,7 @@ protected function initializeTranslation($langcode) { * {@inheritdoc} */ public function hasTranslation($langcode) { - $default_language = $this->language ?: $this->getDefaultLanguage(); - if ($langcode == $default_language->id) { + if ($langcode == $this->language->id) { $langcode = Language::LANGCODE_DEFAULT; } return !empty($this->translations[$langcode]['status']); @@ -715,7 +720,7 @@ public function addTranslation($langcode, array $values = array()) { * {@inheritdoc} */ public function removeTranslation($langcode) { - if (isset($this->translations[$langcode]) && $langcode != Language::LANGCODE_DEFAULT && $langcode != $this->getDefaultLanguage()->id) { + if (isset($this->translations[$langcode]) && $langcode != Language::LANGCODE_DEFAULT && $langcode != $this->language->id) { foreach ($this->getPropertyDefinitions() as $name => $definition) { if (!empty($definition['translatable'])) { unset($this->values[$name][$langcode]); @@ -734,7 +739,7 @@ public function removeTranslation($langcode) { * {@inheritdoc} */ public function initTranslation($langcode) { - if ($langcode != Language::LANGCODE_DEFAULT && $langcode != $this->getDefaultLanguage()->id) { + if ($langcode != Language::LANGCODE_DEFAULT && $langcode != $this->language->id) { $this->translations[$langcode]['status'] = static::TRANSLATION_EXISTING; } } @@ -747,8 +752,7 @@ public function getTranslationLanguages($include_default = TRUE) { unset($translations[Language::LANGCODE_DEFAULT]); if ($include_default) { - $langcode = $this->getDefaultLanguage()->id; - $translations[$langcode] = TRUE; + $translations[$this->language->id] = TRUE; } // Now load language objects based upon translation langcodes. @@ -908,10 +912,7 @@ public function __clone() { // original reference and re-creating its values. $this->clearTranslationCache(); $translations = $this->translations; - unset($this->translations); - // This will trigger the magic setter as the translations array is - // undefined now. - $this->translations = $translations; + $this->translations = &$translations; } } diff --git a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php index 5497efb..d56176a 100644 --- a/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php +++ b/core/lib/Drupal/Core/Entity/FieldableDatabaseStorageController.php @@ -325,7 +325,7 @@ protected function attachPropertyData(array &$entities, $revision_id = FALSE) { // Get the revision IDs. $revision_ids = array(); foreach ($entities as $values) { - $revision_ids[] = $values[$this->revisionKey]; + $revision_ids[] = $values[$this->revisionKey][Language::LANGCODE_DEFAULT]; } $query->condition($this->revisionKey, $revision_ids); } diff --git a/core/lib/Drupal/Core/Field/FieldItemList.php b/core/lib/Drupal/Core/Field/FieldItemList.php index 00dcaba..da50ce1 100644 --- a/core/lib/Drupal/Core/Field/FieldItemList.php +++ b/core/lib/Drupal/Core/Field/FieldItemList.php @@ -39,7 +39,7 @@ class FieldItemList extends ItemList implements FieldItemListInterface { * * @var string */ - protected $langcode = Language::LANGCODE_DEFAULT; + protected $langcode = Language::LANGCODE_NOT_SPECIFIED; /** * Overrides TypedData::__construct(). diff --git a/core/lib/Drupal/Core/Language/Language.php b/core/lib/Drupal/Core/Language/Language.php index 7181b32..2f2dc54 100644 --- a/core/lib/Drupal/Core/Language/Language.php +++ b/core/lib/Drupal/Core/Language/Language.php @@ -59,11 +59,8 @@ class Language { /** * Language code referring to the default language of data, e.g. of an entity. - * - * @todo: Change value to differ from Language::LANGCODE_NOT_SPECIFIED once - * field API leverages the property API. */ - const LANGCODE_DEFAULT = 'und'; + const LANGCODE_DEFAULT = 'xx-default'; /** * The language state when referring to configurable languages. diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php index e2b0d4f..03f4df0 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityTranslationTest.php @@ -118,7 +118,7 @@ protected function _testEntityLanguageMethods($entity_type) { // Get the value. $field = $entity->getTranslation(Language::LANGCODE_DEFAULT)->get($this->field_name); $this->assertEqual($field->value, 'default value', format_string('%entity_type: Untranslated value retrieved.', array('%entity_type' => $entity_type))); - $this->assertEqual($field->getLangcode(), Language::LANGCODE_DEFAULT, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type))); + $this->assertEqual($field->getLangcode(), Language::LANGCODE_NOT_SPECIFIED, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type))); // Set the value in a certain language. As the entity is not // language-specific it should use the default language and so ignore the @@ -131,7 +131,7 @@ protected function _testEntityLanguageMethods($entity_type) { // language-specific entity. $field = $entity->getTranslation($this->langcodes[1])->get($this->field_name); $this->assertEqual($field->value, 'default value2', format_string('%entity_type: Untranslated value retrieved.', array('%entity_type' => $entity_type))); - $this->assertEqual($field->getLangcode(), Language::LANGCODE_DEFAULT, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type))); + $this->assertEqual($field->getLangcode(), Language::LANGCODE_NOT_SPECIFIED, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type))); // Now, make the entity language-specific by assigning a language and test // translating it. @@ -145,7 +145,7 @@ protected function _testEntityLanguageMethods($entity_type) { // Get the value. $field = $entity->get($this->field_name); $this->assertEqual($field->value, 'default value', format_string('%entity_type: Untranslated value retrieved.', array('%entity_type' => $entity_type))); - $this->assertEqual($field->getLangcode(), Language::LANGCODE_DEFAULT, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type))); + $this->assertEqual($field->getLangcode(), Language::LANGCODE_NOT_SPECIFIED, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type))); // Set a translation. $entity->getTranslation($this->langcodes[1])->set($this->field_name, array(0 => array('value' => 'translation 1'))); @@ -156,7 +156,7 @@ protected function _testEntityLanguageMethods($entity_type) { // Make sure the untranslated value stays. $field = $entity->get($this->field_name); $this->assertEqual($field->value, 'default value', 'Untranslated value stays.'); - $this->assertEqual($field->getLangcode(), Language::LANGCODE_DEFAULT, 'Untranslated value has the expected langcode.'); + $this->assertEqual($field->getLangcode(), Language::LANGCODE_NOT_SPECIFIED, 'Untranslated value has the expected langcode.'); $translations[$this->langcodes[1]] = language_load($this->langcodes[1]); $this->assertEqual($entity->getTranslationLanguages(FALSE), $translations, 'Translations retrieved.'); @@ -188,7 +188,7 @@ protected function _testEntityLanguageMethods($entity_type) { // Get the value. $field = $entity->get($field_name); $this->assertEqual($field->value, 'default value2', format_string('%entity_type: Untranslated value set into a translation in non-strict mode.', array('%entity_type' => $entity_type))); - $this->assertEqual($field->getLangcode(), Language::LANGCODE_DEFAULT, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type))); + $this->assertEqual($field->getLangcode(), Language::LANGCODE_NOT_SPECIFIED, format_string('%entity_type: Field object has the expected langcode.', array('%entity_type' => $entity_type))); } /** @@ -217,20 +217,19 @@ protected function _testMultilingualProperties($entity_type) { $entity = entity_create($entity_type, array('name' => $name, 'user_id' => $uid)); $entity->save(); $entity = entity_load($entity_type, $entity->id()); - $this->assertEqual($entity->language()->id, Language::LANGCODE_NOT_SPECIFIED, format_string('%entity_type: Entity created as language neutral.', array('%entity_type' => $entity_type))); + $default_langcode = $entity->language()->id; + $this->assertEqual($default_langcode, Language::LANGCODE_NOT_SPECIFIED, format_string('%entity_type: Entity created as language neutral.', array('%entity_type' => $entity_type))); $field = $entity->getTranslation(Language::LANGCODE_DEFAULT)->get('name'); $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name has been correctly stored as language neutral.', array('%entity_type' => $entity_type))); - $this->assertEqual(Language::LANGCODE_DEFAULT, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); + $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); $this->assertEqual($uid, $entity->getTranslation(Language::LANGCODE_DEFAULT)->get('user_id')->target_id, format_string('%entity_type: The entity author has been correctly stored as language neutral.', array('%entity_type' => $entity_type))); - // As fields, translatable properties should ignore the given langcode and - // use neutral language if the entity is not translatable. $field = $entity->getTranslation($langcode)->get('name'); $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name defaults to neutral language.', array('%entity_type' => $entity_type))); - $this->assertEqual(Language::LANGCODE_DEFAULT, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); + $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->target_id, format_string('%entity_type: The entity author defaults to neutral language.', array('%entity_type' => $entity_type))); $field = $entity->get('name'); $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name can be retrieved without specifying a language.', array('%entity_type' => $entity_type))); - $this->assertEqual(Language::LANGCODE_DEFAULT, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); + $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); $this->assertEqual($uid, $entity->get('user_id')->target_id, format_string('%entity_type: The entity author can be retrieved without specifying a language.', array('%entity_type' => $entity_type))); // Create a language-aware entity and check that properties are stored @@ -238,20 +237,21 @@ protected function _testMultilingualProperties($entity_type) { $entity = entity_create($entity_type, array('name' => $name, 'user_id' => $uid, 'langcode' => $langcode)); $entity->save(); $entity = entity_load($entity_type, $entity->id()); - $this->assertEqual($entity->language()->id, $langcode, format_string('%entity_type: Entity created as language specific.', array('%entity_type' => $entity_type))); + $default_langcode = $entity->language()->id; + $this->assertEqual($default_langcode, $langcode, format_string('%entity_type: Entity created as language specific.', array('%entity_type' => $entity_type))); $field = $entity->getTranslation($langcode)->get('name'); $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name has been correctly stored as a language-aware property.', array('%entity_type' => $entity_type))); - $this->assertEqual(Language::LANGCODE_NOT_SPECIFIED, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); + $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); $this->assertEqual($uid, $entity->getTranslation($langcode)->get('user_id')->target_id, format_string('%entity_type: The entity author has been correctly stored as a language-aware property.', array('%entity_type' => $entity_type))); // Translatable properties on a translatable entity should use default // language if Language::LANGCODE_NOT_SPECIFIED is passed. $field = $entity->getTranslation(Language::LANGCODE_NOT_SPECIFIED)->get('name'); $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name defaults to the default language.', array('%entity_type' => $entity_type))); - $this->assertEqual(Language::LANGCODE_NOT_SPECIFIED, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); + $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); $this->assertEqual($uid, $entity->getTranslation(Language::LANGCODE_NOT_SPECIFIED)->get('user_id')->target_id, format_string('%entity_type: The entity author defaults to the default language.', array('%entity_type' => $entity_type))); $field = $entity->get('name'); $this->assertEqual($name, $field->value, format_string('%entity_type: The entity name can be retrieved without specifying a language.', array('%entity_type' => $entity_type))); - $this->assertEqual(Language::LANGCODE_NOT_SPECIFIED, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); + $this->assertEqual($default_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expect langcode.', array('%entity_type' => $entity_type))); $this->assertEqual($uid, $entity->get('user_id')->target_id, format_string('%entity_type: The entity author can be retrieved without specifying a language.', array('%entity_type' => $entity_type))); // Create property translations. @@ -283,8 +283,7 @@ protected function _testMultilingualProperties($entity_type) { ); $field = $entity->getTranslation($langcode)->get('name'); $this->assertEqual($properties[$langcode]['name'][0], $field->value, format_string('%entity_type: The entity name has been correctly stored for language %langcode.', $args)); - // Fields for the default entity langcode are seen as language neutral. - $field_langcode = ($langcode == $entity->language()->id) ? Language::LANGCODE_NOT_SPECIFIED : $langcode; + $field_langcode = ($langcode == $entity->language()->id) ? $default_langcode : $langcode; $this->assertEqual($field_langcode, $field->getLangcode(), format_string('%entity_type: The field object has the expected langcode %langcode.', $args)); $this->assertEqual($properties[$langcode]['user_id'][0], $entity->getTranslation($langcode)->get('user_id')->target_id, format_string('%entity_type: The entity author has been correctly stored for language %langcode.', $args)); } @@ -480,6 +479,9 @@ function testEntityTranslationAPI() { $cloned = clone $entity; $translation = $cloned->getTranslation($langcode); $this->assertNotIdentical($entity, $translation->getUntranslated(), 'A cloned entity object has no reference to the original one.'); + $entity->removeTranslation($langcode); + $this->assertFalse($entity->hasTranslation($langcode)); + $this->assertTrue($cloned->hasTranslation($langcode)); // Check that per-language defaults are properly populated. $entity = $this->reloadEntity($entity); diff --git a/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php b/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php index 0b47055..49d9f78 100644 --- a/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php +++ b/core/modules/text/lib/Drupal/text/Tests/TextWithSummaryItemTest.php @@ -128,7 +128,7 @@ function testProcessedCache() { $entity = entity_load($entity_type, $entity->id()); $cache = cache('field')->get("field:$entity_type:" . $entity->id()); $this->assertEqual($cache->data, array( - Language::LANGCODE_DEFAULT => array( + Language::LANGCODE_NOT_SPECIFIED => array( 'summary_field' => array( 0 => array( 'value' => $value, @@ -144,7 +144,7 @@ function testProcessedCache() { // Inject fake processed values into the cache to make sure that these are // used as-is and not re-calculated when the entity is loaded. $data = array( - Language::LANGCODE_DEFAULT => array( + Language::LANGCODE_NOT_SPECIFIED => array( 'summary_field' => array( 0 => array( 'value' => $value,