29ea257ce9c3984b4308be5513a00431a36d8ca8
[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', $GLOBALS['BACK_PATH'], '|<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'] . '"' : '') . '>' . $data['HTML'] . htmlspecialchars(\TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs($data['row']['title'], $titleLen)) . ((string)$data['row']['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars(\TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs($data['row']['nav_title'], $titleLen)) . '</em>]' : '') . '</td>';
112 // DEFAULT language:
113 // "View page" link is created:
114 $viewPageLink = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick(
115 $data['row']['uid'], $GLOBALS['BACK_PATH'], '', '', '', '&L=###LANG_UID###')
116 ) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_viewPage') . '">' .
117 IconUtility::getSpriteIcon('actions-document-view') . '</a>';
118 $status = $data['row']['l18n_cfg'] & 1 ? 'c-blocked' : 'c-ok';
119 // Create links:
120 $info = '';
121 $editUid = $data['row']['uid'];
122 $params = '&edit[pages][' . $editUid . ']=edit';
123 $info .= '<a href="#" onclick="' . htmlspecialchars(BackendUtility::editOnClick(
124 $params, $GLOBALS['BACK_PATH'])
125 ) . '" title="' . $GLOBALS['LANG']->sL(
126 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editDefaultLanguagePage'
127 ) . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
128 $info .= '<a href="#" onclick="' . htmlspecialchars(
129 'top.loadEditId(' . (int)$data['row']['uid'] . ',"&SET[language]=0"); return false;'
130 ) . '" title="' . $GLOBALS['LANG']->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editPage') . '">' .
131 IconUtility::getSpriteIcon('actions-page-open') . '</a>';
132 $info .= str_replace('###LANG_UID###', '0', $viewPageLink);
133 $info .= '&nbsp;';
134 $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;';
135 $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;';
136 // Put into cell:
137 $tCells[] = '<td class="' . $status . ' c-leftLine">' . $info . '</td>';
138 $tCells[] = '<td class="' . $status . '" title="' . $GLOBALS['LANG']->sL(
139 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_CEcount'
140 ) . '" align="center">' . $this->getContentElementCount($data['row']['uid'], 0) . '</td>';
141 $modSharedTSconfig = BackendUtility::getModTSconfig($data['row']['uid'], 'mod.SHARED');
142 $disableLanguages = isset($modSharedTSconfig['properties']['disableLanguages']) ? \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $modSharedTSconfig['properties']['disableLanguages'], TRUE) : array();
143 // Traverse system languages:
144 foreach ($languages as $langRow) {
145 if ($this->pObj->MOD_SETTINGS['lang'] == 0 || (int)$this->pObj->MOD_SETTINGS['lang'] === (int)$langRow['uid']) {
146 $row = $this->getLangStatus($data['row']['uid'], $langRow['uid']);
147 $info = '';
148 if (is_array($row)) {
149 $langRecUids[$langRow['uid']][] = $row['uid'];
150 $status = $row['_HIDDEN'] ? (\TYPO3\CMS\Core\Utility\GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || $data['row']['l18n_cfg'] & 1 ? 'c-blocked' : 'c-fallback') : 'c-ok';
151 $icon = IconUtility::getSpriteIconForRecord(
152 'pages_language_overlay',
153 $row,
154 array('class' => 'c-recIcon')
155 );
156 $info = $icon . htmlspecialchars(
157 \TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs($row['title'], $titleLen)
158 ) . ((string)$row['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars(
159 \TYPO3\CMS\Core\Utility\GeneralUtility::fixed_lgd_cs($row['nav_title'], $titleLen)
160 ) . '</em>]' : '') . ($row['_COUNT'] > 1 ? '<div>' . $GLOBALS['LANG']->sL(
161 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_badThingThereAre'
162 ) . '</div>' : '');
163 $tCells[] = '<td class="' . $status . ' c-leftLine">' . $info . '</td>';
164 // Edit whole record:
165 $info = '';
166 $editUid = $row['uid'];
167 $params = '&edit[pages_language_overlay][' . $editUid . ']=edit';
168 $info .= '<a href="#" onclick="' . htmlspecialchars(
169 BackendUtility::editOnClick($params, $GLOBALS['BACK_PATH'])
170 ) . '" title="' . $GLOBALS['LANG']->sL(
171 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editLanguageOverlayRecord'
172 ) . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a>';
173 $info .= '<a href="#" onclick="' . htmlspecialchars(
174 'top.loadEditId(' . (int)$data['row']['uid'] . ',"&SET[language]=' . $langRow['uid'] . '"); return false;'
175 ) . '" title="' . $GLOBALS['LANG']->sL(
176 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editPageLang'
177 ) . '">' . IconUtility::getSpriteIcon('actions-page-open') . '</a>';
178 $info .= str_replace('###LANG_UID###', $langRow['uid'], $viewPageLink);
179 $tCells[] = '<td class="' . $status . '">' . $info . '</td>';
180 $tCells[] = '<td class="' . $status . '" title="' . $GLOBALS['LANG']->sL(
181 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_CEcount'
182 ) . '" align="center">' . $this->getContentElementCount($data['row']['uid'], $langRow['uid']) . '</td>';
183 } else {
184 if (in_array($langRow['uid'], $disableLanguages)) {
185 // Language has been disabled for this page
186 $status = 'c-blocked';
187 $info = '';
188 } else {
189 $status = \TYPO3\CMS\Core\Utility\GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || $data['row']['l18n_cfg'] & 1 ? 'c-blocked' : 'c-fallback';
190 $info = '<input type="checkbox" name="newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']" value="1" />';
191 $newOL_js[$langRow['uid']] .= '
192 +(document.webinfoForm[\'newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']\'].checked ? \'&edit[pages_language_overlay][' . $data['row']['uid'] . ']=new\' : \'\')
193 ';
194 }
195 $tCells[] = '<td class="' . $status . ' c-leftLine">&nbsp;</td>';
196 $tCells[] = '<td class="' . $status . '">&nbsp;</td>';
197 $tCells[] = '<td class="' . $status . '">' . $info . '</td>';
198 }
199 }
200 }
201 $output .= '
202 <tr class="bgColor4">
203 ' . implode('
204 ', $tCells) . '
205 </tr>';
206 }
207 // Put together HEADER:
208 $tCells = array();
209 $tCells[] = '<td>' . $GLOBALS['LANG']->sL('LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_page') . ':</td>';
210 if (is_array($langRecUids[0])) {
211 $params = '&edit[pages][' . implode(',', $langRecUids[0]) . ']=edit&columnsOnly=title,nav_title,l18n_cfg,hidden';
212 $editIco = '<a href="#" onclick="' . htmlspecialchars(
213 BackendUtility::editOnClick($params, $GLOBALS['BACK_PATH'])
214 ) . '" title="' . $GLOBALS['LANG']->sL(
215 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editPageProperties'
216 ) . '">' . IconUtility::getSpriteIcon('actions-document-new') . '</a>';
217 } else {
218 $editIco = '';
219 }
220 $tCells[] = '<td class="c-leftLine" colspan="2">' . $GLOBALS['LANG']->sL(
221 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_default'
222 ) . ':' . $editIco . '</td>';
223 foreach ($languages as $langRow) {
224 if ($this->pObj->MOD_SETTINGS['lang'] == 0 || (int)$this->pObj->MOD_SETTINGS['lang'] === (int)$langRow['uid']) {
225 // Title:
226 $tCells[] = '<td class="c-leftLine">' . htmlspecialchars($langRow['title']) . '</td>';
227 // Edit language overlay records:
228 if (is_array($langRecUids[$langRow['uid']])) {
229 $params = '&edit[pages_language_overlay][' .
230 implode(',', $langRecUids[$langRow['uid']]) .
231 ']=edit&columnsOnly=title,nav_title,hidden';
232 $tCells[] = '<td><a href="#" onclick="' . htmlspecialchars(
233 BackendUtility::editOnClick($params, $GLOBALS['BACK_PATH'])
234 ) . '" title="' . $GLOBALS['LANG']->sL(
235 'LLL:EXT:cms/web_info/locallang.xlf:lang_renderl10n_editLangOverlays'
236 ) . '">' . IconUtility::getSpriteIcon('actions-document-open') . '</a></td>';
237 } else {
238 $tCells[] = '<td>&nbsp;</td>';
239 }
240 // Create new overlay records:
241 $params = '\'' .
242 $newOL_js[$langRow['uid']] .
243 '+\'&columnsOnly=title,hidden,sys_language_uid&defVals[pages_language_overlay][sys_language_uid]=' .
244 $langRow['uid'];
245 $tCells[] = '<td><a href="#" onclick="' . htmlspecialchars(
246 BackendUtility::editOnClick($params, $GLOBALS['BACK_PATH'])
247 ) . '" title="' . $GLOBALS['LANG']->sL(
248 'LLL:EXT:cms/web_info/locallang.xlf:lang_getlangsta_createNewTranslationHeaders'
249 ) . '">' . IconUtility::getSpriteIcon('actions-document-new') . '</a></td>';
250 }
251 }
252
253 $output = '<table id="langTable" class="t3-table">' .
254 '<thead>' .
255 '<tr>' .
256 implode('', $tCells) .
257 '</tr>' .
258 '</thead>' .
259 '<tbody>' .
260 $output .
261 '</tbody>' .
262 '</table>';
263 return $output;
264 }
265
266 /**
267 * Selects all system languages (from sys_language)
268 *
269 * @return array System language records in an array.
270 */
271 public function getSystemLanguages() {
272 if (!$GLOBALS['BE_USER']->user['admin'] && strlen($GLOBALS['BE_USER']->groupData['allowed_languages'])) {
273 $allowed_languages = array_flip(explode(',', $GLOBALS['BE_USER']->groupData['allowed_languages']));
274 }
275 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('*', 'sys_language', '1=1' . BackendUtility::deleteClause('sys_language'));
276 $outputArray = array();
277 while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
278 if (is_array($allowed_languages) && count($allowed_languages)) {
279 if (isset($allowed_languages[$row['uid']])) {
280 $outputArray[] = $row;
281 }
282 } else {
283 $outputArray[] = $row;
284 }
285 }
286 return $outputArray;
287 }
288
289 /**
290 * Get an alternative language record for a specific page / language
291 *
292 * @param int $pageId Page ID to look up for.
293 * @param int $langId Language UID to select for.
294 * @return array pages_languages_overlay record
295 */
296 public function getLangStatus($pageId, $langId) {
297 $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery(
298 '*',
299 'pages_language_overlay',
300 'pid=' . (int)$pageId .
301 ' AND sys_language_uid=' . (int)$langId .
302 BackendUtility::deleteClause('pages_language_overlay') .
303 BackendUtility::versioningPlaceholderClause('pages_language_overlay')
304 );
305 $row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res);
306 BackendUtility::workspaceOL('pages_language_overlay', $row);
307 if (is_array($row)) {
308 $row['_COUNT'] = $GLOBALS['TYPO3_DB']->sql_num_rows($res);
309 $row['_HIDDEN'] = $row['hidden'] || (int)$row['endtime'] > 0 && (int)$row['endtime'] < $GLOBALS['EXEC_TIME'] || $GLOBALS['EXEC_TIME'] < (int)$row['starttime'];
310 }
311 return $row;
312 }
313
314 /**
315 * Counting content elements for a single language on a page.
316 *
317 * @param int $pageId Page id to select for.
318 * @param int $sysLang Sys language uid
319 * @return int Number of content elements from the PID where the language is set to a certain value.
320 */
321 public function getContentElementCount($pageId, $sysLang) {
322 $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'));
323 return $count ?: '-';
324 }
325
326 }