I have two different content types with different settings:
- Document: a simple content type without multilanguage support
- News: it's a multilanguage content type with translation support. It has a node reference field called Documents.

If I create a Document node called "Document 1" with the admin page in english, and then I create a News node in english too, I can reference the Document node in News node. But If I translate this News node in, for example, Catalan, then the Document "Document 1" isn't found.

How can I create language neutral referenced content types?

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

aacraig’s picture

I am experiencing the same problem.

I have English and Italian enabled, and both languages have been configured with a path prefix (so English content is available at example.com/en and Italian at example.com/it). The system is configured to switch the interface to the selected language for translation.

I have created a content type "no_language", and a second content type "language_dependent" with a nodereference field that references no_langauage, and I have created on node instance of the "no_language" type.

I create an instance of no_language. It gets assigned English as it's language in the content view, perhaps due to that being the default language of the site. Then I create an instance of a language_dependent type (in English, again as that's the default) and I am able to see my no_language content in the autocomplete field, select it, and save the new node.

Then I click the translate button and select to add a new translation in Italian. In the reference field, I see " [nid: XX]" (not the expected "Node title [nid:XX]") where XX is the nid of the no_language node. When I save the Italian language node, I get this error:

No language: this post can't be referenced.

"No language" is the name of my content type.

Further, if I try to type into the reference field to get autocomplete suggestions, no values come up.

This is a fresh D7 install, just updated through Drush (so should have the latest recommended version of all modules).

aacraig’s picture

After some sleuthing, I've discovered the problem lies in i18n_select_query_node_access_alter() in i18n_select.module.

This function adds a language column condition to the query, effectively hiding any language independent nodes from the References module, when the interface is not in the default language.

This seems to be a duplicate of #671406: NodeReference and multilanguage contents / db_rewrite_sql(), which is patched for D6.

Any chance this will make it into D7 soon?

aacraig’s picture

For anyone having this problem, you can hack your way around it by telling i18n_select to ignore you when it's query alter hook gets called.

If you have a custom module for your site, you can add the following code and modify it as necessary:


function MYMODULE_query_node_access_alter(QueryAlterableInterface $query) {
  if (isset($query->alterMetaData) && $query->alterMetaData['id'] = "_node_reference_potential_references_standard") {
    // trying to find a referenceable node
    // due to issue http://drupal.org/node/1099956, if the interface is currently not in English, 
    // language independent nodes will not be found, due to i18n_select altering this query to 
    // fiter for only nodes in the current language
    // For node that can reference language independent nodes, we must turn this behavior off
    $args = $query->getArguments();

    // add the machine names of the nodes that can be referenced here
    $ok_nodes = array('referenceable_content_type1', '', ...);
    if (in_array($args[':db_condition_placeholder_0'], $ok_nodes)) {
      $query->addTag('i18n_select');
    }
  }
}
jmones’s picture

subscribe

Cyberwolf’s picture

subscribing

amandine_m’s picture

suscribe

interX’s picture

It seems references cannot deal with this case, as all referenced content gets filtered by node language or LANGUAGE_NONE.
In my case with entity_translation, it's unaware of the translated entities.

Either you can patch i18n_select or you can undo the filtering done in i18n_select_query_node_access_alter() by using this in a custom module :

/**
 * Implements hook_query_TAG_alter().
 */
function MYMODULE_query_node_access_alter(QueryAlterableInterface $query) {
  
  $mode = i18n_select_mode('nodes');
  if ($mode && $query->hasTag('i18n_select') && ($table_alias = i18n_select_check_table($query, 'node', 'nid'))) {

    $conditions =& $query->conditions();
    foreach ($conditions as $index => $condition) {
      if (is_array($condition) && isset($condition['field']) && is_string($condition['field'])) {
        if ($condition['field'] === $table_alias . '.language' && $condition['value'] == i18n_select_langcodes() && $condition['operator'] == 'IN') {
          unset($conditions[$index]);
        }
      }
    }
  }
}

Be aware, i18n select is used from several places for content selection. This might have side effects.

ClaudeS-1’s picture

I'm not sure if this is the same problem, but this thread is the closest I found.

- I have a node reference field from my "Product" content type, to other nodes with the same "Product" content type (i.e. related products).
- Each product is created in default language (EN), but can be translated to other languages (e.g. FR)
- I can select related products from a multi-select box for EN or FR products, referencing EN or FR products. These all get stored in the DB fine, and show up correctly in my view.
- When I return to the edit page for an FR-translated product, the referenced products ARE NOT selected in the multi-select. However, all is fine when editing an EN product, even if an FR product is referenced.

It seems Drupal core has a problem picking up or showing which nodes are referenced when editing a translated node.

The two patches shown didn't seem to help much. Any debugging pointers would be appreciated so I can try to provide some more details.

aacraig’s picture

I'm having the exact same problem, and I'm not sure if it's best handled in core or in this module, as the real culprit is the basic idea that the French node is a separate entity from the English node, which IMHO is insane.

The issue is that French nodes are invisible to you when you are looking at the site in the English language. This basic failure in logic causes all sorts of problems.

When the form loads, the correct node reference is pulled from the database, but then as the list of available nodes doesn't contain that nid (because the database has stored the French nid, for example, and the list of available nodes are the English language versions), the HTML form control will not be set when the page loads, and unless you manually check the node in your current language, no value will be sent when you save the form.

For now, I'm hacking a workaround on a case by case basis. I "solved" your problem by adding code in my custom module that looks up the nid for the node in the current language and sets the form value so that when the form is saved, a new reference is saved to the node in the current language.

This is a huge problem and derives from the wrong approach to translation, which should not be done by copying node instances but instead should implement field level translations, as far as I'm concerned.

For reference, here's the code I wrote (today!) to solve this problem on a site I'm working on. I hope it helps you hack out your own temporary solution:

  // fix default value of the consultant
  // this also works around a bug in node references where editing in the wrong
  // language causes the node reference to disappear
  // only do this on an existing node, as a new node won't have a value set at all
  if (!empty($element['nid']['#value'])) {
    global $language;
    $consultant_nid = $element['#node']->field_consultant[$element['#node']->language][0]['nid'];
    $nids = learningtv_consultant_nids($consultant_nid); // this function returns the nids for both the English and the translated node, ie: array('it' => $nid1, 'en' => $nid2);
    if (!empty($nids[$language->language])) {
      $element['field_consultant'][$element['field_consultant']['#language']][$nids[$language->language]]['#value'] = TRUE;
    }
  }
danielnolde’s picture

The solution in #7 worked in my case (by re-altering the i18n_select-altered query, it helps to avoid the validation errors on node reference fields input with nodes in languages other than the current display language).

But it should really be wrapped in the following conditional statement to limit it to the query really originating from the node reference validation mechanism, thus avoiding uncalculatable side effects on all other queries:

  if (isset($query->alterMetaData) && $query->alterMetaData['id'] = "_node_reference_potential_references_standard") {
    // ... code from #7 ...
  }
PieterDC’s picture

Status: Active » Needs work
FileSize
1.13 KB

@danielnolde got me thinking, cfr. "limit it to the query really originating from the node reference validation mechanism"

I'v attached the patch I've used.

After applying it, you'll be able to exclude node_reference from i18n_select by adding 'node_reference' to the field 'Skip tags' at admin/config/regional/i18n/select
It's quite the same as the 'Entity reference' module uses.

I guess the setting would have to be set automatically if / when i18n_select is enabled?

mmncs’s picture

After doing a bit of testing every thing seems to work just fine with the patch, great work, thanks Peiter

mmncs’s picture

Was a bit to quick.

My site breaks when this is used with a view which contains a content type which has a node reference where the teaser view is shown in that view. I tracked the problem to the node_reference_field_formatter_view function where the item['node'] is null and therefore fails to set the node. I tried to change the function using node_load on id, but that resulted in other problems.

      foreach ($items as $delta => $item) {
        //if ($item['access']) {
        if (isset($item['access']) && $item['access']){
          //$node = $item['node'];
          $node = !empty($item['node']) ? $item['node'] : node_load($item['nid']);
          $label = entity_label('node', $node);
          if ($display['type'] == 'node_reference_default') {
            $uri = entity_uri('node', $node);
            $result[$delta] = array(
              '#type' => 'link',
              '#title' => $label,
              '#href' => $uri['path'],
              '#options' => $uri['options'],
            );
          }
          else {
mmncs’s picture

Status: Needs work » Active
hansrossel’s picture

Entity reference has the same issue still, maybe interesting to see how they fix it #1674792: Rendered entity is not language aware

agileadam’s picture

Like comment #10 I am using this with a conditional to target one specific entity reference field.

It may not be pretty but here's what it looks like with an 80-character limit.

/**
 * Implements hook_query_TAG_alter().
 *
 * @see http://www.drupal.org/project/references/issues/1099956#comment-5387354.
 */
function mymodule_query_node_access_alter(QueryAlterableInterface $query) {
  if (i18n_select_mode('nodes') && $query->hasTag('i18n_select')) {
    $field = $query->getMetaData('field');
    if (empty($field['field_name'])
      || $field['field_name'] != 'field_er_translations') {
      return;
    }

    $table_alias = i18n_select_check_table($query, 'node', 'nid');
    if ($table_alias) {
      $conditions =& $query->conditions();
      foreach ($conditions as $index => $condition) {
        if (is_array($condition)
          && !empty($condition['field'])
          && is_string($condition['field'])) {
          if ($condition['field'] === $table_alias . '.language'
            && $condition['value'] == i18n_select_langcodes()
            && $condition['operator'] == 'IN') {
            unset($conditions[$index]);
          }
        }
      }
    }
  }
}