Description
When symfony/twig-bridge is installed alongside twig-cs-fixer-drupal, running twig-cs-fixer lint fails with:
Error: Tag "trans" is already registered.
Root Cause
DrupalConfig::getConfig() explicitly adds Drupal's TwigTransTokenParser (tag: trans) at line 30:
$config->addTokenParser(new TwigTransTokenParser());
However, StubbedEnvironment::__construct() in vincentlanglet/twig-cs-fixer calls handleOptionalDependencies() before processing custom token parsers. That method registers Symfony's TransTokenParser (also tag: trans) when symfony/twig-bridge is present:
if (class_exists(TransTokenParser::class)) {
$this->addTokenParser(new TransTokenParser());
}
Twig's StagingExtension::addTokenParser() throws a LogicException when a tag is registered twice — there's no override mechanism.
So the registration order is:
StubbedEnvironment::handleOptionalDependencies() → Symfony's TransTokenParser (trans) ✅
- Custom token parsers from config → Drupal's
TwigTransTokenParser (trans) ❌ throws
How to Reproduce
Install a project where symfony/twig-bridge is pulled in by another dependency (e.g. simplesamlphp/simplesamlphp), then run:
vendor/bin/twig-cs-fixer lint
With .twig-cs-fixer.php:
<?php
return \TwigCsFixerDrupal\DrupalConfig::getConfig();
Suggested Fix
DrupalConfig::getConfig() should check whether the trans tag will already be handled by StubbedEnvironment before adding the Drupal token parser. For example:
// Only add Drupal's TwigTransTokenParser if the Symfony Bridge one won't
// be auto-registered by StubbedEnvironment::handleOptionalDependencies().
if (!class_exists(\Symfony\Bridge\Twig\TokenParser\TransTokenParser::class)) {
$config->addTokenParser(new TwigTransTokenParser());
}
Workaround
Replicate DrupalConfig::getConfig() in .twig-cs-fixer.php without the TwigTransTokenParser line. For linting purposes, Symfony's TransTokenParser handles the {% trans %} syntax adequately.
Versions
lullabot/twig-cs-fixer-drupal: 2.3.0
vincentlanglet/twig-cs-fixer: 3.14.0
twig/twig: 3.x
symfony/twig-bridge: 6.4.x (required by simplesamlphp/simplesamlphp)
Description
When
symfony/twig-bridgeis installed alongsidetwig-cs-fixer-drupal, runningtwig-cs-fixer lintfails with:Root Cause
DrupalConfig::getConfig()explicitly adds Drupal'sTwigTransTokenParser(tag:trans) at line 30:However,
StubbedEnvironment::__construct()invincentlanglet/twig-cs-fixercallshandleOptionalDependencies()before processing custom token parsers. That method registers Symfony'sTransTokenParser(also tag:trans) whensymfony/twig-bridgeis present:Twig's
StagingExtension::addTokenParser()throws aLogicExceptionwhen a tag is registered twice — there's no override mechanism.So the registration order is:
StubbedEnvironment::handleOptionalDependencies()→ Symfony'sTransTokenParser(trans) ✅TwigTransTokenParser(trans) ❌ throwsHow to Reproduce
Install a project where
symfony/twig-bridgeis pulled in by another dependency (e.g.simplesamlphp/simplesamlphp), then run:With
.twig-cs-fixer.php:Suggested Fix
DrupalConfig::getConfig()should check whether thetranstag will already be handled byStubbedEnvironmentbefore adding the Drupal token parser. For example:Workaround
Replicate
DrupalConfig::getConfig()in.twig-cs-fixer.phpwithout theTwigTransTokenParserline. For linting purposes, Symfony'sTransTokenParserhandles the{% trans %}syntax adequately.Versions
lullabot/twig-cs-fixer-drupal: 2.3.0vincentlanglet/twig-cs-fixer: 3.14.0twig/twig: 3.xsymfony/twig-bridge: 6.4.x (required bysimplesamlphp/simplesamlphp)