Adding extractors

The extractor library is very SOLID which means that you easily can add extractors without changing existing code. There are some concepts to be aware of

The Extractor object has a collection of FileExtractor that are executed on files with a file type they support. The PHPFileExtractor and TwigFileExtractor are using the visitor pattern. They have a collection of Translation\Extractor\Visitor that will be executed for each file the FileExtractor is running for. To add a custom extractor for a custom PHP class you may only add a visitor for the PHPFileExtractor.

Note

Read more about the architecture at the component description of Extractor.

Example

This is an example of how you would extract the “foobar” from the following PHP script:

$this->translateMe('google', 'foobar');

First you need to create your visitor. Since it is a PHP file we do not need to add another FileExtractor.

use PhpParser\Node;
use PhpParser\NodeVisitor;
use Translation\Extractor\Model\SourceLocation;
use Translation\Extractor\Visitor\Php\BasePHPVisitor;

class TranslateMeVisitor extends BasePHPVisitor implements NodeVisitor
{
    public function enterNode(Node $node)
    {
        if ($node instanceof Node\Expr\MethodCall) {
            if (!is_string($node->name)) {
                return;
            }
            $name = $node->name;

            if ('translateMe' === $name) {
                $label = $this->getStringArgument($node, 1);

                $source = new SourceLocation(
                    $label,
                    $this->getAbsoluteFilePath(),
                    $node->getAttribute('startLine'),
                    ['domain' => 'messages']
                );
                $this->collection->addLocation($source);
            }
        }
    }

    // ...
}

Note

Refer to the documentation of nikic/PHP-Parser for more examples of note types.

Tests

This will work, but we need tests. Each extractor must be properly tested. We use functional tests for each visitor. Add test resources with scripts that you will use to test your visitor. Reusing test resources should be avoided.

By using the BasePHPVisitorTest class you can easily write test will little or no overhead.

class TranslateMeVisitorTest extends BasePHPVisitorTest
{
    public function testExtract()
    {
        $collection = $this->getSourceLocations(new TranslateMeVisitor(), Resources\Php\Symfony\TranslateMeVisitor::class);

        $this->assertCount(1, $collection);
        $source = $collection->first();
        $this->assertEquals('foobar', $source->getMessage());
    }
}