Core

Localization Service Provider

Translator, locale resolver and file-based language loading services.

Responsibility

Registers FileTranslator, TranslatorInterface, LocaleResolver, LocaleResolverInterface, alias translator and alias locale.resolver. These services provide file-based translations, runtime locale override and locale resolution used by controllers, views, validation, pagination, upload and app messages.

Localization config

Application localization config lives in app/Config/Localization.php. It defines default/fallback locale, supported locales and localized URL settings used by routing URL strategy.

<?php

declare(strict_types=1);

use Lemonade\Framework\Support\Env;

return [
    'default_locale' => Env::string('APP_LOCALE', 'cs'),
    'fallback_locale' => Env::string('APP_FALLBACK_LOCALE', 'cs'),
    'supported_locales' => Env::list('APP_SUPPORTED_LOCALES', ['cs', 'en']),
    'url' => [
        'enabled' => Env::bool('APP_LOCALIZED_URLS_ENABLED', true),
        'include_default_locale' => Env::bool('APP_INCLUDE_DEFAULT_LOCALE_IN_URL', false),
        'localized_route_name_prefix' => Env::string('APP_LOCALIZED_ROUTE_PREFIX', 'localized.'),
        'locale_parameter' => Env::string('APP_LOCALE_URL_PARAMETER', 'locale'),
        'route_prefix' => Env::string('APP_LOCALE_ROUTE_PREFIX', '/{locale}'),
    ],
];

Language files

FileTranslator loads framework language files from framework/src/Language/{locale}/{group}.php and app files from app/Language/{locale}/{group}.php. App files overlay framework lines with the same keys.

// app/Language/en/messages.php
return [
    'welcome' => 'Welcome, {name}.',
    'saved' => 'Saved successfully.',
];

// framework/src/Language/en/validation.php
return [
    'required' => '{field} is required.',
    'valid_email' => '{field} must be a valid email.',
];

Translator usage

Inject TranslatorInterface in services. get() reads group.key; keys without a dot use group messages. Replacements use {name} placeholders.

use Lemonade\Framework\Localization\TranslatorInterface;

final class ExampleService
{
    public function __construct(
        private readonly TranslatorInterface $translator,
    ) {}

    public function message(): string
    {
        return $this->translator->get('validation.required', [
            'field' => 'email',
        ]);
    }
}

Locale runtime

TranslatorInterface::setLocale() sets a runtime locale override for the translator instance. LocaleResolverInterface::resolve() chooses runtime translator locale first, then localization.default_locale, then localization.fallback_locale; configured locales must be present in localization.supported_locales.

use Lemonade\Framework\Localization\LocaleResolverInterface;
use Lemonade\Framework\Localization\TranslatorInterface;

$translator = $container->get(TranslatorInterface::class);
$translator->setLocale('en');

$locale = $container->get(LocaleResolverInterface::class)->resolve();

Fallback behavior

get() tries the resolved locale first, then fallback locale. If the key is missing in both, it returns the raw key string. group() merges fallback group lines with resolved locale lines, and all() returns all discovered groups for the resolved locale.

Controller usage

Framework controllers expose the translator through $this->translator() and translation lookup through $this->trans(). Keep controller examples tied to translation keys, not hard-coded rendered copy.

$title = $this->translator()->get('messages.welcome', ['name' => 'Ada']);
$label = $this->trans('validation.required', ['field' => 'email']);

View usage

ViewHelpers exposes translations through $helpers->lang(), $helpers->langGroup(), $helpers->langAll() and $helpers->currentLocale(). Use e() when printing translated text into HTML.

<?= e($helpers->lang('messages.welcome', ['name' => 'Ada'])) ?>
<?= e($helpers->lang('validation.required', ['field' => 'email'])) ?>

Framework messages

Validation uses validation.* lines, pagination uses pagination.* lines and upload validators use upload.* lines through TranslatorInterface. Applications can add their own language groups under app/Language/{locale} and reference them with the same group.key syntax.

Localized routes

LocalizationServiceProvider does not register routes, but its LocaleResolverInterface and localization config are used by routing URL generation. UrlGenerator::localizedRoute() works with localized route settings from localization.url.*.