diff --git a/composer.json b/composer.json
index eb78ab966f34d42a240431c63677008e4a18955a..318fbbc04062e5ac94f381bec0c9687b0e8e0e3b 100644
--- a/composer.json
+++ b/composer.json
@@ -301,6 +301,7 @@
 			"TYPO3Tests\\ParentChildTranslation\\": "typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/parent_child_translation/Classes/",
 			"TYPO3Tests\\TestEid\\": "typo3/sysext/core/Tests/Functional/Fixtures/Extensions/test_eid/Classes/",
 			"TYPO3Tests\\FluidTest\\": "typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/fluid_test/Classes/",
+			"TYPO3Tests\\TestTranslate\\": "typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/Classes/",
 			"TYPO3Tests\\FormCachingTests\\" : "typo3/sysext/form/Tests/Functional/RequestHandling/Fixtures/Extensions/form_caching_tests/Classes/",
 			"TYPO3Tests\\RequestMirror\\": "typo3/sysext/frontend/Tests/Functional/Fixtures/Extensions/test_request_mirror/Classes/",
 			"TYPO3Tests\\TestValidators\\": "typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/test_validators/Classes/",
diff --git a/typo3/sysext/core/Classes/Localization/LanguageServiceFactory.php b/typo3/sysext/core/Classes/Localization/LanguageServiceFactory.php
index 02edccecf330684433b0a9ff3e9bb12270b3a579..19cd958f577b47e80a6d9d918ebd803bc99e78c6 100644
--- a/typo3/sysext/core/Classes/Localization/LanguageServiceFactory.php
+++ b/typo3/sysext/core/Classes/Localization/LanguageServiceFactory.php
@@ -51,10 +51,7 @@ class LanguageServiceFactory
 
     public function createFromUserPreferences(?AbstractUserAuthentication $user): LanguageService
     {
-        if ($user && ($user->user['lang'] ?? false)) {
-            return $this->create($this->locales->createLocale($user->user['lang']));
-        }
-        return $this->create('en');
+        return $this->create($this->locales->createLocaleFromUserPreferences($user));
     }
 
     public function createFromSiteLanguage(SiteLanguage $language): LanguageService
diff --git a/typo3/sysext/core/Classes/Localization/Locales.php b/typo3/sysext/core/Classes/Localization/Locales.php
index ff0fa3ce45ea1d55d83e352605572b657bad4846..a697fa8b8fbb3213bf4fe663eb2a9ae4a3cadcfb 100644
--- a/typo3/sysext/core/Classes/Localization/Locales.php
+++ b/typo3/sysext/core/Classes/Localization/Locales.php
@@ -17,7 +17,10 @@ declare(strict_types=1);
 
 namespace TYPO3\CMS\Core\Localization;
 
+use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Authentication\AbstractUserAuthentication;
 use TYPO3\CMS\Core\Core\Environment;
+use TYPO3\CMS\Core\Http\ApplicationType;
 use TYPO3\CMS\Core\Log\LogManager;
 use TYPO3\CMS\Core\SingletonInterface;
 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
@@ -353,4 +356,25 @@ class Locales implements SingletonInterface
         }
         return true;
     }
+
+    public function createLocaleFromRequest(?ServerRequestInterface $request): Locale
+    {
+        $languageServiceFactory = GeneralUtility::makeInstance(LanguageServiceFactory::class);
+        if ($request !== null && ApplicationType::fromRequest($request)->isFrontend()) {
+            // @todo: the string conversion is needed for the time being, as long as SiteLanguage does not contain
+            // the full locale with all fallbacks, then getTypo3Language() also needs to be removed.
+            $localeString = (string)($request->getAttribute('language')?->getTypo3Language()
+                ?? $request->getAttribute('site')->getDefaultLanguage()->getTypo3Language());
+            return $this->createLocale($localeString);
+        }
+        return $languageServiceFactory->createFromUserPreferences($GLOBALS['BE_USER'] ?? null)->getLocale();
+    }
+
+    public function createLocaleFromUserPreferences(?AbstractUserAuthentication $user): Locale
+    {
+        if ($user && ($user->user['lang'] ?? false)) {
+            return $this->createLocale($user->user['lang']);
+        }
+        return $this->createLocale('en');
+    }
 }
diff --git a/typo3/sysext/extbase/Classes/Utility/LocalizationUtility.php b/typo3/sysext/extbase/Classes/Utility/LocalizationUtility.php
index 898cd06a41562e7989c1a7d15dd82ac819abe447..688af821132c94ee3214256f91c4fb6293152da3 100644
--- a/typo3/sysext/extbase/Classes/Utility/LocalizationUtility.php
+++ b/typo3/sysext/extbase/Classes/Utility/LocalizationUtility.php
@@ -25,7 +25,6 @@ use TYPO3\CMS\Core\Localization\LanguageService;
 use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
 use TYPO3\CMS\Core\Localization\Locale;
 use TYPO3\CMS\Core\Localization\Locales;
-use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 
@@ -66,19 +65,15 @@ class LocalizationUtility
             }
             $languageFilePath = static::getLanguageFilePath($extensionName);
         }
-        if ($languageKey === null) {
-            $languageKey = static::getLanguageKey();
-        }
-        if ($languageKey instanceof Locale) {
-            $languageKey = (string)$languageKey;
-        }
-        $languageService = static::initializeLocalization($languageFilePath, $languageKey, $extensionName);
+        $locale = self::getLocale($languageKey);
+        $languageService = static::initializeLocalization($languageFilePath, $locale, $extensionName);
         $resolvedLabel = $languageService->sL('LLL:' . $languageFilePath . ':' . $key);
         $value = $resolvedLabel !== '' ? $resolvedLabel : null;
 
         // Check if a value was explicitly set to "" via TypoScript, if so, we need to ensure that this is "" and not null
         if ($extensionName) {
             $overrideLabels = static::loadTypoScriptLabels($extensionName);
+            $languageKey = $locale->getName();
             // @todo: probably cannot handle "de-DE" and "de" fallbacks
             if ($value === null && isset($overrideLabels[$languageKey])) {
                 $value = '';
@@ -98,9 +93,9 @@ class LocalizationUtility
      * 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.
      */
-    protected static function initializeLocalization(string $languageFilePath, string $languageKey, ?string $extensionName): LanguageService
+    protected static function initializeLocalization(string $languageFilePath, Locale $locale, ?string $extensionName): LanguageService
     {
-        $languageService = self::buildLanguageService($languageKey, $languageFilePath);
+        $languageService = self::buildLanguageService($locale, $languageFilePath);
         if (!empty($extensionName)) {
             $overrideLabels = static::loadTypoScriptLabels($extensionName);
             if ($overrideLabels !== []) {
@@ -110,13 +105,11 @@ class LocalizationUtility
         return $languageService;
     }
 
-    protected static function buildLanguageService(string $languageKey, string $languageFilePath): LanguageService
+    protected static function buildLanguageService(Locale $locale, string $languageFilePath): LanguageService
     {
-        $languageKeyHash = sha1(json_encode(array_merge([$languageKey], [$languageFilePath])));
+        $languageKeyHash = sha1(json_encode(array_merge([(string)$locale], $locale->getDependencies(), [$languageFilePath])));
         $cache = self::getRuntimeCache();
         if (!$cache->get($languageKeyHash)) {
-            // Using the Locales factory, as it handles dependencies (e.g. "de-AT" falls back to "de")
-            $locale = GeneralUtility::makeInstance(Locales::class)->createLocale($languageKey);
             $languageService = GeneralUtility::makeInstance(LanguageServiceFactory::class)->create($locale);
             $languageService->includeLLFile($languageFilePath);
             $cache->set($languageKeyHash, $languageService);
@@ -133,24 +126,19 @@ class LocalizationUtility
     }
 
     /**
-     * Resolves the currently active language key.
+     * Resolves the currently active locale.
+     * Using the Locales factory, as it handles dependencies (e.g. "de-AT" falls back to "de").
      */
-    protected static function getLanguageKey(): string
+    protected static function getLocale(Locale|string|null $localeOrLanguageKey): Locale
     {
-        if (($GLOBALS['TYPO3_REQUEST'] ?? null) instanceof ServerRequestInterface
-            && ApplicationType::fromRequest($GLOBALS['TYPO3_REQUEST'])->isFrontend()
-        ) {
-            // Frontend application
-            $siteLanguage = self::getCurrentSiteLanguage();
-
-            // Get values from site language
-            if ($siteLanguage !== null) {
-                return $siteLanguage->getTypo3Language();
-            }
-        } elseif (!empty($GLOBALS['BE_USER']->user['lang'])) {
-            return $GLOBALS['BE_USER']->user['lang'];
+        if ($localeOrLanguageKey instanceof Locale) {
+            return $localeOrLanguageKey;
         }
-        return 'default';
+        $localeFactory = GeneralUtility::makeInstance(Locales::class);
+        if (is_string($localeOrLanguageKey)) {
+            return $localeFactory->createLocale($localeOrLanguageKey);
+        }
+        return $localeFactory->createLocaleFromRequest($GLOBALS['TYPO3_REQUEST'] ?? null);
     }
 
     /**
@@ -160,6 +148,11 @@ class LocalizationUtility
      */
     protected static function loadTypoScriptLabels(string $extensionName): array
     {
+        // Only allow overrides in Frontend Context
+        $request = $GLOBALS['TYPO3_REQUEST'] ?? null;
+        if (!$request instanceof ServerRequestInterface || !ApplicationType::fromRequest($request)->isFrontend()) {
+            return [];
+        }
         $configurationManager = GeneralUtility::makeInstance(ConfigurationManagerInterface::class);
         $frameworkConfiguration = $configurationManager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK, $extensionName);
         if (!is_array($frameworkConfiguration['_LOCAL_LANG'] ?? false)) {
@@ -216,18 +209,6 @@ class LocalizationUtility
         return $result;
     }
 
-    /**
-     * Returns the currently configured "site language" if a site is configured (= resolved)
-     * in the current request.
-     */
-    protected static function getCurrentSiteLanguage(): ?SiteLanguage
-    {
-        if ($GLOBALS['TYPO3_REQUEST'] instanceof ServerRequestInterface) {
-            return $GLOBALS['TYPO3_REQUEST']->getAttribute('language');
-        }
-        return null;
-    }
-
     protected static function getRuntimeCache(): FrontendInterface
     {
         return GeneralUtility::makeInstance(CacheManager::class)->getCache('runtime');
diff --git a/typo3/sysext/extbase/Tests/Functional/Utility/LocalizationUtilityTest.php b/typo3/sysext/extbase/Tests/Functional/Utility/LocalizationUtilityTest.php
index 321ac7fc4604724c5ff31576c7a5b8cd1f0a6148..ee46efdd15c2a28570ff7cace5592f1b7e9e97dd 100644
--- a/typo3/sysext/extbase/Tests/Functional/Utility/LocalizationUtilityTest.php
+++ b/typo3/sysext/extbase/Tests/Functional/Utility/LocalizationUtilityTest.php
@@ -18,6 +18,8 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Extbase\Tests\Functional\Utility;
 
 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
+use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
+use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface;
 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
@@ -143,6 +145,9 @@ final class LocalizationUtilityTest extends FunctionalTestCase
      */
     public function loadTypoScriptLabels(): void
     {
+        $GLOBALS['TYPO3_REQUEST'] = new ServerRequest();
+        $GLOBALS['TYPO3_REQUEST'] = $GLOBALS['TYPO3_REQUEST']
+            ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE);
         $configurationType = ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK;
         $configurationManagerInterfaceMock = $this->createMock(ConfigurationManagerInterface::class);
         $configurationManagerInterfaceMock
@@ -180,6 +185,9 @@ final class LocalizationUtilityTest extends FunctionalTestCase
      */
     public function clearLabelWithTypoScript(): void
     {
+        $GLOBALS['TYPO3_REQUEST'] = new ServerRequest();
+        $GLOBALS['TYPO3_REQUEST'] = $GLOBALS['TYPO3_REQUEST']
+            ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE);
         $configurationType = ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK;
         $configurationManagerInterfaceMock = $this->createMock(ConfigurationManagerInterface::class);
         $configurationManagerInterfaceMock
@@ -215,6 +223,9 @@ final class LocalizationUtilityTest extends FunctionalTestCase
      */
     public function translateWillReturnLabelsFromTsEvenIfNoXlfFileExists(): void
     {
+        $GLOBALS['TYPO3_REQUEST'] = new ServerRequest();
+        $GLOBALS['TYPO3_REQUEST'] = $GLOBALS['TYPO3_REQUEST']
+            ->withAttribute('applicationType', SystemEnvironmentBuilder::REQUESTTYPE_FE);
         $typoScriptLocalLang = [
             '_LOCAL_LANG' => [
                 'da' => [
@@ -232,7 +243,7 @@ final class LocalizationUtilityTest extends FunctionalTestCase
             ->willReturn($typoScriptLocalLang);
         GeneralUtility::setSingletonInstance(ConfigurationManagerInterface::class, $configurationManagerInterfaceMock);
 
-        $result = LocalizationUtility::translate('key1', 'core', languageKey: 'da');
+        $result = LocalizationUtility::translate('key1', 'core', [], 'da');
 
         self::assertSame('I am a new key and there is no xlf file', $result);
     }
diff --git a/typo3/sysext/fluid/Classes/ViewHelpers/TranslateViewHelper.php b/typo3/sysext/fluid/Classes/ViewHelpers/TranslateViewHelper.php
index 28096b7c840ed19d7b467dbf5d2d6be17bccabce..fba4f2c5248838d4b9fb2d126550fa489f9b0e80 100644
--- a/typo3/sysext/fluid/Classes/ViewHelpers/TranslateViewHelper.php
+++ b/typo3/sysext/fluid/Classes/ViewHelpers/TranslateViewHelper.php
@@ -18,10 +18,8 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Fluid\ViewHelpers;
 
 use Psr\Http\Message\ServerRequestInterface;
-use TYPO3\CMS\Core\Http\ApplicationType;
-use TYPO3\CMS\Core\Localization\LanguageService;
-use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
 use TYPO3\CMS\Core\Localization\Locale;
+use TYPO3\CMS\Core\Localization\Locales;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Extbase\Mvc\RequestInterface as ExtbaseRequestInterface;
 use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
@@ -123,7 +121,7 @@ final class TranslateViewHelper extends AbstractViewHelper
         $this->registerArgument('default', 'string', 'If the given locallang key could not be found, this value is used. If this argument is not set, child nodes will be used to render the default');
         $this->registerArgument('arguments', 'array', 'Arguments to be replaced in the resulting string');
         $this->registerArgument('extensionName', 'string', 'UpperCamelCased extension key (for example BlogExample)');
-        $this->registerArgument('languageKey', 'string', 'Language key ("da" for example) or "default" to use. If empty, use current language.');
+        $this->registerArgument('languageKey', 'string', 'Language key ("da" for example) or "default" to use. Also a Locale object is possible. If empty, use current locale from the request.');
     }
 
     /**
@@ -155,71 +153,58 @@ final class TranslateViewHelper extends AbstractViewHelper
             $request = $renderingContext->getRequest();
         }
 
-        if (!$request instanceof ExtbaseRequestInterface) {
-            // Straight resolving via core LanguageService in non-extbase context
-            if (!str_starts_with($id, 'LLL:EXT:')) {
-                // Resolve "short key" without LLL:EXT: syntax given, if an extension name is given.
-                // @todo: We could consider to deprecate this case. It is mostly implemented for a more
-                //        smooth transition when (backend) controllers no longer feed an extbase request.
-                if (!empty($extensionName)) {
-                    $id = 'LLL:EXT:' . GeneralUtility::camelCaseToLowerCaseUnderscored($extensionName) . '/Resources/Private/Language/locallang.xlf:' . $id;
-                } elseif (empty($default)) {
-                    // Throw exception in case neither an extension key nor a default value
-                    // are given, since the "short key" shouldn't be considered as a label.
-                    throw new \RuntimeException(
-                        'ViewHelper f:translate in non-extbase context needs attribute "extensionName" to resolve'
-                        . ' key="' . $id . '" without path. Either set attribute "extensionName" together with the short'
-                        . ' key "yourKey" to result in a lookup "LLL:EXT:your_extension/Resources/Private/Language/locallang.xlf:yourKey",'
-                        . ' or (better) use a full LLL reference like key="LLL:EXT:your_extension/Resources/Private/Language/yourFile.xlf:yourKey".'
-                        . ' Alternatively, you can also define a default value.',
-                        1639828178
-                    );
-                }
+        if (empty($extensionName)) {
+            if ($request instanceof ExtbaseRequestInterface) {
+                $extensionName = $request->getControllerExtensionName();
+            } elseif (str_starts_with($id, 'LLL:EXT:')) {
+                $extensionName = substr($id, 8, strpos($id, '/', 8) - 8);
+            } elseif ($default) {
+                return self::handleDefaultValue($default, $translateArguments);
+            } else {
+                // Throw exception in case neither an extension key nor a extbase request
+                // are given, since the "short key" shouldn't be considered as a label.
+                throw new \RuntimeException(
+                    'ViewHelper f:translate in non-extbase context needs attribute "extensionName" to resolve'
+                    . ' key="' . $id . '" without path. Either set attribute "extensionName" together with the short'
+                    . ' key "yourKey" to result in a lookup "LLL:EXT:your_extension/Resources/Private/Language/locallang.xlf:yourKey",'
+                    . ' or (better) use a full LLL reference like key="LLL:EXT:your_extension/Resources/Private/Language/yourFile.xlf:yourKey".'
+                    . ' Alternatively, you can also define a default value.',
+                    1639828178
+                );
             }
-            $value = self::getLanguageService($request, $arguments['languageKey'])->sL($id);
-            if (empty($value) || (!str_starts_with($id, 'LLL:EXT:') && $value === $id)) {
-                // In case $value is empty (LLL: could not be resolved) or $value
-                // is the same as $id and is no "LLL:", fall back to the default.
-                $value = $default;
-            }
-            if (!empty($translateArguments)) {
-                $value = vsprintf($value, $translateArguments);
-            }
-            return $value;
         }
-
-        /** @var ExtbaseRequestInterface $request */
-        $extensionName = $extensionName ?? $request->getControllerExtensionName();
         try {
-            // Trigger full extbase magic: "<f:translate key="key1" />" will look up
-            // "LLL:EXT:current_extension/Resources/Private/Language/locallang.xlf:key1" AND
-            // overloads from _LOCAL_LANG extbase TypoScript settings if specified.
-            // Not this triggers TypoScript parsing via extbase ConfigurationManager
-            // and should be avoided in backend context!
-            $value = LocalizationUtility::translate($id, $extensionName, $translateArguments, $arguments['languageKey']);
+            $locale = self::getUsedLocale($arguments['languageKey'], $request);
+            $value = LocalizationUtility::translate($id, $extensionName, $translateArguments, $locale);
         } catch (\InvalidArgumentException) {
             // @todo: Switch to more specific Exceptions here - for instance those thrown when a package was not found, see #95957
             $value = null;
         }
         if ($value === null) {
-            $value = $default;
-            if (!empty($translateArguments)) {
-                $value = vsprintf($value, $translateArguments);
-            }
+            return self::handleDefaultValue($default, $translateArguments);
         }
         return $value;
     }
 
-    protected static function getLanguageService(ServerRequestInterface $request = null, string|Locale $languageKey = null): LanguageService
+    /**
+     * Ensure that a string is returned, if the underlying logic returns null, or cannot handle a translation
+     */
+    protected static function handleDefaultValue(string $default, ?array $translateArguments): string
+    {
+        if (!empty($translateArguments)) {
+            return vsprintf($default, $translateArguments);
+        }
+        return $default;
+    }
+
+    protected static function getUsedLocale(Locale|string|null $languageKey, ?ServerRequestInterface $request): Locale|string|null
     {
-        $languageServiceFactory = GeneralUtility::makeInstance(LanguageServiceFactory::class);
-        if ($languageKey) {
-            return $languageServiceFactory->create($languageKey);
+        if ($languageKey !== null && $languageKey !== '') {
+            return $languageKey;
         }
-        if ($request !== null && ApplicationType::fromRequest($request)->isFrontend()) {
-            return $languageServiceFactory->createFromSiteLanguage($request->getAttribute('language')
-                ?? $request->getAttribute('site')->getDefaultLanguage());
+        if ($request) {
+            return GeneralUtility::makeInstance(Locales::class)->createLocaleFromRequest($request);
         }
-        return $languageServiceFactory->createFromUserPreferences($GLOBALS['BE_USER'] ?? null);
+        return null;
     }
 }
diff --git a/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/Classes/Controller/TranslateController.php b/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/Classes/Controller/TranslateController.php
new file mode 100644
index 0000000000000000000000000000000000000000..127e766517767481a21772fbf0fbc5ac1560a56a
--- /dev/null
+++ b/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/Classes/Controller/TranslateController.php
@@ -0,0 +1,29 @@
+<?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 TYPO3Tests\TestTranslate\Controller;
+
+use Psr\Http\Message\ResponseInterface;
+use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
+
+class TranslateController extends ActionController
+{
+    public function translateAction(): ResponseInterface
+    {
+        return $this->htmlResponse($this->view->render());
+    }
+}
diff --git a/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/Configuration/Services.yaml b/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/Configuration/Services.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f0428618f6fed2738831dc2a7e0e6f868dbc76b6
--- /dev/null
+++ b/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/Configuration/Services.yaml
@@ -0,0 +1,8 @@
+services:
+  _defaults:
+    autowire: true
+    autoconfigure: true
+    public: false
+
+  TYPO3Tests\TestTranslate\:
+    resource: '../Classes/*'
diff --git a/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/Resources/Private/Templates/Translate.html b/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/Resources/Private/Templates/Translate.html
new file mode 100644
index 0000000000000000000000000000000000000000..c4b9dea991c5d90b9f234e9dbb4d02d9f89526be
--- /dev/null
+++ b/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/Resources/Private/Templates/Translate.html
@@ -0,0 +1,8 @@
+<html
+    xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
+    data-namespace-typo3-fluid="true"
+>
+
+<f:translate key="localized.to.de" />
+
+</html>
diff --git a/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/composer.json b/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/composer.json
index 49b7b149054412ad1957faaa98822542348658df..d856e6037424da7964071bfed060873930670bcd 100644
--- a/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/composer.json
+++ b/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/composer.json
@@ -6,6 +6,11 @@
 	"require": {
 		"typo3/cms-core": "13.0.*@dev"
 	},
+	"autoload": {
+		"psr-4": {
+			"TYPO3Tests\\TestTranslate\\": "Classes"
+		}
+	},
 	"extra": {
 		"typo3/cms": {
 			"extension-key": "test_translate"
diff --git a/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/ext_localconf.php b/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/ext_localconf.php
new file mode 100644
index 0000000000000000000000000000000000000000..7f4f1c4a37ecd3c262c94e10d96db2085db23b8f
--- /dev/null
+++ b/typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate/ext_localconf.php
@@ -0,0 +1,18 @@
+<?php
+
+declare(strict_types=1);
+
+use TYPO3\CMS\Extbase\Utility\ExtensionUtility;
+use TYPO3Tests\TestTranslate\Controller\TranslateController;
+
+defined('TYPO3') or die();
+
+ExtensionUtility::configurePlugin(
+    'TestTranslate',
+    'Test',
+    [
+        TranslateController::class => 'translate',
+    ],
+    [
+    ]
+);
diff --git a/typo3/sysext/fluid/Tests/Functional/Fixtures/pages.csv b/typo3/sysext/fluid/Tests/Functional/Fixtures/pages.csv
index 1670bd5d6f25401fe53fefb4311116929fdfe1c1..6598db095cd9aa0abd5e5f6b53ba2f0bebc37be0 100644
--- a/typo3/sysext/fluid/Tests/Functional/Fixtures/pages.csv
+++ b/typo3/sysext/fluid/Tests/Functional/Fixtures/pages.csv
@@ -1,9 +1,10 @@
-"pages",,,,,,,
-,"uid","pid","title","sorting","deleted","perms_everybody","slug"
-,1,0,"Root",128,0,15,"/"
-,2,1,"Dummy 1-2",128,0,15,"/dummy-1-2"
-,3,2,"Dummy 1-2-3",128,0,15,"/dummy-1-2/dummy-1-2-3"
-,4,3,"Dummy 1-2-3-4",128,0,15,"/dummy-1-2/dummy-1-2-3/dummy-1-2-3-4"
-,5,1,"Dummy 1-5",128,0,15,"/dummy-1-5"
-,6,5,"Dummy 1-5-6",128,0,15,"/dummy-1-5/dummy-1-5-6"
-,7,0,"Root 2",128,0,15,"/"
+"pages"
+,"uid","pid","title","sorting","deleted","sys_language_uid","l10n_parent","perms_everybody","slug"
+,1,0,"Root",128,0,0,0,15,"/"
+,2,1,"Dummy 1-2",128,0,0,0,15,"/dummy-1-2"
+,3,2,"Dummy 1-2-3",128,0,0,0,15,"/dummy-1-2/dummy-1-2-3"
+,4,3,"Dummy 1-2-3-4",128,0,0,0,15,"/dummy-1-2/dummy-1-2-3/dummy-1-2-3-4"
+,5,1,"Dummy 1-5",256,0,0,15,0,"/dummy-1-5"
+,6,5,"Dummy 1-5-6",128,0,0,0,15,"/dummy-1-5/dummy-1-5-6"
+,7,0,"Root 2",128,0,0,0,15,"/"
+,8,1,"Dummy 1-2 DE",129,0,1,2,15,"/de/dummy-1-2"
diff --git a/typo3/sysext/fluid/Tests/Functional/ViewHelpers/TranslateViewHelperTest.php b/typo3/sysext/fluid/Tests/Functional/ViewHelpers/TranslateViewHelperTest.php
index 9ebde00602920b15dee086007821ef3ef8b6df3d..3b9aee7fbe729ce21d23f82fd7e776aa5b1c2601 100644
--- a/typo3/sysext/fluid/Tests/Functional/ViewHelpers/TranslateViewHelperTest.php
+++ b/typo3/sysext/fluid/Tests/Functional/ViewHelpers/TranslateViewHelperTest.php
@@ -18,19 +18,29 @@ declare(strict_types=1);
 namespace TYPO3\CMS\Fluid\Tests\Functional\ViewHelpers;
 
 use TYPO3\CMS\Core\Core\SystemEnvironmentBuilder;
+use TYPO3\CMS\Core\Database\ConnectionPool;
 use TYPO3\CMS\Core\Http\ServerRequest;
 use TYPO3\CMS\Core\Http\Uri;
 use TYPO3\CMS\Core\Localization\Locales;
 use TYPO3\CMS\Core\Site\Entity\SiteLanguage;
+use TYPO3\CMS\Core\Tests\Functional\SiteHandling\SiteBasedTestTrait;
 use TYPO3\CMS\Extbase\Mvc\ExtbaseRequestParameters;
 use TYPO3\CMS\Extbase\Mvc\Request;
 use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextFactory;
+use TYPO3\TestingFramework\Core\Functional\Framework\Frontend\InternalRequest;
 use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
 use TYPO3Fluid\Fluid\Core\ViewHelper\Exception;
 use TYPO3Fluid\Fluid\View\TemplateView;
 
 final class TranslateViewHelperTest extends FunctionalTestCase
 {
+    use SiteBasedTestTrait;
+
+    protected const LANGUAGE_PRESETS = [
+        'EN' => ['id' => 0, 'title' => 'English', 'locale' => 'en_US.UTF8'],
+        'DE' => ['id' => 1, 'title' => 'Deutsch', 'locale' => 'de_DE.UTF8'],
+    ];
+
     protected array $testExtensionsToLoad = [
         'typo3/sysext/fluid/Tests/Functional/Fixtures/Extensions/test_translate',
     ];
@@ -418,4 +428,66 @@ final class TranslateViewHelperTest extends FunctionalTestCase
         $templateView->assign('myLocale', (new Locales())->createLocale('de_at'));
         self::assertSame('DE_AT label', $templateView->render());
     }
+
+    /**
+     * @test
+     */
+    public function renderInExtbaseFrontendContextHandlesLabelOverrideWithTypoScriptInDefaultLanguage(): void
+    {
+        $this->importCSVDataSet(__DIR__ . '/../Fixtures/pages.csv');
+        $this->writeSiteConfiguration(
+            'test',
+            $this->buildSiteConfiguration(1, '/'),
+        );
+        (new ConnectionPool())->getConnectionForTable('sys_template')->insert('sys_template', [
+            'pid' => 1,
+            'root' => 1,
+            'clear' => 1,
+            'config' => <<<EOT
+page = PAGE
+page.10 = EXTBASEPLUGIN
+page.10 {
+    extensionName = TestTranslate
+    pluginName = Test
+}
+plugin.tx_testtranslate_test._LOCAL_LANG.default.localized\.to\.de = TypoScript default label
+EOT
+        ]);
+        $response = $this->executeFrontendSubRequest((new InternalRequest())->withPageId(2));
+        self::assertStringContainsString('TypoScript default label', (string)$response->getBody());
+
+    }
+
+    /**
+     * @test
+     */
+    public function renderInExtbaseFrontendContextHandlesLabelOverrideWithTypoScriptInLocalizedPage(): void
+    {
+        $this->importCSVDataSet(__DIR__ . '/../Fixtures/pages.csv');
+        $this->writeSiteConfiguration(
+            'test',
+            $this->buildSiteConfiguration(1, '/'),
+            [
+                $this->buildDefaultLanguageConfiguration('EN', '/'),
+                $this->buildLanguageConfiguration('DE', '/de/', ['EN']),
+            ]
+        );
+        (new ConnectionPool())->getConnectionForTable('sys_template')->insert('sys_template', [
+            'pid' => 1,
+            'root' => 1,
+            'clear' => 1,
+            'config' => <<<EOT
+page = PAGE
+page.10 = EXTBASEPLUGIN
+page.10 {
+    extensionName = TestTranslate
+    pluginName = Test
+}
+plugin.tx_testtranslate_test._LOCAL_LANG.de-DE.localized\.to\.de = TypoScript de label
+EOT
+        ]);
+        $response = $this->executeFrontendSubRequest((new InternalRequest())->withPageId(2)->withLanguageId(1));
+        self::assertStringContainsString('TypoScript de label', (string)$response->getBody());
+
+    }
 }