TYPO3 CMS  TYPO3_8-7
TranslationStatusController.php
Go to the documentation of this file.
1 <?php
2 
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  $this->getPageRenderer()->loadRequireJsModule('TYPO3/CMS/Frontend/TranslationStatus');
90 
91  // Depth selector:
92  $theOutput .= '<div class="form-inline form-inline-spaced">';
93  $h_func = BackendUtility::getDropdownMenu($this->pObj->id, 'SET[depth]', $this->pObj->MOD_SETTINGS['depth'], $this->pObj->MOD_MENU['depth']);
94  $h_func .= BackendUtility::getDropdownMenu($this->pObj->id, 'SET[lang]', $this->pObj->MOD_SETTINGS['lang'], $this->pObj->MOD_MENU['lang']);
95  $theOutput .= $h_func;
96  // Add CSH:
97  $theOutput .= BackendUtility::cshItem('_MOD_web_info', 'lang', null, '<div class="form-group"><span class="btn btn-default btn-sm">|</span></div><br />');
98  $theOutput .= '</div>';
99  // Showing the tree:
100  // Initialize starting point of page tree:
101  $treeStartingPoint = (int)$this->pObj->id;
102  $treeStartingRecord = BackendUtility::getRecordWSOL('pages', $treeStartingPoint);
103  $depth = $this->pObj->MOD_SETTINGS['depth'];
104  // Initialize tree object:
105  $tree = GeneralUtility::makeInstance(PageTreeView::class);
106  $tree->init('AND ' . $this->getBackendUser()->getPagePermsClause(1));
107  $tree->addField('l18n_cfg');
108  // Creating top icon; the current page
109  $HTML = $this->iconFactory->getIconForRecord('pages', $treeStartingRecord, Icon::SIZE_SMALL)->render();
110  $tree->tree[] = [
111  'row' => $treeStartingRecord,
112  'HTML' => $HTML
113  ];
114  // Create the tree from starting point:
115  if ($depth) {
116  $tree->getTree($treeStartingPoint, $depth, '');
117  }
118  // Render information table:
119  $theOutput .= $this->renderL10nTable($tree);
120  }
121  return $theOutput;
122  }
123 
130  public function renderL10nTable(&$tree)
131  {
132  $lang = $this->getLanguageService();
133  // System languages retrieved:
134  $languages = $this->getSystemLanguages();
135  // Title length:
136  $titleLen = $this->getBackendUser()->uc['titleLen'];
137  // Put together the TREE:
138  $output = '';
139  $newOL_js = [];
140  $langRecUids = [];
141  foreach ($tree->tree as $data) {
142  $tCells = [];
143  $langRecUids[0][] = $data['row']['uid'];
144  // Page icons / titles etc.
145  $tCells[] = '<td' . ($data['row']['_CSSCLASS'] ? ' class="' . $data['row']['_CSSCLASS'] . '"' : '') . '>' .
146  ($data['depthData'] ?: '') .
147  BackendUtility::wrapClickMenuOnIcon($data['HTML'], 'pages', $data['row']['uid']) .
148  '<a href="#" onclick="' . htmlspecialchars(
149  'top.loadEditId(' . (int)$data['row']['uid'] . ',"&SET[language]=0"); return false;'
150  ) . '" title="' . $lang->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editPage') . '">' .
151  htmlspecialchars(GeneralUtility::fixed_lgd_cs($data['row']['title'], $titleLen)) .
152  '</a>' .
153  ((string)$data['row']['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars(GeneralUtility::fixed_lgd_cs($data['row']['nav_title'], $titleLen)) . '</em>]' : '') .
154  '</td>';
155  // DEFAULT language:
156  // "View page" link is created:
157  $viewPageLink = '<a href="#" onclick="' . htmlspecialchars(
159  $data['row']['uid'],
160  '',
161  null,
162  '',
163  '',
164  '&L=###LANG_UID###'
165  )
166  ) . '" class="btn btn-default" title="' . $lang->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_viewPage') . '">' .
167  $this->iconFactory->getIcon('actions-document-view', Icon::SIZE_SMALL)->render() . '</a>';
168  $viewPageLink = '<a href="#" onclick="' . htmlspecialchars(
170  $data['row']['uid'],
171  '',
172  null,
173  '',
174  '',
175  '&L=###LANG_UID###'
176  )
177  ) . '" class="btn btn-default" title="' . $lang->sL('LLL:EXT:info/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_viewPage') . '">' .
178  $this->iconFactory->getIcon('actions-view', Icon::SIZE_SMALL)->render() . '</a>';
179  $status = GeneralUtility::hideIfDefaultLanguage($data['row']['l18n_cfg']) ? 'danger' : 'success';
180  // Create links:
181  $editUrl = BackendUtility::getModuleUrl('record_edit', [
182  'edit' => [
183  'pages' => [
184  $data['row']['uid'] => 'edit'
185  ]
186  ],
187  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
188  ]);
189  $info = str_replace('###LANG_UID###', '0', $viewPageLink);
190  $info .= '<a href="' . htmlspecialchars($editUrl)
191  . '" class="btn btn-default" title="' . $lang->sL(
192  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editDefaultLanguagePage'
193  ) . '">' . $this->iconFactory->getIcon('actions-page-open', Icon::SIZE_SMALL)->render() . '</a>';
194  $info .= '&nbsp;';
195  $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;';
196  $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;';
197  // Put into cell:
198  $tCells[] = '<td class="' . $status . ' col-border-left"><div class="btn-group">' . $info . '</div></td>';
199  $tCells[] = '<td class="' . $status . '" title="' . $lang->sL(
200  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_CEcount'
201  ) . '" align="center">' . $this->getContentElementCount($data['row']['uid'], 0) . '</td>';
202  $modSharedTSconfig = BackendUtility::getModTSconfig($data['row']['uid'], 'mod.SHARED');
203  $disableLanguages = isset($modSharedTSconfig['properties']['disableLanguages']) ? GeneralUtility::trimExplode(',', $modSharedTSconfig['properties']['disableLanguages'], true) : [];
204  // Traverse system languages:
205  foreach ($languages as $langRow) {
206  if ($this->pObj->MOD_SETTINGS['lang'] == 0 || (int)$this->pObj->MOD_SETTINGS['lang'] === (int)$langRow['uid']) {
207  $row = $this->getLangStatus($data['row']['uid'], $langRow['uid']);
208  $info = '';
209  if (is_array($row)) {
210  $langRecUids[$langRow['uid']][] = $row['uid'];
211  $status = $row['_HIDDEN'] ? (GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || GeneralUtility::hideIfDefaultLanguage($data['row']['l18n_cfg']) ? 'danger' : '') : 'success';
212  $icon = $this->iconFactory->getIconForRecord('pages_language_overlay', $row, Icon::SIZE_SMALL)->render();
213  $info = $icon . htmlspecialchars(
214  GeneralUtility::fixed_lgd_cs($row['title'], $titleLen)
215  ) . ((string)$row['nav_title'] !== '' ? ' [Nav: <em>' . htmlspecialchars(
216  GeneralUtility::fixed_lgd_cs($row['nav_title'], $titleLen)
217  ) . '</em>]' : '') . ($row['_COUNT'] > 1 ? '<div>' . $lang->sL(
218  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_badThingThereAre'
219  ) . '</div>' : '');
220  $tCells[] = '<td class="' . $status . ' col-border-left">' .
221  '<a href="#" onclick="' . htmlspecialchars(
222  'top.loadEditId(' . (int)$data['row']['uid'] . ',"&SET[language]=' . $langRow['uid'] . '"); return false;'
223  ) . '" title="' . $lang->sL(
224  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editPageLang'
225  ) . '">' . $info . '</a></td>';
226  // Edit whole record:
227  // Create links:
228  $editUrl = BackendUtility::getModuleUrl('record_edit', [
229  'edit' => [
230  'pages_language_overlay' => [
231  $row['uid'] => 'edit'
232  ]
233  ],
234  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
235  ]);
236  $info = str_replace('###LANG_UID###', $langRow['uid'], $viewPageLink);
237  $info .= '<a href="' . htmlspecialchars($editUrl)
238  . '" class="btn btn-default" title="' . $lang->sL(
239  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editLanguageOverlayRecord'
240  ) . '">' . $this->iconFactory->getIcon('actions-open', Icon::SIZE_SMALL)->render() . '</a>';
241  $tCells[] = '<td class="' . $status . '"><div class="btn-group">' . $info . '</div></td>';
242  $tCells[] = '<td class="' . $status . '" title="' . $lang->sL(
243  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_CEcount'
244  ) . '" align="center">' . $this->getContentElementCount($data['row']['uid'], $langRow['uid']) . '</td>';
245  } else {
246  if (in_array($langRow['uid'], $disableLanguages)) {
247  // Language has been disabled for this page
248  $status = 'danger';
249  $info = '';
250  } else {
251  $status = GeneralUtility::hideIfNotTranslated($data['row']['l18n_cfg']) || GeneralUtility::hideIfDefaultLanguage($data['row']['l18n_cfg']) ? 'danger' : '';
252  $info = '<div class="btn-group"><label class="btn btn-default btn-checkbox">';
253  $info .= '<input type="checkbox" data-lang="' . (int)$langRow['uid'] . '" name="newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']" value="1" />';
254  $info .= '<span class="t3-icon fa"></span></label></div>';
255  $newOL_js[$langRow['uid']] .=
256  '+(document.webinfoForm['
257  . GeneralUtility::quoteJSvalue('newOL[' . $langRow['uid'] . '][' . $data['row']['uid'] . ']')
258  . '].checked ? '
259  . GeneralUtility::quoteJSvalue('&edit[pages_language_overlay][' . $data['row']['uid'] . ']=new')
260  . ' : \'\')'
261  ;
262  }
263  $tCells[] = '<td class="' . $status . ' col-border-left">&nbsp;</td>';
264  $tCells[] = '<td class="' . $status . '">&nbsp;</td>';
265  $tCells[] = '<td class="' . $status . '">' . $info . '</td>';
266  }
267  }
268  }
269  $output .= '
270  <tr>
271  ' . implode('
272  ', $tCells) . '
273  </tr>';
274  }
275  // Put together HEADER:
276  $tCells = [];
277  $tCells[] = '<td>' . $lang->sL('LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_page') . ':</td>';
278  if (is_array($langRecUids[0])) {
279  $editUrl = BackendUtility::getModuleUrl('record_edit', [
280  'edit' => [
281  'pages' => [
282  implode(',', $langRecUids[0]) => 'edit'
283  ]
284  ],
285  'columnsOnly' => 'title,nav_title,l18n_cfg,hidden',
286  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
287  ]);
288  $editIco = '<a href="' . htmlspecialchars($editUrl)
289  . '" class="btn btn-default" title="' . $lang->sL(
290  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editPageProperties'
291  ) . '">' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
292  } else {
293  $editIco = '';
294  }
295  $tCells[] = '<td class="col-border-left" colspan="2">' . $lang->sL(
296  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_default'
297  ) . ':' . $editIco . '</td>';
298  foreach ($languages as $langRow) {
299  if ($this->pObj->MOD_SETTINGS['lang'] == 0 || (int)$this->pObj->MOD_SETTINGS['lang'] === (int)$langRow['uid']) {
300  // Title:
301  $tCells[] = '<td class="col-border-left">' . htmlspecialchars($langRow['title']) . '</td>';
302  // Edit language overlay records:
303  if (is_array($langRecUids[$langRow['uid']])) {
304  $editUrl = BackendUtility::getModuleUrl('record_edit', [
305  'edit' => [
306  'pages_language_overlay' => [
307  implode(',', $langRecUids[$langRow['uid']]) => 'edit'
308  ]
309  ],
310  'columnsOnly' => 'title,nav_title,hidden',
311  'returnUrl' => GeneralUtility::getIndpEnv('REQUEST_URI')
312  ]);
313  $editButton = '<a href="' . htmlspecialchars($editUrl)
314  . '" class="btn btn-default" title="' . $lang->sL(
315  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_renderl10n_editLangOverlays'
316  ) . '">' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '</a>';
317  } else {
318  $editButton = '';
319  }
320  // Create new overlay records:
321  $params = '&columnsOnly=title,hidden,sys_language_uid&overrideVals[pages_language_overlay][sys_language_uid]=' . $langRow['uid'];
322  $onClick = BackendUtility::editOnClick($params);
323  if (!empty($newOL_js[$langRow['uid']])) {
324  $onClickArray = explode('?', $onClick, 2);
325  $lastElement = array_pop($onClickArray);
326  $onClickArray[] = '\'' . $newOL_js[$langRow['uid']] . ' + \'&' . $lastElement;
327  $onClick = implode('?', $onClickArray);
328  }
329  $newButton = '<a href="#" class="btn btn-default disabled t3js-language-new-' . (int)$langRow['uid'] . '" onclick="' . htmlspecialchars($onClick)
330  . '" title="' . $lang->sL(
331  'LLL:EXT:frontend/Resources/Private/Language/locallang_webinfo.xlf:lang_getlangsta_createNewTranslationHeaders'
332  ) . '">' . $this->iconFactory->getIcon('actions-document-new', Icon::SIZE_SMALL)->render() . '</a>';
333 
334  $tCells[] = '<td class="btn-group">' . $editButton . $newButton . '</td>';
335  $tCells[] = '<td>&nbsp;</td>';
336  }
337  }
338 
339  $output =
340  '<div class="table-fit">' .
341  '<table class="table table-striped table-hover" id="langTable">' .
342  '<thead>' .
343  '<tr>' .
344  implode('', $tCells) .
345  '</tr>' .
346  '</thead>' .
347  '<tbody>' .
348  $output .
349  '</tbody>' .
350  '</table>' .
351  '</div>';
352  return $output;
353  }
354 
360  public function getSystemLanguages()
361  {
362  if (!$this->getBackendUser()->user['admin'] && $this->getBackendUser()->groupData['allowed_languages'] !== '') {
363  $allowed_languages = array_flip(explode(',', $this->getBackendUser()->groupData['allowed_languages']));
364  }
365  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
366  ->getQueryBuilderForTable('sys_language')
367  ->select('*')
368  ->from('sys_language')
369  ->orderBy('sorting');
370  $res = $queryBuilder->execute();
371  $outputArray = [];
372  if (is_array($allowed_languages) && !empty($allowed_languages)) {
373  while ($output = $res->fetch()) {
374  if (isset($allowed_languages[$output['uid']])) {
375  $outputArray[] = $output;
376  }
377  }
378  } else {
379  $outputArray = $res->fetchAll();
380  }
381  return $outputArray;
382  }
383 
391  public function getLangStatus($pageId, $langId)
392  {
393  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
394  ->getQueryBuilderForTable(static::$pageLanguageOverlayTable);
395  $queryBuilder
396  ->getRestrictions()
397  ->removeAll()
398  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class))
399  ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
400  $result = $queryBuilder
401  ->select('*')
402  ->from(static::$pageLanguageOverlayTable)
403  ->where(
404  $queryBuilder->expr()->eq(
405  'pid',
406  $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
407  )
408  )
409  ->andWhere(
410  $queryBuilder->expr()->eq(
411  'sys_language_uid',
412  $queryBuilder->createNamedParameter($langId, \PDO::PARAM_INT)
413  )
414  )
415  ->execute();
416 
417  $row = $result->fetch();
418  BackendUtility::workspaceOL(static::$pageLanguageOverlayTable, $row);
419  if (is_array($row)) {
420  $row['_COUNT'] = $result->rowCount();
421  $row['_HIDDEN'] = $row['hidden'] || (int)$row['endtime'] > 0 && (int)$row['endtime'] < $GLOBALS['EXEC_TIME'] || $GLOBALS['EXEC_TIME'] < (int)$row['starttime'];
422  }
423  $result->closeCursor();
424  return $row;
425  }
426 
434  public function getContentElementCount($pageId, $sysLang)
435  {
436  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
437  ->getQueryBuilderForTable(static::$pageLanguageOverlayTable);
438  $queryBuilder->getRestrictions()
439  ->removeAll()
440  ->add(GeneralUtility::makeInstance(DeletedRestriction::class))
441  ->add(GeneralUtility::makeInstance(BackendWorkspaceRestriction::class));
442  $count = $queryBuilder
443  ->count('uid')
444  ->from('tt_content')
445  ->where(
446  $queryBuilder->expr()->eq(
447  'pid',
448  $queryBuilder->createNamedParameter($pageId, \PDO::PARAM_INT)
449  )
450  )
451  ->andWhere(
452  $queryBuilder->expr()->eq(
453  'sys_language_uid',
454  $queryBuilder->createNamedParameter($sysLang, \PDO::PARAM_INT)
455  )
456  )
457  ->execute()
458  ->fetchColumn(0);
459  return $count ?: '-';
460  }
461 
467  protected function getLanguageService()
468  {
469  return $GLOBALS['LANG'];
470  }
471 
477  protected function getBackendUser()
478  {
479  return $GLOBALS['BE_USER'];
480  }
481 }
static getRecordWSOL( $table, $uid, $fields=' *', $where='', $useDeleteClause=true, $unsetMovePointers=false)
static wrapClickMenuOnIcon( $content, $table, $uid=0, $context='', $_addParams='', $_enDisItems='', $returnTagParameters=false)
static editOnClick($params, $_='', $requestUri='')
static viewOnClick( $pageUid, $backPath='', $rootLine=null, $anchorSection='', $alternativeUrl='', $additionalGetVars='', $switchFocus=true)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static hideIfDefaultLanguage($localizationConfiguration)
static workspaceOL($table, &$row, $wsid=-99, $unsetMovePointers=false)
static makeInstance($className,... $constructorArguments)
static hideIfNotTranslated($l18n_cfg_fieldValue)
static cshItem($table, $field, $_='', $wrap='')
static fixed_lgd_cs($string, $chars, $appendString='...')
static getDropdownMenu( $mainParams, $elementName, $currentValue, $menuItems, $script='', $addParams='')
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']