diff --git a/src/Symfony/Component/Translation/Extractor/PhpAstExtractor.php b/src/Symfony/Component/Translation/Extractor/PhpAstExtractor.php index 12d93295440d2..827ace0d5bc70 100644 --- a/src/Symfony/Component/Translation/Extractor/PhpAstExtractor.php +++ b/src/Symfony/Component/Translation/Extractor/PhpAstExtractor.php @@ -46,13 +46,20 @@ public function extract(iterable|string $resource, MessageCatalogue $catalogue): { foreach ($this->extractFiles($resource) as $file) { $traverser = new NodeTraverser(); + + $nodes = $this->parser->parse(file_get_contents($file)); + + // First run is needed to resolve namespaces in class methods/constants. + $traverser->addVisitor(new NodeVisitor\NameResolver()); + $traverser->traverse($nodes); + /** @var AbstractVisitor&NodeVisitor $visitor */ foreach ($this->visitors as $visitor) { $visitor->initialize($catalogue, $file, $this->prefix); $traverser->addVisitor($visitor); } - $nodes = $this->parser->parse(file_get_contents($file)); + // Second run is used for the custom visitors. $traverser->traverse($nodes); } } diff --git a/src/Symfony/Component/Translation/Extractor/Visitor/AbstractVisitor.php b/src/Symfony/Component/Translation/Extractor/Visitor/AbstractVisitor.php index ae0474ac5b54d..ef2c3f8709812 100644 --- a/src/Symfony/Component/Translation/Extractor/Visitor/AbstractVisitor.php +++ b/src/Symfony/Component/Translation/Extractor/Visitor/AbstractVisitor.php @@ -119,6 +119,16 @@ private function getStringValue(Node $node): ?string return $node->expr->value; } + if ($node instanceof Node\Expr\ClassConstFetch) { + try { + $reflection = new \ReflectionClass($node->class->toString()); + $constant = $reflection->getReflectionConstant($node->name->toString()); + if (false !== $constant && \is_string($constant->getValue())) { + return $constant->getValue(); + } + } catch (\ReflectionException) {} + } + return null; } } diff --git a/src/Symfony/Component/Translation/Tests/Extractor/PhpAstExtractorTest.php b/src/Symfony/Component/Translation/Tests/Extractor/PhpAstExtractorTest.php index 96a12bd216ca9..93a3023118828 100644 --- a/src/Symfony/Component/Translation/Tests/Extractor/PhpAstExtractorTest.php +++ b/src/Symfony/Component/Translation/Tests/Extractor/PhpAstExtractorTest.php @@ -20,6 +20,8 @@ final class PhpAstExtractorTest extends TestCase { + public const OTHER_DOMAIN = 'not_messages'; + /** * @dataProvider resourcesProvider */ @@ -124,6 +126,7 @@ public function testExtraction(iterable|string $resource) 'variable-assignation-inlined-with-named-arguments-in-trans-method' => 'prefixvariable-assignation-inlined-with-named-arguments-in-trans-method', 'mix-named-arguments-without-parameters' => 'prefixmix-named-arguments-without-parameters', 'mix-named-arguments-disordered' => 'prefixmix-named-arguments-disordered', + 'const-domain' => 'prefixconst-domain' ], 'validators' => [ 'message-in-constraint-attribute' => 'prefixmessage-in-constraint-attribute', diff --git a/src/Symfony/Component/Translation/Tests/fixtures/extractor-ast/translation.html.php b/src/Symfony/Component/Translation/Tests/fixtures/extractor-ast/translation.html.php index db27b303c5945..68d966bcdd38d 100644 --- a/src/Symfony/Component/Translation/Tests/fixtures/extractor-ast/translation.html.php +++ b/src/Symfony/Component/Translation/Tests/fixtures/extractor-ast/translation.html.php @@ -62,3 +62,8 @@ trans('mix-named-arguments-disordered', domain: 'not_messages', parameters: []); ?> trans(...); // should not fail ?> + +trans('const-domain', [], PhpAstExtractorTest::OTHER_DOMAIN); +?>