Q:

Programatically translate an entity

I'm working on a custom solution that leverages the ECK module to handle the entity field creation and display. These custom ECK entities are then attached to nodes via a custom interface.
I'm trying to also build in the ability to translate these entities.
I have a controller that displays the form:
namespace Drupal\MODULE\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\content_translation\Controller\ContentTranslationController;

class MODULEController extends ControllerBase {

  public function edit($node) {
    $entity        = MODULE_load_entity($node);
    $entity_form   = [];
    if ($entity) {
      $form_state_additions = [];
      $operation = 'default';

      // Determine if the entity being added/edited is an origin or a
      // translation and handle the translation if applicable. Start by
      // determining the entity language and the current language.
      $languages        = \Drupal::languageManager()->getLanguages();
      $current_langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
      $entity_langcode  = $entity->get('langcode')->getValue();
      $entity_langcode  = $entity_langcode[0]['value'];
      if ($entity_langcode != $current_langcode) {

        // Create the translation elements on the form.
        $manager    = \Drupal::service('content_translation.manager');
        $controller = new ContentTranslationController($manager);
        $controller->prepareTranslation($entity, $languages[$entity_langcode], $languages[$current_langcode]);

        // Use the add form handler, if available, otherwise default.
        $operation = $entity->getEntityType()->hasHandlerClass('form', 'add') ? 'add' : 'default';

        $form_state_additions['langcode'] = $languages[$current_langcode]->getId();
        $form_state_additions['content_translation']['source'] = $languages[$entity_langcode];
        $form_state_additions['content_translation']['target'] = $languages[$current_langcode];
        $form_state_additions['content_translation']['translation_form'] = !$entity->access('update');
      }

      $entity_form = $this->entityFormBuilder()
        ->getForm($entity, $operation, $form_state_additions);
    }

    return $entity_form;
  }
}

This allows me to create the default version and the translated version and the data in the tables looks ok. But when I try to edit the translated version I get this exception:

The website encountered an unexpected error. Please try again
  later.InvalidArgumentException:
  Invalid translation language (fr) specified. in Drupal\Core\Entity\ContentEntityBase->addTranslation()
  (line 863 of core/lib/Drupal/Core/Entity/ContentEntityBase.php).
  
  Drupal\content_translation\Controller\ContentTranslationController->prepareTranslation(Object,
  Object, Object) (Line: 52)
  Drupal\MODULE\Controller\MODULEController->edit('1')
  call_user_func_array(Array, Array) (Line: 123)
  Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
  (Line: 576)
  Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object)
  (Line: 124)
  Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array,
  Array) (Line: 97)
  Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
  call_user_func_array(Object, Array) (Line: 153)
  Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1)
  (Line: 68) Symfony\Component\HttpKernel\HttpKernel->handle(Object,
  1, 1) (Line: 57)
  Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line:
  47) Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1,
  1) (Line: 99)
  Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1)
  (Line: 78)
  Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1)
  (Line: 47)
  Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object,
  1, 1) (Line: 50)
  Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object,
  1, 1) (Line: 23) Stack\StackedHttpKernel->handle(Object, 1, 1)
  (Line: 657) Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
  

Obviously I'm doing something wrong, but I can't seem to figure out what it is. Any insight into fixing these issues would be much appreciated.
UPDATE4: issue from the previous update fixes the first issue. I've removed it from the ticket since the second issue still remains.

A:

I was treating the creation of the entity translation the same as the editing of the translation. See the following code change which takes into account both types of form.
<?php

namespace Drupal\MODULE\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\content_translation\Controller\ContentTranslationController;

class MODULEController extends ControllerBase {

  public function edit($node) {
    $entity        = MODULE_load_entity($node);
    $entity_form   = [];
    if ($entity) {
      $form_state_additions = [];
      $operation = 'default';

      // Determine if the entity being added/edited is an origin or a
      // translation and handle the translation if applicable. Start by
      // determining the entity language and the current language.
      $languages        = \Drupal::languageManager()->getLanguages();
      $current_langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
      $entity_langcode  = $entity->get('langcode')->getValue();
      $entity_langcode  = $entity_langcode[0]['value'];
      if ($entity_langcode != $current_langcode) {

        // Editing an existing translation.
        if ($entity->hasTranslation($current_langcode)) {

          // Use the edit form handler, if available, otherwise default.
          $operation = $entity->getEntityType()->hasHandlerClass('form', 'edit') ? 'edit' : 'default';

          // Set the form state additions.
          $form_state_additions = [];
          $form_state_additions['langcode'] = $languages[$current_langcode]->getId();
          $form_state_additions['content_translation']['translation_form'] = TRUE;
        }

        // Adding a new translation.
        else {

          // Create the translation elements on the form.
          $manager    = \Drupal::service('content_translation.manager');
          $controller = new ContentTranslationController($manager);
          $controller->prepareTranslation($entity, $languages[$entity_langcode], $languages[$current_langcode]);

          // Use the add form handler, if available, otherwise default.
          $operation = $entity->getEntityType()->hasHandlerClass('form', 'add') ? 'add' : 'default';

          // Set the form state additions.
          $form_state_additions['langcode'] = $languages[$current_langcode]->getId();
          $form_state_additions['content_translation']['source'] = $languages[$entity_langcode];
          $form_state_additions['content_translation']['target'] = $languages[$current_langcode];
          $form_state_additions['content_translation']['translation_form'] = !$entity->access('update');
        }
      }

      // Build the entity form.
      $entity_form = $this->entityFormBuilder()
        ->getForm($entity, $operation, $form_state_additions);
    }

    return $entity_form;
  }
}

