[BUGFIX] Flush l10n cache after translation update
[Packages/TYPO3.CMS.git] / typo3 / sysext / lang / Classes / Controller / LanguageController.php
1 <?php
2 namespace TYPO3\CMS\Lang\Controller;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16 use TYPO3\CMS\Backend\Template\Components\ButtonBar;
17 use TYPO3\CMS\Backend\Template\Components\Menu\Menu;
18 use TYPO3\CMS\Backend\Template\Components\Menu\MenuItem;
19 use TYPO3\CMS\Backend\View\BackendTemplateView;
20 use TYPO3\CMS\Core\Cache\CacheManager;
21 use TYPO3\CMS\Core\Imaging\Icon;
22 use TYPO3\CMS\Core\Utility\GeneralUtility;
23 use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
24 use TYPO3\CMS\Extbase\Mvc\Web\Routing\UriBuilder;
25 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
26
27 /**
28 * Language controller
29 */
30 class LanguageController extends ActionController
31 {
32 /**
33 * @var string
34 */
35 protected $defaultViewObjectName = BackendTemplateView::class;
36
37 /**
38 * @var BackendTemplateView
39 */
40 protected $view;
41
42 /**
43 * @var \TYPO3\CMS\Lang\Domain\Repository\LanguageRepository
44 */
45 protected $languageRepository;
46
47 /**
48 * @var \TYPO3\CMS\Lang\Domain\Repository\ExtensionRepository
49 */
50 protected $extensionRepository;
51
52 /**
53 * @var \TYPO3\CMS\Lang\Service\TranslationService
54 */
55 protected $translationService;
56
57 /**
58 * @var \TYPO3\CMS\Lang\Service\RegistryService
59 */
60 protected $registryService;
61
62 /**
63 * @param \TYPO3\CMS\Lang\Domain\Repository\LanguageRepository $languageRepository
64 */
65 public function injectLanguageRepository(\TYPO3\CMS\Lang\Domain\Repository\LanguageRepository $languageRepository)
66 {
67 $this->languageRepository = $languageRepository;
68 }
69
70 /**
71 * @param \TYPO3\CMS\Lang\Domain\Repository\ExtensionRepository $extensionRepository
72 */
73 public function injectExtensionRepository(\TYPO3\CMS\Lang\Domain\Repository\ExtensionRepository $extensionRepository)
74 {
75 $this->extensionRepository = $extensionRepository;
76 }
77
78 /**
79 * @param \TYPO3\CMS\Lang\Service\TranslationService $translationService
80 */
81 public function injectTranslationService(\TYPO3\CMS\Lang\Service\TranslationService $translationService)
82 {
83 $this->translationService = $translationService;
84 }
85
86 /**
87 * @param \TYPO3\CMS\Lang\Service\RegistryService $registryService
88 */
89 public function injectRegistryService(\TYPO3\CMS\Lang\Service\RegistryService $registryService)
90 {
91 $this->registryService = $registryService;
92 }
93
94 /**
95 * List languages
96 *
97 * @return void
98 */
99 public function listLanguagesAction()
100 {
101 $this->prepareDocHeaderMenu();
102 $this->prepareDocHeaderButtons();
103
104 $languages = $this->languageRepository->findAll();
105 $this->view->assign('languages', $languages);
106 }
107
108 /**
109 * List translations
110 *
111 * @return void
112 */
113 public function listTranslationsAction()
114 {
115 $this->prepareDocHeaderMenu();
116
117 $languages = $this->languageRepository->findSelected();
118 $this->view->assign('languages', $languages);
119 }
120
121 /**
122 * Returns the translations
123 *
124 * @return void
125 */
126 public function getTranslationsAction()
127 {
128 $this->view->assign('extensions', $this->extensionRepository->findAll());
129 $this->view->assign('languages', $this->languageRepository->findSelected());
130 }
131
132 /**
133 * Fetch all translations for given locale
134 *
135 * @param array $data The request data
136 * @return void
137 */
138 public function updateLanguageAction(array $data)
139 {
140 $numberOfExtensionsToUpdate = 10;
141 $response = array(
142 'success' => false,
143 'progress' => 0,
144 );
145 if (!empty($data['locale'])) {
146 $allCount = 0;
147 for ($i = 0; $i < $numberOfExtensionsToUpdate; $i++) {
148 $offset = (int)$data['count'] * $numberOfExtensionsToUpdate + $i;
149 $extension = $this->extensionRepository->findOneByOffset($offset);
150 if (empty($extension)) {
151 // No more extensions to update
152 break;
153 }
154 if ($allCount === 0) {
155 $allCount = (int)$this->extensionRepository->countAll();
156 }
157 $extensionKey = $extension->getKey();
158 $result = $this->translationService->updateTranslation($extensionKey, $data['locale']);
159 $progress = round((($offset + 1) * 100) / $allCount, 2);
160 $response['result'][$data['locale']][$extensionKey] = $result[$data['locale']];
161 if (empty($result[$extensionKey][$data['locale']]['error'])) {
162 $response['success'] = true;
163 } else {
164 // Could not update an extension, stop here!
165 $response['success'] = false;
166 break;
167 }
168 }
169 }
170 if ($response['success']) {
171 $this->registryService->set($data['locale'], $GLOBALS['EXEC_TIME']);
172 $response['timestamp'] = $GLOBALS['EXEC_TIME'];
173 $response['progress'] = $progress > 100 ? 100 : $progress;
174 }
175 $this->view->assign('response', $response);
176 // Flush language cache
177 GeneralUtility::makeInstance(CacheManager::class)->getCache('l10n')->flush();
178 }
179
180 /**
181 * Fetch the translation for given extension and locale
182 *
183 * @param array $data The request data
184 * @return void
185 */
186 public function updateTranslationAction(array $data)
187 {
188 $response = array('success' => false);
189 if (!empty($data['extension']) && !empty($data['locale'])) {
190 $result = $this->translationService->updateTranslation($data['extension'], $data['locale']);
191 if (empty($result[$data['extension']][$data['locale']]['error'])) {
192 $response = array(
193 'success' => true,
194 'result' => $result,
195 );
196 }
197 }
198 $this->view->assign('response', $response);
199 // Flush language cache
200 GeneralUtility::makeInstance(CacheManager::class)->getCache('l10n')->flush();
201 }
202
203 /**
204 * Activate a language
205 *
206 * @param array $data The request data
207 * @return void
208 */
209 public function activateLanguageAction(array $data)
210 {
211 $response = array('success' => false);
212 if (!empty($data['locale'])) {
213 $response = $this->languageRepository->activateByLocale($data['locale']);
214 }
215 $this->view->assign('response', $response);
216 }
217
218 /**
219 * Deactivate a language
220 *
221 * @param array $data The request data
222 * @return void
223 */
224 public function deactivateLanguageAction(array $data)
225 {
226 $response = array('success' => false);
227 if (!empty($data['locale'])) {
228 $response = $this->languageRepository->deactivateByLocale($data['locale']);
229 }
230 $this->view->assign('response', $response);
231 }
232
233 /**
234 * DocHeaderMenu
235 */
236 protected function prepareDocHeaderMenu()
237 {
238 $this->view->getModuleTemplate()->setModuleName('typo3-module-lang');
239 $this->view->getModuleTemplate()->setModuleId('typo3-module-lang');
240
241 $this->view->getModuleTemplate()->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Lang/LanguageModule');
242
243 $extensionKey = 'lang';
244 $addJsInlineLabels = [
245 'flashmessage.error',
246 'flashmessage.information',
247 'flashmessage.success',
248 'flashmessage.multipleErrors',
249 'flashmessage.updateComplete',
250 'flashmessage.canceled',
251 'flashmessage.languageActivated',
252 'flashmessage.languageDeactivated',
253 'flashmessage.noLanguageActivated',
254 'flashmessage.errorOccurred',
255 'table.processing',
256 'table.search',
257 'table.loadingRecords',
258 'table.zeroRecords',
259 'table.emptyTable',
260 'table.dateFormat',
261 ];
262 foreach ($addJsInlineLabels as $key) {
263 $label = LocalizationUtility::translate($key, $extensionKey);
264 $this->view->getModuleTemplate()->getPageRenderer()->addInlineLanguageLabel($key, $label);
265 }
266
267 $uriBuilder = $this->objectManager->get(UriBuilder::class);
268 $uriBuilder->setRequest($this->request);
269
270 /** @var Menu $menu */
271 $menu = GeneralUtility::makeInstance(Menu::class);
272 $menu->setIdentifier('_languageMenu');
273 $menu->setLabel($this->getLanguageService()->sL('LLL:EXT:lang/locallang_general.xlf:LGL.language', true));
274
275 /** @var MenuItem $languageListMenuItem */
276 $languageListMenuItem = GeneralUtility::makeInstance(MenuItem::class);
277 $action = 'listLanguages';
278 $isActive = $this->request->getControllerActionName() === $action ? true : false;
279 $languageListMenuItem->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang.xlf:header.languages'));
280 $uri = $uriBuilder->reset()->uriFor('listLanguages', array(), 'Language');
281 $languageListMenuItem->setHref($uri)->setActive($isActive);
282
283 /** @var MenuItem $translationMenuItem */
284 $translationMenuItem = GeneralUtility::makeInstance(MenuItem::class);
285 $action = 'listTranslations';
286 $isActive = $this->request->getControllerActionName() === $action ? true : false;
287 $translationMenuItem->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang.xlf:header.translations'));
288 $uri = $uriBuilder->reset()->uriFor('listTranslations', array(), 'Language');
289 $translationMenuItem->setHref($uri)->setActive($isActive);
290
291 $menu->addMenuItem($languageListMenuItem);
292 $menu->addMenuItem($translationMenuItem);
293 $this->view->getModuleTemplate()->getDocHeaderComponent()->getMenuRegistry()->addMenu($menu);
294 $this->view->getModuleTemplate()->setFlashMessageQueue($this->controllerContext->getFlashMessageQueue());
295 }
296
297 /**
298 * Returns LanguageService
299 *
300 * @return \TYPO3\CMS\Lang\LanguageService
301 */
302 protected function getLanguageService()
303 {
304 return $GLOBALS['LANG'];
305 }
306
307 /**
308 * DocHeaderButtons
309 */
310 protected function prepareDocHeaderButtons()
311 {
312 // @todo: the html structure needed to operate the buttons correctly is broken now.
313 // @todo: LanguageModule.js and backend.css -> div.typo3-module-lang div.menuItems
314
315 $downloadAllButton = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar()->makeLinkButton()
316 ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-system-extension-download', Icon::SIZE_SMALL))
317 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang.xlf:button.downloadAll'))
318 ->setClasses('menuItem updateItem t3js-button-update')
319 ->setDataAttributes(['action' => 'updateActiveLanguages'])
320 ->setHref('#');
321 $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar()->addButton($downloadAllButton, ButtonBar::BUTTON_POSITION_LEFT);
322
323 $cancelButton = $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar()->makeLinkButton()
324 ->setIcon($this->view->getModuleTemplate()->getIconFactory()->getIcon('actions-document-close', Icon::SIZE_SMALL))
325 ->setTitle($this->getLanguageService()->sL('LLL:EXT:lang/Resources/Private/Language/locallang.xlf:button.cancel'))
326 ->setClasses('menuItem cancelItem disabled t3js-button-cancel')
327 ->setDataAttributes(['action' => 'cancelLanguageUpdate'])
328 ->setHref('#');
329
330 $this->view->getModuleTemplate()->getDocHeaderComponent()->getButtonBar()->addButton($cancelButton, ButtonBar::BUTTON_POSITION_LEFT);
331 }
332 }