[BUGFIX] Fix missing flag icons on flex localization view 40/43340/11
authorThorsten Bringewatt <t.bringewatt@mittwald.de>
Tue, 15 Sep 2015 14:57:09 +0000 (16:57 +0200)
committerChristian Kuhn <lolli@schwarzbu.ch>
Sun, 20 Sep 2015 19:51:05 +0000 (21:51 +0200)
Extend the system language row data with additional data
and use it in render part of FormEngine to remove another
helper method from FormEngineUtility.

Resolves: #69890
Releases: master
Change-Id: I44dbd98a86f740e8682540aed6a3ceb336bb4d0a
Reviewed-on: http://review.typo3.org/43340
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Reviewed-by: Christian Kuhn <lolli@schwarzbu.ch>
Tested-by: Christian Kuhn <lolli@schwarzbu.ch>
typo3/sysext/backend/Classes/Form/Container/FlexFormElementContainer.php
typo3/sysext/backend/Classes/Form/Container/FlexFormLanguageContainer.php
typo3/sysext/backend/Classes/Form/Container/SingleFieldContainer.php
typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseLanguageRows.php
typo3/sysext/backend/Classes/Form/FormDataProvider/DatabaseSystemLanguageRows.php
typo3/sysext/backend/Classes/Form/FormDataProvider/TcaFlexProcess.php
typo3/sysext/backend/Classes/Form/Utility/FormEngineUtility.php
typo3/sysext/backend/Tests/Unit/Form/FormDataProvider/DatabaseSystemLanguageRowsTest.php

index 1362914..2614d35 100644 (file)
@@ -14,6 +14,8 @@ namespace TYPO3\CMS\Backend\Form\Container;
  * The TYPO3 project - inspiring people to share!
  */
 
+use TYPO3\CMS\Core\Imaging\Icon;
+use TYPO3\CMS\Core\Imaging\IconFactory;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Lang\LanguageService;
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
@@ -39,7 +41,6 @@ class FlexFormElementContainer extends AbstractContainer {
        public function render() {
                $table = $this->data['tableName'];
                $row = $this->data['databaseRow'];
-               $fieldName = $this->data['fieldName'];
                $flexFormDataStructureArray = $this->data['flexFormDataStructureArray'];
                $flexFormRowData = $this->data['flexFormRowData'];
                $flexFormFormPrefix = $this->data['flexFormFormPrefix'];
@@ -47,6 +48,8 @@ class FlexFormElementContainer extends AbstractContainer {
                $metaData = $this->data['parameterArray']['fieldConf']['config']['ds']['meta'];
 
                $languageService = $this->getLanguageService();
+               /** @var IconFactory $iconFactory */
+               $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
                $resultArray = $this->initializeResultArray();
                foreach ($flexFormDataStructureArray as $flexFormFieldName => $flexFormFieldArray) {
                        if (
@@ -79,16 +82,13 @@ class FlexFormElementContainer extends AbstractContainer {
                                $sectionContainerResult = $this->nodeFactory->create($options)->render();
                                $resultArray = $this->mergeChildReturnIntoExistingResult($resultArray, $sectionContainerResult);
                        } else {
-                               // Single element
-                               $vDEFkey = 'vDEF';
-
                                if (is_array($metaData) && isset($metaData['langChildren']) && isset($metaData['languagesOnElement'])) {
                                        $lkeys = $metaData['languagesOnElement'];
                                        array_walk($lkeys, function (&$value) {
                                                $value = 'v' . $value;
                                        });
                                } else {
-                                       $lkeys = array($vDEFkey);
+                                       $lkeys = array('vDEF');
                                }
                                $html = array();
                                foreach ($lkeys as $lkey) {
@@ -144,18 +144,25 @@ class FlexFormElementContainer extends AbstractContainer {
                                        $theTitle = htmlspecialchars($fakeParameterArray['fieldConf']['label']);
                                        $defInfo = array();
 
-                                       $languageIcon = '';
-                                       if ($vDEFkey !== 'vDEF') {
-                                               $languageIcon = FormEngineUtility::getLanguageIcon($table, $row, $vDEFkey);
-                                       }
                                        // Possible line breaks in the label through xml: \n => <br/>, usage of nl2br() not possible, so it's done through str_replace (?!)
                                        $processedTitle = str_replace('\\n', '<br />', $theTitle);
                                        // @todo: Similar to the processing within SingleElementContainer ... use it from there?!
                                        $html[] = '<div class="form-group t3js-formengine-palette-field t3js-formengine-validation-marker">';
                                        $html[] = '<label class="t3js-formengine-label">';
-                                       $html[] = $languageIcon;
-                                       if (is_array($metaData) && isset($metaData['langChildren'])) {
-                                               $html[] = FormEngineUtility::getLanguageIcon($table, $row, $lkey);
+                                       if (is_array($metaData) && isset($metaData['langChildren']) && $metaData['langChildren']) {
+                                               // Find language uid of this iso code
+                                               $languageUid = 0;
+                                               $lKeyWithoutV = substr($lkey, 1);
+                                               if ($lKeyWithoutV !== 'DEF') {
+                                                       foreach ($this->data['systemLanguageRows'] as $systemLanguageRow) {
+                                                               if ($systemLanguageRow['iso'] === $lKeyWithoutV) {
+                                                                       $languageUid = $systemLanguageRow['uid'];
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                               $languageIcon = $iconFactory->getIcon($this->data['systemLanguageRows'][$languageUid]['flagIconIdentifier'], Icon::SIZE_SMALL)->render();
+                                               $html[] = $languageIcon;
                                        }
                                        $html[] = BackendUtility::wrapInHelp($parameterArray['_cshKey'], $flexFormFieldName, $processedTitle);
                                        $html[] = '</label>';
index 0cc118f..1160022 100644 (file)
@@ -14,7 +14,9 @@ namespace TYPO3\CMS\Backend\Form\Container;
  * The TYPO3 project - inspiring people to share!
  */
 
-use TYPO3\CMS\Backend\Form\Utility\FormEngineUtility;
+use TYPO3\CMS\Core\Imaging\Icon;
+use TYPO3\CMS\Core\Imaging\IconFactory;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
 
 /**
  * Handle flex form language overlays.
@@ -31,14 +33,14 @@ class FlexFormLanguageContainer extends AbstractContainer {
         * Entry method
         *
         * @return array As defined in initializeResultArray() of AbstractNode
-        * @todo: Implement langChildren=1 case where each single element is localized and not the whole thing.
         */
        public function render() {
-               $table = $this->data['tableName'];
-               $row = $this->data['databaseRow'];
                $flexFormDataStructureArray = $this->data['parameterArray']['fieldConf']['config']['ds'];
                $flexFormRowData = $this->data['parameterArray']['itemFormElValue'];
 
+               /** @var IconFactory $iconFactory */
+               $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
+
                // Tabs or no tabs - that's the question
                $hasTabs = FALSE;
                if (count($flexFormDataStructureArray['sheets']) > 1) {
@@ -50,7 +52,21 @@ class FlexFormLanguageContainer extends AbstractContainer {
                foreach ($flexFormDataStructureArray['meta']['languagesOnSheetLevel'] as $lKey) {
                        // Add language as header
                        if (!$flexFormDataStructureArray['meta']['langChildren'] && !$flexFormDataStructureArray['meta']['langDisable']) {
-                               $resultArray['html'] .= LF . '<strong>' . FormEngineUtility::getLanguageIcon($table, $row, ('v' . $lKey)) . $lKey . ':</strong>';
+                               // Find language uid of this iso code
+                               $languageUid = 0;
+                               if ($lKey !== 'DEF') {
+                                       foreach ($this->data['systemLanguageRows'] as $systemLanguageRow) {
+                                               if ($systemLanguageRow['iso'] === $lKey) {
+                                                       $languageUid = $systemLanguageRow['uid'];
+                                                       break;
+                                               }
+                                       }
+                               }
+                               $resultArray['html'] .= LF
+                                       . '<strong>'
+                                       . $iconFactory->getIcon($this->data['systemLanguageRows'][$languageUid]['flagIconIdentifier'], Icon::SIZE_SMALL)->render()
+                                       . htmlspecialchars($this->data['systemLanguageRows'][$languageUid]['title'])
+                                       . '</strong>';
                        }
 
                        // Default language "lDEF", other options are "lUK" or whatever country code
index e2fdaba..b31c7d0 100644 (file)
@@ -321,9 +321,11 @@ class SingleFieldContainer extends AbstractContainer {
                        $fieldConfig = $this->data['processedTca']['columns'][$field];
                        // Don't show content if it's for IRRE child records:
                        if ($fieldConfig['config']['type'] !== 'inline') {
+                               /** @var IconFactory $iconFactory */
+                               $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
                                if ($defaultLanguageValue !== '') {
                                        $item .= '<div class="t3-form-original-language" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_misc.xlf:localizeMergeIfNotBlank', TRUE) . '">'
-                                               . FormEngineUtility::getLanguageIcon($table, $row, 0)
+                                               . $iconFactory->getIcon($this->data['systemLanguageRows'][0]['flagIconIdentifier'], Icon::SIZE_SMALL)->render()
                                                . $this->getMergeBehaviourIcon($fieldConfig['l10n_mode'])
                                                . $this->previewFieldValue($defaultLanguageValue, $fieldConfig, $field) . '</div>';
                                }
@@ -338,7 +340,7 @@ class SingleFieldContainer extends AbstractContainer {
                                        );
                                        if ($defaultLanguageValue !== '') {
                                                $item .= '<div class="t3-form-original-language" title="' . $this->getLanguageService()->sL('LLL:EXT:lang/locallang_misc.xlf:localizeMergeIfNotBlank', TRUE) . '">'
-                                                       . FormEngineUtility::getLanguageIcon($table, $row, $previewLanguage['sys_language_uid'])
+                                                       . $iconFactory->getIcon($this->data['systemLanguageRows'][$previewLanguage['sys_language_uid']]['flagIconIdentifier'], Icon::SIZE_SMALL)->render()
                                                        . $this->getMergeBehaviourIcon($fieldConfig['l10n_mode'])
                                                        . $this->previewFieldValue($defaultLanguageValue, $fieldConfig, $field) . '</div>';
                                        }
index fb13beb..ead02e7 100644 (file)
@@ -79,8 +79,9 @@ class DatabaseLanguageRows implements FormDataProviderInterface {
                                        /** @var TranslationConfigurationProvider $translationProvider */
                                        $translationProvider = GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
                                        foreach ($additionalLanguageUids as $additionalLanguageUid) {
-                                               // Continue if this system language record does not exist or if 0 is requested or if row is the same as the to-be-displayed row
-                                               if ($additionalLanguageUid === 0
+                                               // Continue if this system language record does not exist or if 0 or -1 is requested
+                                               // or if row is the same as the to-be-displayed row
+                                               if ($additionalLanguageUid <= 0
                                                        || !isset($result['systemLanguageRows'][$additionalLanguageUid])
                                                        || $additionalLanguageUid === (int)$result['databaseRow'][$languageField]
                                                ) {
index 41984b8..69440d0 100644 (file)
@@ -16,6 +16,7 @@ namespace TYPO3\CMS\Backend\Form\FormDataProvider;
 
 use TYPO3\CMS\Backend\Form\FormDataProviderInterface;
 use TYPO3\CMS\Backend\Utility\BackendUtility;
+use TYPO3\CMS\Backend\Utility\IconUtility;
 use TYPO3\CMS\Core\Database\DatabaseConnection;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Messaging\FlashMessageService;
@@ -31,27 +32,47 @@ class DatabaseSystemLanguageRows implements FormDataProviderInterface {
        /**
         * Fetch available system languages and resolve iso code if necessary.
         *
-        * @todo: This is similar to what TranslationConfigurationProvider->getSystemLanguages() does,
-        * @todo: use the method as soon as bugs have been fixed in there.
-        *
         * @param array $result
         * @return array
         * @throws \UnexpectedValueException
         */
        public function addData(array $result) {
                $database = $this->getDatabase();
+               $languageService = $this->getLanguageService();
+
+               $pageTs = $result['pageTsConfig'];
+               $defaultLanguageLabel = $languageService->sL('LLL:EXT:lang/locallang_mod_web_list.xlf:defaultLanguage');
+               if (isset($pageTs['mod.']['SHARED.']['defaultLanguageLabel'])) {
+                       $defaultLanguageLabel = $pageTs['mod.']['SHARED.']['defaultLanguageLabel'] . ' (' . $languageService->sL($defaultLanguageLabel) . ')';
+               }
+               $defaultLanguageFlag = 'empty-empty';
+               if (isset($pageTs['mod.']['SHARED.']['defaultLanguageFlag'])) {
+                       $defaultLanguageFlag = 'flags-' . $pageTs['mod.']['SHARED.']['defaultLanguageFlag'];
+               }
 
                $languageRows = [
+                       -1 => [
+                               // -1: "All" languages
+                               'uid' => -1,
+                               'title' => $languageService->sL('LLL:EXT:lang/locallang_mod_web_list.xlf:multipleLanguages'),
+                               // Same as for 0, but iso is used in flex form context only and duplication handled there
+                               // @todo: Maybe drop this if flex form language handling is extracted?
+                               'iso' => 'DEF',
+                               'flagIconIdentifier' => 'flags-multiple',
+                       ],
                        0 => [
+                               // 0: "Default" language
                                'uid' => 0,
-                               'title' => 'Default Language',
+                               'title' => $defaultLanguageLabel,
                                // Default "DEF" is a fallback preparation for flex form iso codes "lDEF"
+                               // @todo: Maybe drop this if flex form language handling is extracted?
                                'iso' => 'DEF',
+                               'flagIconIdentifier' => $defaultLanguageFlag,
                        ],
                ];
 
                $dbRows = $database->exec_SELECTgetRows(
-                       'uid,title,language_isocode,static_lang_isocode',
+                       'uid,title,language_isocode,static_lang_isocode,flag',
                        'sys_language',
                        'pid=0 AND hidden=0'
                );
@@ -65,8 +86,14 @@ class DatabaseSystemLanguageRows implements FormDataProviderInterface {
 
                $isStaticInfoTablesLoaded = ExtensionManagementUtility::isLoaded('static_info_tables');
                foreach ($dbRows as $dbRow) {
+                       $uid = $dbRow['uid'];
+                       $languageRows[$uid] = [
+                               'uid' => $uid,
+                               'title' => $dbRow['title'],
+                               'flagIconIdentifier' => 'flags-' . $dbRow['flag'],
+                       ];
                        if (!empty($dbRow['language_isocode'])) {
-                               $dbRow['iso'] = $dbRow['language_isocode'];
+                               $languageRows[$uid]['iso'] = $dbRow['language_isocode'];
                        } elseif ($isStaticInfoTablesLoaded && !empty($dbRow['static_lang_isocode'])) {
                                GeneralUtility::deprecationLog(
                                        'Usage of the field "static_lang_isocode" is discouraged, and will stop working with CMS 8. Use the built-in'
@@ -74,7 +101,7 @@ class DatabaseSystemLanguageRows implements FormDataProviderInterface {
                                );
                                $lg_iso_2 = BackendUtility::getRecord('static_languages', $dbRow['static_lang_isocode'], 'lg_iso_2');
                                if ($lg_iso_2['lg_iso_2']) {
-                                       $dbRow['iso'] = $lg_iso_2['lg_iso_2'];
+                                       $languageRows[$uid]['iso'] = $lg_iso_2['lg_iso_2'];
                                }
                        } else {
                                // No iso code could be found. This is currently possible in the system but discouraged.
@@ -83,10 +110,12 @@ class DatabaseSystemLanguageRows implements FormDataProviderInterface {
                                // incomplete configuration here.
                                // It might be possible to convert this to a non-catchable exception later if
                                // it iso code is enforced on a different layer of the system (tca required + migration wizard).
+                               // @todo: This could be relaxed again if flex form language handling is extracted,
+                               // @todo: since the rest of the FormEngine code does not rely on iso code?
                                $message = sprintf(
-                                       $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:error.missingLanguageIsocode'),
+                                       $languageService->sL('LLL:EXT:lang/locallang_core.xlf:error.missingLanguageIsocode'),
                                        $dbRow['title'],
-                                       $dbRow['uid']
+                                       $uid
                                );
                                /** @var FlashMessage $flashMessage */
                                $flashMessage = GeneralUtility::makeInstance(
@@ -99,11 +128,8 @@ class DatabaseSystemLanguageRows implements FormDataProviderInterface {
                                $flashMessageService = GeneralUtility::makeInstance(FlashMessageService::class);
                                $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
                                $defaultFlashMessageQueue->enqueue($flashMessage);
-                               $dbRow['iso'] = '';
+                               $languageRows[$uid]['iso'] = '';
                        }
-                       unset($dbRow['language_isocode']);
-                       unset($dbRow['static_lang_isocode']);
-                       $languageRows[(int)$dbRow['uid']] = $dbRow;
                }
 
                $result['systemLanguageRows'] = $languageRows;
@@ -124,4 +150,5 @@ class DatabaseSystemLanguageRows implements FormDataProviderInterface {
        protected function getLanguageService() {
                return $GLOBALS['LANG'];
        }
+
 }
index cf2e3dd..bc53304 100644 (file)
@@ -260,6 +260,7 @@ class TcaFlexProcess extends AbstractItemProvider implements FormDataProviderInt
 
                // Contains all language iso code that are valid and user has access to
                $availableLanguageCodes = [];
+               $defaultCodeWasAdded = FALSE;
                foreach ($systemLanguageRows as $systemLanguageRow) {
                        $isoCode = $systemLanguageRow['iso'];
                        $isAvailable = TRUE;
@@ -282,9 +283,15 @@ class TcaFlexProcess extends AbstractItemProvider implements FormDataProviderInt
                                        $isAvailable = FALSE;
                                }
                        }
+                       if ($isoCode === 'DEF' && $defaultCodeWasAdded) {
+                               $isAvailable = FALSE;
+                       }
                        if ($isAvailable) {
                                $availableLanguageCodes[] = $isoCode;
                        }
+                       if ($isoCode === 'DEF') {
+                               $defaultCodeWasAdded = TRUE;
+                       }
                }
                // Set the list of available languages in the data structure "meta" section to have it
                // available for the render engine to iterate over it.
@@ -603,7 +610,6 @@ class TcaFlexProcess extends AbstractItemProvider implements FormDataProviderInt
         * @return array Modified result
         */
        protected function setLanguageSheetsInDataValues(array $result, $fieldName, array $allowedKeys) {
-               $availableLanguageCodes = $result['processedTca']['columns'][$fieldName]['config']['ds']['meta']['availableLanguageCodes'];
                $valueArray = [];
                if (isset($result['databaseRow'][$fieldName]['data']) && is_array($result['databaseRow'][$fieldName]['data'])) {
                        $valueArray = $result['databaseRow'][$fieldName]['data'];
index 2bc1f12..1b55308 100644 (file)
@@ -57,11 +57,6 @@ class FormEngineUtility {
        );
 
        /**
-        * @var array Cache of getLanguageIcon()
-        */
-       static protected $cachedLanguageFlag = array();
-
-       /**
         * Overrides the TCA field configuration by TSconfig settings.
         *
         * Example TSconfig: TCEform.<table>.<field>.config.appearance.useSortable = 1
@@ -93,44 +88,6 @@ class FormEngineUtility {
        }
 
        /**
-        * Initializes language icons etc.
-        *
-        * @param string $table Table name
-        * @param array $row Record
-        * @param string $sys_language_uid Sys language uid OR ISO language code prefixed with "v", eg. "vDA
-        * @return string
-        * @internal
-        */
-       static public function getLanguageIcon($table, $row, $sys_language_uid) {
-               $mainKey = $table . ':' . $row['uid'];
-               if (!isset(static::$cachedLanguageFlag[$mainKey])) {
-                       BackendUtility::fixVersioningPid($table, $row);
-                       list($tscPID) = BackendUtility::getTSCpidCached($table, $row['uid'], $row['pid']);
-                       /** @var $t8Tools TranslationConfigurationProvider */
-                       $t8Tools = GeneralUtility::makeInstance(TranslationConfigurationProvider::class);
-                       static::$cachedLanguageFlag[$mainKey] = $t8Tools->getSystemLanguages($tscPID);
-               }
-               // Convert sys_language_uid to sys_language_uid if input was in fact a string (ISO code expected then)
-               if (!MathUtility::canBeInterpretedAsInteger($sys_language_uid)) {
-                       foreach (static::$cachedLanguageFlag[$mainKey] as $rUid => $cD) {
-                               if ('v' . $cD['ISOcode'] === $sys_language_uid) {
-                                       $sys_language_uid = $rUid;
-                               }
-                       }
-               }
-               $out = '';
-               if (static::$cachedLanguageFlag[$mainKey][$sys_language_uid]['flagIcon'] && static::$cachedLanguageFlag[$mainKey][$sys_language_uid]['flagIcon'] != 'empty-empty') {
-                       $iconFactory = GeneralUtility::makeInstance(IconFactory::class);
-                       $out .= $iconFactory->getIcon(static::$cachedLanguageFlag[$mainKey][$sys_language_uid]['flagIcon'], Icon::SIZE_SMALL)->render();
-                       $out .= '&nbsp;';
-               } elseif (static::$cachedLanguageFlag[$mainKey][$sys_language_uid]['title']) {
-                       $out .= '[' . static::$cachedLanguageFlag[$mainKey][$sys_language_uid]['title'] . ']';
-                       $out .= '&nbsp;';
-               }
-               return $out;
-       }
-
-       /**
         * Returns TSconfig for given table and row
         *
         * @param string $table The table name
index a8e5e2d..2e2412e 100644 (file)
@@ -49,7 +49,9 @@ class DatabaseSystemLanguageRowsTest extends UnitTestCase {
                $this->singletonInstances = GeneralUtility::getSingletonInstances();
                $this->dbProphecy = $this->prophesize(DatabaseConnection::class);
                $GLOBALS['TYPO3_DB'] = $this->dbProphecy->reveal();
-
+               $languageService = $this->prophesize(LanguageService::class);
+               $GLOBALS['LANG'] = $languageService->reveal();
+               $languageService->sL(Argument::cetera())->willReturnArgument(0);
                $this->subject = new DatabaseSystemLanguageRows();
        }
 
@@ -72,13 +74,20 @@ class DatabaseSystemLanguageRowsTest extends UnitTestCase {
        /**
         * @test
         */
-       public function addDataSetsDefaultLanguageEntry() {
+       public function addDataSetsDefaultLanguageAndAllEntries() {
                $expected = [
                        'systemLanguageRows' => [
+                               -1 => [
+                                       'uid' => -1,
+                                       'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:multipleLanguages',
+                                       'iso' => 'DEF',
+                                       'flagIconIdentifier' => 'flags-multiple',
+                               ],
                                0 => [
                                        'uid' => 0,
-                                       'title' => 'Default Language',
+                                       'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:defaultLanguage',
                                        'iso' => 'DEF',
+                                       'flagIconIdentifier' => 'empty-empty',
                                ],
                        ],
                ];
@@ -89,6 +98,70 @@ class DatabaseSystemLanguageRowsTest extends UnitTestCase {
        /**
         * @test
         */
+       public function addDataSetsDefaultLanguageTitleFromPageTsConfig() {
+               $input = [
+                       'pageTsConfig' => [
+                               'mod.' => [
+                                       'SHARED.' => [
+                                               'defaultLanguageLabel' => 'foo',
+                                       ],
+                               ]
+                       ],
+               ];
+               $this->dbProphecy->exec_SELECTgetRows(Argument::cetera())->willReturn([]);
+               $expected = $input;
+               $expected['systemLanguageRows'] = [
+                       -1 => [
+                               'uid' => -1,
+                               'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:multipleLanguages',
+                               'iso' => 'DEF',
+                               'flagIconIdentifier' => 'flags-multiple',
+                       ],
+                       0 => [
+                               'uid' => 0,
+                               'title' => 'foo (LLL:EXT:lang/locallang_mod_web_list.xlf:defaultLanguage)',
+                               'iso' => 'DEF',
+                               'flagIconIdentifier' => 'empty-empty',
+                       ],
+               ];
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
+       public function addDataSetsDefaultLanguageFlagFromPageTsConfig() {
+               $input = [
+                       'pageTsConfig' => [
+                               'mod.' => [
+                                       'SHARED.' => [
+                                               'defaultLanguageFlag' => 'uk',
+                                       ],
+                               ]
+                       ],
+               ];
+               $this->dbProphecy->exec_SELECTgetRows(Argument::cetera())->willReturn([]);
+               $expected = $input;
+               $expected['systemLanguageRows'] = [
+                       -1 => [
+                               'uid' => -1,
+                               'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:multipleLanguages',
+                               'iso' => 'DEF',
+                               'flagIconIdentifier' => 'flags-multiple',
+                       ],
+                       0 => [
+                               'uid' => 0,
+                               'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:defaultLanguage',
+                               'iso' => 'DEF',
+                               'flagIconIdentifier' => 'flags-uk',
+                       ],
+               ];
+               $this->assertSame($expected, $this->subject->addData($input));
+       }
+
+       /**
+        * @test
+        */
        public function addDataResolvesLanguageIsocodeFromDatabaseField() {
                $dbRows = [
                        [
@@ -96,19 +169,28 @@ class DatabaseSystemLanguageRowsTest extends UnitTestCase {
                                'title' => 'french',
                                'language_isocode' => 'fr',
                                'static_lang_isocode' => '',
+                               'flag' => 'fr',
                        ],
                ];
-               $this->dbProphecy->exec_SELECTgetRows('uid,title,language_isocode,static_lang_isocode', 'sys_language', 'pid=0 AND hidden=0')->willReturn($dbRows);
+               $this->dbProphecy->exec_SELECTgetRows('uid,title,language_isocode,static_lang_isocode,flag', 'sys_language', 'pid=0 AND hidden=0')->willReturn($dbRows);
                $expected = [
                        'systemLanguageRows' => [
+                               -1 => [
+                                       'uid' => -1,
+                                       'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:multipleLanguages',
+                                       'iso' => 'DEF',
+                                       'flagIconIdentifier' => 'flags-multiple',
+                               ],
                                0 => [
                                        'uid' => 0,
-                                       'title' => 'Default Language',
+                                       'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:defaultLanguage',
                                        'iso' => 'DEF',
+                                       'flagIconIdentifier' => 'empty-empty',
                                ],
                                3 => [
                                        'uid' => 3,
                                        'title' => 'french',
+                                       'flagIconIdentifier' => 'flags-fr',
                                        'iso' => 'fr',
                                ],
                        ],
@@ -129,22 +211,31 @@ class DatabaseSystemLanguageRowsTest extends UnitTestCase {
                                'title' => 'french',
                                'language_isocode' => '',
                                'static_lang_isocode' => 42,
+                               'flag' => 'fr',
                        ],
                ];
-               $this->dbProphecy->exec_SELECTgetRows('uid,title,language_isocode,static_lang_isocode', 'sys_language', 'pid=0 AND hidden=0')->shouldBeCalled()->willReturn($dbRows);
+               $this->dbProphecy->exec_SELECTgetRows('uid,title,language_isocode,static_lang_isocode,flag', 'sys_language', 'pid=0 AND hidden=0')->shouldBeCalled()->willReturn($dbRows);
                // Needed for backendUtility::getRecord()
                $GLOBALS['TCA']['static_languages'] = [ 'foo' ];
                $this->dbProphecy->exec_SELECTgetSingleRow('lg_iso_2', 'static_languages', 'uid=42')->shouldBeCalled()->willReturn( [ 'lg_iso_2' => 'FR' ] );
                $expected = [
                        'systemLanguageRows' => [
+                               -1 => [
+                                       'uid' => -1,
+                                       'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:multipleLanguages',
+                                       'iso' => 'DEF',
+                                       'flagIconIdentifier' => 'flags-multiple',
+                               ],
                                0 => [
                                        'uid' => 0,
-                                       'title' => 'Default Language',
+                                       'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:defaultLanguage',
                                        'iso' => 'DEF',
+                                       'flagIconIdentifier' => 'empty-empty',
                                ],
                                3 => [
                                        'uid' => 3,
                                        'title' => 'french',
+                                       'flagIconIdentifier' => 'flags-fr',
                                        'iso' => 'FR',
                                ],
                        ],
@@ -162,30 +253,35 @@ class DatabaseSystemLanguageRowsTest extends UnitTestCase {
                                'title' => 'french',
                                'language_isocode' => '',
                                'static_lang_isocode' => '',
+                               'flag' => 'fr',
                        ],
                ];
-               $this->dbProphecy->exec_SELECTgetRows('uid,title,language_isocode,static_lang_isocode', 'sys_language', 'pid=0 AND hidden=0')->shouldBeCalled()->willReturn($dbRows);
+               $this->dbProphecy->exec_SELECTgetRows('uid,title,language_isocode,static_lang_isocode,flag', 'sys_language', 'pid=0 AND hidden=0')->shouldBeCalled()->willReturn($dbRows);
                // Needed for backendUtility::getRecord()
                $GLOBALS['TCA']['static_languages'] = [ 'foo' ];
                $expected = [
                        'systemLanguageRows' => [
+                               -1 => [
+                                       'uid' => -1,
+                                       'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:multipleLanguages',
+                                       'iso' => 'DEF',
+                                       'flagIconIdentifier' => 'flags-multiple',
+                               ],
                                0 => [
                                        'uid' => 0,
-                                       'title' => 'Default Language',
+                                       'title' => 'LLL:EXT:lang/locallang_mod_web_list.xlf:defaultLanguage',
                                        'iso' => 'DEF',
+                                       'flagIconIdentifier' => 'empty-empty',
                                ],
                                3 => [
                                        'uid' => 3,
                                        'title' => 'french',
+                                       'flagIconIdentifier' => 'flags-fr',
                                        'iso' => '',
                                ],
                        ],
                ];
 
-               $languageService = $this->prophesize(LanguageService::class);
-               $GLOBALS['LANG'] = $languageService->reveal();
-               $languageService->sL(Argument::cetera())->willReturnArgument(0);
-
                /** @var FlashMessage|ObjectProphecy $flashMessage */
                $flashMessage = $this->prophesize(FlashMessage::class);
                GeneralUtility::addInstance(FlashMessage::class, $flashMessage->reveal());