When for example you have english and french enabled you will have 2 indexes for them:
content-node-en
content-node-fr

While initially node without translation is saved into either one of those indexes, then changing the language on the node, will save the entry to correct index but leave the old entry intact.

Comments

hkirsman created an issue.

hkirsman’s picture

I added orphanCleanup() function to my custon module in the index() method.

   /**
   * {@inheritdoc}
   */
  public function index($source) {
    /** @var \Drupal\node\NodeInterface $source */

    foreach ($source->getTranslationLanguages() as $langcode => $language) {
      if ($source->hasTranslation($langcode)) {
        $translation = $source->getTranslation($langcode);
        if ($translation->isPublished()) {
          parent::index($translation);
        }
        else {
          parent::delete($translation);
        }
      }
    }
    \Drupal::messenger()->addMessage('Elasticsearch indexed ' . $source->label());

    $this->orphanCleanup($source);
  }

  /**
   * Remove entries from index when switching node language.
   *
   * If node does not have all translations and when changing the language
   * then the old entry will remain in the index. To fix this, we go though
   * all enabled languages and fetch data from Elasticsearch for languages
   * that there are no translations in Drupal.
   *
   * @param $source
   *   The data to be indexed.
   */
  private function orphanCleanup($source) {
    $all_languages = \Drupal::languageManager()->getLanguages();

    // If we are already saving to all language indexes then there can't be any
    // orphans left.
    if (count($all_languages) === count($source->getTranslationLanguages())) {
      return;
    }

    foreach ($all_languages as $langcode => $language) {
      try {
        $source_translation = $source->getTranslation($langcode);
      }
      catch (\InvalidArgumentException $e) {
        $params = [
          'index' => str_replace('{langcode}', $langcode, $this->pluginDefinition['indexName']),
          'type' => $this->pluginDefinition['typeName'],
          'id' => $source->id(),
        ];
        $result = $this->client->get($params);

        if ($result['found']) {
          $this->client->delete($params);
        }
      }
    }
  }