TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
TranslationStatusController.php
Go to the documentation of this file.
1 <?php
2 
3 namespace TYPO3\CMS\Frontend\Controller;
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
26 
31 {
35  protected $iconFactory;
36 
41  protected static $pageLanguageOverlayTable = 'pages_language_overlay';
42 
46  public function __construct()
47  {
48  $this->iconFactory = GeneralUtility::makeInstance(IconFactory::class);
49  }
50 
56  public function modMenu()
57  {
58  $lang = $this->getLanguageService();
59  $menuArray = [
60  'depth' => [
61  0 => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_0'),
62  1 => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_1'),
63  2 => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_2'),
64  3 => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_3'),
65  4 => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_4'),
66  999 => $lang->sL('LLL:EXT:lang/Resources/Private/Language/locallang_core.xlf:labels.depth_infi')
67  ]
68  ];
69  // Languages:
70  $lang = $this->getSystemLanguages();
71  $menuArray['lang'] = [
72  0 => '[All]'
73  ];
74  foreach ($lang as $langRec) {
75  $menuArray['lang'][$langRec['uid']] = $langRec['title'];
76  }
77  return $menuArray;
78  }
79 
85  public function main()
86  {
87  $theOutput = '<h1>' . htmlspecialchars($this->getLanguageService()->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_title')) . '</h1>';
88  if ($this->pObj->id) {
89  // Depth selector:
90  $theOutput .= '<div class="form-inline form-inline-spaced">';
91  $h_func = BackendUtility::getDropdownMenu($this->pObj->id, 'SET[depth]', $this->pObj->MOD_SETTINGS['depth'], $this->pObj->MOD_MENU['depth']);
92  $h_func .= BackendUtility::getDropdownMenu($this->pObj->id, 'SET[lang]', $this->pObj->MOD_SETTINGS['lang'], $this->pObj->MOD_MENU['lang']);
93  $theOutput .= $h_func;
94  // Add CSH:
95  $theOutput .= BackendUtility::cshItem('_MOD_web_info', 'lang', null, '<div class="form-group"><span class="btn btn-default btn-sm">|</span></div><br />');
96  $theOutput .= '</div>';
97  // Showing the tree:
98  // Initialize starting point of page tree:
99  $treeStartingPoint = (int)$this->pObj->id;
100  $treeStartingRecord = BackendUtility::getRecordWSOL('pages', $treeStartingPoint);
101  $depth = $this->pObj->MOD_SETTINGS['depth'];
102  // Initialize tree object:
103  $tree = GeneralUtility::makeInstance(PageTreeView::class);
104  $tree->init('AND ' . $this->getBackendUser()->getPagePermsClause(1));
105  $tree->addField('l18n_cfg');
106  // Creating top icon; the current page
107  $HTML = $this->iconFactory->getIconForRecord('pages', $treeStartingRecord, Icon::SIZE_SMALL)->render();
108  $tree->tree[] = [
109  'row' => $treeStartingRecord,
110  'HTML' => $HTML
111  ];
112  // Create the tree from starting point:
113  if ($depth) {
114  $tree->getTree($treeStartingPoint, $depth, '');
115  }
116  // Render information table:
117  $theOutput .= $this->renderL10nTable($tree);
118  }
119  return $theOutput;
120  }
121 
128  public function renderL10nTable(&$tree)
129  {
130  $lang = $this->getLanguageService();
131  // System languages retrieved:
132  $languages = $this->getSystemLanguages();
133  // Title length:
134  $titleLen = $this->getBackendUser()->uc['titleLen'];
135  // Put together the TREE:
136  $output = '';
137  $newOL_js = [];
138  $langRecUids = [];
139  foreach ($tree->tree as $data) {
140  $tCells = [];
141  $langRecUids[0][] = $data['row']['uid'];
142  // Page icons / titles etc.
143  $tCells[] = '<td' . ($data['row']['_CSSCLASS'] ? ' class="' . $data['row']['_CSSCLASS'] . '"' : '') . '>' .
144  ($data['depthData'] ?: '') .
145  BackendUtility::wrapClickMenuOnIcon($data['HTML'], 'pages', $data['row']['uid']) .
146  '<a href="#" onclick="' . htmlspecialchars(
147  'top.loadEditId(' . (int)$data['row']['uid'] . ',"&SET[language]=0"); return false;'
148  ) . '" title="' . $lang->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editPage') . '">' .
149  htmlspecialchars(GeneralUtility::fixed_lgd_cs($data['row']['title'], $titleLen)) .
150  '</a>' .
151  ((string)$data['row']['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($data['row']['nav_title'], $titleLen)) . '</em>]' : '') .
152  '</td>';
153  // DEFAULT language:
154  // "View page" link is created:
155  $viewPageLink = '<a href="#" onclick="' . htmlspecialchars(BackendUtility::viewOnClick(
156  $data['row']['uid'], '', '', '', '', '&L=###LANG_UID###')
157  ) . '" class="btn btn-default" title="' . $lang->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_viewPage') . '">' .
158  $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . '</a>';
159  $status = GeneralUtility::hideIfDefaultLanguage($data['row']['l18n_cfg']) ? 'danger' : 'success';
160  // Create links:
161  $editUrl = BackendUtility::getModuleUrl('record_edit', [
162  'edit' => [
163  'pages' => [
164  $data['row']['uid'] => 'edit'
165  ]
166  ],
167  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
168  ]);
169  $info = str_replace('###LANG_UID###', '0', $viewPageLink);
170  $info .= '<a href="' . htmlspecialchars($editUrl)
171  . '" class="btn btn-default" title="' . $lang->sL(
172  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editDefaultLanguagePage'
173  ) . '">' . $this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render() . '</a>';
174  $info .= '&nbsp;';
175  $info .= GeneralUtility::hideIfDefaultLanguage($data['row']['l18n_cfg']) ? '<span title="' . htmlspecialchars($lang->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.l18n_cfg.I.1')) . '">D</span>' : '&nbsp;';
176  $info .= GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) ? '<span title="' . htmlspecialchars($lang->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_tca.xlf:pages.l18n_cfg.I.2')) . '">N</span>' : '&nbsp;';
177  // Put into cell:
178  $tCells[] = '<td class="' . $status . ' col-border-left"><div class="btn-group">' . $info . '</div></td>';
179  $tCells[] = '<td class="' . $status . '" title="' . $lang->sL(
180  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_CEcount'
181  ) . '" align="center">' . $this->getContentElementCount($data['row']['uid'], 0) . '</td>';
182  $modSharedTSconfig = BackendUtility::getModTSconfig($data['row']['uid'], 'mod.SHARED');
183  $disableLanguages = isset($modSharedTSconfig['properties']['disableLanguages']) ? GeneralUtility::trimExplode(',', $modSharedTSconfig['properties']['disableLanguages'], true) : [];
184  // Traverse system languages:
185  foreach ($languages as $langRow) {
186  if ($this->pObj->MOD_SETTINGS['lang'] == 0 || (int)$this->pObj->MOD_SETTINGS['lang'] === (int)$langRow['uid']) {
187  $row = $this->getLangStatus($data['row']['uid'], $langRow['uid']);
188  $info = '';
189  if (is_array($row)) {
190  $langRecUids[$langRow['uid']][] = $row['uid'];
191  $status = $row['_HIDDEN'] ? (GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || GeneralUtility::hideIfDefaultLanguage($data['row']['l18n_cfg']) ? 'danger' : '') : 'success';
192  $icon = $this->iconFactory->getIconForRecord('pages_language_overlay', $row, Icon::SIZE_SMALL)->render();
193  $info = $icon . htmlspecialchars(
194  GeneralUtility::fixed_lgd_cs($row['title'], $titleLen)
195  ) . ((string)$row['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars(
196  GeneralUtility::fixed_lgd_cs($row['nav_title'], $titleLen)
197  ) . '</em>]' : '') . ($row['_COUNT'] > 1 ? '<div>' . $lang->sL(
198  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_badThingThereAre'
199  ) . '</div>' : '');
200  $tCells[] = '<td class="' . $status . ' col-border-left">' .
201  '<a href="#" onclick="' . htmlspecialchars(
202  'top.loadEditId(' . (int)$data['row']['uid'] . ',"&SET[language]=' . $langRow['uid'] . '"); return false;'
203  ) . '" title="' . $lang->sL(
204  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editPageLang'
205  ) . '">' . $info . '</a></td>';
206  // Edit whole record:
207  // Create links:
208  $editUrl = BackendUtility::getModuleUrl('record_edit', [
209  'edit' => [
210  'pages_language_overlay' => [
211  $row['uid'] => 'edit'
212  ]
213  ],
214  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
215  ]);
216  $info = str_replace('###LANG_UID###', $langRow['uid'], $viewPageLink);
217  $info .= '<a href="' . htmlspecialchars($editUrl)
218  . '" class="btn btn-default" title="' . $lang->sL(
219  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editLanguageOverlayRecord'
220  ) . '">' . $this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render() . '</a>';
221  $tCells[] = '<td class="' . $status . '"><div class="btn-group">' . $info . '</div></td>';
222  $tCells[] = '<td class="' . $status . '" title="' . $lang->sL(
223  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_CEcount'
224  ) . '" align="center">' . $this->getContentElementCount($data['row']['uid'], $langRow['uid']) . '</td>';
225  } else {
226  if (in_array($langRow['uid'], $disableLanguages)) {
227  // Language has been disabled for this page
228  $status = 'danger';
229  $info = '';
230  } else {
231  $status = GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || GeneralUtility::hideIfDefaultLanguage($data['row']['l18n_cfg']) ? 'danger' : '';
232  $info = '<div class="btn-group"><label class="btn btn-default btn-checkbox">';
233  $info .= '<input type="checkbox" name="newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']" value="1" />';
234  $info .= '<span class="t3-icon fa"></span></label></div>';
235  $newOL_js[$langRow['uid']] .= '
236  +(document.webinfoForm['
237  . GeneralUtility::quoteJSvalue('newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']')
238  . '].checked ? '
239  . GeneralUtility::quoteJSvalue('&edit[pages_language_overlay][' . $data['row']['uid'] . ']=new')
240  . ' : \'\')
241  ';
242  }
243  $tCells[] = '<td class="' . $status . ' col-border-left">&nbsp;</td>';
244  $tCells[] = '<td class="' . $status . '">&nbsp;</td>';
245  $tCells[] = '<td class="' . $status . '">' . $info . '</td>';
246  }
247  }
248  }
249  $output .= '
250  <tr>
251  ' . implode('
252  ', $tCells) . '
253  </tr>';
254  }
255  // Put together HEADER:
256  $tCells = [];
257  $tCells[] = '<td>' . $lang->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_page') . ':</td>';
258  if (is_array($langRecUids[0])) {
259  $editUrl = BackendUtility::getModuleUrl('record_edit', [
260  'edit' => [
261  'pages' => [
262  implode(',', $langRecUids[0]) => 'edit'
263  ]
264  ],
265  'columnsOnly' => 'title,nav_title,l18n_cfg,hidden',
266  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
267  ]);
268  $editIco = '<a href="' . htmlspecialchars($editUrl)
269  . '" class="btn btn-default" title="' . $lang->sL(
270  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editPageProperties'
271  ) . '">' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
272  } else {
273  $editIco = '';
274  }
275  $tCells[] = '<td class="col-border-left" colspan="2">' . $lang->sL(
276  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_default'
277  ) . ':' . $editIco . '</td>';
278  foreach ($languages as $langRow) {
279  if ($this->pObj->MOD_SETTINGS['lang'] == 0 || (int)$this->pObj->MOD_SETTINGS['lang'] === (int)$langRow['uid']) {
280  // Title:
281  $tCells[] = '<td class="col-border-left">' . htmlspecialchars($langRow['title']) . '</td>';
282  // Edit language overlay records:
283  if (is_array($langRecUids[$langRow['uid']])) {
284  $editUrl = BackendUtility::getModuleUrl('record_edit', [
285  'edit' => [
286  'pages_language_overlay' => [
287  implode(',', $langRecUids[$langRow['uid']]) => 'edit'
288  ]
289  ],
290  'columnsOnly' => 'title,nav_title,hidden',
291  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
292  ]);
293  $editButton = '<a href="' . htmlspecialchars($editUrl)
294  . '" class="btn btn-default" title="' . $lang->sL(
295  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editLangOverlays'
296  ) . '">' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
297  } else {
298  $editButton = '';
299  }
300  // Create new overlay records:
301  $params = '&columnsOnly=title,hidden,sys_language_uid&overrideVals[pages_language_overlay][sys_language_uid]=' . $langRow['uid'];
302  $onClick = BackendUtility::editOnClick($params);
303  if (!empty($newOL_js[$langRow['uid']])) {
304  $onClickArray = explode('?', $onClick, 2);
305  $lastElement = array_pop($onClickArray);
306  array_push($onClickArray, '\'' . $newOL_js[$langRow['uid']] . ' + \'&' . $lastElement);
307  $onClick = implode('?', $onClickArray);
308  }
309  $newButton = '<a href="#" class="btn btn-default" onclick="' . htmlspecialchars($onClick)
310  . '" title="' . $lang->sL(
311  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_getlangsta_createNewTranslationHeaders'
312  ) . '">' . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render() . '</a>';
313 
314  $tCells[] = '<td class="btn-group">' . $editButton . $newButton . '</td>';
315  $tCells[] = '<td>&nbsp;</td>';
316  }
317  }
318 
319  $output =
320  '<div class="table-fit">' .
321  '<table class="table table-striped table-hover" id="langTable">' .
322  '<thead>' .
323  '<tr>' .
324  implode('', $tCells) .
325  '</tr>' .
326  '</thead>' .
327  '<tbody>' .
328  $output .
329  '</tbody>' .
330  '</table>' .
331  '</div>';
332  return $output;
333  }
334 
340  public function getSystemLanguages()
341  {
342  if (!$this->getBackendUser()->user['admin'] && $this->getBackendUser()->groupData['allowed_languages'] !== '') {
343  $allowed_languages = array_flip(explode(',', $this->getBackendUser()->groupData['allowed_languages']));
344  }
345  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
346  ->getQueryBuilderForTable('sys_language');
347  $queryBuilder
348  ->getRestrictions()
349  ->removeAll();
350  $queryBuilder
351  ->select('*')
352  ->from('sys_language')
353  ->orderBy('sorting');
354  $res = $queryBuilder->execute();
355  $outputArray = [];
356  if (is_array($allowed_languages) && !empty($allowed_languages)) {
357  while ($output = $res->fetch()) {
358  if (isset($allowed_languages[$output['uid']])) {
359  $outputArray[] = $output;
360  }
361  }
362  } else {
363  $outputArray = $res->fetchAll();
364  }
365  return $outputArray;
366  }
367 
375  public function getLangStatus($pageId, $langId)
376  {
377  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
378  ->getQueryBuilderForTable(static::$pageLanguageOverlayTable);
379  $queryBuilder
380  ->getRestrictions()
381  ->removeAll()
382  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class))
383  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
384  $result = $queryBuilder
385  ->select('*')
386  ->from(static::$pageLanguageOverlayTable)
387  ->where(
388  $queryBuilder->expr()->eq(
389  'pid',
390  $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
391  )
392  )
393  ->andWhere(
394  $queryBuilder->expr()->eq(
395  'sys_language_uid',
396  $queryBuilder->createNamedParameter($langId, \PDO::PARAM_INT)
397  )
398  )
399  ->execute();
400 
401  $row = $result->fetch();
402  BackendUtility::workspaceOL(static::$pageLanguageOverlayTable, $row);
403  if (is_array($row)) {
404  $row['_COUNT'] = $result->rowCount();
405  $row['_HIDDEN'] = $row['hidden'] || (int)$row['endtime'] > 0 && (int)$row['endtime'] < $GLOBALS['EXEC_TIME'] || $GLOBALS['EXEC_TIME'] < (int)$row['starttime'];
406  }
407  $result->closeCursor();
408  return $row;
409  }
410 
418  public function getContentElementCount($pageId, $sysLang)
419  {
420  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
421  ->getQueryBuilderForTable(static::$pageLanguageOverlayTable);
422  $queryBuilder->getRestrictions()
423  ->removeAll()
424  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
425  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
426  $count = $queryBuilder
427  ->count('uid')
428  ->from('tt_content')
429  ->where(
430  $queryBuilder->expr()->eq(
431  'pid',
432  $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
433  )
434  )
435  ->andWhere(
436  $queryBuilder->expr()->eq(
437  'sys_language_uid',
438  $queryBuilder->createNamedParameter($sysLang, \PDO::PARAM_INT)
439  )
440  )
441  ->execute()
442  ->fetchColumn(0);
443  return $count ?: '-';
444  }
445 
451  protected function getLanguageService()
452  {
453  return $GLOBALS['LANG'];
454  }
455 
461  protected function getBackendUser()
462  {
463  return $GLOBALS['BE_USER'];
464  }
465 }
static getRecordWSOL($table, $uid, $fields= '*', $where= '', $useDeleteClause=true, $unsetMovePointers=false)
static hideIfNotTranslated($l18n_cfg_fieldValue)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static getDropdownMenu($mainParams, $elementName, $currentValue, $menuItems, $script= '', $addParams= '')
static hideIfDefaultLanguage($localizationConfiguration)
static viewOnClick($pageUid, $backPath= '', $rootLine=null, $anchorSection= '', $alternativeUrl= '', $additionalGetVars= '', $switchFocus=true)
static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
if(TYPO3_MODE=== 'BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
static makeInstance($className,...$constructorArguments)
static wrapClickMenuOnIcon($content, $table, $uid=0, $listFrame=true, $addParams= '', $enDisItems= '', $returnTagParameters=false)