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:

EXT:my_extension/Classes/UserFunction/MyUserFunction.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 LanguageServiceFactory $languageServiceFactory;

    public function __construct(LanguageServiceFactory $languageServiceFactory) {
        $this->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 {
        return $this->getLanguageService($request)->getLL(
            'LLL:EXT:my_extension/Resources/Private/Language/locallang.xlf:something.'
        );
    }
}
Copied!

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.

EXT:my_extension/Classes/Backend/MyBackendClass.php
<?php
declare(strict_types=1);

namespace MyVendor\MyExtension\Backend;

use TYPO3\CMS\Core\Localization\LanguageService;

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

    private function getLanguageService(): LanguageService
    {
        return $GLOBALS['LANG'];
    }

    // ...
}
Copied!

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
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);
    }
}
Copied!

Localization in Extbase

In Extbase context you can use the method \TYPO3\CMS\Extbase\Utility\LocalizationUtility::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:

Class T3docsExamplesControllerModuleController
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');
    }
}
Copied!

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>
Copied!

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.