comparison core/lib/Drupal/Core/Template/TwigNodeTrans.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
comparison
equal deleted inserted replaced
-1:000000000000 0:4c8ae668cc8c
1 <?php
2
3 namespace Drupal\Core\Template;
4
5 /**
6 * A class that defines the Twig 'trans' tag for Drupal.
7 *
8 * This Twig extension was originally based on Twig i18n extension. It has been
9 * severely modified to work properly with the complexities of the Drupal
10 * translation system.
11 *
12 * @see http://twig.sensiolabs.org/doc/extensions/i18n.html
13 * @see https://github.com/fabpot/Twig-extensions
14 */
15 class TwigNodeTrans extends \Twig_Node {
16
17 /**
18 * {@inheritdoc}
19 */
20 public function __construct(\Twig_Node $body, \Twig_Node $plural = NULL, \Twig_Node_Expression $count = NULL, \Twig_Node_Expression $options = NULL, $lineno, $tag = NULL) {
21 parent::__construct([
22 'count' => $count,
23 'body' => $body,
24 'plural' => $plural,
25 'options' => $options,
26 ], [], $lineno, $tag);
27 }
28
29 /**
30 * {@inheritdoc}
31 */
32 public function compile(\Twig_Compiler $compiler) {
33 $compiler->addDebugInfo($this);
34
35 $options = $this->getNode('options');
36
37 list($singular, $tokens) = $this->compileString($this->getNode('body'));
38 $plural = NULL;
39
40 if (NULL !== $this->getNode('plural')) {
41 list($plural, $pluralTokens) = $this->compileString($this->getNode('plural'));
42 $tokens = array_merge($tokens, $pluralTokens);
43 }
44
45 // Start writing with the function to be called.
46 $compiler->write('echo ' . (empty($plural) ? 't' : '\Drupal::translation()->formatPlural') . '(');
47
48 // Move the count to the beginning of the parameters list.
49 if (!empty($plural)) {
50 $compiler->raw('abs(')->subcompile($this->getNode('count'))->raw('), ');
51 }
52
53 // Write the singular text parameter.
54 $compiler->subcompile($singular);
55
56 // Write the plural text parameter, if necessary.
57 if (!empty($plural)) {
58 $compiler->raw(', ')->subcompile($plural);
59 }
60
61 // Write any tokens found as an associative array parameter, otherwise just
62 // leave as an empty array.
63 $compiler->raw(', array(');
64 foreach ($tokens as $token) {
65 $compiler->string($token->getAttribute('placeholder'))->raw(' => ')->subcompile($token)->raw(', ');
66 }
67 $compiler->raw(')');
68
69 // Write any options passed.
70 if (!empty($options)) {
71 $compiler->raw(', ')->subcompile($options);
72 }
73
74 // Write function closure.
75 $compiler->raw(')');
76
77 // @todo Add debug output, see https://www.drupal.org/node/2512672
78
79 // End writing.
80 $compiler->raw(";\n");
81 }
82
83 /**
84 * Extracts the text and tokens for the "trans" tag.
85 *
86 * @param \Twig_Node $body
87 * The node to compile.
88 *
89 * @return array
90 * Returns an array containing the two following parameters:
91 * - string $text
92 * The extracted text.
93 * - array $tokens
94 * The extracted tokens as new \Twig_Node_Expression_Name instances.
95 */
96 protected function compileString(\Twig_Node $body) {
97 if ($body instanceof \Twig_Node_Expression_Name || $body instanceof \Twig_Node_Expression_Constant || $body instanceof \Twig_Node_Expression_TempName) {
98 return [$body, []];
99 }
100
101 $tokens = [];
102 if (count($body)) {
103 $text = '';
104
105 foreach ($body as $node) {
106 if (get_class($node) === 'Twig_Node' && $node->getNode(0) instanceof \Twig_Node_SetTemp) {
107 $node = $node->getNode(1);
108 }
109
110 if ($node instanceof \Twig_Node_Print) {
111 $n = $node->getNode('expr');
112 while ($n instanceof \Twig_Node_Expression_Filter) {
113 $n = $n->getNode('node');
114 }
115
116 $args = $n;
117
118 // Support TwigExtension->renderVar() function in chain.
119 if ($args instanceof \Twig_Node_Expression_Function) {
120 $args = $n->getNode('arguments')->getNode(0);
121 }
122
123 // Detect if a token implements one of the filters reserved for
124 // modifying the prefix of a token. The default prefix used for
125 // translations is "@". This escapes the printed token and makes them
126 // safe for templates.
127 // @see TwigExtension::getFilters()
128 $argPrefix = '@';
129 while ($args instanceof \Twig_Node_Expression_Filter) {
130 switch ($args->getNode('filter')->getAttribute('value')) {
131 case 'placeholder':
132 $argPrefix = '%';
133 break;
134 }
135 $args = $args->getNode('node');
136 }
137 if ($args instanceof \Twig_Node_Expression_GetAttr) {
138 $argName = [];
139 // Reuse the incoming expression.
140 $expr = $args;
141 // Assemble a valid argument name by walking through the expression.
142 $argName[] = $args->getNode('attribute')->getAttribute('value');
143 while ($args->hasNode('node')) {
144 $args = $args->getNode('node');
145 if ($args instanceof \Twig_Node_Expression_Name) {
146 $argName[] = $args->getAttribute('name');
147 }
148 else {
149 $argName[] = $args->getNode('attribute')->getAttribute('value');
150 }
151 }
152 $argName = array_reverse($argName);
153 $argName = implode('.', $argName);
154 }
155 else {
156 $argName = $n->getAttribute('name');
157 if (!is_null($args)) {
158 $argName = $args->getAttribute('name');
159 }
160 $expr = new \Twig_Node_Expression_Name($argName, $n->getLine());
161 }
162 $placeholder = sprintf('%s%s', $argPrefix, $argName);
163 $text .= $placeholder;
164 $expr->setAttribute('placeholder', $placeholder);
165 $tokens[] = $expr;
166 }
167 else {
168 $text .= $node->getAttribute('data');
169 }
170 }
171 }
172 elseif (!$body->hasAttribute('data')) {
173 throw new \Twig_Error_Syntax('{% trans %} tag cannot be empty');
174 }
175 else {
176 $text = $body->getAttribute('data');
177 }
178
179 return [new \Twig_Node([new \Twig_Node_Expression_Constant(trim($text), $body->getLine())]), $tokens];
180 }
181
182 }