43870a4e0d67baaa8130ef07d01b86e5b21ba23a
[Packages/TYPO3.CMS.git] / typo3 / sysext / frontend / Classes / Controller / TranslationStatusController.php
1 <?php
2 namespace TYPO3\CMS\Frontend\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
17 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Backend\Utility\IconUtility;
19
20 /**
21 * Class for displaying translation status of pages in the tree.
22 *
23 * @author Kasper Skårhøj <kasperYYYY@typo3.com>
24 */
25 class TranslationStatusController extends \TYPO3\CMS\Backend\Module\AbstractFunctionModule {
26
27 /**
28 * Returns the menu array
29 *
30 * @return array
31 */
32 public function modMenu() {
33 $menuArray = array(
34 'depth' => array(
35 0 => $GLOBALS['LANG']->getLL('depth_0'),
36 1 => $GLOBALS['LANG']->getLL('depth_1'),
37 2 => $GLOBALS['LANG']->getLL('depth_2'),
38 3 => $GLOBALS['LANG']->getLL('depth_3'),
39 999 => $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_core.xlf:labels.depth_infi')
40 )
41 );
42 // Languages:
43 $lang = $this->getSystemLanguages();
44 $menuArray['lang'] = array(
45 0 => '[All]'
46 );
47 foreach ($lang as $langRec) {
48 $menuArray['lang'][$langRec['uid']] = $langRec['title'];
49 }
50 return $menuArray;
51 }
52
53 /**
54 * MAIN function for page information of localization
55 *
56 * @return string Output HTML for the module.
57 */
58 public function main() {
59 $theOutput = $this->pObj->doc->header($GLOBALS['LANG']->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_title'));
60 if ($this->pObj->id) {
61 // Depth selector:
62 $h_func = BackendUtility::getFuncMenu($this->pObj->id, 'SET[depth]', $this->pObj->MOD_SETTINGS['depth'], $this->pObj->MOD_MENU['depth']);
63 $h_func .= BackendUtility::getFuncMenu($this->pObj->id, 'SET[lang]', $this->pObj->MOD_SETTINGS['lang'], $this->pObj->MOD_MENU['lang']);
64 $theOutput .= $h_func;
65 // Add CSH:
66 $theOutput .= BackendUtility::cshItem('_MOD_web_info', 'lang', NULL, '|<br />');
67 // Showing the tree:
68 // Initialize starting point of page tree:
69 $treeStartingPoint = (int)$this->pObj->id;
70 $treeStartingRecord = BackendUtility::getRecordWSOL('pages', $treeStartingPoint);
71 $depth = $this->pObj->MOD_SETTINGS['depth'];
72 // Initialize tree object:
73 $tree = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Tree\View\PageTreeView::class);
74 $tree->init('AND ' . $GLOBALS['BE_USER']->getPagePermsClause(1));
75 $tree->addField('l18n_cfg');
76 // Creating top icon; the current page
77 $HTML = IconUtility::getSpriteIconForRecord('pages', $treeStartingRecord);
78 $tree->tree[] = array(
79 'row' => $treeStartingRecord,
80 'HTML' => $HTML
81 );
82 // Create the tree from starting point:
83 if ($depth) {
84 $tree->getTree($treeStartingPoint, $depth, '');
85 }
86 // Render information table:
87 $theOutput .= $this->renderL10nTable($tree);
88 }
89 return $theOutput;
90 }
91
92 /**
93 * Rendering the localization information table.
94 *
95 * @param array $tree The Page tree data
96 * @return string HTML for the localization information table.
97 */
98 public function renderL10nTable(&$tree) {
99 // System languages retrieved:
100 $languages = $this->getSystemLanguages();
101 // Title length:
102 $titleLen = $GLOBALS['BE_USER']->uc['titleLen'];
103 // Put together the TREE:
104 $output = '';
105 $newOL_js = array();
106 $langRecUids = array();
107 foreach ($tree->tree as $data) {
108 $tCells = array();
109 $langRecUids[0][] = $data['row']['uid'];
110 // Page icons / titles etc.
111 $tCells[] = '<td' . ($data['row']['_CSSCLASS'] ? ' class="' . $data['row']['_CSSCLASS'] . '"' : '') . '>' .
112 $GLOBALS['SOBE']->doc->wrapClickMenuOnIcon($data['HTML'], 'pages', $data['row']['uid']) .
113 htmlspecialchars(\TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs($data['row']['title'], $titleLen)) .
114 ((string)$data['row']['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars(\TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs($data['row']['nav_title'], $titleLen)) . '</em>]' : '') .
115 '</td>';
116 // DEFAULT language:
117 // "View page" link is created:
118 $viewPageLink = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick(
119 $data['row']['uid'], $GLOBALS['BACK_PATH'], '', '', '', '&L=###LANG_UID###')
120 ) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_viewPage') . '">' .
121 IconUtility::getSpriteIcon('actions-document-view') . '</a>';
122 $status = $data['row']['l18n_cfg'] & 1 ? 'danger' : 'success';
123 // Create links:
124 $info = '';
125 $editUid = $data['row']['uid'];
126 $params = '&edit[pages][' . $editUid . ']=edit';
127 $info .= '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick(
128 $params, $GLOBALS['BACK_PATH'])
129 ) . '" title="' . $GLOBALS['LANG']->sL(
130 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editDefaultLanguagePage'
131 ) . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
132 $info .= '<a href="#" onclick="' . htmlspecialchars(
133 'top.loadEditId(' . (int)$data['row']['uid'] . ',"&SET[language]=0"); return false;'
134 ) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editPage') . '">' .
135 IconUtility::getSpriteIcon('actions-page-open') . '</a>';
136 $info .= str_replace('###LANG_UID###', '0', $viewPageLink);
137 $info .= '&nbsp;';
138 $info .= $data['row']['l18n_cfg'] & 1 ? '<span title="' . $GLOBALS['LANG']->sL('LLL:EXT:cms/locallang_tca.xlf:pages.l18n_cfg.I.1', TRUE) . '">D</span>' : '&nbsp;';
139 $info .= \TYPO3\CMS\Core\Utility\GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) ? '<span title="' . $GLOBALS['LANG']->sL('LLL:EXT:cms/locallang_tca.xlf:pages.l18n_cfg.I.2', TRUE) . '">N</span>' : '&nbsp;';
140 // Put into cell:
141 $tCells[] = '<td class="' . $status . ' col-border-left">' . $info . '</td>';
142 $tCells[] = '<td class="' . $status . '" title="' . $GLOBALS['LANG']->sL(
143 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_CEcount'
144 ) . '" align="center">' . $this->getContentElementCount($data['row']['uid'], 0) . '</td>';
145 $modSharedTSconfig = BackendUtility::getModTSconfig($data['row']['uid'], 'mod.SHARED');
146 $disableLanguages = isset($modSharedTSconfig['properties']['disableLanguages']) ? \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $modSharedTSconfig['properties']['disableLanguages'], TRUE) : array();
147 // Traverse system languages:
148 foreach ($languages as $langRow) {
149 if ($this->pObj->MOD_SETTINGS['lang'] == 0 || (int)$this->pObj->MOD_SETTINGS['lang'] === (int)$langRow['uid']) {
150 $row = $this->getLangStatus($data['row']['uid'], $langRow['uid']);
151 $info = '';
152 if (is_array($row)) {
153 $langRecUids[$langRow['uid']][] = $row['uid'];
154 $status = $row['_HIDDEN'] ? (\TYPO3\CMS\Core\Utility\GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || $data['row']['l18n_cfg'] & 1 ? 'danger' : '') : 'success';
155 $icon = IconUtility::getSpriteIconForRecord(
156 'pages_language_overlay',
157 $row,
158 array('class' => 'c-recIcon')
159 );
160 $info = $icon . htmlspecialchars(
161 \TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs($row['title'], $titleLen)
162 ) . ((string)$row['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars(
163 \TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs($row['nav_title'], $titleLen)
164 ) . '</em>]' : '') . ($row['_COUNT'] > 1 ? '<div>' . $GLOBALS['LANG']->sL(
165 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_badThingThereAre'
166 ) . '</div>' : '');
167 $tCells[] = '<td class="' . $status . ' col-border-left">' . $info . '</td>';
168 // Edit whole record:
169 $info = '';
170 $editUid = $row['uid'];
171 $params = '&edit[pages_language_overlay][' . $editUid . ']=edit';
172 $info .= '<a href="#" onclick="' . htmlspecialchars(
173 BackendUtility::editOnClick($params, $GLOBALS['BACK_PATH'])
174 ) . '" title="' . $GLOBALS['LANG']->sL(
175 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editLanguageOverlayRecord'
176 ) . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
177 $info .= '<a href="#" onclick="' . htmlspecialchars(
178 'top.loadEditId(' . (int)$data['row']['uid'] . ',"&SET[language]=' . $langRow['uid'] . '"); return false;'
179 ) . '" title="' . $GLOBALS['LANG']->sL(
180 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editPageLang'
181 ) . '">' . IconUtility::getSpriteIcon('actions-page-open') . '</a>';
182 $info .= str_replace('###LANG_UID###', $langRow['uid'], $viewPageLink);
183 $tCells[] = '<td class="' . $status . '">' . $info . '</td>';
184 $tCells[] = '<td class="' . $status . '" title="' . $GLOBALS['LANG']->sL(
185 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_CEcount'
186 ) . '" align="center">' . $this->getContentElementCount($data['row']['uid'], $langRow['uid']) . '</td>';
187 } else {
188 if (in_array($langRow['uid'], $disableLanguages)) {
189 // Language has been disabled for this page
190 $status = 'danger';
191 $info = '';
192 } else {
193 $status = \TYPO3\CMS\Core\Utility\GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || $data['row']['l18n_cfg'] & 1 ? 'danger' : '';
194 $info = '<input type="checkbox" name="newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']" value="1" />';
195 $newOL_js[$langRow['uid']] .= '
196 +(document.webinfoForm[\'newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']\'].checked ? \'&edit[pages_language_overlay][' . $data['row']['uid'] . ']=new\' : \'\')
197 ';
198 }
199 $tCells[] = '<td class="' . $status . ' col-border-left">&nbsp;</td>';
200 $tCells[] = '<td class="' . $status . '">&nbsp;</td>';
201 $tCells[] = '<td class="' . $status . '">' . $info . '</td>';
202 }
203 }
204 }
205 $output .= '
206 <tr>
207 ' . implode('
208 ', $tCells) . '
209 </tr>';
210 }
211 // Put together HEADER:
212 $tCells = array();
213 $tCells[] = '<td>' . $GLOBALS['LANG']->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_page') . ':</td>';
214 if (is_array($langRecUids[0])) {
215 $params = '&edit[pages][' . implode(',', $langRecUids[0]) . ']=edit&columnsOnly=title,nav_title,l18n_cfg,hidden';
216 $editIco = '<a href="#" onclick="' . htmlspecialchars(
217 BackendUtility::editOnClick($params, $GLOBALS['BACK_PATH'])
218 ) . '" title="' . $GLOBALS['LANG']->sL(
219 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editPageProperties'
220 ) . '">' . IconUtility::getSpriteIcon('actions-document-new') . '</a>';
221 } else {
222 $editIco = '';
223 }
224 $tCells[] = '<td class="col-border-left" colspan="2">' . $GLOBALS['LANG']->sL(
225 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_default'
226 ) . ':' . $editIco . '</td>';
227 foreach ($languages as $langRow) {
228 if ($this->pObj->MOD_SETTINGS['lang'] == 0 || (int)$this->pObj->MOD_SETTINGS['lang'] === (int)$langRow['uid']) {
229 // Title:
230 $tCells[] = '<td class="col-border-left">' . htmlspecialchars($langRow['title']) . '</td>';
231 // Edit language overlay records:
232 if (is_array($langRecUids[$langRow['uid']])) {
233 $params = '&edit[pages_language_overlay][' .
234 implode(',', $langRecUids[$langRow['uid']]) .
235 ']=edit&columnsOnly=title,nav_title,hidden';
236 $tCells[] = '<td><a href="#" onclick="' . htmlspecialchars(
237 BackendUtility::editOnClick($params, $GLOBALS['BACK_PATH'])
238 ) . '" title="' . $GLOBALS['LANG']->sL(
239 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editLangOverlays'
240 ) . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a></td>';
241 } else {
242 $tCells[] = '<td>&nbsp;</td>';
243 }
244 // Create new overlay records:
245 $params = '\'' .
246 $newOL_js[$langRow['uid']] .
247 '+\'&columnsOnly=title,hidden,sys_language_uid&defVals[pages_language_overlay][sys_language_uid]=' .
248 $langRow['uid'];
249 $tCells[] = '<td><a href="#" onclick="' . htmlspecialchars(
250 BackendUtility::editOnClick($params, $GLOBALS['BACK_PATH'])
251 ) . '" title="' . $GLOBALS['LANG']->sL(
252 'LLL:EXT:cms/web_info/locallang.xlf:lang_getlangsta_createNewTranslationHeaders'
253 ) . '">' . IconUtility::getSpriteIcon('actions-document-new') . '</a></td>';
254 }
255 }
256
257 $output =
258 '<div class="table-fit">' .
259 '<table class="table table-striped table-hover" id="langTable">' .
260 '<thead>' .
261 '<tr>' .
262 implode('', $tCells) .
263 '</tr>' .
264 '</thead>' .
265 '<tbody>' .
266 $output .
267 '</tbody>' .
268 '</table>' .
269 '</div>';
270 return $output;
271 }
272
273 /**
274 * Selects all system languages (from sys_language)
275 *
276 * @return array System language records in an array.
277 */
278 public function getSystemLanguages() {
279 if (!$GLOBALS['BE_USER']->user['admin'] && strlen($GLOBALS['BE_USER']->groupData['allowed_languages'])) {
280 $allowed_languages = array_flip(explode(',', $GLOBALS['BE_USER']->groupData['allowed_languages']));
281 }
282 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_language', '1=1' . BackendUtility::deleteClause('sys_language'));
283 $outputArray = array();
284 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
285 if (is_array($allowed_languages) && count($allowed_languages)) {
286 if (isset($allowed_languages[$row['uid']])) {
287 $outputArray[] = $row;
288 }
289 } else {
290 $outputArray[] = $row;
291 }
292 }
293 return $outputArray;
294 }
295
296 /**
297 * Get an alternative language record for a specific page / language
298 *
299 * @param int $pageId Page ID to look up for.
300 * @param int $langId Language UID to select for.
301 * @return array pages_languages_overlay record
302 */
303 public function getLangStatus($pageId, $langId) {
304 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
305 '*',
306 'pages_language_overlay',
307 'pid=' . (int)$pageId .
308 ' AND sys_language_uid=' . (int)$langId .
309 BackendUtility::deleteClause('pages_language_overlay') .
310 BackendUtility::versioningPlaceholderClause('pages_language_overlay')
311 );
312 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
313 BackendUtility::workspaceOL('pages_language_overlay', $row);
314 if (is_array($row)) {
315 $row['_COUNT'] = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
316 $row['_HIDDEN'] = $row['hidden'] || (int)$row['endtime'] > 0 && (int)$row['endtime'] < $GLOBALS['EXEC_TIME'] || $GLOBALS['EXEC_TIME'] < (int)$row['starttime'];
317 }
318 return $row;
319 }
320
321 /**
322 * Counting content elements for a single language on a page.
323 *
324 * @param int $pageId Page id to select for.
325 * @param int $sysLang Sys language uid
326 * @return int Number of content elements from the PID where the language is set to a certain value.
327 */
328 public function getContentElementCount($pageId, $sysLang) {
329 $count = $GLOBALS['TYPO3_DB']->exec_SELECTcountRows('uid', 'tt_content', 'pid=' . (int)$pageId . ' AND sys_language_uid=' . (int)$sysLang . BackendUtility::deleteClause('tt_content') . BackendUtility::versioningPlaceholderClause('tt_content'));
330 return $count ?: '-';
331 }
332
333 }