Localization in 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

Localization in frontend context

In plain PHP use the class LanguageServiceFactory to create a LanguageService from the current site language:

<?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;

/**
 * File EXT:my_extension/Classes/UserFunction/MyUserFunction.php
 */
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->getLL(
            'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:something.'
        );
    }
}

Dependency injection 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

In the backend context you can use the global variable $GLOBALS['LANG'] which contains the LanguageService.

<?php
declare(strict_types=1);

namespace MyVendor\MyExtension\Backend;

/**
 * File EXT:my_extension/Classes/Backend/MyBackendClass.php
 */
final class MyBackendClass
{
    private function translateSomething(string $lll): string
    {
        return $GLOBALS['LANG']->sL($lll);
    }

    // ...
}

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

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:

<?php
declare(strict_types=1);

namespace MyVendor\MyExtension\Utility;

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

/**
 * File EXT:my_extension/Classes/Utility/MyUtility.php
 */
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

In Extbase context you can use the method TYPO3CMSExtbaseUtilityLocalizationUtility::translate($key, $extensionName).

This method requires the localization key as the first and the extension's name as optional second parameter. For all available parameters see below. 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.

Example

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

The string in the translation file is defined like this:

<?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.

This behaviour is the same like in a Fluid translate ViewHelper with arguments.