---
title: "Localization in PHP"
manual: "TYPO3 Explained"
version: "12.4"
permalink: "https://docs.typo3.org/permalink/t3coreapi:extension-localization-php@12.4"
source: "ExtensionArchitecture/HowTo/Localization/Php.rst"
rendered: "2026-10-21T15:29:37+00:00"
---

> [!WARNING]
> **Attention**
>
> TYPO3 v12 has reached end-of-life as of April 30th 2026 and
> is no longer being maintained. Use the version switcher on the top
> left of this page to select documentation for a supported version of TYPO3.
>
> Need more time before upgrading?
> You can purchase Extended Long Term Support (ELTS) for TYPO3 v12 here:
> [TYPO3 ELTS](https://typo3.com/services/extended-support-elts).

# Localization in PHP {#extension-localization-php}

Sometimes you have to localize a string in PHP code, for
example inside of a controller or a user function.

Which method of localization to use depends on the current context:

-   [Localization in plain PHP](https://docs.typo3.org/permalink/t3coreapi:localization-in-plain-php@12.4)
-   [Localization in Extbase](https://docs.typo3.org/permalink/t3coreapi:localization-in-extbase@12.4)
-   [Examples](https://docs.typo3.org/permalink/t3coreapi:examples@12.4)

## Localization in plain PHP {#localization-in-plain-php}

### Localization in frontend context {#localization-in-frontend-context}

In plain PHP use the class [LanguageServiceFactory](https://docs.typo3.org/permalink/t3coreapi:languageservicefactory-api@12.4)
to create a [LanguageService](https://docs.typo3.org/permalink/t3coreapi:languageservice-api@12.4) from the current
site language:

**EXT:my_extension/Classes/UserFunction/MyUserFunction.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Backend;

use Psr\Http\Message\ServerRequestInterface;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;

final class MyUserFunction
{
    private LanguageService $languageService;

    public function __construct(
        private readonly LanguageServiceFactory $languageServiceFactory,
    ) {}

    private function getLanguageService(
        ServerRequestInterface $request,
    ): LanguageService {
        return $this->languageServiceFactory->createFromSiteLanguage(
            $request->getAttribute('language')
            ?? $request->getAttribute('site')->getDefaultLanguage(),
        );
    }

    public function main(
        string $content,
        array $conf,
        ServerRequestInterface $request,
    ): string {
        $this->languageService = $this->getLanguageService($request);
        return $this->languageService->sL(
            'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:something',
        );
    }
}

```

[Dependency injection](https://docs.typo3.org/permalink/t3coreapi:dependencyinjection@12.4) should be available in most contexts where you need
translations. Also the current request is available in entry point such as
custom non-Extbase controllers, user functions, data processors etc.

### Localization in backend context {#localization-in-backend-context}

In the backend context you should use the
[LanguageServiceFactory](https://docs.typo3.org/permalink/t3coreapi:languageservicefactory-api@12.4)
to create the required [LanguageService](https://docs.typo3.org/permalink/t3coreapi:languageservice-api@12.4).

**EXT:my_extension/Classes/Backend/MyBackendClass.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Backend;

use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;

final class MyBackendClass
{
    public function __construct(
        private readonly LanguageServiceFactory $languageServiceFactory,
    ) {}

    private function translateSomething(string $input): string
    {
        return $this->getLanguageService()->sL($input);
    }

    private function getLanguageService(): LanguageService
    {
        return $this->languageServiceFactory
            ->createFromUserPreferences($this->getBackendUserAuthentication());
    }

    private function getBackendUserAuthentication(): BackendUserAuthentication
    {
        return $GLOBALS['BE_USER'];
    }

    // ...
}

```

> [!WARNING]
> **Attention**
>
> During development you are usually logged into the backend. So the global
> variable `$GLOBALS['LANG']` might be available in the frontend. Once
> logged out it is usually not available. **Never** depend on
> `$GLOBALS['LANG']` in the frontend unless you know what you are doing.

### Localization without context {#localization-without-context}

If you should happen to be in a context where none of these are available,
for example a static function, you can still do translations:

**EXT:my_extension/Classes/Utility/MyUtility.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Utility;

use TYPO3\CMS\Core\Localization\LanguageServiceFactory;
use TYPO3\CMS\Core\Utility\GeneralUtility;

final class MyUtility
{
    private static function translateSomething(string $lll): string
    {
        $languageServiceFactory = GeneralUtility::makeInstance(
            LanguageServiceFactory::class,
        );
        // As we are in a static context we cannot get the current request in
        // another way this usually points to general flaws in your software-design
        $request = $GLOBALS['TYPO3_REQUEST'];
        $languageService = $languageServiceFactory->createFromSiteLanguage(
            $request->getAttribute('language')
            ?? $request->getAttribute('site')->getDefaultLanguage(),
        );
        return $languageService->sL($lll);
    }
}

```

## Localization in Extbase {#extension-localization-extbase}

In [Extbase](https://docs.typo3.org/permalink/t3coreapi:extbase@12.4) context you can use the method
[\\TYPO3\\CMS\\Extbase\\Utility\\LocalizationUtility::translate($key, $extensionName)](https://docs.typo3.org/permalink/t3coreapi:extbase-localization-utility-api@12.4).

This method requires the localization key as the first and the extension's
name as optional second parameter. For all available parameters
see [below](https://docs.typo3.org/permalink/t3coreapi:extbase-localization-utility-api@12.4). Then the corresponding
text in the current language will be loaded from this extension's
`locallang.xlf` file.

The method `translate()` takes translation overrides from TypoScript into
account. See [Changing localized terms using TypoScript](https://docs.typo3.org/permalink/t3coreapi:localization-typoscript-local-lang@12.4).

### Example {#example}

In this example the content of the flash message to be displayed in the backend
gets translated:

**Class T3docs\\Examples\\Controller\\ModuleController**

```php
use Psr\Http\Message\ResponseInterface;
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;

class ModuleController extends ActionController implements LoggerAwareInterface
{
    /**
     * Adds a count of entries to the flash message
     */
    public function countAction(string $tablename = 'pages'): ResponseInterface
    {
        $count = $this->tableInformationService->countRecords($tablename);

        $message = LocalizationUtility::translate(
            key: 'record_count_message',
            extensionName: 'examples',
            arguments: [$count, $tablename]
        );

        $this->addFlashMessage(
            messageBody: $message,
            messageTitle: 'Information',
            severity: ContextualFeedbackSeverity::INFO
        );
        return $this->redirect('flash');
    }
}
```

The string in the translation file is defined like this:

```xml
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<!-- EXT:examples/Resources/Private/Language/locallang.xlf -->
<xliff version="1.0">
    <file source-language="en" datatype="plaintext" original="messages" date="2013-03-09T18:44:59Z" product-name="examples">
        <header />
        <body>
            <trans-unit id="new_relation" xml:space="preserve">
                <source>Content element "%1$s" (uid: %2$d) has the following relations:</source>
            </trans-unit>
        </body>
    </file>
</xliff>

```

The `arguments` will be replaced in the localized strings by
the [PHP function sprintf](https://www.php.net/manual/en/function.sprintf.php).

This behaviour is the same like in a
[Fluid translate ViewHelper with arguments](https://docs.typo3.org/permalink/t3coreapi:extension-localization-fluid-arguments@12.4).

## Examples {#examples}

### Provide localized strings via JSON by a middleware {#example-localization-middleware}

In the following example we use the [language service API](https://docs.typo3.org/permalink/t3coreapi:languageservice-api@12.4)
to provide a list of localized season names. This list could then be loaded in
the frontend via Ajax.

You can finde the complete example on
[GitHub, EXT:examples, HaikuSeasonList](https://github.com/TYPO3-Documentation/t3docs-examples/blob/main/Classes/Middleware/HaikuSeasonList.php).

As we do not need a full frontend context with TypoScript the JSON is returned
by a [PSR-15 middleware](https://docs.typo3.org/permalink/t3coreapi:request-handling@12.4).

Beside other factories needed by our response, we inject the
[LanguageServiceFactory](https://docs.typo3.org/permalink/t3coreapi:languageservicefactory-api@12.4) with
[constructor dependency injection](https://docs.typo3.org/permalink/t3coreapi:constructor-injection@12.4).

**Class T3docs\\Examples\\Middleware\\HaikuSeasonList**

```php
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\StreamFactoryInterface;
use TYPO3\CMS\Core\Localization\LanguageServiceFactory;

/**
 * This middleware can be used to retrieve a list of seasons with their according translation.
 * To get the correct translation the URL must be within a base path defined in site
 * handling. Some examples:
 * "/en/haiku-season-list.json" for English translation (if /en is the configured base path)
 * "/de/haiku-season-list.json" for German translation (if /de is the configured base path)
 * If the base path is not available in the according site the default language will be used.
 */
final class HaikuSeasonList implements MiddlewareInterface
{
    public function __construct(
        private readonly LanguageServiceFactory $languageServiceFactory,
        private readonly ResponseFactoryInterface $responseFactory,
        private readonly StreamFactoryInterface $streamFactory
    ) {}
}
```

The main method `process()` is called with a
`\Psr\Http\Message\ServerRequestInterface` as argument that can be used to detect the
current language and is therefore passed on to the private method `getSeasons()` doing the
actual translation:

**Class T3docs\\Examples\\Middleware\\HaikuSeasonList**

```php
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

final class HaikuSeasonList implements MiddlewareInterface
{
    private const URL_SEGMENT = '/haiku-season-list.json';

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        if (!str_contains($request->getUri()->getPath(), self::URL_SEGMENT)) {
            return $handler->handle($request);
        }

        $seasons = json_encode($this->getSeasons($request), JSON_THROW_ON_ERROR);

        return $this->responseFactory->createResponse()
            ->withHeader('Content-Type', 'application/json')
            ->withBody($this->streamFactory->createStream($seasons));
    }
}
```

Now we can let the `\TYPO3\CMS\Core\Localization\LanguageServiceFactory` to
create a `\TYPO3\CMS\Core\Localization\LanguageService` from the request's
language, falling back to the default language of the site.

The `LanguageService` can then be queried for the localized strings:

**Class T3docs\\Examples\\Middleware\\HaikuSeasonList**

```php
use Psr\Http\Message\ServerRequestInterface;

final class HaikuSeasonList implements MiddlewareInterface
{
    private const SEASONS = ['spring', 'summer', 'autumn', 'winter', 'theFifthSeason'];
    private const TRANSLATION_PATH = 'LLL:EXT:examples/Resources/Private/Language/PluginHaiku/locallang.xlf:season.';

    private function getSeasons(ServerRequestInterface $request): array
    {
        $languageService = $this->languageServiceFactory->createFromSiteLanguage(
            $request->getAttribute('language') ?? $request->getAttribute('site')->getDefaultLanguage()
        );

        $translatedSeasons = [];
        foreach (self::SEASONS as $season) {
            $translatedSeasons[$season] = $languageService->sL(self::TRANSLATION_PATH . $season);
        }

        return $translatedSeasons;
    }
}
```
