diff --git a/core/modules/locale/locale.services.yml b/core/modules/locale/locale.services.yml
index 1d55460..cd0c20c 100644
--- a/core/modules/locale/locale.services.yml
+++ b/core/modules/locale/locale.services.yml
@@ -16,6 +16,9 @@ services:
   locale.project:
     class: Drupal\locale\LocaleProjectStorage
     arguments: ['@keyvalue']
+  locale.translation_updater:
+    class: Drupal\locale\TranslationUpdater
+    arguments: ['@module_handler', '@state', '@locale.project']
   locale.plural.formula:
     class: Drupal\locale\PluralFormula
     arguments: ['@language_manager', '@state']
diff --git a/core/modules/locale/src/Controller/LocaleController.php b/core/modules/locale/src/Controller/LocaleController.php
index 9216296..9e4135e 100644
--- a/core/modules/locale/src/Controller/LocaleController.php
+++ b/core/modules/locale/src/Controller/LocaleController.php
@@ -7,6 +7,8 @@
 namespace Drupal\locale\Controller;
 
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\locale\TranslationUpdaterInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Return response for manual check translations.
@@ -14,6 +16,30 @@
 class LocaleController extends ControllerBase {
 
   /**
+   * The translation updater.
+   *
+   * @var \Drupal\locale\TranslationUpdaterInterface
+   */
+  protected $translationUpdater;
+
+  /**
+   * Constructs a LocaleController object.
+   *
+   * @param \Drupal\locale\TranslationUpdaterInterface $translation_updater
+   *   The translation updater.
+   */
+  public function __construct(TranslationUpdaterInterface $translation_updater) {
+    $this->translationUpdater = $translation_updater;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static($container->get('locale.translation_updater'));
+  }
+
+  /**
    * Checks for translation updates and displays the translations status.
    *
    * Manually checks the translation status without the use of cron.
@@ -22,13 +48,7 @@ class LocaleController extends ControllerBase {
    *   A redirection to translations reports page.
    */
   public function checkTranslation() {
-    $this->moduleHandler()->loadInclude('locale', 'inc', 'locale.compare');
-
-    // Check translation status of all translatable project in all languages.
-    // First we clear the cached list of projects. Although not strictly
-    // necessary, this is helpful in case the project list is out of sync.
-    locale_translation_flush_projects();
-    locale_translation_check_projects();
+    $this->translationUpdater->check();
 
     // Execute a batch if required. A batch is only used when remote files
     // are checked.
diff --git a/core/modules/locale/src/Form/TranslationStatusForm.php b/core/modules/locale/src/Form/TranslationStatusForm.php
index fab5635..66a59ec 100644
--- a/core/modules/locale/src/Form/TranslationStatusForm.php
+++ b/core/modules/locale/src/Form/TranslationStatusForm.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\State\StateInterface;
+use Drupal\locale\TranslationUpdaterInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -33,12 +34,20 @@ class TranslationStatusForm extends FormBase {
   protected $state;
 
   /**
+   * The translation updater.
+   *
+   * @var \Drupal\locale\TranslationUpdaterInterface
+   */
+  protected $translationUpdater;
+
+  /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('module_handler'),
-      $container->get('state')
+      $container->get('state'),
+      $container->get('locale.translation_updater')
     );
   }
 
@@ -49,10 +58,13 @@ public static function create(ContainerInterface $container) {
    *   A module handler.
    * @param \Drupal\Core\State\StateInterface $state
    *   The state service.
+   * @param \Drupal\locale\TranslationUpdaterInterface $translation_updater
+   *   The translation updater.
    */
-  public function __construct(ModuleHandlerInterface $module_handler, StateInterface $state) {
+  public function __construct(ModuleHandlerInterface $module_handler, StateInterface $state, TranslationUpdaterInterface $translation_updater) {
     $this->moduleHandler = $module_handler;
     $this->state = $state;
+    $this->translationUpdater = $translation_updater;
   }
 
   /**
@@ -268,34 +280,10 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
-    $this->moduleHandler->loadInclude('locale', 'fetch.inc');
-    $this->moduleHandler->loadInclude('locale', 'bulk.inc');
-
-    $langcodes = array_filter($form_state->getValue('langcodes'));
     $projects = array_filter($form_state->getValue('projects_update'));
+    $langcodes = array_filter($form_state->getValue('langcodes'));
 
-    // Set the translation import options. This determines if existing
-    // translations will be overwritten by imported strings.
-    $options = _locale_translation_default_update_options();
-
-    // If the status was updated recently we can immediately start fetching the
-    // translation updates. If the status is expired we clear it an run a batch to
-    // update the status and then fetch the translation updates.
-    $last_checked = $this->state->get('locale.translation_last_checked');
-    if ($last_checked < REQUEST_TIME - LOCALE_TRANSLATION_STATUS_TTL) {
-      locale_translation_clear_status();
-      $batch = locale_translation_batch_update_build(array(), $langcodes, $options);
-      batch_set($batch);
-    }
-    else {
-      // Set a batch to download and import translations.
-      $batch = locale_translation_batch_fetch_build($projects, $langcodes, $options);
-      batch_set($batch);
-      // Set a batch to update configuration as well.
-      if ($batch = locale_config_batch_update_components($options, $langcodes)) {
-        batch_set($batch);
-      }
-    }
+    $this->translationUpdater->update($projects, $langcodes);
   }
 
 }
diff --git a/core/modules/locale/src/TranslationUpdater.php b/core/modules/locale/src/TranslationUpdater.php
new file mode 100644
index 0000000..6b615b4e
--- /dev/null
+++ b/core/modules/locale/src/TranslationUpdater.php
@@ -0,0 +1,100 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\locale\TranslationUpdater.
+ */
+
+namespace Drupal\locale;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\State\StateInterface;
+use Drupal\locale\LocaleProjectStorageInterface;
+
+/**
+ * Checks for updated translations and imports them.
+ */
+class TranslationUpdater implements TranslationUpdaterInterface {
+
+  /**
+   * The locale project storage.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
+   * The state service.
+   *
+   * @var \Drupal\Core\State\StateInterface
+   */
+  protected $state;
+
+  /**
+   * The Locale Project Storage service.
+   *
+   * @var \Drupal\locale\LocaleProjectStorageInterface
+   */
+  protected $localeProject;
+
+  /**
+   * Constructs a TranslationUpdater object.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The locale project storage.
+   * @param \Drupal\Core\State\StateInterface $state
+   *   The state service.
+   */
+  public function __construct(ModuleHandlerInterface $module_handler, StateInterface $state, LocaleProjectStorageInterface $locale_project) {
+    $this->moduleHandler = $module_handler;
+    $this->state = $state;
+    $this->localeProject = $locale_project;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function check() {
+    $this->moduleHandler->loadInclude('locale', 'inc', 'locale.compare');
+
+    // Check translation status of all translatable project in all languages.
+    // First we clear the cached list of projects. Although not strictly
+    // necessary, this is helpful in case the project list is out of sync.
+    $this->localeProject->deleteAll();
+    locale_translation_check_projects();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function update(array $projects = NULL, array $langcodes = NULL) {
+    $this->moduleHandler->loadInclude('locale', 'fetch.inc');
+    $this->moduleHandler->loadInclude('locale', 'bulk.inc');
+
+    // Set the translation import options. This determines if existing
+    // translations will be overwritten by imported strings.
+    $options = _locale_translation_default_update_options();
+
+    // If the status was updated recently we can immediately start fetching the
+    // translation updates. If the status is expired we clear it an run a batch to
+    // update the status and then fetch the translation updates.
+    $last_checked = $this->state->get('locale.translation_last_checked');
+    if ($last_checked < REQUEST_TIME - LOCALE_TRANSLATION_STATUS_TTL) {
+      locale_translation_clear_status();
+      $batch = locale_translation_batch_update_build(array(), $langcodes, $options);
+      batch_set($batch);
+    }
+    else {
+      // Set a batch to download and import translations.
+      $batch = locale_translation_batch_fetch_build($projects, $langcodes, $options);
+      batch_set($batch);
+      // Set a batch to update configuration as well.
+      if ($batch = locale_config_batch_update_components($options, $langcodes)) {
+        batch_set($batch);
+      }
+    }
+  }
+
+
+}
+
diff --git a/core/modules/locale/src/TranslationUpdaterInterface.php b/core/modules/locale/src/TranslationUpdaterInterface.php
new file mode 100644
index 0000000..0164d66
--- /dev/null
+++ b/core/modules/locale/src/TranslationUpdaterInterface.php
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\locale\TranslationUpdaterInterface.
+ */
+
+namespace Drupal\locale;
+
+/**
+ * Provides an interface for translation updaters.
+ *
+ * A translation updater checks for updated translations and imports them.
+ */
+interface TranslationUpdaterInterface {
+
+  /**
+   * Checks whether updated translations are available.
+   *
+   * This checks for translations available in the local filesystem as well as
+   * on a remote translation server. If remote checking is enabled, this method
+   * will set a batch, which calling code needs to take into account:
+   * @code
+   *   $translation_update->check()
+   *   if (batch_get()) {
+   *     batch_process();
+   *   }
+   * @endcode
+   *
+   * @see batch_get()
+   * @see batch_process()
+   */
+  public function check();
+
+  /**
+   * Imports the available translation updates.
+   *
+   * Note that this does not actually check whether translation updates are
+   * available, TranslationUpdateInterface::check() needs to be used for that.
+   *
+   * This method will set a batch, which calling code needs to take into
+   * account:
+   * @code
+   *   $translation_update->update()
+   *   batch_process();
+   * @endcode
+   *
+   * @param array $projects
+   *   (optional) A list of projects to update. If omitted, all translatable
+   *   projects will be updated.
+   * @param array $langcodes
+   *   (optional) A list of languages to update translations for. If omitted,
+   *   translations will be updated for all languages.
+   *
+   * @see batch_process()
+   */
+  public function update(array $projects = NULL, array $langcodes = NULL);
+
+}
