Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/TranslationSourceLocationContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/*
* This file is part of the PHP Translation package.
*
* (c) PHP Translation team <tobias.nyholm@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Translation\Extractor;

use Translation\Extractor\Model\SourceLocation;

/**
* This interface is recognized by the extractors. Use this on your Form classes
* or anywhere where you have dynamic translation strings.
*
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
interface TranslationSourceLocationContainer
{
/**
* Return an array of source locations.
*
* @return SourceLocation[]
*/
public static function getTranslationSourceLocations();
}
100 changes: 100 additions & 0 deletions src/Visitor/Php/SourceLocationContainerExtractor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

/*
* This file is part of the PHP Translation package.
*
* (c) PHP Translation team <tobias.nyholm@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Translation\Extractor\Visitor\Php;

use PhpParser\Node;
use PhpParser\NodeVisitor;
use Translation\Extractor\Model\SourceLocation;

/**
* Extract translations from classes implementing
* Translation\Extractor\Model\SourceLocation\TranslationSourceLocationContainer.
*
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
*/
class SourceLocationContainerExtractor extends BasePHPVisitor implements NodeVisitor
{
/**
* @var string
*/
private $namespace = '';

/**
* @var array
*/
private $useStatements = [];

public function beforeTraverse(array $nodes)
{
}

public function enterNode(Node $node)
{
if ($node instanceof Node\Stmt\Namespace_) {
if (isset($node->name)) {
// Save namespace of this class for later.
$this->namespace = implode('\\', $node->name->parts);
}
$this->useStatements = [];

return;
}

if ($node instanceof Node\Stmt\UseUse) {
$this->useStatements[$node->alias] = implode('\\', $node->name->parts);

return;
}

if (!$node instanceof Node\Stmt\Class_) {
return;
}

$isContainer = false;
foreach ($node->implements as $interface) {
$name = implode('\\', $interface->parts);
if (isset($this->useStatements[$name])) {
$name = $this->useStatements[$name];
}

if ('Translation\Extractor\TranslationSourceLocationContainer' === $name) {
$isContainer = true;
break;
}
}

if (!$isContainer) {
return;
}

$sourceLocations = call_user_func([$this->namespace.'\\'.$node->name, 'getTranslationSourceLocations']);
if (!is_array($sourceLocations)) {
throw new \RuntimeException(sprintf('%s::getTranslationSourceLocations() was expected to return an array of SourceLocations, but got %s.', $this->namespace.'\\'.$node->name, gettype($sourceLocations)));
}

foreach ($sourceLocations as $sourceLocation) {
if (!$sourceLocation instanceof SourceLocation) {
throw new \RuntimeException(sprintf('%s::getTranslationSourceLocations() was expected to return an array of SourceLocations, but got an array which contains an item of type %s.', $this->namespace.'\\'.$node->name, gettype($sourceLocation)));
}

$this->collection->addLocation($sourceLocation);
}
}

public function leaveNode(Node $node)
{
}

public function afterTraverse(array $nodes)
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the PHP Translation package.
*
* (c) PHP Translation team <tobias.nyholm@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Translation\Extractor\Tests\Functional\Visitor\Php;

use Translation\Extractor\Visitor\Php\SourceLocationContainerExtractor;
use Translation\Extractor\Tests\Resources;

class SourceLocationContainerExtractorTest extends BasePHPVisitorTest
{
public function testExtract()
{
$collection = $this->getSourceLocations(new SourceLocationContainerExtractor(), Resources\Php\SourceLocationContainer::class);

$this->assertCount(2, $collection);
$source = $collection->first();
$this->assertEquals('foo', $source->getMessage());
}
}
17 changes: 17 additions & 0 deletions tests/Resources/Php/SourceLocationContainer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Translation\Extractor\Tests\Resources\Php;

use Translation\Extractor\Model\SourceLocation;
use Translation\Extractor\TranslationSourceLocationContainer;

class SourceLocationContainer implements TranslationSourceLocationContainer
{
public static function getTranslationSourceLocations()
{
return [
SourceLocation::createHere('foo'),
SourceLocation::createHere('bar'),
];
}
}