TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:15 +02:00
commit 6830982e7d
295 changed files with 31995 additions and 0 deletions
+161
View File
@@ -0,0 +1,161 @@
<?php
declare(strict_types=1);
/*
* 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!
*/
namespace TYPO3\CMS\Extbase\Utility;
use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
use TYPO3\CMS\Core\Localization\Locale;
use TYPO3\CMS\Core\Localization\Locales;
use TYPO3\CMS\Core\Localization\TranslationDomainMapper;
use TYPO3\CMS\Core\Localization\TranslationDomainResolver;
use TYPO3\CMS\Core\TypoScript\FrontendTypoScript;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Request;
/**
* Localization helper which should be used to fetch localized labels.
*/
class LocalizationUtility
{
/**
* Returns the localized label of the LOCAL_LANG key, $key.
*
* @param string $key The key from the LOCAL_LANG array for which to return the value.
* @param string|null $extensionName The name of the extension or domain name (such as "myextension.messages")
* @param array|null $arguments The arguments for the label. For sprintf-style labels (e.g., "Downloaded %d times"),
* use positional arguments [42]. For ICU MessageFormat labels
* (e.g., "{count, plural, one {# file} other {# files}}"), use named arguments ['count' => 42].
* @param Locale|string|null $languageKey The language key or null for using the current language from the system
* @return string|null The value from LOCAL_LANG or null if no translation was found.
*/
public static function translate(string $key, ?string $extensionName = null, ?array $arguments = null, Locale|string|null $languageKey = null, ?ServerRequestInterface $request = null): ?string
{
if ($key === '') {
// Early return guard: returns null if the key was empty, because the key may be a dynamic value
// (from for example Fluid). Returning null allows null coalescing to a default value when that happens.
return null;
}
$languageFilePath = null;
if (str_starts_with($key, 'LLL:EXT:')) {
$keyParts = explode(':', $key);
unset($keyParts[0]);
$key = array_pop($keyParts);
$languageFilePath = implode(':', $keyParts);
} elseif ($extensionName) {
if (str_contains($extensionName, '.')) {
// We assume this is a valid domain now
$languageFilePath = $extensionName;
$extensionName = self::getExtensionNameFromDomain($languageFilePath);
} else {
$languageFilePath = GeneralUtility::camelCaseToLowerCaseUnderscored($extensionName) . '.messages';
}
} elseif (str_contains($key, ':')) {
[$languageFilePath, $key, $extensionName] = self::extractLanguageInfoFromDomainString($key);
}
if ($languageFilePath === null || $key === '') {
throw new \InvalidArgumentException(
'Parameter $extensionName cannot be empty if a fully-qualified key is not specified.',
1498144052
);
}
$request = $request ?? $GLOBALS['TYPO3_REQUEST'] ?? null;
$locale = self::getLocale($languageKey, $request);
$languageService = GeneralUtility::makeInstance(LanguageServiceFactory::class)->create($locale);
if (!empty($extensionName) && $request instanceof ServerRequestInterface) {
$typoScript = $request->getAttribute('frontend.typoscript');
if ($typoScript instanceof FrontendTypoScript) {
// Loads local-language values by looking for a "locallang.xlf" file in the plugin resources directory and if found includes it.
// Locallang values set in the TypoScript property "_LOCAL_LANG" are merged onto the values found in the "locallang.xlf" file.
$overrideLabels = $languageService->loadTypoScriptLabelsFromExtension($extensionName, $typoScript, self::getPluginName($request));
if ($overrideLabels !== []) {
$languageService->overrideLabels($languageFilePath, $overrideLabels);
}
}
}
try {
return $languageService->translate($key, $languageFilePath, $arguments ?? []);
} catch (\ValueError $e) {
return sprintf('Error: could not translate key "%s" with value "%s" and %d argument(s)!', $key, $e->getMessage(), count($arguments));
}
}
/**
* Resolves the currently active locale.
* Using the Locales factory, as it handles dependencies (e.g. "de-AT" falls back to "de").
*/
protected static function getLocale(Locale|string|null $localeOrLanguageKey, ?ServerRequestInterface $request): Locale
{
if ($localeOrLanguageKey instanceof Locale) {
return $localeOrLanguageKey;
}
$localeFactory = GeneralUtility::makeInstance(Locales::class);
if (is_string($localeOrLanguageKey)) {
return $localeFactory->createLocale($localeOrLanguageKey);
}
return $localeFactory->createLocaleFromRequest($request);
}
/**
* Allow plugin.tx_myextension._LOCAL_LANG and plugin.tx_myextension_myplugin._LOCAL_LANG
*/
protected static function getPluginName(?ServerRequestInterface $request): string
{
if ($request instanceof Request) {
return strtolower($request->getPluginName());
}
return '';
}
private static function getExtensionNameFromDomain(string $possibleDomain): ?string
{
[$extensionName, $filePart] = explode('.', $possibleDomain, 2);
if ($filePart !== 'messages') {
return null;
}
return $extensionName;
}
/**
* @return array<?string>
*/
private static function extractLanguageInfoFromDomainString(string $key): array
{
$languageFilePath = null;
$extensionName = null;
if (str_starts_with($key, 'LLL:')) {
$key = substr($key, 4);
}
[$possibleDomain, $possibleId] = explode(':', $key, 2);
$domainMapper = GeneralUtility::makeInstance(TranslationDomainMapper::class);
$domainResolver = GeneralUtility::makeInstance(TranslationDomainResolver::class);
if ($domainResolver->isValidDomainName($possibleDomain) && $domainMapper->mapDomainToFileName($possibleDomain) !== $possibleDomain) {
$languageFilePath = $possibleDomain;
$key = trim($possibleId);
$extensionName = self::getExtensionNameFromDomain($languageFilePath);
}
return [
$languageFilePath,
$key,
$extensionName,
];
}
}