The current implementations of entity_metadata_field_property_get and entity_metadata_field_verbatim_get both call the entity_metadata_field_get_language function with its $fallback parameter set to TRUE. This causes entity wrappers to fetch field values in the default language if the requested language doesn't have a value which means that it is not possible to have explicitly "no value" for a field in a non-default language. In my opintion, this behavior should be configurable to prevent language fallback.

Attached is a patch that fixes this issue for me by allowing my code to override the wrapper info 'langfallback' with FALSE which then in turn stops the language fallback.

Comments

mfernea’s picture

Status: Active » Needs review
StatusFileSize
new2.4 KB

+1 for @getu-lar patch.
Here is another version if you want to have a different behaviour on the admin UI. Not 100% perfect but it might be useful.

Status: Needs review » Needs work

The last submitted patch, 1: entity-language-fallback-2335357-1.patch, failed testing.

valderama’s picture

Version: 7.x-1.5 » 7.x-1.x-dev
Category: Feature request » Bug report
StatusFileSize
new149.96 KB
new1.87 KB

Entity Translation provides a setting "Enable language fallback" (See attached screenshot) - I propose to use this value. I have attached a patch, which does this.

That way I can disable language fallback - which is the only thing I need to do :)

However, it should be noted that the language fallback logic as it is currently implemented in Entity API differs to how core determines fallback languages for field values to display them. Entity API uses only the language of the parent entity as fallback, while core tries to find data for this field from all other languages (For details see locale_field_language_fallback).

BUT, it seems as fago does not want to use field-level fallback languages as he notes in a code comment: "Note that we cannot use field_language() as we are not about to display values, but generally read/write values.". Which makes sense somehow, but then I wonder why there is this fallback logic anyhow.

valderama’s picture

Category: Bug report » Feature request
valderama’s picture

Issue tags: -language fallback

Removing the unneeded tags.

valderama’s picture

StatusFileSize
new825 bytes

Here is an alternative patch, which simply uses field_language to determine the language when reading a value.

I am testing this on an existing project which uses entity translation heavily.

valderama’s picture

StatusFileSize
new1.37 KB

In my patch from #6 I forgot another getter callback which needs to used field_language. In the entity_metadata_field_property_get function I need it too. This function is used for properties on fields (eg for the value of plain text fields).

TiMESPLiNTER’s picture

Would be happy to see this feature soon. I've a content type with dates. The dates are different in each language or maybe there are no dates in a language. So if this is the case it should not happen that it displays the dates from the default language.

My workaround is to disable the language fallback in general. But I like the node fallback feature but not for each no-value field in a translated node.

jcisio’s picture

I didn't see this and created a duplicated issue #2761319: Why always fallback to entity language when read field value?. I think patch #6 is not acceptable because it is a revert of the linked commit (http://cgit.drupalcode.org/entity/commit/modules/callbacks.inc?id=658db8...).

valderama’s picture

Status: Needs work » Needs review

Setting to "needs review".

The last submitted patch, 6: use-field-language-2335357-6.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 7: use-field-language-2335357-7.patch, failed testing.

The last submitted patch, 3: entity-language-fallback-2335357-3.patch, failed testing.

ciss’s picture

Here's a condensed excerpt of the failing test:

$body['en'][0] = array('value' => '<b>English body.</b>', 'summary' => '<b>The body.</b>');
$node = $this->drupalCreateNode(array('body' => $body, 'language' => 'en', 'type' => 'page'));
$wrapper = entity_metadata_wrapper('node', $node);
// ...
$wrapper->language('de');
// ...
$wrapper->body->set(array('value' => "<b>Der zweite Text.</b>"));
// ...
$wrapper->language(LANGUAGE_NONE);
// ...
$this->assertEqual($wrapper->body->value->value(), "<p>English body.</p>\n", 'Default language text is still there.');
james.williams’s picture

@jcisio (comment 9) - the big difference between this patch and the reverse of that commit is that this only changes the fallback for getters, which were the only places that already used the contentious fallback. It mustn't change setters, I'd agree on that!

(The fallback in those getters will just change from the entity's inherent language, to whatever fallback is appropriate for the specific field in question. Given that these getters are field-specific, I believe this is the correct approach.)

mlee11111’s picture

I had the same issue where language fallback config and entity_metadata_wrapper getters didn't jive. In our case, we don't use fallback ever, so rather then patching, I just tweaked for our use case...

/**
 * Implements hook_entity_property_info_alter().
 *
 * Address issue where entity_metadata_wrapper get doesn't respect the
 * fallback config setting.
 *
 * @see https://www.drupal.org/project/entity/issues/2335357
 */
function et_override_entity_property_info_alter(&$info) {
  // Minimize impact of this alter.
  $bundles = [
    'dct_device',
    'dct_product',
  ];

  foreach ($info['node']['bundles'] as $bundle_name => &$bundle) {
    if (in_array($bundle_name, $bundles)) {
      foreach ($bundle['properties'] as $property_name => &$property) {
        if ($property['translatable'] && $property['getter callback'] == 'entity_metadata_field_property_get') {
          $property['getter callback'] = 'et_override_entity_metadata_field_property_get';
        }
      }
    }
  }
}

/**
 * Entity translate override version of entity_metadata_field_property_get().
 *
 * Addresses shortfall where entity_metadata_field_get_language is called
 * with language fallback hardcoded to TRUE.
 *
 * @see https://www.drupal.org/project/entity/issues/2335357
 */
function et_override_entity_metadata_field_property_get($entity, array $options, $name, $entity_type, $info) {
  $field = field_info_field($name);
  $columns = array_keys($field['columns']);
  $langcode = isset($options['language']) ? $options['language']->language : LANGUAGE_NONE;
  $langcode = entity_metadata_field_get_language($entity_type, $entity, $field, $langcode, FALSE);
  $values = array();
  if (isset($entity->{$name}[$langcode])) {
    foreach ($entity->{$name}[$langcode] as $delta => $data) {
      $values[$delta] = $data[$columns[0]];
      if ($info['type'] == 'boolean' || $info['type'] == 'list<boolean>') {
        // Ensure that we have a clean boolean data type.
        $values[$delta] = (boolean) $values[$delta];
      }
    }
  }
  // For an empty single-valued field, we have to return NULL.
  return $field['cardinality'] == 1 ? ($values ? reset($values) : NULL) : $values;
}