diff --git a/typo3/sysext/lang/Classes/Command/UpdateCommandController.php b/typo3/sysext/lang/Classes/Command/UpdateCommandController.php
new file mode 100644
index 0000000000000000000000000000000000000000..f89c5c16125f8fd6b0752bd60c198093e3f229f8
--- /dev/null
+++ b/typo3/sysext/lang/Classes/Command/UpdateCommandController.php
@@ -0,0 +1,65 @@
+<?php
+namespace TYPO3\CMS\Lang\Command;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2013 Wouter Wolters <typo3@wouterwolters.nl>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Update languages translation command
+ */
+class UpdateCommandController extends \TYPO3\CMS\Extbase\Mvc\Controller\CommandController {
+
+	/**
+	 * Update language file for each extension
+	 *
+	 * @param string $localesToUpdate Comma separated list of locales that needs to be updated
+	 * @return void
+	 */
+	public function updateCommand($localesToUpdate = '') {
+		/** @var $listUtility \TYPO3\CMS\Extensionmanager\Utility\ListUtility */
+		$listUtility = $this->objectManager->get('TYPO3\\CMS\\Extensionmanager\\Utility\\ListUtility');
+		$availableExtensions = $listUtility->getAvailableExtensions();
+		$extensions = $listUtility->getAvailableAndInstalledExtensions($availableExtensions);
+
+		/** @var $updateTranslationService \TYPO3\CMS\Lang\Service\UpdateTranslationService */
+		$updateTranslationService = $this->objectManager->get('TYPO3\\CMS\\Lang\Service\\UpdateTranslationService');
+		/** @var $languageRepository \TYPO3\CMS\Lang\Domain\Repository\LanguageRepository */
+		$languageRepository = $this->objectManager->get('TYPO3\\CMS\\Lang\\Domain\\Repository\\LanguageRepository');
+
+		$locales = array();
+		if (!empty($localesToUpdate)) {
+			$locales = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $localesToUpdate, TRUE);
+		} else {
+			$languages = $languageRepository->findSelected();
+			foreach ($languages as $language) {
+				$locales[] = $language->getLocale();
+			}
+		}
+
+		foreach ($extensions as $extension) {
+			$updateTranslationService->updateTranslation($extension['key'], $locales);
+		}
+	}
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/lang/Classes/Controller/LanguageController.php b/typo3/sysext/lang/Classes/Controller/LanguageController.php
index dcbd144af8a5ce2ae6c119e601ad08aa328cabb0..6228ac886a3ad7c6dc818e472d1b004c207e83a4 100644
--- a/typo3/sysext/lang/Classes/Controller/LanguageController.php
+++ b/typo3/sysext/lang/Classes/Controller/LanguageController.php
@@ -33,16 +33,6 @@ namespace TYPO3\CMS\Lang\Controller;
  */
 class LanguageController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionController {
 
-	/**
-	 * Status codes for AJAX response
-	 */
-	const TRANSLATION_NOT_AVAILABLE = 0;
-	const TRANSLATION_AVAILABLE = 1;
-	const TRANSLATION_FAILED = 2;
-	const TRANSLATION_OK = 3;
-	const TRANSLATION_INVALID = 4;
-	const TRANSLATION_UPDATED = 5;
-
 	/**
 	 * @var \TYPO3\CMS\Lang\Domain\Repository\LanguageRepository
 	 * @inject
@@ -56,21 +46,10 @@ class LanguageController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl
 	protected $extensionRepository;
 
 	/**
-	 * @var \TYPO3\CMS\Extensionmanager\Utility\Repository\Helper
-	 * @inject
-	 */
-	protected $repositoryHelper;
-
-	/**
-	 * @var \TYPO3\CMS\Lang\Utility\Connection\Ter
+	 * @var \TYPO3\CMS\Lang\Service\UpdateTranslationService
 	 * @inject
 	 */
-	protected $terConnection;
-
-	/**
-	 * @var array
-	 */
-	protected $translationStates = array();
+	protected $updateTranslationService;
 
 	/**
 	 * JSON actions
@@ -141,117 +120,10 @@ class LanguageController extends \TYPO3\CMS\Extbase\Mvc\Controller\ActionControl
 	 * @return void
 	 */
 	public function updateTranslationAction($extension, $locales) {
-		if (is_string($locales)) {
-			$locales = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $locales);
-		}
-		$locales = array_flip((array) $locales);
-
-		foreach ($locales as $locale => $key) {
-			$state = static::TRANSLATION_INVALID;
-			try {
-				$state = $this->getTranslationStateForExtension($extension, $locale);
-				if ($state === static::TRANSLATION_AVAILABLE) {
-					$state = $this->updateTranslationForExtension($extension, $locale);
-				}
-			} catch (\Exception $exception) {
-				$error = $exception->getMessage();
-			}
-			$locales[$locale] = array(
-				'state'  => $state,
-				'error'  => $error,
-			);
-		}
-
+		$locales = $this->updateTranslationService->updateTranslation($extension, $locales);
 		$this->view->assign('extension', $extension);
 		$this->view->assign('locales', $locales);
 	}
 
-	/**
-	 * Returns the translation state for an extension
-	 *
-	 * @param string $extensionKey The extension key
-	 * @param string $locale Locale to return
-	 * @return integer Translation state
-	 */
-	protected function getTranslationStateForExtension($extensionKey, $locale) {
-		if (empty($extensionKey) || empty($locale)) {
-			return static::TRANSLATION_INVALID;
-		}
-
-		$identifier = $extensionKey . '-' . $locale;
-		if (isset($this->translationStates[$identifier])) {
-			return $this->translationStates[$identifier];
-		}
-
-		$selectedLanguages = $this->languageRepository->findSelected();
-		if (empty($selectedLanguages) || !is_array($selectedLanguages)) {
-			return static::TRANSLATION_INVALID;
-		}
-
-		$mirrorUrl = $this->repositoryHelper->getMirrors()->getMirrorUrl();
-		$status = $this->terConnection->fetchTranslationStatus($extensionKey, $mirrorUrl);
-
-		foreach ($selectedLanguages as $language) {
-			$stateLocale = $language->getLocale();
-			$stateIdentifier = $extensionKey . '-' . $stateLocale;
-			$this->translationStates[$stateIdentifier] = static::TRANSLATION_INVALID;
-
-			if (empty($status[$stateLocale]) || !is_array($status[$stateLocale])) {
-				$this->translationStates[$stateIdentifier] = static::TRANSLATION_NOT_AVAILABLE;
-				continue;
-			}
-
-			$md5 = $this->getTranslationFileMd5($extensionKey, $stateLocale);
-			if ($md5 !== $status[$stateLocale]['md5']) {
-				$this->translationStates[$stateIdentifier] = static::TRANSLATION_AVAILABLE;
-				continue;
-			}
-
-			$this->translationStates[$stateIdentifier] = static::TRANSLATION_OK;
-		}
-
-		return $this->translationStates[$identifier];
-	}
-
-	/**
-	 * Returns the md5 of a translation file
-	 *
-	 * @param string $extensionKey The extension key
-	 * @param string $locale The locale
-	 * @return string The md5 value
-	 */
-	protected function getTranslationFileMd5($extensionKey, $locale) {
-		if (empty($extensionKey) || empty($locale)) {
-			return '';
-		}
-		$fileName = PATH_site . 'typo3temp' . DIRECTORY_SEPARATOR . $extensionKey . '-l10n-' . $locale . '.zip';
-		if (is_file($fileName)) {
-			return md5_file($fileName);
-		}
-		return '';
-	}
-
-	/**
-	 * Update the translation for an extension
-	 *
-	 * @param string $extensionKey The extension key
-	 * @param string $locale Locale to update
-	 * @return integer Translation state
-	 */
-	protected function updateTranslationForExtension($extensionKey, $locale) {
-		if (empty($extensionKey) || empty($locale)) {
-			return static::TRANSLATION_INVALID;
-		}
-
-		$state = static::TRANSLATION_FAILED;
-		$mirrorUrl = $this->repositoryHelper->getMirrors()->getMirrorUrl();
-		$updateResult = $this->terConnection->updateTranslation($extensionKey, $locale, $mirrorUrl);
-		if ($updateResult === TRUE) {
-			$state = static::TRANSLATION_UPDATED;
-		}
-
-		return $state;
-	}
-
 }
 ?>
\ No newline at end of file
diff --git a/typo3/sysext/lang/Classes/Service/UpdateTranslationService.php b/typo3/sysext/lang/Classes/Service/UpdateTranslationService.php
new file mode 100644
index 0000000000000000000000000000000000000000..3d01bc48b89e12d617d4bfbb45575bd91a2d7823
--- /dev/null
+++ b/typo3/sysext/lang/Classes/Service/UpdateTranslationService.php
@@ -0,0 +1,184 @@
+<?php
+namespace TYPO3\CMS\Lang\Service;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2013 Wouter Wolters <typo3@wouterwolters.nl>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+/**
+ * Update languages service
+ */
+class UpdateTranslationService {
+
+	/**
+	 * Status codes for AJAX response
+	 */
+	const TRANSLATION_NOT_AVAILABLE = 0;
+	const TRANSLATION_AVAILABLE = 1;
+	const TRANSLATION_FAILED = 2;
+	const TRANSLATION_OK = 3;
+	const TRANSLATION_INVALID = 4;
+	const TRANSLATION_UPDATED = 5;
+
+	/**
+	 * @var \TYPO3\CMS\Lang\Domain\Repository\LanguageRepository
+	 * @inject
+	 */
+	protected $languageRepository;
+
+	/**
+	 * @var \TYPO3\CMS\Extensionmanager\Utility\Repository\Helper
+	 * @inject
+	 */
+	protected $repositoryHelper;
+
+	/**
+	 * @var \TYPO3\CMS\Lang\Utility\Connection\Ter
+	 * @inject
+	 */
+	protected $terConnection;
+
+	/**
+	 * @var array
+	 */
+	protected $translationStates = array();
+
+	/**
+	 * Update translation for given extension
+	 *
+	 * @param string $extension The extension key
+	 * @param string $locales Comma separated list of locales to update
+	 * @return array
+	 */
+	public function updateTranslation($extension, $locales) {
+		if (is_string($locales)) {
+			$locales = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $locales);
+		}
+		$locales = array_flip((array) $locales);
+
+		foreach ($locales as $locale => $key) {
+			$state = static::TRANSLATION_INVALID;
+			try {
+				$state = $this->getTranslationStateForExtension($extension, $locale);
+				if ($state === static::TRANSLATION_AVAILABLE) {
+					$state = $this->updateTranslationForExtension($extension, $locale);
+				}
+			} catch (\Exception $exception) {
+				$error = $exception->getMessage();
+			}
+			$locales[$locale] = array(
+				'state'  => $state,
+				'error'  => $error,
+			);
+		}
+		return $locales;
+	}
+
+	/**
+	 * Returns the translation state for an extension
+	 *
+	 * @param string $extensionKey The extension key
+	 * @param string $locale Locale to return
+	 * @return integer Translation state
+	 */
+	protected function getTranslationStateForExtension($extensionKey, $locale) {
+		if (empty($extensionKey) || empty($locale)) {
+			return static::TRANSLATION_INVALID;
+		}
+
+		$identifier = $extensionKey . '-' . $locale;
+		if (isset($this->translationStates[$identifier])) {
+			return $this->translationStates[$identifier];
+		}
+
+		$selectedLanguages = $this->languageRepository->findSelected();
+		if (empty($selectedLanguages) || !is_array($selectedLanguages)) {
+			return static::TRANSLATION_INVALID;
+		}
+
+		$mirrorUrl = $this->repositoryHelper->getMirrors()->getMirrorUrl();
+		$status = $this->terConnection->fetchTranslationStatus($extensionKey, $mirrorUrl);
+
+		foreach ($selectedLanguages as $language) {
+			$stateLocale = $language->getLocale();
+			$stateIdentifier = $extensionKey . '-' . $stateLocale;
+			$this->translationStates[$stateIdentifier] = static::TRANSLATION_INVALID;
+
+			if (empty($status[$stateLocale]) || !is_array($status[$stateLocale])) {
+				$this->translationStates[$stateIdentifier] = static::TRANSLATION_NOT_AVAILABLE;
+				continue;
+			}
+
+			$md5 = $this->getTranslationFileMd5($extensionKey, $stateLocale);
+			if ($md5 !== $status[$stateLocale]['md5']) {
+				$this->translationStates[$stateIdentifier] = static::TRANSLATION_AVAILABLE;
+				continue;
+			}
+
+			$this->translationStates[$stateIdentifier] = static::TRANSLATION_OK;
+		}
+
+		return $this->translationStates[$identifier];
+	}
+
+	/**
+	 * Returns the md5 of a translation file
+	 *
+	 * @param string $extensionKey The extension key
+	 * @param string $locale The locale
+	 * @return string The md5 value
+	 */
+	protected function getTranslationFileMd5($extensionKey, $locale) {
+		if (empty($extensionKey) || empty($locale)) {
+			return '';
+		}
+		$fileName = PATH_site . 'typo3temp' . DIRECTORY_SEPARATOR . $extensionKey . '-l10n-' . $locale . '.zip';
+		if (is_file($fileName)) {
+			return md5_file($fileName);
+		}
+		return '';
+	}
+
+	/**
+	 * Update the translation for an extension
+	 *
+	 * @param string $extensionKey The extension key
+	 * @param string $locale Locale to update
+	 * @return integer Translation state
+	 */
+	protected function updateTranslationForExtension($extensionKey, $locale) {
+		if (empty($extensionKey) || empty($locale)) {
+			return static::TRANSLATION_INVALID;
+		}
+
+		$state = static::TRANSLATION_FAILED;
+		$mirrorUrl = $this->repositoryHelper->getMirrors()->getMirrorUrl();
+		$updateResult = $this->terConnection->updateTranslation($extensionKey, $locale, $mirrorUrl);
+		if ($updateResult === TRUE) {
+			$state = static::TRANSLATION_UPDATED;
+		}
+
+		return $state;
+	}
+
+}
+?>
\ No newline at end of file
diff --git a/typo3/sysext/lang/Resources/Private/Language/locallang.xlf b/typo3/sysext/lang/Resources/Private/Language/locallang.xlf
index fe0742278441f99d27f0f181e61c373d4b06e289..4781ff76887ccd37ea5c0fd407e96ffd32e8fa32 100644
--- a/typo3/sysext/lang/Resources/Private/Language/locallang.xlf
+++ b/typo3/sysext/lang/Resources/Private/Language/locallang.xlf
@@ -63,7 +63,6 @@
 			<trans-unit id="flashmessage.canceled" xml:space="preserve">
 				<source>The process has been canceled.</source>
 			</trans-unit>
-
 		</body>
 	</file>
 </xliff>
\ No newline at end of file
diff --git a/typo3/sysext/lang/ext_localconf.php b/typo3/sysext/lang/ext_localconf.php
index be9ab19dfff320176dc6970d8a8b9814c0af97e3..f8fdec13a42f09b642a50413c502e154770aea9e 100644
--- a/typo3/sysext/lang/ext_localconf.php
+++ b/typo3/sysext/lang/ext_localconf.php
@@ -18,4 +18,7 @@ if (isset($GLOBALS['TYPO3_CONF_VARS']['SYS']['lang']['cache']['clear_menu']) &&
 }
 // Register Ajax call
 $GLOBALS['TYPO3_CONF_VARS']['BE']['AJAX']['lang::clearCache'] = 'TYPO3\CMS\Lang\LanguageCacheClearer->clearCache';
+
+// Register language update command controller
+$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'TYPO3\\CMS\\Lang\\Command\\UpdateCommandController';
 ?>
\ No newline at end of file