[FEATURE] Support custom translation servers for extensions
[Packages/TYPO3.CMS.git] / typo3 / sysext / lang / Classes / Service / UpdateTranslationService.php
1 <?php
2 namespace TYPO3\CMS\Lang\Service;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2013 Wouter Wolters <typo3@wouterwolters.nl>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 /**
28 * Update languages service
29 */
30 class UpdateTranslationService {
31
32 /**
33 * Status codes for AJAX response
34 */
35 const TRANSLATION_NOT_AVAILABLE = 0;
36 const TRANSLATION_AVAILABLE = 1;
37 const TRANSLATION_FAILED = 2;
38 const TRANSLATION_OK = 3;
39 const TRANSLATION_INVALID = 4;
40 const TRANSLATION_UPDATED = 5;
41
42 /**
43 * @var \TYPO3\CMS\Lang\Domain\Repository\LanguageRepository
44 * @inject
45 */
46 protected $languageRepository;
47
48 /**
49 * @var \TYPO3\CMS\Extensionmanager\Utility\Repository\Helper
50 * @inject
51 */
52 protected $repositoryHelper;
53
54 /**
55 * @var \TYPO3\CMS\Lang\Utility\Connection\Ter
56 * @inject
57 */
58 protected $terConnection;
59
60 /**
61 * @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher
62 * @inject
63 */
64 protected $signalSlotDispatcher;
65
66 /**
67 * @var array
68 */
69 protected $translationStates = array();
70
71 /**
72 * Update translation for given extension
73 *
74 * @param string $extension The extension key
75 * @param string $locales Comma separated list of locales to update
76 * @return array
77 */
78 public function updateTranslation($extension, $locales) {
79 if (is_string($locales)) {
80 $locales = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $locales);
81 }
82 $locales = array_flip((array) $locales);
83
84 foreach ($locales as $locale => $key) {
85 $state = static::TRANSLATION_INVALID;
86 try {
87 $state = $this->getTranslationStateForExtension($extension, $locale);
88 if ($state === static::TRANSLATION_AVAILABLE) {
89 $state = $this->updateTranslationForExtension($extension, $locale);
90 }
91 } catch (\Exception $exception) {
92 $error = $exception->getMessage();
93 }
94 $locales[$locale] = array(
95 'state' => $state,
96 'error' => $error,
97 );
98 }
99 return $locales;
100 }
101
102 /**
103 * Returns the translation state for an extension
104 *
105 * @param string $extensionKey The extension key
106 * @param string $locale Locale to return
107 * @return integer Translation state
108 */
109 protected function getTranslationStateForExtension($extensionKey, $locale) {
110 if (empty($extensionKey) || empty($locale)) {
111 return static::TRANSLATION_INVALID;
112 }
113
114 $identifier = $extensionKey . '-' . $locale;
115 if (isset($this->translationStates[$identifier])) {
116 return $this->translationStates[$identifier];
117 }
118
119 $selectedLanguages = $this->languageRepository->findSelected();
120 if (empty($selectedLanguages) || !is_array($selectedLanguages)) {
121 return static::TRANSLATION_INVALID;
122 }
123
124 $mirrorUrl = $this->getMirrorUrl($extensionKey);
125 $status = $this->terConnection->fetchTranslationStatus($extensionKey, $mirrorUrl);
126
127 foreach ($selectedLanguages as $language) {
128 $stateLocale = $language->getLocale();
129 $stateIdentifier = $extensionKey . '-' . $stateLocale;
130 $this->translationStates[$stateIdentifier] = static::TRANSLATION_INVALID;
131
132 if (empty($status[$stateLocale]) || !is_array($status[$stateLocale])) {
133 $this->translationStates[$stateIdentifier] = static::TRANSLATION_NOT_AVAILABLE;
134 continue;
135 }
136
137 $md5 = $this->getTranslationFileMd5($extensionKey, $stateLocale);
138 if ($md5 !== $status[$stateLocale]['md5']) {
139 $this->translationStates[$stateIdentifier] = static::TRANSLATION_AVAILABLE;
140 continue;
141 }
142
143 $this->translationStates[$stateIdentifier] = static::TRANSLATION_OK;
144 }
145
146 return $this->translationStates[$identifier];
147 }
148
149 /**
150 * Returns the md5 of a translation file
151 *
152 * @param string $extensionKey The extension key
153 * @param string $locale The locale
154 * @return string The md5 value
155 */
156 protected function getTranslationFileMd5($extensionKey, $locale) {
157 if (empty($extensionKey) || empty($locale)) {
158 return '';
159 }
160 $fileName = PATH_site . 'typo3temp' . DIRECTORY_SEPARATOR . $extensionKey . '-l10n-' . $locale . '.zip';
161 if (is_file($fileName)) {
162 return md5_file($fileName);
163 }
164 return '';
165 }
166
167 /**
168 * Update the translation for an extension
169 *
170 * @param string $extensionKey The extension key
171 * @param string $locale Locale to update
172 * @return integer Translation state
173 */
174 protected function updateTranslationForExtension($extensionKey, $locale) {
175 if (empty($extensionKey) || empty($locale)) {
176 return static::TRANSLATION_INVALID;
177 }
178
179 $state = static::TRANSLATION_FAILED;
180 $mirrorUrl = $this->getMirrorUrl($extensionKey);
181 $updateResult = $this->terConnection->updateTranslation($extensionKey, $locale, $mirrorUrl);
182 if ($updateResult === TRUE) {
183 $state = static::TRANSLATION_UPDATED;
184 }
185
186 return $state;
187 }
188
189 /**
190 * Returns the mirror URL for a given extension.
191 *
192 * @param string $extensionKey
193 * @return string
194 */
195 protected function getMirrorUrl($extensionKey) {
196 $mirrorUrl = $this->repositoryHelper->getMirrors()->getMirrorUrl();
197
198 $this->signalSlotDispatcher->dispatch(
199 __CLASS__,
200 'postProcessMirrorUrl',
201 array(
202 'extensionKey' => $extensionKey,
203 'mirrorUrl' => &$mirrorUrl,
204 )
205 );
206
207 return $mirrorUrl;
208 }
209
210 }
211 ?>