first commit

This commit is contained in:
salam committed 2026-10-19 08:18:39 +02:00
commit 1218dd1517
12716 files changed
+989233

No files matched your search

@@ -0,0 +1,134 @@
<?php
declare(strict_types = 1);
namespace TYPO3\CMS\Form\Service;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\ResourceFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* This class is subjected to change.
* **Do NOT subclass**
*
* Scope: frontend / backend
* @internal
*/
class DatabaseService
{
/**
* Returns an array with all sys_refindex database rows which be
* connected to a formDefinition identified by $persistenceIdentifier
*
* @param string $persistenceIdentifier
* @return array
* @throws \InvalidArgumentException
* @internal
*/
public function getReferencesByPersistenceIdentifier(string $persistenceIdentifier): array
{
if (empty($persistenceIdentifier)) {
throw new \InvalidArgumentException('$persistenceIdentifier must not be empty.', 1472238493);
}
$resourceFactory = GeneralUtility::makeInstance(ResourceFactory::class);
$file = $resourceFactory->retrieveFileOrFolderObject($persistenceIdentifier);
if ($file === null) {
return [];
}
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
return $queryBuilder
->select('*')
->from('sys_refindex')
->where(
$queryBuilder->expr()->eq('deleted', 0),
$queryBuilder->expr()->eq('softref_key', $queryBuilder->createNamedParameter('formPersistenceIdentifier', \PDO::PARAM_STR)),
$queryBuilder->expr()->orX(
$queryBuilder->expr()->eq('ref_string', $queryBuilder->createNamedParameter($persistenceIdentifier, \PDO::PARAM_STR)),
$queryBuilder->expr()->eq('ref_uid', $queryBuilder->createNamedParameter($file->getUid(), \PDO::PARAM_INT))
),
$queryBuilder->expr()->eq('tablename', $queryBuilder->createNamedParameter('tt_content', \PDO::PARAM_STR))
)
->execute()
->fetchAll();
}
/**
* Returns an array with all form definition persistenceIdentifiers
* as keys and their reference counts as values.
*
* @return array
* @internal
*/
public function getAllReferencesForPersistenceIdentifier(): array
{
$items = [];
foreach ($this->getAllReferences('ref_string') as $item) {
$items[$item['identifier']] = $item['items'];
}
return $items;
}
/**
* Returns an array with all form definition file uids as keys
* and their reference counts as values.
*
* @return array
* @internal
*/
public function getAllReferencesForFileUid(): array
{
$items = [];
foreach ($this->getAllReferences('ref_uid') as $item) {
$items[$item['identifier']] = $item['items'];
}
return $items;
}
/**
* @param string $column
* @return array
* @throws \InvalidArgumentException
*/
protected function getAllReferences(string $column): array
{
if ($column !== 'ref_string' && $column !== 'ref_uid') {
throw new \InvalidArgumentException('$column must not be "ref_string" or "ref_uid".', 1535406600);
}
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
$constraints = [$queryBuilder->expr()->eq('softref_key', $queryBuilder->createNamedParameter('formPersistenceIdentifier', \PDO::PARAM_STR))];
if ($column === 'ref_string') {
$constraints[] = $queryBuilder->expr()->neq('ref_string', $queryBuilder->createNamedParameter('', \PDO::PARAM_STR));
} else {
$constraints[] = $queryBuilder->expr()->gt('ref_uid', $queryBuilder->createNamedParameter(0, \PDO::PARAM_INT));
}
return $queryBuilder
->select($column . ' AS identifier')
->addSelectLiteral('COUNT(' . $queryBuilder->quoteIdentifier($column) . ') AS ' . $queryBuilder->quoteIdentifier('items'))
->from('sys_refindex')
->where(...$constraints)
->groupBy($column)
->execute()
->fetchAll();
}
}
@@ -0,0 +1,771 @@
<?php
declare(strict_types = 1);
namespace TYPO3\CMS\Form\Service;
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Localization\Locales;
use TYPO3\CMS\Core\Localization\LocalizationFactory;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
use TYPO3\CMS\Core\Utility\ArrayUtility;
use TYPO3\CMS\Core\Utility\Exception\MissingArrayPathException;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Form\Domain\Model\FormElements\FormElementInterface;
use TYPO3\CMS\Form\Domain\Model\Renderable\RootRenderableInterface;
use TYPO3\CMS\Form\Domain\Runtime\FormRuntime;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
/**
* Advanced translations
* This class is subjected to change.
* **Do NOT subclass**
*
* Scope: frontend / backend
* @internal
*/
class TranslationService implements SingletonInterface
{
/**
* Local Language content
*
* @var array
*/
protected $LOCAL_LANG = [];
/**
* Contains those LL keys, which have been set to (empty) in TypoScript.
* This is necessary, as we cannot distinguish between a nonexisting
* translation and a label that has been cleared by TS.
* In both cases ['key'][0]['target'] is "".
*
* @var array
*/
protected $LOCAL_LANG_UNSET = [];
/**
* Key of the language to use
*
* @var string
*/
protected $languageKey;
/**
* Pointer to alternative fall-back language to use
*
* @var array
*/
protected $alternativeLanguageKeys = [];
/**
* @var \TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface
*/
protected $configurationManager;
/**
* Return TranslationService as singleton
*
* @return TranslationService
* @internal
*/
public static function getInstance()
{
return GeneralUtility::makeInstance(ObjectManager::class)->get(self::class);
}
/**
* Returns the localized label of the LOCAL_LANG key, $key.
*
* @param mixed $key The key from the LOCAL_LANG array for which to return the value.
* @param array $arguments the arguments of the extension, being passed over to vsprintf
* @param string $locallangPathAndFilename
* @param string $language
* @param mixed $defaultValue
* @return mixed The value from LOCAL_LANG or $defaultValue if no translation was found.
* @internal
*/
public function translate(
$key,
array $arguments = null,
string $locallangPathAndFilename = null,
string $language = null,
$defaultValue = ''
) {
$value = null;
$key = (string)$key;
if ($locallangPathAndFilename) {
$key = $locallangPathAndFilename . ':' . $key;
}
$keyParts = explode(':', $key);
if (GeneralUtility::isFirstPartOfStr($key, 'LLL:')) {
$locallangPathAndFilename = $keyParts[1] . ':' . $keyParts[2];
$key = $keyParts[3];
} elseif (GeneralUtility::isFirstPartOfStr($key, 'EXT:')) {
$locallangPathAndFilename = $keyParts[0] . ':' . $keyParts[1];
$key = $keyParts[2];
} else {
if (count($keyParts) === 2) {
$locallangPathAndFilename = $keyParts[0];
$key = $keyParts[1];
}
}
if ($language) {
$this->languageKey = $language;
}
$this->initializeLocalization($locallangPathAndFilename ?? '');
// The "from" charset of csConv() is only set for strings from TypoScript via _LOCAL_LANG
if (!empty($this->LOCAL_LANG[$this->languageKey][$key][0]['target'])
|| isset($this->LOCAL_LANG_UNSET[$this->languageKey][$key])
) {
// Local language translation for key exists
$value = $this->LOCAL_LANG[$this->languageKey][$key][0]['target'];
} elseif (!empty($this->alternativeLanguageKeys)) {
$languages = array_reverse($this->alternativeLanguageKeys);
foreach ($languages as $language) {
if (!empty($this->LOCAL_LANG[$language][$key][0]['target'])
|| isset($this->LOCAL_LANG_UNSET[$language][$key])
) {
// Alternative language translation for key exists
$value = $this->LOCAL_LANG[$language][$key][0]['target'];
break;
}
}
}
if ($value === null && (!empty($this->LOCAL_LANG['default'][$key][0]['target'])
|| isset($this->LOCAL_LANG_UNSET['default'][$key]))
) {
// Default language translation for key exists
// No charset conversion because default is English and thereby ASCII
$value = $this->LOCAL_LANG['default'][$key][0]['target'];
}
if (is_array($arguments) && !empty($arguments) && $value !== null) {
$value = vsprintf($value, $arguments);
} else {
if (empty($value)) {
$value = $defaultValue;
}
}
return $value;
}
/**
* Recursively translate values.
*
* @param array $array
* @param array|string|null $translationFile
* @return array the modified array
* @internal
*/
public function translateValuesRecursive(array $array, $translationFile = null): array
{
$result = $array;
foreach ($result as $key => $value) {
if (is_array($value)) {
$result[$key] = $this->translateValuesRecursive($value, $translationFile);
} else {
$translationFiles = null;
if (is_string($translationFile)) {
$translationFiles = [$translationFile];
} elseif (is_array($translationFile)) {
$translationFiles = $this->sortArrayWithIntegerKeysDescending($translationFile);
}
if ($translationFiles) {
foreach ($translationFiles as $_translationFile) {
$translatedValue = $this->translate($value, null, $_translationFile, null);
if (!empty($translatedValue)) {
$result[$key] = $translatedValue;
break;
}
}
} else {
$result[$key] = $this->translate($value, null, null, null, $value);
}
}
}
return $result;
}
/**
* @param string $key
* @param array $arguments
* @param array $translationFiles
* @return array the modified array
* @internal
*/
public function translateToAllBackendLanguages(
string $key,
array $arguments = null,
array $translationFiles = []
): array {
$result = [];
$translationFiles = $this->sortArrayWithIntegerKeysDescending($translationFiles);
foreach ($this->getAllTypo3BackendLanguages() as $language) {
$result[$language] = $key;
foreach ($translationFiles as $translationFile) {
$translatedValue = $this->translate($key, $arguments, $translationFile, $language, $key);
if ($translatedValue !== $key) {
$result[$language] = $translatedValue;
break;
}
}
}
return $result;
}
/**
* @param FormRuntime $formRuntime
* @param string $finisherIdentifier
* @param string $optionKey
* @param string $optionValue
* @param array $renderingOptions
* @return string
* @throws \InvalidArgumentException
*/
public function translateFinisherOption(
FormRuntime $formRuntime,
string $finisherIdentifier,
string $optionKey,
string $optionValue,
array $renderingOptions = []
): string {
if (empty($finisherIdentifier)) {
throw new \InvalidArgumentException('The argument "finisherIdentifier" is empty', 1476216059);
}
if (empty($optionKey)) {
throw new \InvalidArgumentException('The argument "optionKey" is empty', 1476216060);
}
$finisherIdentifier = preg_replace('/Finisher$/', '', $finisherIdentifier);
$translationFile = $renderingOptions['translationFile'] ?? null;
if (empty($translationFile)) {
$translationFile = $formRuntime->getRenderingOptions()['translation']['translationFile'];
}
if (is_string($translationFile)) {
$translationFiles = [$translationFile];
} else {
$translationFiles = $this->sortArrayWithIntegerKeysDescending($translationFile);
}
if (isset($renderingOptions['translatePropertyValueIfEmpty'])) {
$translatePropertyValueIfEmpty = (bool)$renderingOptions['translatePropertyValueIfEmpty'];
} else {
$translatePropertyValueIfEmpty = true;
}
if (empty($optionValue) && !$translatePropertyValueIfEmpty) {
return $optionValue;
}
$language = null;
if (isset($renderingOptions['language'])) {
$language = $renderingOptions['language'];
}
try {
$arguments = ArrayUtility::getValueByPath($renderingOptions['arguments'] ?? [], $optionKey, '.');
} catch (MissingArrayPathException $e) {
$arguments = [];
}
$originalFormIdentifier = null;
if (isset($formRuntime->getRenderingOptions()['_originalIdentifier'])) {
$originalFormIdentifier = $formRuntime->getRenderingOptions()['_originalIdentifier'];
}
$translationKeyChain = [];
foreach ($translationFiles as $translationFile) {
if (!empty($originalFormIdentifier)) {
$translationKeyChain[] = sprintf('%s:%s.finisher.%s.%s', $translationFile, $originalFormIdentifier, $finisherIdentifier, $optionKey);
}
$translationKeyChain[] = sprintf('%s:%s.finisher.%s.%s', $translationFile, $formRuntime->getIdentifier(), $finisherIdentifier, $optionKey);
$translationKeyChain[] = sprintf('%s:finisher.%s.%s', $translationFile, $finisherIdentifier, $optionKey);
}
$translatedValue = $this->processTranslationChain($translationKeyChain, $language, $arguments);
$translatedValue = empty($translatedValue) ? $optionValue : $translatedValue;
return $translatedValue;
}
/**
* @param RootRenderableInterface $element
* @param array $propertyParts
* @param FormRuntime $formRuntime
* @return string|array
* @throws \InvalidArgumentException
* @internal
*/
public function translateFormElementValue(
RootRenderableInterface $element,
array $propertyParts,
FormRuntime $formRuntime
) {
if (empty($propertyParts)) {
throw new \InvalidArgumentException('The argument "propertyParts" is empty', 1476216007);
}
$propertyType = 'properties';
$property = implode('.', $propertyParts);
$renderingOptions = $element->getRenderingOptions();
if ($property === 'label') {
$defaultValue = $element->getLabel();
} else {
if ($element instanceof FormElementInterface) {
try {
$defaultValue = ArrayUtility::getValueByPath($element->getProperties(), $propertyParts, '.');
} catch (MissingArrayPathException $exception) {
$defaultValue = null;
}
} else {
$propertyType = 'renderingOptions';
try {
$defaultValue = ArrayUtility::getValueByPath($renderingOptions, $propertyParts, '.');
} catch (MissingArrayPathException $exception) {
$defaultValue = null;
}
}
}
if (isset($renderingOptions['translation']['translatePropertyValueIfEmpty'])) {
$translatePropertyValueIfEmpty = $renderingOptions['translation']['translatePropertyValueIfEmpty'];
} else {
$translatePropertyValueIfEmpty = true;
}
if (empty($defaultValue) && !$translatePropertyValueIfEmpty) {
return $defaultValue;
}
$defaultValue = empty($defaultValue) ? '' : $defaultValue;
$translationFile = $renderingOptions['translation']['translationFile'] ?? null;
if (empty($translationFile)) {
$translationFile = $formRuntime->getRenderingOptions()['translation']['translationFile'];
}
if (is_string($translationFile)) {
$translationFiles = [$translationFile];
} else {
$translationFiles = $this->sortArrayWithIntegerKeysDescending($translationFile);
}
$language = null;
if (isset($renderingOptions['translation']['language'])) {
$language = $renderingOptions['translation']['language'];
}
try {
$arguments = ArrayUtility::getValueByPath($renderingOptions['translation']['arguments'] ?? [], $propertyParts, '.');
} catch (MissingArrayPathException $e) {
$arguments = [];
}
$originalFormIdentifier = null;
if (isset($formRuntime->getRenderingOptions()['_originalIdentifier'])) {
$originalFormIdentifier = $formRuntime->getRenderingOptions()['_originalIdentifier'];
}
if ($property === 'options' && is_array($defaultValue)) {
foreach ($defaultValue as $optionValue => &$optionLabel) {
$translationKeyChain = [];
foreach ($translationFiles as $translationFile) {
if (!empty($originalFormIdentifier)) {
if ($element instanceof FormRuntime) {
$translationKeyChain[] = sprintf('%s:%s.element.%s.%s.%s.%s', $translationFile, $originalFormIdentifier, $originalFormIdentifier, $propertyType, $property, $optionValue);
$translationKeyChain[] = sprintf('%s:element.%s.%s.%s.%s', $translationFile, $originalFormIdentifier, $propertyType, $property, $optionValue);
} else {
$translationKeyChain[] = sprintf('%s:%s.element.%s.%s.%s.%s', $translationFile, $originalFormIdentifier, $element->getIdentifier(), $propertyType, $property, $optionValue);
}
}
$translationKeyChain[] = sprintf('%s:%s.element.%s.%s.%s.%s', $translationFile, $formRuntime->getIdentifier(), $element->getIdentifier(), $propertyType, $property, $optionValue);
$translationKeyChain[] = sprintf('%s:element.%s.%s.%s.%s', $translationFile, $element->getIdentifier(), $propertyType, $property, $optionValue);
$translationKeyChain[] = sprintf('%s:element.%s.%s.%s.%s', $translationFile, $element->getType(), $propertyType, $property, $optionValue);
}
$translatedValue = $this->processTranslationChain($translationKeyChain, $language, $arguments);
$optionLabel = empty($translatedValue) ? $optionLabel : $translatedValue;
}
$translatedValue = $defaultValue;
} elseif ($property === 'fluidAdditionalAttributes' && is_array($defaultValue)) {
foreach ($defaultValue as $propertyName => &$propertyValue) {
$translationKeyChain = [];
foreach ($translationFiles as $translationFile) {
if (!empty($originalFormIdentifier)) {
if ($element instanceof FormRuntime) {
$translationKeyChain[] = sprintf('%s:%s.element.%s.%s.%s', $translationFile, $originalFormIdentifier, $originalFormIdentifier, $propertyType, $propertyName);
$translationKeyChain[] = sprintf('%s:element.%s.%s.%s', $translationFile, $originalFormIdentifier, $propertyType, $propertyName);
} else {
$translationKeyChain[] = sprintf('%s:%s.element.%s.%s.%s', $translationFile, $originalFormIdentifier, $element->getIdentifier(), $propertyType, $propertyName);
}
}
$translationKeyChain[] = sprintf('%s:%s.element.%s.%s.%s', $translationFile, $formRuntime->getIdentifier(), $element->getIdentifier(), $propertyType, $propertyName);
$translationKeyChain[] = sprintf('%s:element.%s.%s.%s', $translationFile, $element->getIdentifier(), $propertyType, $propertyName);
$translationKeyChain[] = sprintf('%s:element.%s.%s.%s', $translationFile, $element->getType(), $propertyType, $propertyName);
}
$translatedValue = $this->processTranslationChain($translationKeyChain, $language, $arguments);
$propertyValue = empty($translatedValue) ? $propertyValue : $translatedValue;
}
$translatedValue = $defaultValue;
} else {
$translationKeyChain = [];
foreach ($translationFiles as $translationFile) {
if (!empty($originalFormIdentifier)) {
if ($element instanceof FormRuntime) {
$translationKeyChain[] = sprintf('%s:%s.element.%s.%s.%s', $translationFile, $originalFormIdentifier, $originalFormIdentifier, $propertyType, $property);
$translationKeyChain[] = sprintf('%s:element.%s.%s.%s', $translationFile, $originalFormIdentifier, $propertyType, $property);
} else {
$translationKeyChain[] = sprintf('%s:%s.element.%s.%s.%s', $translationFile, $originalFormIdentifier, $element->getIdentifier(), $propertyType, $property);
}
}
$translationKeyChain[] = sprintf('%s:%s.element.%s.%s.%s', $translationFile, $formRuntime->getIdentifier(), $element->getIdentifier(), $propertyType, $property);
$translationKeyChain[] = sprintf('%s:element.%s.%s.%s', $translationFile, $element->getIdentifier(), $propertyType, $property);
$translationKeyChain[] = sprintf('%s:element.%s.%s.%s', $translationFile, $element->getType(), $propertyType, $property);
}
$translatedValue = $this->processTranslationChain($translationKeyChain, $language, $arguments);
$translatedValue = empty($translatedValue) ? $defaultValue : $translatedValue;
}
return $translatedValue;
}
/**
* @param RootRenderableInterface $element
* @param int $code
* @param string $defaultValue
* @param array $arguments
* @param FormRuntime $formRuntime
* @return string
* @throws \InvalidArgumentException
* @internal
*/
public function translateFormElementError(
RootRenderableInterface $element,
int $code,
array $arguments,
string $defaultValue = '',
FormRuntime $formRuntime
): string {
if (empty($code)) {
throw new \InvalidArgumentException('The argument "code" is empty', 1489272978);
}
$validationErrors = $element->getProperties()['validationErrorMessages'] ?? null;
if (is_array($validationErrors)) {
foreach ($validationErrors as $validationError) {
if ((int)$validationError['code'] === $code) {
return sprintf($validationError['message'], $arguments);
}
}
}
$renderingOptions = $element->getRenderingOptions();
$translationFile = $renderingOptions['translation']['translationFile'] ?? null;
if (empty($translationFile)) {
$translationFile = $formRuntime->getRenderingOptions()['translation']['translationFile'];
}
if (is_string($translationFile)) {
$translationFiles = [$translationFile];
} else {
$translationFiles = $this->sortArrayWithIntegerKeysDescending($translationFile);
}
$language = null;
if (isset($renderingOptions['language'])) {
$language = $renderingOptions['language'];
}
$originalFormIdentifier = null;
if (isset($formRuntime->getRenderingOptions()['_originalIdentifier'])) {
$originalFormIdentifier = $formRuntime->getRenderingOptions()['_originalIdentifier'];
}
$translationKeyChain = [];
foreach ($translationFiles as $translationFile) {
if (!empty($originalFormIdentifier)) {
if ($element instanceof FormRuntime) {
$translationKeyChain[] = sprintf('%s:%s.validation.error.%s.%s', $translationFile, $originalFormIdentifier, $originalFormIdentifier, $code);
$translationKeyChain[] = sprintf('%s:validation.error.%s.%s', $translationFile, $originalFormIdentifier, $code);
} else {
$translationKeyChain[] = sprintf('%s:%s.validation.error.%s.%s', $translationFile, $originalFormIdentifier, $element->getIdentifier(), $code);
}
$translationKeyChain[] = sprintf('%s:%s.validation.error.%s', $translationFile, $originalFormIdentifier, $code);
}
$translationKeyChain[] = sprintf('%s:%s.validation.error.%s.%s', $translationFile, $formRuntime->getIdentifier(), $element->getIdentifier(), $code);
$translationKeyChain[] = sprintf('%s:%s.validation.error.%s', $translationFile, $formRuntime->getIdentifier(), $code);
$translationKeyChain[] = sprintf('%s:validation.error.%s.%s', $translationFile, $element->getIdentifier(), $code);
$translationKeyChain[] = sprintf('%s:validation.error.%s', $translationFile, $code);
}
$translatedValue = $this->processTranslationChain($translationKeyChain, $language, $arguments);
$translatedValue = empty($translatedValue) ? $defaultValue : $translatedValue;
return $translatedValue;
}
/**
* @param string $languageKey
* @internal
*/
public function setLanguage(string $languageKey)
{
$this->languageKey = $languageKey;
}
/**
* @return string
* @internal
*/
public function getLanguage(): string
{
return $this->languageKey;
}
/**
* @param array $translationKeyChain
* @param string $language
* @param array $arguments
* @return string|null
*/
protected function processTranslationChain(
array $translationKeyChain,
string $language = null,
array $arguments = null
) {
$translatedValue = null;
foreach ($translationKeyChain as $translationKey) {
$translatedValue = $this->translate($translationKey, $arguments, null, $language);
if (!empty($translatedValue)) {
break;
}
}
return $translatedValue;
}
/**
* @param string $locallangPathAndFilename
*/
protected function initializeLocalization(string $locallangPathAndFilename)
{
if (empty($this->languageKey)) {
$this->setLanguageKeys();
}
if (!empty($locallangPathAndFilename)) {
/** @var LocalizationFactory $languageFactory */
$languageFactory = GeneralUtility::makeInstance(LocalizationFactory::class);
$this->LOCAL_LANG = $languageFactory->getParsedData($locallangPathAndFilename, $this->languageKey);
foreach ($this->alternativeLanguageKeys as $language) {
$tempLL = $languageFactory->getParsedData($locallangPathAndFilename, $language);
if ($this->languageKey !== 'default' && isset($tempLL[$language])) {
$this->LOCAL_LANG[$language] = $tempLL[$language];
}
}
}
$this->loadTypoScriptLabels();
}
/**
* Sets the currently active language/language_alt keys.
* Default values are "default" for language key and "" for language_alt key.
*/
protected function setLanguageKeys()
{
$this->languageKey = 'default';
$this->alternativeLanguageKeys = [];
if (TYPO3_MODE === 'FE') {
$tsfe = $this->getTypoScriptFrontendController();
if ($this->getCurrentSiteLanguage() instanceof SiteLanguage) {
$this->languageKey = $this->getCurrentSiteLanguage()->getTypo3Language();
} elseif (isset($tsfe->config['config']['language'])) {
$this->languageKey = $tsfe->config['config']['language'];
if (isset($tsfe->config['config']['language_alt'])) {
$this->alternativeLanguageKeys[] = $tsfe->config['config']['language_alt'];
}
}
if ($this->languageKey !== 'default' && empty($this->alternativeLanguageKeys)) {
/** @var \TYPO3\CMS\Core\Localization\Locales $locales */
$locales = GeneralUtility::makeInstance(Locales::class);
if (in_array($this->languageKey, $locales->getLocales(), true)) {
foreach ($locales->getLocaleDependencies($this->languageKey) as $language) {
$this->alternativeLanguageKeys[] = $language;
}
}
}
} elseif (!empty($GLOBALS['BE_USER']->uc['lang'])) {
$this->languageKey = $GLOBALS['BE_USER']->uc['lang'];
} elseif (!empty($this->getLanguageService()->lang)) {
$this->languageKey = $this->getLanguageService()->lang;
}
}
/**
* Overwrites labels that are set via TypoScript.
* TS locallang labels have to be configured like:
* plugin.tx_form._LOCAL_LANG.languageKey.key = value
*/
protected function loadTypoScriptLabels()
{
$frameworkConfiguration = $this->getConfigurationManager()
->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, 'form');
if (!is_array($frameworkConfiguration['_LOCAL_LANG'] ?? null)) {
return;
}
$this->LOCAL_LANG_UNSET = [];
foreach ($frameworkConfiguration['_LOCAL_LANG'] as $languageKey => $labels) {
if (!(is_array($labels) && isset($this->LOCAL_LANG[$languageKey]))) {
continue;
}
foreach ($labels as $labelKey => $labelValue) {
if (is_string($labelValue)) {
$this->LOCAL_LANG[$languageKey][$labelKey][0]['target'] = $labelValue;
if ($labelValue === '') {
$this->LOCAL_LANG_UNSET[$languageKey][$labelKey] = '';
}
} elseif (is_array($labelValue)) {
$labelValue = $this->flattenTypoScriptLabelArray($labelValue, $labelKey);
foreach ($labelValue as $key => $value) {
$this->LOCAL_LANG[$languageKey][$key][0]['target'] = $value;
if ($value === '') {
$this->LOCAL_LANG_UNSET[$languageKey][$key] = '';
}
}
}
}
}
}
/**
* Flatten TypoScript label array; converting a hierarchical array into a flat
* array with the keys separated by dots.
*
* Example Input: array('k1' => array('subkey1' => 'val1'))
* Example Output: array('k1.subkey1' => 'val1')
*
* @param array $labelValues Hierarchical array of labels
* @param string $parentKey the name of the parent key in the recursion; is only needed for recursion.
* @return array flattened array of labels.
*/
protected function flattenTypoScriptLabelArray(array $labelValues, string $parentKey = ''): array
{
$result = [];
foreach ($labelValues as $key => $labelValue) {
if (!empty($parentKey)) {
$key = $parentKey . '.' . $key;
}
if (is_array($labelValue)) {
$labelValue = $this->flattenTypoScriptLabelArray($labelValue, $key);
$result = array_merge($result, $labelValue);
} else {
$result[$key] = $labelValue;
}
}
return $result;
}
/**
* If the array contains numerical keys only, sort it in descending order
*
* @param array $array
* @return array
*/
protected function sortArrayWithIntegerKeysDescending(array $array)
{
if (count(array_filter(array_keys($array), 'is_string')) === 0) {
krsort($array);
}
return $array;
}
/**
* Returns instance of the configuration manager
*
* @return ConfigurationManagerInterface
*/
protected function getConfigurationManager(): ConfigurationManagerInterface
{
if ($this->configurationManager !== null) {
return $this->configurationManager;
}
$this->configurationManager = GeneralUtility::makeInstance(ObjectManager::class)
->get(ConfigurationManagerInterface::class);
return $this->configurationManager;
}
/**
* Returns the currently configured "site language" if a site is configured (= resolved) in the current request.
*
* @return SiteLanguage|null
*/
protected function getCurrentSiteLanguage(): ?SiteLanguage
{
if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) {
return $GLOBALS['TYPO3_REQUEST']->getAttribute('language', null);
}
return null;
}
/**
* @return array
*/
protected function getAllTypo3BackendLanguages(): array
{
$languages = array_merge(
['default'],
array_values($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['lang']['availableLanguages'] ?? [])
);
return $languages;
}
/**
* @return LanguageService
*/
protected function getLanguageService(): LanguageService
{
return $GLOBALS['LANG'];
}
/**
* @return TypoScriptFrontendController
*/
protected function getTypoScriptFrontendController(): TypoScriptFrontendController
{
return $GLOBALS['TSFE'];
}
}