Chris@0: addDebugInfo($this); Chris@0: Chris@0: list($singular, $tokens) = $this->compileString($this->getNode('body')); Chris@0: $plural = NULL; Chris@0: Chris@18: if ($this->hasNode('plural')) { Chris@0: list($plural, $pluralTokens) = $this->compileString($this->getNode('plural')); Chris@0: $tokens = array_merge($tokens, $pluralTokens); Chris@0: } Chris@0: Chris@0: // Start writing with the function to be called. Chris@0: $compiler->write('echo ' . (empty($plural) ? 't' : '\Drupal::translation()->formatPlural') . '('); Chris@0: Chris@0: // Move the count to the beginning of the parameters list. Chris@0: if (!empty($plural)) { Chris@0: $compiler->raw('abs(')->subcompile($this->getNode('count'))->raw('), '); Chris@0: } Chris@0: Chris@0: // Write the singular text parameter. Chris@0: $compiler->subcompile($singular); Chris@0: Chris@0: // Write the plural text parameter, if necessary. Chris@0: if (!empty($plural)) { Chris@0: $compiler->raw(', ')->subcompile($plural); Chris@0: } Chris@0: Chris@0: // Write any tokens found as an associative array parameter, otherwise just Chris@0: // leave as an empty array. Chris@0: $compiler->raw(', array('); Chris@0: foreach ($tokens as $token) { Chris@0: $compiler->string($token->getAttribute('placeholder'))->raw(' => ')->subcompile($token)->raw(', '); Chris@0: } Chris@0: $compiler->raw(')'); Chris@0: Chris@0: // Write any options passed. Chris@18: if ($this->hasNode('options')) { Chris@18: $compiler->raw(', ')->subcompile($this->getNode('options')); Chris@0: } Chris@0: Chris@0: // Write function closure. Chris@0: $compiler->raw(')'); Chris@0: Chris@0: // @todo Add debug output, see https://www.drupal.org/node/2512672 Chris@0: Chris@0: // End writing. Chris@0: $compiler->raw(";\n"); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Extracts the text and tokens for the "trans" tag. Chris@0: * Chris@0: * @param \Twig_Node $body Chris@0: * The node to compile. Chris@0: * Chris@0: * @return array Chris@0: * Returns an array containing the two following parameters: Chris@0: * - string $text Chris@0: * The extracted text. Chris@0: * - array $tokens Chris@0: * The extracted tokens as new \Twig_Node_Expression_Name instances. Chris@0: */ Chris@0: protected function compileString(\Twig_Node $body) { Chris@0: if ($body instanceof \Twig_Node_Expression_Name || $body instanceof \Twig_Node_Expression_Constant || $body instanceof \Twig_Node_Expression_TempName) { Chris@0: return [$body, []]; Chris@0: } Chris@0: Chris@0: $tokens = []; Chris@0: if (count($body)) { Chris@0: $text = ''; Chris@0: Chris@0: foreach ($body as $node) { Chris@0: if (get_class($node) === 'Twig_Node' && $node->getNode(0) instanceof \Twig_Node_SetTemp) { Chris@0: $node = $node->getNode(1); Chris@0: } Chris@0: Chris@0: if ($node instanceof \Twig_Node_Print) { Chris@0: $n = $node->getNode('expr'); Chris@0: while ($n instanceof \Twig_Node_Expression_Filter) { Chris@0: $n = $n->getNode('node'); Chris@0: } Chris@0: Chris@18: if ($n instanceof CheckToStringNode) { Chris@18: $n = $n->getNode('expr'); Chris@18: } Chris@0: $args = $n; Chris@0: Chris@0: // Support TwigExtension->renderVar() function in chain. Chris@0: if ($args instanceof \Twig_Node_Expression_Function) { Chris@0: $args = $n->getNode('arguments')->getNode(0); Chris@0: } Chris@0: Chris@0: // Detect if a token implements one of the filters reserved for Chris@0: // modifying the prefix of a token. The default prefix used for Chris@0: // translations is "@". This escapes the printed token and makes them Chris@0: // safe for templates. Chris@0: // @see TwigExtension::getFilters() Chris@0: $argPrefix = '@'; Chris@0: while ($args instanceof \Twig_Node_Expression_Filter) { Chris@0: switch ($args->getNode('filter')->getAttribute('value')) { Chris@0: case 'placeholder': Chris@0: $argPrefix = '%'; Chris@0: break; Chris@0: } Chris@0: $args = $args->getNode('node'); Chris@0: } Chris@18: if ($args instanceof CheckToStringNode) { Chris@18: $args = $args->getNode('expr'); Chris@18: } Chris@0: if ($args instanceof \Twig_Node_Expression_GetAttr) { Chris@0: $argName = []; Chris@0: // Reuse the incoming expression. Chris@0: $expr = $args; Chris@0: // Assemble a valid argument name by walking through the expression. Chris@0: $argName[] = $args->getNode('attribute')->getAttribute('value'); Chris@0: while ($args->hasNode('node')) { Chris@0: $args = $args->getNode('node'); Chris@0: if ($args instanceof \Twig_Node_Expression_Name) { Chris@0: $argName[] = $args->getAttribute('name'); Chris@0: } Chris@0: else { Chris@0: $argName[] = $args->getNode('attribute')->getAttribute('value'); Chris@0: } Chris@0: } Chris@0: $argName = array_reverse($argName); Chris@0: $argName = implode('.', $argName); Chris@0: } Chris@0: else { Chris@0: $argName = $n->getAttribute('name'); Chris@0: if (!is_null($args)) { Chris@0: $argName = $args->getAttribute('name'); Chris@0: } Chris@14: $expr = new \Twig_Node_Expression_Name($argName, $n->getTemplateLine()); Chris@0: } Chris@0: $placeholder = sprintf('%s%s', $argPrefix, $argName); Chris@0: $text .= $placeholder; Chris@0: $expr->setAttribute('placeholder', $placeholder); Chris@0: $tokens[] = $expr; Chris@0: } Chris@0: else { Chris@0: $text .= $node->getAttribute('data'); Chris@0: } Chris@0: } Chris@0: } Chris@0: elseif (!$body->hasAttribute('data')) { Chris@0: throw new \Twig_Error_Syntax('{% trans %} tag cannot be empty'); Chris@0: } Chris@0: else { Chris@0: $text = $body->getAttribute('data'); Chris@0: } Chris@0: Chris@14: return [ Chris@14: new \Twig_Node([new \Twig_Node_Expression_Constant(trim($text), $body->getTemplateLine())]), Chris@14: $tokens, Chris@14: ]; Chris@0: } Chris@0: Chris@0: }