Problem/Motivation

$node !== $node->getUntranslated() always evals to FALSE, but should be TRUE on the translated node page.

Repro:

  1. Install Google Analytics and go to ga settings
  2. Enter a fake UA code e.g. UA-1234-1
  3. Enable Track translation sets as one unit
  4. Save settings
  5. Create a node in English
  6. Create a German translation of these English node
  7. Edit google_analytics.module near line 172+ and enable the debugging
    krumo($node != $node->getUntranslated()); // FALSE
    krumo($node !== $node->getUntranslated()); // FALSE
    
  8. Load page in German, $node !== $node->getUntranslated() should be TRUE and not FALSE

Proposed resolution

Remaining tasks

User interface changes

None

API changes

?

Original report by @username

What is the upgrade path for this function? I need to know with a bool if the content type is enabled for translation or not.

translation_supported_type($node->type)

I cannot believe that everyone need to copy this code to his module. This qualifies for an API addition if not there.

[content_translation.pages.inc]

    // Determine whether the current entity is translatable.
    $translatable = FALSE;
    foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
      $field = $instance->getField();
      if ($field['translatable']) {
        $translatable = TRUE;
        break;
      }
    }

Comments

hass’s picture

Issue summary: View changes

a

catch’s picture

Category: bug » support
hass’s picture

Removing important API functions without replacing them with a new is a regression = bug.

hass’s picture

Maybe content_translation_enabled('node', $node->getType())... ?

hass’s picture

Status: Active » Fixed
plach’s picture

You can also use the translatable key of the entity bundle info.

plach’s picture

Priority: Major » Normal

If you have the node object you can also simply do $node->isTranslatable().

hass’s picture

Thanks a lot, this may makes things more easier... looking into it again.

I end up with:

    // If this node is a translation of another node, pass the original
    // node instead.
    if (\Drupal::moduleHandler()->moduleExists('content_translation') && $config->get('translation_set')) {
      // Check if we have a node object, it has translation enabled, and its
      // language code does not match its source language code.
      $request = \Drupal::request();
      if ($request->attributes->has('node')) {
        $node = $request->attributes->get('node');
        if ($node && $node->isTranslatable() && $node->language()->id != $node->prepareLangcode()) {
          $languages = language_list();
          $url_custom = Json::encode(url('node/' . $node->id(), array('language' => $languages[$node->language()->id])));
        }
      }
    }

I still guess this can be re-factored to less code...

Gave you the credit http://drupalcode.org/project/google_analytics.git/commit/e3eb255

plach’s picture

Thanks :)

<?php
  if ($node && $node->isTranslatable() && $node->language()->id != $node->prepareLangcode()) {
?>

Not sure what Node::prepareLangcode() is supposed to do, but if you want to check whether the node object is not the original one the quickest way is the following:

<?php
  if ($node && $node !== $node->getUntranslated()) {
?>
hass’s picture

It looks like $node->language()->id returns 'en' if the node was created with English first. If a node was created in German it returns 'de'. All translations will always return the original $node->language()->id and prepareLangcode() returns the language code of the current shown translation. I need the original language code here.

I do not need to check $node->isTranslatable() at all in this case? Less code is always better :-)

plach’s picture

$node->language() returns the language of the active translation, $node->getUntranslated() returns the original entity object, hence $node->getUntranslated()->language() returns the original language. If $node !== $node->getUntranslated() you are sure you are dealing with a translation so you don't need to check whether the node is translatable.

See the documentation page for details.

hass’s picture

I guess $node->getUntranslated()->language()->id is the one I should use in url() function...

plach’s picture

Yes, definitely :)

You can just use $node->getUntranslated()->language() which already returns the language object.

hass’s picture

Status: Fixed » Active

I'm opening it as I see a lot of questions coming in my mind now.

dpm($node->language()); // 'en' also if I view the German content
dpm($node->getUntranslated()->language()); // 'en'

Both return the same? But if I switch the page language to German and see the German translation of my english node it's still an English language object with $node->language().

Aside of this you pointed me to https://drupal.org/node/2040721 and this is talking about $node->language()->langcode, but there is no 'langcode'. It seems to be $node->language()->id. If I'm not totally wrong this documentation is outdated or is - how it should be in future? Currently dpm($node->language()->langcode); give me Notice: Undefined property: Drupal\Core\Language\Language::$langcode

The condition $node !== $node->getUntranslated() also does not change if I switch the website from english to german or back. It's always FALSE.

I'm confused now...

plach’s picture

The documentation was outdated wrt the ->langcode part which has changed to ->id meanwhile, updated that.

Regarding node language in itself, you should be aware that we are not done yet with the Entity Translation API: we are currently working on #2019055: Switch from field-level language fallback to entity-level language fallback, which is dealing with entity language negotiation, that is determining the proper translation object to be used in a particular context. We will take care of passing around the proper translation object, where we can reliably determine it. We will also provide a new method to easily determine the most fitting translation object for a given context.

Hope this helps :)

Btw, you are welcome to join us over there and provide your feedback.

hass’s picture

Ok, this means re-visit these lines in some days/weeks... :-)

Trying my best... Aside - I believe "langcode" is a lot more intuitive to understand than "id", but I guess this has already been discussed somewhere else to a death end. Just like to say it... Thanks a lot for your help.

plach’s picture

You are probably right, but now language objects are configuration entities so they inherited the entity terminology.

hass’s picture

Status: Active » Fixed
hass’s picture

Issue summary: View changes

a

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

hass’s picture

Per discussion with plach, moving to bug.

$node !== $node->getUntranslated() always evals to FALSE, but should be TRUE on the translated node page.

Repro:

  1. Install Google Analytics
  2. Enable Track translation sets as one unit
  3. Create a node in English
  4. Create a translation of these English node in German
  5. Edit google_analytics.module near line 172+ and enable the debugging
    krumo($node != $node->getUntranslated()); // FALSE
    krumo($node !== $node->getUntranslated()); // FALSE
    
  6. Load page in German, $node !== $node->getUntranslated() should be TRUE
hass’s picture

Title: D8 upgrade of translation_supported_type()? » $node !== $node->getUntranslated() always FALSE
Issue summary: View changes
hass’s picture

Issue summary: View changes
hass’s picture

Issue summary: View changes
plach’s picture

Issue summary: View changes
hass’s picture

Issue summary: View changes
hass’s picture

Issue summary: View changes
plach’s picture

Category: Bug report » Support request
Status: Active » Needs review

It's not a core bug: you need to pick the correct translation. The following snippet seems to work:

<?php
    // If this node is a translation of another node, pass the original
    // node instead.
    if (\Drupal::moduleHandler()->moduleExists('content_translation') && $config->get('translation_set')) {
      // Check if we have a node object, it has translation enabled, and its
      // language code does not match its source language code.
      $request = \Drupal::request();
      if ($request->attributes->has('node')) {
        $node = $request->attributes->get('node');
        if ($node && $node->isTranslatable() && \Drupal::entityManager()->getTranslationFromContext($node) !== $node->getUntranslated()) {
          $url_custom = Json::encode(url('node/' . $node->id(), array('language' => $node->getUntranslated()->language())));
        }
      }
    }
?>

We are evaluating the possibility to perform entity language negotiation earlier, but for now this is the right way to do it.

hass’s picture

That's really not so easy to guess. But I still need $node->isTranslatable()?

plach’s picture

Nope, that looks unecessary now :)

hass’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.