symfony/translation · error · LogicException

Cannot parse message translation: please install the "intl"…

Error message

Cannot parse message translation: please install the "intl" PHP extension or the "symfony/polyfill-intl-messageformatter" package.

What it means

Thrown by IntlFormatter::formatIntl when the message uses ICU MessageFormat syntax but neither the intl PHP extension (MessageFormatter class) nor symfony/polyfill-intl-messageformatter is available. Without a MessageFormatter implementation, ICU-formatted messages cannot be parsed.

Solutions

  1. Install the intl PHP extension (`apk add php-intl` / `apt install php-intl` / enable extension=intl in php.ini)
  2. Or run `composer require symfony/polyfill-intl-messageformatter` as a pure-PHP fallback
  3. Align PHP extensions between dev and production images

Example fix

// before (Dockerfile)
FROM php:8.2-fpm
// after
FROM php:8.2-fpm
RUN docker-php-ext-install intl
Defensive patterns

Strategy: fallback

Validate before calling

if (!class_exists(\MessageFormatter::class) && !extension_loaded('intl')) { // install ext-intl or symfony/polyfill-intl-messageformatter before serving ICU messages }

Type guard

function intlMessageFormattingAvailable(): bool { return class_exists(\MessageFormatter::class); }

Try / catch

try { $msg = $translator->trans($id, $params, $domain, $locale); } catch (LogicException $e) { if (str_contains($e->getMessage(), 'intl')) { $msg = $this->fallbackSimpleTrans($id, $params); } else { throw $e; } }

Prevention

When it happens

Trigger: Calling $translator->trans() (via MessageFormatter/IntlFormatter) on a message containing ICU syntax (e.g. '{count, plural, ...}') in a PHP build compiled without intl and without the polyfill installed.

Common situations: Deploying to a PHP environment (alpine/minimal Docker, some shared hosts) without ext-intl while local dev had it; production staging with different PHP images; translation files containing ICU plural/select messages.

Understand the failure class

Background: "X is not installed. Please install it with pip install Y": missing optional dependency errors — ImportError/ValueError raised when a library's optional extra was never installed — this error's family across 22 libraries.

Related errors


AI-assisted analysis of symfony/translation@ae9e8a51bc (2026-09-15). Data as JSON: /api/errors/c8238ebb892665f8. Report an issue: GitHub.

Appendix: source

Thrown at Formatter/IntlFormatter.php:35

/**
 * @author Guilherme Blanco <guilhermeblanco@hotmail.com>
 * @author Abdellatif Ait boudad <a.aitboudad@gmail.com>
 */
class IntlFormatter implements IntlFormatterInterface
{
    private bool $hasMessageFormatter;
    private array $cache = [];

    public function formatIntl(string $message, string $locale, array $parameters = []): string
    {
        // MessageFormatter constructor throws an exception if the message is empty
        if ('' === $message) {
            return '';
        }

        if (!$formatter = $this->cache[$locale][$message] ?? null) {
            if (!$this->hasMessageFormatter ??= class_exists(\MessageFormatter::class)) {
                throw new LogicException('Cannot parse message translation: please install the "intl" PHP extension or the "symfony/polyfill-intl-messageformatter" package.');
            }
            try {
                $this->cache[$locale][$message] = $formatter = new \MessageFormatter($locale, $message);
            } catch (\IntlException $e) {
                throw new InvalidArgumentException(\sprintf('Invalid message format (error #%d): ', intl_get_error_code()).intl_get_error_message(), 0, $e);
            }
        }

        foreach ($parameters as $key => $value) {
            if (\in_array($key[0] ?? null, ['%', '{'], true)) {
                unset($parameters[$key]);
                $parameters[trim($key, '%{ }')] = $value;
            }
        }

        if (false === $message = $formatter->format($parameters)) {
            throw new InvalidArgumentException(\sprintf('Unable to format message (error #%s): ', $formatter->getErrorCode()).$formatter->getErrorMessage());
        }

View on GitHub (pinned to ae9e8a51bc)