/** * @param \Twig_NodeInterface $node * @param \Twig_Environment $env * @return \Twig_NodeInterface */ public function enterNode(\Twig_NodeInterface $node, \Twig_Environment $env) { $this->stack[] = $node; if ($node instanceof TransNode) { $id = $node->getNode('body')->getAttribute('data'); $domain = 'messages'; if (null !== ($domainNode = $node->getNode('domain'))) { $domain = $domainNode->getAttribute('value'); } $message = new Message($id, $domain); $message->addSource($this->fileSourceFactory->create($this->file, $node->getLine())); $this->catalogue->add($message); } elseif ($node instanceof \Twig_Node_Expression_Filter) { $name = $node->getNode('filter')->getAttribute('value'); if ('trans' === $name || 'transchoice' === $name) { $idNode = $node->getNode('node'); if (!$idNode instanceof \Twig_Node_Expression_Constant) { return $node; // FIXME: see below // throw new \RuntimeException(sprintf('Cannot infer translation id from node "%s". Please refactor to only translate constants.', get_class($idNode))); } $id = $idNode->getAttribute('value'); $index = 'trans' === $name ? 1 : 2; $domain = 'messages'; $arguments = $node->getNode('arguments'); if ($arguments->hasNode($index)) { $argument = $arguments->getNode($index); if (!$argument instanceof \Twig_Node_Expression_Constant) { return $node; // FIXME: Throw exception if there is some way for the user to turn this off // on a case-by-case basis, similar to @Ignore in PHP } $domain = $argument->getAttribute('value'); } $message = new Message($id, $domain); $message->addSource($this->fileSourceFactory->create($this->file, $node->getLine())); for ($i = count($this->stack) - 2; $i >= 0; $i -= 1) { if (!$this->stack[$i] instanceof \Twig_Node_Expression_Filter) { break; } $name = $this->stack[$i]->getNode('filter')->getAttribute('value'); if ('desc' === $name || 'meaning' === $name) { $arguments = $this->stack[$i]->getNode('arguments'); if (!$arguments->hasNode(0)) { throw new RuntimeException(sprintf('The "%s" filter requires exactly one argument, the description text.', $name)); } $text = $arguments->getNode(0); if (!$text instanceof \Twig_Node_Expression_Constant) { throw new RuntimeException(sprintf('The first argument of the "%s" filter must be a constant expression, such as a string.', $name)); } $message->{'set' . $name}($text->getAttribute('value')); } elseif ('trans' === $name) { break; } } $this->catalogue->add($message); } } return $node; }
/** * @param Node $node * @return void */ public function enterNode(Node $node) { if (!$node instanceof Node\Expr\MethodCall || !is_string($node->name) || !in_array(strtolower($node->name), array_map('strtolower', array_keys($this->methodsToExtractFrom)))) { $this->previousNode = $node; return; } $ignore = false; $desc = $meaning = null; if (null !== ($docComment = $this->getDocCommentForNode($node))) { if ($docComment instanceof Doc) { $docComment = $docComment->getText(); } foreach ($this->docParser->parse($docComment, 'file ' . $this->file . ' near line ' . $node->getLine()) as $annot) { if ($annot instanceof Ignore) { $ignore = true; } elseif ($annot instanceof Desc) { $desc = $annot->text; } elseif ($annot instanceof Meaning) { $meaning = $annot->text; } } } if (!$node->args[0]->value instanceof String_) { if ($ignore) { return; } $message = sprintf('Can only extract the translation id from a scalar string, but got "%s". Please refactor your code to make it extractable, or add the doc comment /** @Ignore */ to this code element (in %s on line %d).', get_class($node->args[0]->value), $this->file, $node->args[0]->value->getLine()); if ($this->logger) { $this->logger->error($message); return; } throw new RuntimeException($message); } $id = $node->args[0]->value->value; $index = $this->methodsToExtractFrom[strtolower($node->name)]; if (isset($node->args[$index])) { if (!$node->args[$index]->value instanceof String_) { if ($ignore) { return; } $message = sprintf('Can only extract the translation domain from a scalar string, but got "%s". Please refactor your code to make it extractable, or add the doc comment /** @Ignore */ to this code element (in %s on line %d).', get_class($node->args[0]->value), $this->file, $node->args[0]->value->getLine()); if ($this->logger) { $this->logger->error($message); return; } throw new RuntimeException($message); } $domain = $node->args[$index]->value->value; } else { $domain = 'messages'; } $message = new Message($id, $domain); $message->setDesc($desc); $message->setMeaning($meaning); $message->addSource($this->fileSourceFactory->create($this->file, $node->getLine())); $this->catalogue->add($message); }
/** * @param $item * @param null $domain */ private function parseItem($item, $domain = null) { // get doc comment $ignore = false; $desc = $meaning = $docComment = null; if ($item->key) { $docComment = $item->key->getDocComment(); } if (!$docComment) { $docComment = $item->value->getDocComment(); } $docComment = is_object($docComment) ? $docComment->getText() : null; if ($docComment) { if ($docComment instanceof Doc) { $docComment = $docComment->getText(); } foreach ($this->docParser->parse($docComment, 'file ' . $this->file . ' near line ' . $item->value->getLine()) as $annot) { if ($annot instanceof Ignore) { $ignore = true; } elseif ($annot instanceof Desc) { $desc = $annot->text; } elseif ($annot instanceof Meaning) { $meaning = $annot->text; } } } // check if the value is explicitly set to false => e.g. for FormField that should be rendered without label $ignore = $ignore || !$item->value instanceof Node\Scalar\String_ || $item->value->value == false; if (!$item->value instanceof Node\Scalar\String_ && !$item->value instanceof Node\Scalar\LNumber) { if ($ignore) { return; } $message = sprintf('Unable to extract translation id for form label/title/placeholder from non-string values, but got "%s" in %s on line %d. Please refactor your code to pass a string, or add "/** @Ignore */".', get_class($item->value), $this->file, $item->value->getLine()); if ($this->logger) { $this->logger->error($message); return; } throw new RuntimeException($message); } if ($domain === false) { // Don't translate when domain is `false` return; } $source = $this->fileSourceFactory->create($this->file, $item->value->getLine()); $id = $item->value->value; if (null === $domain) { $this->defaultDomainMessages[] = array('id' => $id, 'source' => $source, 'desc' => $desc, 'meaning' => $meaning); } else { $this->addToCatalogue($id, $source, $domain, $desc, $meaning); } }
/** * @param Node $node */ public function enterNode(Node $node) { if (!$node instanceof Node\Expr\New_ || !is_string($node->class) || strtolower($node->class) !== 'validationerror') { $this->previousNode = $node; return; } $ignore = false; $desc = $meaning = null; if (null !== ($docComment = $this->getDocCommentForNode($node))) { if ($docComment instanceof Doc) { $docComment = $docComment->getText(); } foreach ($this->docParser->parse($docComment, 'file ' . $this->file . ' near line ' . $node->getLine()) as $annot) { if ($annot instanceof Ignore) { $ignore = true; } elseif ($annot instanceof Desc) { $desc = $annot->text; } elseif ($annot instanceof Meaning) { $meaning = $annot->text; } } } if (!$node->args[0]->value instanceof String_) { if ($ignore) { return; } $message = sprintf('Can only extract the translation id from a scalar string, but got "%s". Please refactor your code to make it extractable, or add the doc comment /** @Ignore */ to this code element (in %s on line %d).', get_class($node->args[0]->value), $this->file, $node->args[0]->value->getLine()); if ($this->logger) { $this->logger->error($message); return; } throw new RuntimeException($message); } $message = new Message($node->args[0]->value->value, $this->defaultDomain); $message->setDesc($desc); $message->setMeaning($meaning); $message->addSource($this->fileSourceFactory->create($this->file, $node->getLine())); $this->catalogue->add($message); // plural if ($node->args[1]->value instanceof String_) { $message = new Message($node->args[1]->value->value, $this->defaultDomain); $message->setDesc($desc); $message->setMeaning($meaning); $message->addSource($this->fileSourceFactory->create($this->file, $node->getLine())); $this->catalogue->add($message); } }
public function testExtractWithSimpleTestFixtures() { $expected = array(); $basePath = __DIR__ . '/Fixture/SimpleTest/'; $fileSourceFactory = new FileSourceFactory('faux'); // Controller $message = new Message('controller.foo'); $message->addSource($fileSourceFactory->create(new \SplFileInfo($basePath . 'Controller/DefaultController.php'), 27)); $message->setDesc('Foo'); $expected['controller.foo'] = $message; // Form Model $expected['form.foo'] = new Message('form.foo'); $expected['form.bar'] = new Message('form.bar'); // Templates foreach (array('php', 'twig') as $engine) { $message = new Message($engine . '.foo'); $message->addSource($fileSourceFactory->create(new \SplFileInfo($basePath . 'Resources/views/' . $engine . '_template.html.' . $engine), 1)); $expected[$engine . '.foo'] = $message; $message = new Message($engine . '.bar'); $message->setDesc('Bar'); $message->addSource($fileSourceFactory->create(new \SplFileInfo($basePath . 'Resources/views/' . $engine . '_template.html.' . $engine), 3)); $expected[$engine . '.bar'] = $message; $message = new Message($engine . '.baz'); $message->setMeaning('Baz'); $message->addSource($fileSourceFactory->create(new \SplFileInfo($basePath . 'Resources/views/' . $engine . '_template.html.' . $engine), 5)); $expected[$engine . '.baz'] = $message; $message = new Message($engine . '.foo_bar'); $message->setDesc('Foo'); $message->setMeaning('Bar'); $message->addSource($fileSourceFactory->create(new \SplFileInfo($basePath . 'Resources/views/' . $engine . '_template.html.' . $engine), 7)); $expected[$engine . '.foo_bar'] = $message; } // File with global namespace. $message = new Message('globalnamespace.foo'); $message->addSource($fileSourceFactory->create(new \SplFileInfo($basePath . 'GlobalNamespace.php'), 27)); $message->setDesc('Bar'); $expected['globalnamespace.foo'] = $message; $actual = $this->extract(__DIR__ . '/Fixture/SimpleTest')->getDomain('messages')->all(); asort($expected); asort($actual); $this->assertEquals($expected, $actual); }
/** * @param Node $node * @return void */ public function enterNode(Node $node) { if ($node instanceof Node\Stmt\Namespace_) { if (isset($node->name)) { $this->namespace = implode('\\', $node->name->parts); } return; } if ($node instanceof Node\Stmt\Class_) { $name = '' === $this->namespace ? $node->name : $this->namespace . '\\' . $node->name; if (!class_exists($name)) { return; } $ref = new \ReflectionClass($name); if (!$ref->isSubclassOf('Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException') && $ref->name !== 'Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException') { return; } if (!$ref->hasMethod('getMessageKey')) { return; } $this->inAuthException = true; return; } if (!$this->inAuthException) { return; } if ($node instanceof Node\Stmt\ClassMethod) { if ('getmessagekey' === strtolower($node->name)) { $this->inGetMessageKey = true; } return; } if (!$this->inGetMessageKey) { return; } if (!$node instanceof Node\Stmt\Return_) { return; } $ignore = false; $desc = $meaning = null; if ($docComment = $node->getDocComment()) { foreach ($this->docParser->parse($docComment->getText(), 'file ' . $this->file . ' near line ' . $node->getLine()) as $annot) { if ($annot instanceof Ignore) { $ignore = true; } elseif ($annot instanceof Desc) { $desc = $annot->text; } elseif ($annot instanceof Meaning) { $meaning = $annot->text; } } } if (!$node->expr instanceof Node\Scalar\String_) { if ($ignore) { return; } $message = sprintf('Could not extract id from return value, expected scalar string but got %s (in %s on line %d).', get_class($node->expr), $this->file, $node->expr->getLine()); if ($this->logger) { $this->logger->error($message); return; } throw new RuntimeException($message); } $message = Message::create($node->expr->value, $this->domain)->setDesc($desc)->setMeaning($meaning)->addSource($this->fileSourceFactory->create($this->file, $node->expr->getLine())); $this->catalogue->add($message); }