---
title: "Localization outside the frontend context"
manual: "TYPO3 Explained"
version: "main"
permalink: "https://docs.typo3.org/permalink/t3coreapi:extbase-localisation-no-frontend@main"
source: "ExtensionArchitecture/Extbase/Localization/NoFrontendContext.rst"
rendered: "2026-09-26T10:15:30+00:00"
---

# Localization outside the frontend context {#extbase-localisation-no-frontend}

When rendering a typical frontend request, TYPO3 resolves the active site and
language aspect before any Extbase code executes. However, backend modules, CLI
commands, and custom middleware operate outside this standard pipeline and
frequently lack a language context. This guide outlines how localization
behaves in non-frontend environments and how to explicitly manage languages in
your Extbase code.

> [!NOTE]
> For a broader look at establishing execution environments outside the
> frontend (such as configuring storage PIDs), see
> [Using Extbase outside a frontend request](https://docs.typo3.org/permalink/t3coreapi:extbase-no-frontend@main).

## Understanding the default behavior {#extbase-localisation-no-frontend-default}

If no language context is explicitly provided, Extbase queries the Context API
and falls back to a default fallback state:

-   **Fallback Target:** An initialized
    `\TYPO3\CMS\Core\Context\LanguageAspect` with an ID of 0.
-   **Overlay Mode:** OVERLAYS_ON_WITH_FLOATING.

**The Impact:** Your backend modules or CLI commands will behave as if they are
executing against a site configured with `fallbackType: strict` in the default
language. **Only default language records will be returned.**

While acceptable for simple tasks, this default behavior breaks features like
CLI commands that send localized email alerts, generate localized reports, or
export multi-language datasets.

## Setting the language explicitly {#extbase-localisation-no-frontend-explicit}

To query records in a specific locale, you must manually pass the language
aspect to your query settings.

The following CLI command demonstrates how to fetch a frontend user's preferred
language from their record, resolve it against the site configuration, and
query the repository using that specific context. The command sends a reminder
about upcoming conferences to all frontend users, in the language stored on
their user record.

**EXT:my_extension/Classes/Command/ConferenceReminderCommand.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Command;

use MyVendor\MyExtension\Domain\Repository\ConferenceRepository;
use MyVendor\MyExtension\Domain\Repository\FrontendUserRepository;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use TYPO3\CMS\Core\Context\LanguageAspectFactory;
use TYPO3\CMS\Core\Site\SiteFinder;

#[AsCommand(
  name: 'myextension:conferencereminder',
  description: 'Mail all frontend users a reminder in their own language',
)]
class ConferenceReminderCommand extends Command
{
  public function __construct(
    protected readonly ConferenceRepository $conferenceRepository,
    protected readonly FrontendUserRepository $frontendUserRepository,
    protected readonly SiteFinder $siteFinder,
  ) {
    parent::__construct();
  }

  protected function execute(
    InputInterface $input,
    OutputInterface $output,
  ): int {
    // There is no site in a command, so the site the mails belong to has
    // to be named explicitly.
    $site = $this->siteFinder->getSiteByIdentifier('my-site');

    foreach ($this->frontendUserRepository->findAll() as $user) {
      // for sake of this example the user record provides a chosen language
      // in line with the site configuration
      $siteLanguage = $site->getLanguageById($user->getLanguageId());

      // The language's own configuration, exactly as the frontend of
      // this site would apply it.
      $languageAspect = LanguageAspectFactory::createFromSiteLanguage(
        $siteLanguage,
      );

      $conferences = $this->conferenceRepository
          ->findAllForLanguageAspect($languageAspect);

      // Send the mail, using $conferences and $siteLanguage->getLocale()
    }

    return Command::SUCCESS;
  }
}

```

Because this method relies on `findAllForLanguageAspect()`, the exact same
repository logic remains reusable across both the frontend (where the aspect is
provided natively) and CLI commands (where you supply it manually). See also
[Deciding the language per query](https://docs.typo3.org/permalink/t3coreapi:extbase-localisation-query-settings@main).

> [!TIP]
> **UI Text vs. Database Records:** Query settings only affect data records.
> If you need to translate email subject lines or template text strings
> (labels) in your command, use the Core Language Service instead. See
> [Translating labels in PHP](https://docs.typo3.org/permalink/t3coreapi:extension-localization-php@main).

## Backend modules {#extbase-localisation-no-frontend-backend}

How you manage localization in backend modules depends entirely on whether your
module interacts with the page tree.

### Global modules (no page tree) {#extbase-localisation-no-frontend-backend-without-page}

Modules that manage global records independently of specific pages (for
example, global settings, system reports, or job queues) do not have a page
and so do not have a site configuration to take a `fallbackType` from. They
default to the primary language aspect. You must explicitly specify target
languages in your query settings.

### Page-bound modules (with page tree) {#extbase-localisation-no-frontend-backend-with-page}

If your module utilizes the backend page tree navigation component, TYPO3 knows
exactly which page the editor is viewing. Because pages map directly to sites,
you can automatically inherit the site's full localization rules—including
the site's languages, language titles for the language selector, and fallback
types.

To match the exact translation behavior your visitors see on the live frontend,
resolve the site language from the active page and generate the aspect using
the factory. Then hand the aspect to `findAllForLanguageAspect()` (see
[Setting a language aspect](https://docs.typo3.org/permalink/t3coreapi:extbase-localisation-query-settings-aspect@main))
to add it to the query settings and execute the query.

**EXT:my_extension/Classes/Controller/ConferenceModuleController.php**

```php
<?php

namespace MyVendor\MyExtension\Controller;

use MyVendor\MyExtension\Domain\Repository\ConferenceRepository;
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
use TYPO3\CMS\Core\Context\LanguageAspectFactory;
use TYPO3\CMS\Core\Site\SiteFinder;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;

class ConferenceModuleController extends ActionController
{
  public function __construct(
    protected readonly ModuleTemplateFactory $moduleTemplateFactory,
    protected readonly ConferenceRepository $conferenceRepository,
    protected readonly SiteFinder $siteFinder,
  ) {}

  public function indexAction(
    int $pageUid = 0,
    int $languageId = 0,
  ): ResponseInterface {
    // The page selected in the page tree determines the site, and with it
    // the available languages and their fallback configuration.
    $site = $this->siteFinder->getSiteByPageId($pageUid);
    $siteLanguage = $site->getLanguageById($languageId);

    // The same aspect the frontend would use for this site language.
    $languageAspect = LanguageAspectFactory::createFromSiteLanguage(
      $siteLanguage,
    );

    $moduleTemplate = $this->moduleTemplateFactory->create($this->request);
    $moduleTemplate->assign('languages', $site->getLanguages());
    $moduleTemplate->assign('selectedLanguage', $siteLanguage);
    $moduleTemplate->assign(
      'conferences',
      $this->conferenceRepository->findAllForLanguageAspect($languageAspect),
    );

    return $moduleTemplate->renderResponse('Conference/Index');
  }
}

```

Using `LanguageAspectFactory::createFromSiteLanguage()` ensures your
backend module's data listings stay perfectly synchronized with the frontend
site configuration.

> [!NOTE]
> **See also**
>
> -   [Extbase in backend modules](https://docs.typo3.org/permalink/t3coreapi:extbase-no-frontend-backend-module@main)
>     for more general information on using Extbase in backend modules.
> -   [Resolving the storagePid in a backend module](https://docs.typo3.org/permalink/t3coreapi:extbase-persistence-storagepid-backend@main) describes where backend
>     modules look for records, which is also resolved differently without a
>     site.

## How relations are handled {#extbase-localisation-no-frontend-relations}

Relational fields follow the exact same translation mapping rules used
throughout TYPO3. They are automatically resolved based on the specific
language aspect assigned to the parent query.

If you rely on the fallback environment (the default language aspect), any
relational child records fetched inside your commands will resolve to the
default language. If you explicitly fetch a parent record in a localized
language, its underlying relations will automatically match that localized
language context.
