diff --git a/core/lib/Drupal/Component/Utility/DiffArray.php b/core/lib/Drupal/Component/Utility/DiffArray.php
index 719049e305..d6a0cd64aa 100644
--- a/core/lib/Drupal/Component/Utility/DiffArray.php
+++ b/core/lib/Drupal/Component/Utility/DiffArray.php
@@ -47,4 +47,38 @@ public static function diffAssocRecursive(array $array1, array $array2) {
     return $difference;
   }
 
+  /**
+   * Computes the difference of arrays.
+   *
+   * The main difference from the array_diff() is that this method does not
+   * remove duplicates. For example:
+   * @code
+   *   array_diff([1, 1, 1], [1]); // []
+   *   \Drupal\Component\Utility\DiffArray::diffOnce([1, 1, 1], [1]); // [1, 1]
+   * @endcode
+   *
+   * Keys are maintained from the $array1.
+   *
+   * The comparison of items is always performed in the strict (===) mode.
+   *
+   * @param array $array1
+   *   The array to compare from.
+   * @param array $array2
+   *   The array to compare to.
+   *
+   * @return array
+   *   Returns the difference between the two arrays.
+   */
+  public static function diffOnce(array $array1, array $array2) {
+    foreach ($array2 as $item) {
+      // Always use strict mode because otherwise there could be fatal errors on
+      // object conversions.
+      $key = array_search($item, $array1, TRUE);
+      if ($key !== FALSE) {
+        unset($array1[$key]);
+      }
+    }
+    return $array1;
+  }
+
 }
diff --git a/core/modules/editor/editor.module b/core/modules/editor/editor.module
index 8df1f0460a..cbcbc13c0b 100644
--- a/core/modules/editor/editor.module
+++ b/core/modules/editor/editor.module
@@ -5,7 +5,10 @@
  * Adds bindings for client-side "text editors" to text formats.
  */
 
+use Drupal\Component\Utility\DiffArray;
 use Drupal\Component\Utility\Html;
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\TypedData\TranslatableInterface;
 use Drupal\editor\Entity\Editor;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
@@ -384,13 +387,13 @@ function editor_entity_update(EntityInterface $entity) {
 
     // Detect file usages that should be incremented.
     foreach ($uuids_by_field as $field => $uuids) {
-      $added_files = array_diff($uuids_by_field[$field], $original_uuids_by_field[$field]);
+      $added_files = DiffArray::diffOnce($uuids_by_field[$field], $original_uuids_by_field[$field]);
       _editor_record_file_usage($added_files, $entity);
     }
 
     // Detect file usages that should be decremented.
     foreach ($original_uuids_by_field as $field => $uuids) {
-      $removed_files = array_diff($original_uuids_by_field[$field], $uuids_by_field[$field]);
+      $removed_files = DiffArray::diffOnce($original_uuids_by_field[$field], $uuids_by_field[$field]);
       _editor_delete_file_usage($removed_files, $entity, 1);
     }
   }
@@ -543,23 +546,39 @@ function editor_file_download($uri) {
 /**
  * Finds all files referenced (data-entity-uuid) by formatted text fields.
  *
- * @param EntityInterface $entity
+ * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
  *   An entity whose fields to analyze.
  *
  * @return array
  *   An array of file entity UUIDs.
  */
-function _editor_get_file_uuids_by_field(EntityInterface $entity) {
+function _editor_get_file_uuids_by_field(FieldableEntityInterface $entity) {
   $uuids = array();
 
+  $field_definitions = $entity->getFieldDefinitions();
   $formatted_text_fields = _editor_get_formatted_text_fields($entity);
   foreach ($formatted_text_fields as $formatted_text_field) {
+
+    // In case of a translatable field, iterate over all its translations.
+    if ($field_definitions[$formatted_text_field]->isTranslatable() && $entity instanceof TranslatableInterface) {
+      $langcodes = array_keys($entity->getTranslationLanguages());
+    }
+    else {
+      $langcodes = [LanguageInterface::LANGCODE_NOT_APPLICABLE];
+    }
+
     $text = '';
-    $field_items = $entity->get($formatted_text_field);
-    foreach ($field_items as $field_item) {
-      $text .= $field_item->value;
-      if ($field_item->getFieldDefinition()->getType() == 'text_with_summary') {
-        $text .= $field_item->summary;
+    foreach ($langcodes as $langcode) {
+      if ($langcode == LanguageInterface::LANGCODE_NOT_APPLICABLE) {
+        $field_items = $entity->get($formatted_text_field);
+      }
+      else {
+        $field_items = $entity->getTranslation($langcode)->get($formatted_text_field);
+      }
+      foreach ($field_items as $field_item) {
+        if ($field_item->getFieldDefinition()->getType() == 'text_with_summary') {
+          $text .= $field_item->summary;
+        }
       }
     }
     $uuids[$formatted_text_field] = _editor_parse_file_uuids($text);
diff --git a/core/modules/editor/editor.post_update.php b/core/modules/editor/editor.post_update.php
index 3715b6dc57..e2deb8d05e 100644
--- a/core/modules/editor/editor.post_update.php
+++ b/core/modules/editor/editor.post_update.php
@@ -5,6 +5,8 @@
  * Post update functions for Editor.
  */
 
+use Drupal\Core\Entity\FieldableEntityInterface;
+
 /**
  * @addtogroup updates-8.2.x
  * @{
@@ -19,3 +21,112 @@ function editor_post_update_clear_cache_for_file_reference_filter() {
 /**
  * @} End of "addtogroup updates-8.2.x".
  */
+
+/**
+ * @addtogroup updates-8.3.x
+ * @{
+ */
+
+/**
+ * Recalculates file usages.
+ */
+function editor_post_update_recalculate_file_usage(&$sandbox) {
+  $entity_load_limit = 50;
+
+  if (!\Drupal::moduleHandler()->moduleExists('file')) {
+    return;
+  }
+
+  if (!isset($sandbox['current'])) {
+    $result = \Drupal::entityQuery('file')->count()->execute();
+    if (empty($result)) {
+      return;
+    }
+    $sandbox['data']['total_file'] = $result;
+    $sandbox['data']['current_file_id'] = 0;
+    $sandbox['data']['count_file_id'] = 0;
+
+    foreach (\Drupal::entityTypeManager()->getDefinitions() as $entity_type) {
+      if ($entity_type->isSubclassOf(FieldableEntityInterface::class)) {
+        $entity_type_id = $entity_type->id();
+        $query = \Drupal::entityQuery($entity_type_id);
+        if ($entity_type->isRevisionable()) {
+          $query->allRevisions();
+        }
+        $result = $query->count()->execute();
+        if (!empty($result)) {
+          // We need result keys because they are either revision IDs (in case
+          // of revisionable entities) or entity IDs (in other case).
+          $sandbox['data']['total_entity_id'][$entity_type_id] = $result;
+          $sandbox['data']['current_entity_id'][$entity_type_id] = 0;
+          $sandbox['data']['count_entity_id'][$entity_type_id] = 0;
+        }
+      }
+    }
+
+    $sandbox['current'] = 0;
+    $sandbox['max'] = $sandbox['data']['total_file'] + array_sum($sandbox['data']['total_entity_id']);
+  }
+
+  if (!empty($sandbox['data']['total_file'])) {
+    // Step 1: delete existing file usages.
+    /** @var \Drupal\file\FileUsage\FileUsageInterface $file_usage */
+    $file_usage = \Drupal::service('file.usage');
+
+    $file_ids = \Drupal::entityQuery('file')
+      ->condition('fid', $sandbox['current_file_id'], '>')
+      ->sort('fid', 'ASC')
+      ->pager($entity_load_limit)
+      ->execute();
+    $files = $files = \Drupal::entityTypeManager()
+      ->getStorage('file')
+      ->loadMultiple($file_ids);
+    foreach ($files as $file) {
+      $usages = $file_usage->listUsage($file);
+      if (!empty($usages['editor'])) {
+        $file_usage->delete($file, 'editor', NULL, NULL, 0);
+      }
+    }
+
+    $sandbox['data']['count_file_id'] += count($file_ids);
+  }
+  else {
+    // Step 2: recalculate file usages.
+    reset($sandbox['data']['last_entity_id']);
+    $entity_type_id = key($sandbox['data']['last_entity_id']);
+
+    $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
+    $ids = \Drupal::entityQuery($entity_type_id)
+      ->condition($entity_type->getKey('id'), $sandbox['data']['last_entity_id'][$entity_type_id], '>')
+      ->pager($entity_load_limit)
+      ->sort($entity_type->getKey('id'), 'ASC')
+      ->execute();
+    if ($entity_type->isRevisionable()) {
+      foreach ($ids as $revision_id) {
+        $entity = \Drupal::entityTypeManager()
+          ->getStorage($entity_type_id)
+          ->loadRevision($revision_id);
+        editor_entity_insert($entity);
+      }
+    }
+    else {
+      $entities = \Drupal::entityTypeManager()
+        ->getStorage($entity_type_id)
+        ->loadMultiple($ids);
+      foreach ($entities as $entity) {
+        editor_entity_insert($entity);
+      }
+    }
+    if (empty($ids)) {
+      unset($sandbox['data']['last_entity_id'][$entity_type_id]);
+    }
+    else {
+      $sandbox['data']['count_entity_id'][$entity_type_id] += count($ids);
+      $sandbox['data']['last_entity_id'][$entity_type_id] = end($ids);
+    }
+  }
+
+  $current_amount = count($sandbox['data']['count_file_id']) + array_sum($sandbox['data']['count_entity_id']);
+  $sandbox['current'] = $sandbox['max'] - $current_amount;
+  $sandbox['#finished'] = empty($current_amount) ? 1 : ($sandbox['current'] / $sandbox['max']);
+}
diff --git a/core/modules/editor/src/Tests/Update/EditorUpdateTest.php b/core/modules/editor/src/Tests/Update/EditorUpdateTest.php
index e7f0f4435b..65cc6b72dc 100644
--- a/core/modules/editor/src/Tests/Update/EditorUpdateTest.php
+++ b/core/modules/editor/src/Tests/Update/EditorUpdateTest.php
@@ -2,6 +2,10 @@
 
 namespace Drupal\editor\Tests\Update;
 
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\file\Entity\File;
+use Drupal\language\Entity\ConfigurableLanguage;
+use Drupal\node\Entity\Node;
 use Drupal\system\Tests\Update\UpdatePathTestBase;
 
 /**
@@ -19,6 +23,7 @@ public function setDatabaseDumpFiles() {
       __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.bare.standard.php.gz',
       // Simulate an un-synchronized environment.
       __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.editor-editor_update_8001.php',
+      __DIR__ . '/../../../../system/tests/fixtures/update/drupal-8.language-enabled.php',
     ];
   }
 
@@ -67,4 +72,77 @@ public function testEditorUpdate8001() {
     $this->assertIdentical($format_full_html->get('status'), $editor_full_html->get('status'));
   }
 
+  /**
+   * Tests editor_update_8002().
+   *
+   * @see editor_update_8002()
+   */
+  public function testEditorUpdate8002() {
+
+    // Prepare second language.
+    ConfigurableLanguage::createFromLangcode('fr')->save();
+
+    // Make body field translatable.
+    FieldStorageConfig::loadByName('node', 'body')
+      ->setTranslatable(TRUE)
+      ->save();
+
+    // Prepare a test file.
+    $file_path = 'core/misc/druplicon.png';
+    $file = File::create();
+    $file->setFileUri($file_path);
+    $file->setFilename($this->container->get('file_system')->basename($file->getFileUri()));
+    $file->save();
+
+    $img_string = '<img src="' . $file_path . '" data-entity-type="file" data-entity-uuid="' . $file->uuid() . '" />';
+
+    // Initially reference file 2 times. Total file usages should be 2.
+    $node = Node::create([
+      'language' => 'en',
+      'type' => 'page',
+      'title' => 'test',
+      'body' => [
+        0 => [
+          'value' => str_repeat($img_string, 2),
+          'format' => 'full_html',
+        ],
+      ],
+      'uid' => 1,
+    ]);
+    $node->save();
+
+    // Add 2 more usages. Total file usages should be 4 now.
+    $node->get('body')->value = $node->get('body')->value . str_repeat($img_string, 2);
+    $node->save();
+
+    // Create a node translation having 5 file usages and force a new revision.
+    // Total file usages should be 15 now:
+    //  initial revision: en - 4, fr - does not exists,
+    //  new revision: en - 4, fr - 7.
+    $node->addTranslation('fr', [
+      'title' => 'test fr', 
+      'body' => [
+        0 => [
+          'value' => str_repeat($img_string, 7),
+          'format' => 'full_html',
+        ],
+      ],
+    ]);
+    $node->setNewRevision(TRUE);
+    $node->save();
+
+    // Now mess up file usages.
+    /** @var \Drupal\file\FileUsage\FileUsageInterface $file_usage */
+    $file_usage = $this->container->get('file.usage');
+    $file_usage->add($file, 'editor', 'node', $node->id(), 99999);
+
+    $usages = $file_usage->listUsage($file);
+    $this->assert($usages['editor']['node'][$node->id()] != 15, 'File usages are messed up.');
+
+    $this->runUpdates();
+
+    $usages = $file_usage->listUsage($file);
+    $this->assert($usages['editor']['node'][$node->id()] == 15, 'File usages are correct.');
+  }
+
 }
diff --git a/core/modules/editor/tests/src/Kernel/EditorFileUsageTest.php b/core/modules/editor/tests/src/Kernel/EditorFileUsageTest.php
index 04113880cd..eea3a857aa 100644
--- a/core/modules/editor/tests/src/Kernel/EditorFileUsageTest.php
+++ b/core/modules/editor/tests/src/Kernel/EditorFileUsageTest.php
@@ -4,6 +4,7 @@
 
 use Drupal\editor\Entity\Editor;
 use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
+use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\node\Entity\Node;
 use Drupal\node\Entity\NodeType;
 use Drupal\file\Entity\File;
@@ -23,7 +24,14 @@ class EditorFileUsageTest extends EntityKernelTestBase {
    *
    * @var array
    */
-  public static $modules = array('editor', 'editor_test', 'node', 'file');
+  public static $modules = array('editor', 'editor_test', 'node', 'file', 'language');
+
+  /**
+   * Languages to enable.
+   *
+   * @var array
+   */
+  protected $langcodes = array('fr', 'en');
 
   protected function setUp() {
     parent::setUp();
@@ -41,8 +49,14 @@ protected function setUp() {
     ));
     $filtered_html_format->save();
 
+    // Add languages.
+    foreach ($this->langcodes as $langcode) {
+      ConfigurableLanguage::createFromLangcode($langcode)->save();
+    }
+
     // Set cardinality for body field.
     FieldStorageConfig::loadByName('node', 'body')
+      ->setTranslatable(TRUE)
       ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
       ->save();
 
@@ -69,6 +83,9 @@ public function testEditorEntityHooks() {
       2 => 'core/misc/help.png',
     );
 
+    /** @var \Drupal\file\FileUsage\FileUsageInterface $file_usage */
+    $file_usage = $this->container->get('file.usage');
+
     $image_entities = array();
     foreach ($image_paths as $key => $image_path) {
       $image = File::create();
@@ -76,7 +93,6 @@ public function testEditorEntityHooks() {
       $image->setFilename(drupal_basename($image->getFileUri()));
       $image->save();
 
-      $file_usage = $this->container->get('file.usage');
       $this->assertIdentical(array(), $file_usage->listUsage($image), 'The image ' . $image_paths[$key] . ' has zero usages.');
 
       $image_entities[] = $image;
@@ -103,7 +119,8 @@ public function testEditorEntityHooks() {
 
     // Test editor_entity_insert(): increment.
     $this->createUser();
-    $node = $node = Node::create([
+    $node = Node::create([
+      'language' => 'en',
       'type' => 'page',
       'title' => 'test',
       'body' => $body,
@@ -199,11 +216,68 @@ public function testEditorEntityHooks() {
       $this->assertIdentical(array('editor' => array('node' => array(1 => '2'))), $file_usage->listUsage($image_entity), 'The image ' . $image_paths[$key] . ' has 2 usages.');
     }
 
+    // Test editor_entity_translation_insert(): increment, by adding a new
+    // translation.
+    $translation = $node->addTranslation('fr', ['title' => 'test fr', 'body' => $original_values]);
+    $translation->save();
+    foreach ($image_entities as $key => $image_entity) {
+      $this->assertIdentical(array('editor' => array('node' => array(1 => '3'))), $file_usage->listUsage($image_entity), 'The image ' . $image_paths[$key] . ' has 3 usages.');
+    }
+
+    // Test editor_entity_translation_delete(): decrement, by deleting a
+    // translation.
+    $node->removeTranslation('fr');
+    $node->save();
+    foreach ($image_entities as $key => $image_entity) {
+      $this->assertIdentical(array('editor' => array('node' => array(1 => '2'))), $file_usage->listUsage($image_entity), 'The image ' . $image_paths[$key] . ' has 2 usages.');
+    }
+
     // Test editor_entity_delete().
     $node->delete();
     foreach ($image_entities as $key => $image_entity) {
       $this->assertIdentical(array(), $file_usage->listUsage($image_entity), 'The image ' . $image_paths[$key] . ' has zero usages again.');
     }
+
+    // Prepare a new node having only one file entity referenced in the body
+    // field.
+    $image_entity_1 = $image_entities[0];
+    $body_value = '<img src="awesome-llama-0.jpg" data-entity-type="file" data-entity-uuid="' . $image_entity_1->uuid() . '" />';
+    $node = Node::create([
+      'language' => 'en',
+      'type' => 'page',
+      'title' => 'test',
+      'body' => [
+        0 => [
+          'value' => $body_value,
+          'format' => 'filtered_html',
+        ]
+      ],
+      'uid' => 1,
+    ]);
+    $node->save();
+    $nid = $node->id();
+    $this->assertIdentical(array('editor' => array('node' => array($nid => '1'))), $file_usage->listUsage($image_entity_1), 'The image ' . $image_entity_1->getFileUri() . ' has 1 usage.');
+
+    // Add a translation.
+    $translation = $node->addTranslation('fr', [
+      'title' => 'test fr',
+      'body' => $node->get('body')->getValue(),
+    ]);
+    $node->save();
+    $this->assertIdentical(array('editor' => array('node' => array($nid => '2'))), $file_usage->listUsage($image_entity_1), 'The image ' . $image_entity_1->getFileUri() . ' has 2 usages.');
+
+    // Replace image in the French translation.
+    $image_entity_2 = $image_entities[1];
+    $translation->get('body')->value = '<img src="awesome-llama-1.jpg" data-entity-type="file" data-entity-uuid="' . $image_entity_2->uuid() . '" />';;
+    $node->save();
+    $this->assertIdentical(array('editor' => array('node' => array($nid => '1'))), $file_usage->listUsage($image_entity_1), 'The image ' . $image_entity_1->getFileUri() . ' has 1 usage.');
+    $this->assertIdentical(array('editor' => array('node' => array($nid => '1'))), $file_usage->listUsage($image_entity_2), 'The image ' . $image_entity_2->getFileUri() . ' has 1 usage.');
+
+    // Re-save translation with no image and check if usage changed
+    $translation->get('body')->value = '';
+    $node->save();
+    $this->assertIdentical(array('editor' => array('node' => array($nid => '1'))), $file_usage->listUsage($image_entity_1), 'The image ' . $image_entity_1->getFileUri() . ' has 1 usage.');
+    $this->assertIdentical(array(), $file_usage->listUsage($image_entity_2), 'The image ' . $image_entity_2->getFileUri() . ' has zero usages.');
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/Common/DiffArrayTest.php b/core/tests/Drupal/Tests/Core/Common/DiffArrayTest.php
index 4112eaeb16..3f590c8e62 100644
--- a/core/tests/Drupal/Tests/Core/Common/DiffArrayTest.php
+++ b/core/tests/Drupal/Tests/Core/Common/DiffArrayTest.php
@@ -9,27 +9,15 @@
  * Tests the DiffArray helper class.
  *
  * @group Common
+ * @coversDefaultClass \Drupal\Component\Utility\DiffArray
  */
 class DiffArrayTest extends UnitTestCase {
 
   /**
-   * Array to use for testing.
-   *
-   * @var array
+   * @covers  ::diffAssocRecursive
    */
-  protected $array1;
-
-  /**
-   * Array to use for testing.
-   *
-   * @var array
-   */
-  protected $array2;
-
-  protected function setUp() {
-    parent::setUp();
-
-    $this->array1 = array(
+  public function testDiffAssocRecursive() {
+    $array1 = array(
       'same' => 'yes',
       'different' => 'no',
       'array_empty_diff' => array(),
@@ -40,7 +28,7 @@ protected function setUp() {
       'string_compared_to_array' => 'value',
       'new' => 'new',
     );
-    $this->array2 = array(
+    $array2 = array(
       'same' => 'yes',
       'different' => 'yes',
       'array_empty_diff' => array(),
@@ -50,12 +38,7 @@ protected function setUp() {
       'array_compared_to_string' => 'value',
       'string_compared_to_array' => array('value'),
     );
-  }
 
-  /**
-   * Tests DiffArray::diffAssocRecursive().
-   */
-  public function testDiffAssocRecursive() {
     $expected = array(
       'different' => 'no',
       'int_diff' => 1,
@@ -66,7 +49,51 @@ public function testDiffAssocRecursive() {
       'new' => 'new',
     );
 
-    $this->assertSame(DiffArray::diffAssocRecursive($this->array1, $this->array2), $expected);
+    $this->assertSame(DiffArray::diffAssocRecursive($array1, $array2), $expected);
+  }
+
+  /**
+   * @covers ::diffOnce
+   * @dataProvider providerTestDiffOnce
+   */
+  public function testDiffOnce($array1, $array2, $expected) {
+    $this->assertSame($expected, DiffArray::diffOnce($array1, $array2));
+  }
+
+  /**
+   * Provides test data for testDiffOnce().
+   */
+  public function providerTestDiffOnce() {
+    $object1 = new \stdClass();
+    $object2 = new \stdClass();
+    $data = [
+      [
+        [1, 1, 1, 1, 1],
+        [1, 1, 1],
+        [3 => 1, 4 => 1],
+      ],
+      [
+        [1, 1, 2, 2, 3, 3, 4],
+        ['4', 3, 2, 1],
+        [1 => 1, 3 => 2, 5 => 3, 6 => 4],
+      ],
+      [
+        [' ', '', 0, FALSE],
+        [0, 0, 0, 0, 'not used'],
+        [0 => ' ', 1 => '', 3 => FALSE],
+      ],
+      [
+        [$this, [], $object1, $object1, $object2],
+        [$object1, $object2, [], $this],
+        [3 => $object1],
+      ],
+      [
+        [['x' => ['y' => 'z']], [$object1]],
+        [1, 2, 3, '4', TRUE, [$object2], ['x' => ['y' => 'z']]],
+        [1 => [$object1]],
+      ],
+    ];
+    return $data;
   }
 
 }
