aeafe7aeb11469f15c47d5a58ed874eb6ac53123
[yaffs-website] / web / core / modules / system / tests / src / Functional / Theme / TwigTransTest.php
1 <?php
2
3 namespace Drupal\Tests\system\Functional\Theme;
4
5 use Drupal\Core\Language\LanguageInterface;
6 use Drupal\Tests\BrowserTestBase;
7
8 /**
9  * Tests Twig "trans" tags.
10  *
11  * @group Theme
12  */
13 class TwigTransTest extends BrowserTestBase {
14
15   /**
16    * Modules to enable.
17    *
18    * @var array
19    */
20   public static $modules = [
21     'theme_test',
22     'twig_theme_test',
23     'locale',
24     'language',
25   ];
26
27   /**
28    * An administrative user for testing.
29    *
30    * @var \Drupal\user\Entity\User
31    */
32   protected $adminUser;
33
34   /**
35    * Custom languages.
36    *
37    * @var array
38    */
39   protected $languages = [
40     'xx' => 'Lolspeak',
41     'zz' => 'Lolspeak2',
42   ];
43
44   /**
45    * {@inheritdoc}
46    */
47   protected function setUp() {
48     parent::setUp();
49
50     // Setup test_theme.
51     \Drupal::service('theme_handler')->install(['test_theme']);
52     $this->config('system.theme')->set('default', 'test_theme')->save();
53
54     // Create and log in as admin.
55     $this->adminUser = $this->drupalCreateUser([
56       'administer languages',
57       'access administration pages',
58       'administer site configuration',
59       'translate interface',
60     ]);
61     $this->drupalLogin($this->adminUser);
62
63     // Install languages.
64     $this->installLanguages();
65
66     // Assign Lolspeak (xx) to be the default language.
67     $this->config('system.site')->set('default_langcode', 'xx')->save();
68     $this->rebuildContainer();
69
70     // Check that lolspeak is the default language for the site.
71     $this->assertEqual(\Drupal::languageManager()->getDefaultLanguage()->getId(), 'xx', 'Lolspeak is the default language');
72   }
73
74   /**
75    * Test Twig "trans" tags.
76    */
77   public function testTwigTransTags() {
78     // Run this once without and once with Twig debug because trans can work
79     // differently depending on that setting.
80     $this->drupalGet('twig-theme-test/trans', ['language' => \Drupal::languageManager()->getLanguage('xx')]);
81     $this->assertTwigTransTags();
82
83     // Enable debug, rebuild the service container, and clear all caches.
84     $parameters = $this->container->getParameter('twig.config');
85     $parameters['debug'] = TRUE;
86     $this->setContainerParameter('twig.config', $parameters);
87     $this->rebuildContainer();
88     $this->resetAll();
89
90     $this->drupalGet('twig-theme-test/trans', ['language' => \Drupal::languageManager()->getLanguage('xx')]);
91     $this->assertTwigTransTags();
92   }
93
94   /**
95    * Test empty Twig "trans" tags.
96    */
97   public function testEmptyTwigTransTags() {
98     $elements = [
99       '#type' => 'inline_template',
100       '#template' => '{% trans %}{% endtrans %}',
101     ];
102     /** @var \Drupal\Core\Render\RendererInterface $renderer */
103     $renderer = \Drupal::service('renderer');
104
105     try {
106       $renderer->renderPlain($elements);
107
108       $this->fail('{% trans %}{% endtrans %} did not throw an exception.');
109     }
110     catch (\Twig_Error_Syntax $e) {
111       $this->assertTrue(strstr($e->getMessage(), '{% trans %} tag cannot be empty'), '{% trans %}{% endtrans %} threw the expected exception.');
112     }
113     catch (\Exception $e) {
114       $this->fail('{% trans %}{% endtrans %} threw an unexpected exception.');
115     }
116   }
117
118   /**
119    * Asserts Twig trans tags.
120    */
121   protected function assertTwigTransTags() {
122     $this->assertText(
123       'OH HAI SUNZ',
124       '{% trans "Hello sun." %} was successfully translated.'
125     );
126
127     $this->assertText(
128       'O HAI SUNZZZZZZZ',
129       '{% trans "Hello sun." with {"context": "Lolspeak"} %} was successfully translated.'
130     );
131
132     $this->assertText(
133       'O HERRO ERRRF.',
134       '{{ "Hello Earth."|trans }} was successfully translated.'
135     );
136
137     $this->assertText(
138       'OH HAI TEH MUUN',
139       '{% trans %}Hello moon.{% endtrans %} was successfully translated.'
140     );
141
142     $this->assertText(
143       'O HAI STARRRRR',
144       '{% trans %} with {% plural count = 1 %} was successfully translated.'
145     );
146
147     $this->assertText(
148       'O HAI 2 STARZZZZ',
149       '{% trans %} with {% plural count = 2 %} was successfully translated.'
150     );
151
152     $this->assertRaw(
153       'ESCAPEE: &amp;&quot;&lt;&gt;',
154       '{{ token }} was successfully translated and prefixed with "@".'
155     );
156
157     $this->assertRaw(
158       'PLAYSHOLDR: <em class="placeholder">&amp;&quot;&lt;&gt;</em>',
159       '{{ token|placeholder }} was successfully translated and prefixed with "%".'
160     );
161
162     $this->assertRaw(
163       'DIS complex token HAZ LENGTH OV: 3. IT CONTAYNZ: <em class="placeholder">12345</em> AN &amp;&quot;&lt;&gt;.',
164       '{{ complex.tokens }} were successfully translated with appropriate prefixes.'
165     );
166
167     $this->assertText(
168       'I have context.',
169       '{% trans %} with a context only msgid was excluded from translation.'
170     );
171
172     $this->assertText(
173       'I HAZ KONTEX.',
174       '{% trans with {"context": "Lolspeak"} %} was successfully translated with context.'
175     );
176
177     $this->assertText(
178       'O HAI NU TXT.',
179       '{% trans with {"langcode": "zz"} %} was successfully translated in specified language.'
180     );
181
182     $this->assertText(
183       'O HAI NU TXTZZZZ.',
184       '{% trans with {"context": "Lolspeak", "langcode": "zz"} %} was successfully translated with context in specified language.'
185     );
186     // Makes sure https://www.drupal.org/node/2489024 doesn't happen without
187     // twig debug.
188     $this->assertNoText(pi(), 'Running php code inside a Twig trans is not possible.');
189   }
190
191   /**
192    * Helper function: install languages.
193    */
194   protected function installLanguages() {
195     foreach ($this->languages as $langcode => $name) {
196       // Generate custom .po contents for the language.
197       $contents = $this->poFileContents($langcode);
198       if ($contents) {
199         // Add test language for translation testing.
200         $edit = [
201           'predefined_langcode' => 'custom',
202           'langcode' => $langcode,
203           'label' => $name,
204           'direction' => LanguageInterface::DIRECTION_LTR,
205         ];
206
207         // Install the language in Drupal.
208         $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
209         $this->assertRaw('"edit-languages-' . $langcode . '-weight"', 'Language code found.');
210
211         // Import the custom .po contents for the language.
212         $filename = \Drupal::service('file_system')->tempnam('temporary://', "po_") . '.po';
213         file_put_contents($filename, $contents);
214         $options = [
215           'files[file]' => $filename,
216           'langcode' => $langcode,
217           'customized' => TRUE,
218         ];
219         $this->drupalPostForm('admin/config/regional/translate/import', $options, t('Import'));
220         drupal_unlink($filename);
221       }
222     }
223     $this->container->get('language_manager')->reset();
224   }
225
226   /**
227    * Generate a custom .po file for a specific test language.
228    *
229    * @param string $langcode
230    *   The langcode of the specified language.
231    *
232    * @return string|false
233    *   The .po contents for the specified language or FALSE if none exists.
234    */
235   protected function poFileContents($langcode) {
236     if ($langcode === 'xx') {
237       return <<< EOF
238 msgid ""
239 msgstr ""
240 "Project-Id-Version: Drupal 8\\n"
241 "MIME-Version: 1.0\\n"
242 "Content-Type: text/plain; charset=UTF-8\\n"
243 "Content-Transfer-Encoding: 8bit\\n"
244 "Plural-Forms: nplurals=2; plural=(n > 1);\\n"
245
246 msgid "Hello sun."
247 msgstr "OH HAI SUNZ"
248
249 msgctxt "Lolspeak"
250 msgid "Hello sun."
251 msgstr "O HAI SUNZZZZZZZ"
252
253 msgid "Hello Earth."
254 msgstr "O HERRO ERRRF."
255
256 msgid "Hello moon."
257 msgstr "OH HAI TEH MUUN"
258
259 msgid "Hello star."
260 msgid_plural "Hello @count stars."
261 msgstr[0] "O HAI STARRRRR"
262 msgstr[1] "O HAI @count STARZZZZ"
263
264 msgid "Escaped: @string"
265 msgstr "ESCAPEE: @string"
266
267 msgid "Placeholder: %string"
268 msgstr "PLAYSHOLDR: %string"
269
270 msgid "This @token.name has a length of: @count. It contains: %token.numbers and @token.bad_text."
271 msgstr "DIS @token.name HAZ LENGTH OV: @count. IT CONTAYNZ: %token.numbers AN @token.bad_text."
272
273 msgctxt "Lolspeak"
274 msgid "I have context."
275 msgstr "I HAZ KONTEX."
276 EOF;
277     }
278     elseif ($langcode === 'zz') {
279       return <<< EOF
280 msgid ""
281 msgstr ""
282 "Project-Id-Version: Drupal 8\\n"
283 "MIME-Version: 1.0\\n"
284 "Content-Type: text/plain; charset=UTF-8\\n"
285 "Content-Transfer-Encoding: 8bit\\n"
286 "Plural-Forms: nplurals=2; plural=(n > 1);\\n"
287
288 msgid "Hello new text."
289 msgstr "O HAI NU TXT."
290
291 msgctxt "Lolspeak"
292 msgid "Hello new text."
293 msgstr "O HAI NU TXTZZZZ."
294 EOF;
295     }
296     return FALSE;
297   }
298
299 }