Commit 39044397 authored by alexpott's avatar alexpott

Issue #2571695 by dawehner, plach, stefan.r, jaredsmith, lauriii, YesCT, xjm,...

Issue #2571695 by dawehner, plach, stefan.r, jaredsmith, lauriii, YesCT, xjm, catch, alexpott, joelpittet, Ryan Weal, Sutharsan, subhojit777, justAChris, nlisgo, effulgentsia, rpayanm, larowlan, chx, geertvd: Remove !placeholder and unsafe string return from SafeMarkup::format()
parent 3287afb0
...@@ -50,15 +50,6 @@ trait PlaceholderTrait { ...@@ -50,15 +50,6 @@ trait PlaceholderTrait {
* Url::fromUri($user_input)->toString() (which either throws an exception * Url::fromUri($user_input)->toString() (which either throws an exception
* or returns a well-formed URL) before passing the result into a * or returns a well-formed URL) before passing the result into a
* ":variable" placeholder. * ":variable" placeholder.
* - !variable: Inserted as is, with no sanitization or formatting. Only
* use this when the resulting string is being generated for one of:
* - Non-HTML usage, such as a plain-text email.
* - Non-direct HTML output, such as a plain-text variable that will be
* printed as an HTML attribute value and therefore formatted with
* self::checkPlain() as part of that.
* - Some other special reason for suppressing sanitization.
* @param bool &$safe
* A boolean indicating whether the string is safe or not (optional).
* *
* @return string * @return string
* The string with the placeholders replaced. * The string with the placeholders replaced.
...@@ -72,24 +63,13 @@ trait PlaceholderTrait { ...@@ -72,24 +63,13 @@ trait PlaceholderTrait {
* @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() * @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols()
* @see \Drupal\Core\Url::fromUri() * @see \Drupal\Core\Url::fromUri()
*/ */
protected static function placeholderFormat($string, array $args, &$safe = TRUE) { protected static function placeholderFormat($string, array $args) {
// Transform arguments before inserting them. // Transform arguments before inserting them.
foreach ($args as $key => $value) { foreach ($args as $key => $value) {
switch ($key[0]) { switch ($key[0]) {
case '@': case '@':
// Escaped only. // Escaped only.
if (!SafeMarkup::isSafe($value)) { $args[$key] = static::placeholderEscape($value);
$args[$key] = Html::escape($value);
}
break;
case '%':
default:
// Escaped and placeholder.
if (!SafeMarkup::isSafe($value)) {
$value = Html::escape($value);
}
$args[$key] = '<em class="placeholder">' . $value . '</em>';
break; break;
case ':': case ':':
...@@ -100,14 +80,28 @@ protected static function placeholderFormat($string, array $args, &$safe = TRUE) ...@@ -100,14 +80,28 @@ protected static function placeholderFormat($string, array $args, &$safe = TRUE)
$args[$key] = Html::escape(UrlHelper::stripDangerousProtocols($value)); $args[$key] = Html::escape(UrlHelper::stripDangerousProtocols($value));
break; break;
case '!': case '%':
// Pass-through. default:
if (!SafeMarkup::isSafe($value)) { // Escaped and placeholder.
$safe = FALSE; $args[$key] = '<em class="placeholder">' . static::placeholderEscape($value) . '</em>';
} break;
} }
} }
return strtr($string, $args); return strtr($string, $args);
} }
/**
* Escapes a placeholder replacement value if needed.
*
* @param string|\Drupal\Component\Utility\SafeStringInterface $value
* A placeholder replacement value.
*
* @return string
* The properly escaped replacement value.
*/
protected static function placeholderEscape($value) {
return SafeMarkup::isSafe($value) ? (string) $value : Html::escape($value);
}
} }
...@@ -183,20 +183,7 @@ public static function checkPlain($text) { ...@@ -183,20 +183,7 @@ public static function checkPlain($text) {
* Use \Drupal\Component\Utility\FormattableString. * Use \Drupal\Component\Utility\FormattableString.
*/ */
public static function format($string, array $args) { public static function format($string, array $args) {
// If the string has arguments that start with '!' we consider it unsafe return new FormattableString($string, $args);
// and return a string instead of an object for backward compatibility
// purposes.
// @todo https://www.drupal.org/node/2571695 remove this temporary
// workaround.
$safe = TRUE;
foreach ($args as $key => $value) {
if ($key[0] == '!' && !static::isSafe($value)) {
$safe = FALSE;
}
}
$safe_string = new FormattableString($string, $args);
return $safe ? $safe_string : (string) $safe_string;
} }
} }
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
namespace Drupal\Core\StringTranslation; namespace Drupal\Core\StringTranslation;
use Drupal\Component\Utility\PlaceholderTrait; use Drupal\Component\Utility\PlaceholderTrait;
use Drupal\Component\Utility\SafeMarkup;
/** /**
* A class to hold plural translatable strings. * A class to hold plural translatable strings.
...@@ -107,21 +106,9 @@ public function __construct($count, $singular, $plural, array $args = [], array ...@@ -107,21 +106,9 @@ public function __construct($count, $singular, $plural, array $args = [], array
* A PluralTranslatableString object. * A PluralTranslatableString object.
*/ */
public static function createFromTranslatedString($count, $translated_string, array $args = [], array $options = []) { public static function createFromTranslatedString($count, $translated_string, array $args = [], array $options = []) {
$safe = TRUE;
foreach (array_keys($args) as $arg_key) {
// If the string has arguments that start with '!' we consider it unsafe
// and return the translation as a string for backward compatibility
// purposes.
// @todo https://www.drupal.org/node/2570037 remove this temporary
// workaround.
if (0 === strpos($arg_key, '!') && !SafeMarkup::isSafe($args[$arg_key])) {
$safe = FALSE;
break;
}
}
$plural = new static($count, '', '', $args, $options); $plural = new static($count, '', '', $args, $options);
$plural->translatedString = $translated_string; $plural->translatedString = $translated_string;
return $safe ? $plural : (string) $plural; return $plural;
} }
/** /**
......
...@@ -33,7 +33,7 @@ interface TranslationInterface { ...@@ -33,7 +33,7 @@ interface TranslationInterface {
* what is used to display the page. * what is used to display the page.
* - 'context': The context the source string belongs to. * - 'context': The context the source string belongs to.
* *
* @return string|\Drupal\Core\StringTranslation\TranslatableString * @return \Drupal\Core\StringTranslation\TranslatableString
* The translated string. * The translated string.
* *
* @see \Drupal\Component\Utility\SafeMarkup::format() * @see \Drupal\Component\Utility\SafeMarkup::format()
......
...@@ -110,20 +110,7 @@ public function getStringTranslation($langcode, $string, $context) { ...@@ -110,20 +110,7 @@ public function getStringTranslation($langcode, $string, $context) {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function translate($string, array $args = array(), array $options = array()) { public function translate($string, array $args = array(), array $options = array()) {
$safe = TRUE; return new TranslatableString($string, $args, $options, $this);
foreach (array_keys($args) as $arg_key) {
// If the string has arguments that start with '!' we consider it unsafe
// and return the translation as a string for backward compatibility
// purposes.
// @todo https://www.drupal.org/node/2570037 remove this temporary
// workaround.
if (0 === strpos($arg_key, '!') && !SafeMarkup::isSafe($args[$arg_key])) {
$safe = FALSE;
break;
}
}
$wrapper = new TranslatableString($string, $args, $options, $this);
return $safe ? $wrapper : (string) $wrapper;
} }
/** /**
...@@ -161,20 +148,7 @@ protected function doTranslate($string, array $options = array()) { ...@@ -161,20 +148,7 @@ protected function doTranslate($string, array $options = array()) {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function formatPlural($count, $singular, $plural, array $args = array(), array $options = array()) { public function formatPlural($count, $singular, $plural, array $args = array(), array $options = array()) {
$safe = TRUE; return new PluralTranslatableString($count, $singular, $plural, $args, $options, $this);
foreach (array_keys($args) as $arg_key) {
// If the string has arguments that start with '!' we consider it unsafe
// and return the translation as a string for backward compatibility
// purposes.
// @todo https://www.drupal.org/node/2570037 remove this temporary
// workaround.
if (0 === strpos($arg_key, '!') && !SafeMarkup::isSafe($args[$arg_key])) {
$safe = FALSE;
break;
}
}
$plural = new PluralTranslatableString($count, $singular, $plural, $args, $options, $this);
return $safe ? $plural : (string) $plural;
} }
/** /**
......
...@@ -154,7 +154,6 @@ public function getFilters() { ...@@ -154,7 +154,6 @@ public function getFilters() {
// "raw" filter and give it identifiable names. These filters should only // "raw" filter and give it identifiable names. These filters should only
// be used in "trans" tags. // be used in "trans" tags.
// @see TwigNodeTrans::compileString() // @see TwigNodeTrans::compileString()
new \Twig_SimpleFilter('passthrough', 'twig_raw_filter', array('is_safe' => array('html'))),
new \Twig_SimpleFilter('placeholder', [$this, 'escapePlaceholder'], array('is_safe' => array('html'), 'needs_environment' => TRUE)), new \Twig_SimpleFilter('placeholder', [$this, 'escapePlaceholder'], array('is_safe' => array('html'), 'needs_environment' => TRUE)),
// Replace twig's escape filter with our own. // Replace twig's escape filter with our own.
......
...@@ -136,9 +136,6 @@ protected function compileString(\Twig_NodeInterface $body) { ...@@ -136,9 +136,6 @@ protected function compileString(\Twig_NodeInterface $body) {
$argPrefix = '@'; $argPrefix = '@';
while ($args instanceof \Twig_Node_Expression_Filter) { while ($args instanceof \Twig_Node_Expression_Filter) {
switch ($args->getNode('filter')->getAttribute('value')) { switch ($args->getNode('filter')->getAttribute('value')) {
case 'passthrough':
$argPrefix = '!';
break;
case 'placeholder': case 'placeholder':
$argPrefix = '%'; $argPrefix = '%';
break; break;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace Drupal\Tests\book\Unit; namespace Drupal\Tests\book\Unit;
use Drupal\simpletest\AssertHelperTrait;
use Drupal\Tests\UnitTestCase; use Drupal\Tests\UnitTestCase;
/** /**
...@@ -15,6 +16,8 @@ ...@@ -15,6 +16,8 @@
*/ */
class BookUninstallValidatorTest extends UnitTestCase { class BookUninstallValidatorTest extends UnitTestCase {
use AssertHelperTrait;
/** /**
* @var \Drupal\book\BookUninstallValidator|\PHPUnit_Framework_MockObject_MockObject * @var \Drupal\book\BookUninstallValidator|\PHPUnit_Framework_MockObject_MockObject
*/ */
...@@ -44,7 +47,7 @@ public function testValidateNotBook() { ...@@ -44,7 +47,7 @@ public function testValidateNotBook() {
$module = 'not_book'; $module = 'not_book';
$expected = []; $expected = [];
$reasons = $this->bookUninstallValidator->validate($module); $reasons = $this->bookUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -61,7 +64,7 @@ public function testValidateEntityQueryWithoutResults() { ...@@ -61,7 +64,7 @@ public function testValidateEntityQueryWithoutResults() {
$module = 'book'; $module = 'book';
$expected = []; $expected = [];
$reasons = $this->bookUninstallValidator->validate($module); $reasons = $this->bookUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -78,7 +81,7 @@ public function testValidateEntityQueryWithResults() { ...@@ -78,7 +81,7 @@ public function testValidateEntityQueryWithResults() {
$module = 'book'; $module = 'book';
$expected = ['To uninstall Book, delete all content that has the Book content type']; $expected = ['To uninstall Book, delete all content that has the Book content type'];
$reasons = $this->bookUninstallValidator->validate($module); $reasons = $this->bookUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -94,7 +97,7 @@ public function testValidateOutlineStorage() { ...@@ -94,7 +97,7 @@ public function testValidateOutlineStorage() {
$module = 'book'; $module = 'book';
$expected = ['To uninstall Book, delete all content that is part of a book']; $expected = ['To uninstall Book, delete all content that is part of a book'];
$reasons = $this->bookUninstallValidator->validate($module); $reasons = $this->bookUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
} }
...@@ -140,7 +140,7 @@ protected function setUp() { ...@@ -140,7 +140,7 @@ protected function setUp() {
*/ */
public function testGetTitle() { public function testGetTitle() {
$result = $this->configNamesMapper->getTitle(); $result = $this->configNamesMapper->getTitle();
$this->assertSame($this->pluginDefinition['title'], $result); $this->assertSame($this->pluginDefinition['title'], (string) $result);
} }
/** /**
...@@ -397,7 +397,7 @@ public function testPopulateFromRequest() { ...@@ -397,7 +397,7 @@ public function testPopulateFromRequest() {
*/ */
public function testGetTypeLabel() { public function testGetTypeLabel() {
$result = $this->configNamesMapper->getTypeLabel(); $result = $this->configNamesMapper->getTypeLabel();
$this->assertSame($this->pluginDefinition['title'], $result); $this->assertSame($this->pluginDefinition['title'], (string) $result);
} }
/** /**
...@@ -624,7 +624,7 @@ public function providerTestHasTranslation() { ...@@ -624,7 +624,7 @@ public function providerTestHasTranslation() {
*/ */
public function testGetTypeName() { public function testGetTypeName() {
$result = $this->configNamesMapper->getTypeName(); $result = $this->configNamesMapper->getTypeName();
$this->assertSame('Settings', $result); $this->assertSame('Settings', (string) $result);
} }
/** /**
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace Drupal\Tests\field\Unit; namespace Drupal\Tests\field\Unit;
use Drupal\simpletest\AssertHelperTrait;
use Drupal\Tests\UnitTestCase; use Drupal\Tests\UnitTestCase;
/** /**
...@@ -15,6 +16,8 @@ ...@@ -15,6 +16,8 @@
*/ */
class FieldUninstallValidatorTest extends UnitTestCase { class FieldUninstallValidatorTest extends UnitTestCase {
use AssertHelperTrait;
/** /**
* @var \Drupal\field\FieldUninstallValidator|\PHPUnit_Framework_MockObject_MockObject * @var \Drupal\field\FieldUninstallValidator|\PHPUnit_Framework_MockObject_MockObject
*/ */
...@@ -43,7 +46,7 @@ public function testValidateNoStorages() { ...@@ -43,7 +46,7 @@ public function testValidateNoStorages() {
$module = $this->randomMachineName(); $module = $this->randomMachineName();
$expected = []; $expected = [];
$reasons = $this->fieldUninstallValidator->validate($module); $reasons = $this->fieldUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -63,7 +66,7 @@ public function testValidateDeleted() { ...@@ -63,7 +66,7 @@ public function testValidateDeleted() {
$module = $this->randomMachineName(); $module = $this->randomMachineName();
$expected = ['Fields pending deletion']; $expected = ['Fields pending deletion'];
$reasons = $this->fieldUninstallValidator->validate($module); $reasons = $this->fieldUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -83,7 +86,7 @@ public function testValidateNoDeleted() { ...@@ -83,7 +86,7 @@ public function testValidateNoDeleted() {
$module = $this->randomMachineName(); $module = $this->randomMachineName();
$expected = ['Fields type(s) in use']; $expected = ['Fields type(s) in use'];
$reasons = $this->fieldUninstallValidator->validate($module); $reasons = $this->fieldUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
} }
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace Drupal\Tests\filter\Unit; namespace Drupal\Tests\filter\Unit;
use Drupal\simpletest\AssertHelperTrait;
use Drupal\Tests\UnitTestCase; use Drupal\Tests\UnitTestCase;
/** /**
...@@ -15,6 +16,8 @@ ...@@ -15,6 +16,8 @@
*/ */
class FilterUninstallValidatorTest extends UnitTestCase { class FilterUninstallValidatorTest extends UnitTestCase {
use AssertHelperTrait;
/** /**
* @var \Drupal\filter\FilterUninstallValidator|\PHPUnit_Framework_MockObject_MockObject * @var \Drupal\filter\FilterUninstallValidator|\PHPUnit_Framework_MockObject_MockObject
*/ */
...@@ -45,7 +48,7 @@ public function testValidateNoPlugins() { ...@@ -45,7 +48,7 @@ public function testValidateNoPlugins() {
$module = $this->randomMachineName(); $module = $this->randomMachineName();
$expected = []; $expected = [];
$reasons = $this->filterUninstallValidator->validate($module); $reasons = $this->filterUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -67,7 +70,7 @@ public function testValidateNoFormats() { ...@@ -67,7 +70,7 @@ public function testValidateNoFormats() {
$module = $this->randomMachineName(); $module = $this->randomMachineName();
$expected = []; $expected = [];
$reasons = $this->filterUninstallValidator->validate($module); $reasons = $this->filterUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -162,7 +165,7 @@ public function testValidateNoMatchingFormats() { ...@@ -162,7 +165,7 @@ public function testValidateNoMatchingFormats() {
'Provides a filter plugin that is in use in the following filter formats: <em class="placeholder">Filter Format 1 Label, Filter Format 2 Label</em>' 'Provides a filter plugin that is in use in the following filter formats: <em class="placeholder">Filter Format 1 Label, Filter Format 2 Label</em>'
]; ];
$reasons = $this->filterUninstallValidator->validate($this->randomMachineName()); $reasons = $this->filterUninstallValidator->validate($this->randomMachineName());
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
} }
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace Drupal\Tests\forum\Unit; namespace Drupal\Tests\forum\Unit;
use Drupal\simpletest\AssertHelperTrait;
use Drupal\Tests\UnitTestCase; use Drupal\Tests\UnitTestCase;
/** /**
...@@ -15,6 +16,8 @@ ...@@ -15,6 +16,8 @@
*/ */
class ForumUninstallValidatorTest extends UnitTestCase { class ForumUninstallValidatorTest extends UnitTestCase {
use AssertHelperTrait;
/** /**
* @var \Drupal\forum\ForumUninstallValidator|\PHPUnit_Framework_MockObject_MockObject * @var \Drupal\forum\ForumUninstallValidator|\PHPUnit_Framework_MockObject_MockObject
*/ */
...@@ -46,7 +49,7 @@ public function testValidateNotForum() { ...@@ -46,7 +49,7 @@ public function testValidateNotForum() {
$module = 'not_forum'; $module = 'not_forum';
$expected = []; $expected = [];
$reasons = $this->forumUninstallValidator->validate($module); $reasons = $this->forumUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -69,7 +72,7 @@ public function testValidate() { ...@@ -69,7 +72,7 @@ public function testValidate() {
$module = 'forum'; $module = 'forum';
$expected = []; $expected = [];
$reasons = $this->forumUninstallValidator->validate($module); $reasons = $this->forumUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -94,7 +97,7 @@ public function testValidateHasForumNodes() { ...@@ -94,7 +97,7 @@ public function testValidateHasForumNodes() {
'To uninstall Forum, first delete all <em>Forum</em> content', 'To uninstall Forum, first delete all <em>Forum</em> content',
]; ];
$reasons = $this->forumUninstallValidator->validate($module); $reasons = $this->forumUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -129,7 +132,7 @@ public function testValidateHasTermsForVocabularyWithNodesAccess() { ...@@ -129,7 +132,7 @@ public function testValidateHasTermsForVocabularyWithNodesAccess() {
'To uninstall Forum, first delete all <a href="/path/to/vocabulary/overview"><em class="placeholder">Vocabulary label</em></a> terms', 'To uninstall Forum, first delete all <a href="/path/to/vocabulary/overview"><em class="placeholder">Vocabulary label</em></a> terms',
]; ];
$reasons = $this->forumUninstallValidator->validate($module); $reasons = $this->forumUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -163,7 +166,7 @@ public function testValidateHasTermsForVocabularyWithNodesNoAccess() { ...@@ -163,7 +166,7 @@ public function testValidateHasTermsForVocabularyWithNodesNoAccess() {
'To uninstall Forum, first delete all <em class="placeholder">Vocabulary label</em> terms', 'To uninstall Forum, first delete all <em class="placeholder">Vocabulary label</em> terms',
]; ];
$reasons = $this->forumUninstallValidator->validate($module); $reasons = $this->forumUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -197,7 +200,7 @@ public function testValidateHasTermsForVocabularyAccess() { ...@@ -197,7 +200,7 @@ public function testValidateHasTermsForVocabularyAccess() {
'To uninstall Forum, first delete all <a href="/path/to/vocabulary/overview"><em class="placeholder">Vocabulary label</em></a> terms', 'To uninstall Forum, first delete all <a href="/path/to/vocabulary/overview"><em class="placeholder">Vocabulary label</em></a> terms',
]; ];
$reasons = $this->forumUninstallValidator->validate($module); $reasons = $this->forumUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
/** /**
...@@ -230,7 +233,7 @@ public function testValidateHasTermsForVocabularyNoAccess() { ...@@ -230,7 +233,7 @@ public function testValidateHasTermsForVocabularyNoAccess() {
'To uninstall Forum, first delete all <em class="placeholder">Vocabulary label</em> terms', 'To uninstall Forum, first delete all <em class="placeholder">Vocabulary label</em> terms',
]; ];
$reasons = $this->forumUninstallValidator->validate($module); $reasons = $this->forumUninstallValidator->validate($module);
$this->assertSame($expected, $reasons); $this->assertSame($expected, $this->castSafeStrings($reasons));
} }
} }
...@@ -40,8 +40,6 @@ function testT() { ...@@ -40,8 +40,6 @@ function testT() {
$this->assertEqual($text, 'Escaped text: &lt;script&gt;', 't replaces and escapes string.'); $this->assertEqual($text, 'Escaped text: &lt;script&gt;', 't replaces and escapes string.');
$text = t('Placeholder text: %value', array('%value' => '<script>')); $text = t('Placeholder text: %value', array('%value' => '<script>'));
$this->assertEqual($text, 'Placeholder text: <em class="placeholder">&lt;script&gt;</em>', 't replaces, escapes and themes string.'); $this->assertEqual($text, 'Placeholder text: <em class="placeholder">&lt;script&gt;</em>', 't replaces, escapes and themes string.');
$text = t('Verbatim text: !value', array('!value' => '<script>'));
$this->assertEqual($text, 'Verbatim text: <script>', 't replaces verbatim string as-is.');
} }
/** /**
......
...@@ -138,18 +138,13 @@ protected function assertTwigTransTags() { ...@@ -138,18 +138,13 @@ protected function assertTwigTransTags() {
'{{ token }} was successfully translated and prefixed with "@".' '{{ token }} was successfully translated and prefixed with "@".'
); );
$this->assertRaw(
'PAS-THRU: &"<>',
'{{ token|passthrough }} was successfully translated and prefixed with "!".'
);
$this->assertRaw( $this->assertRaw(
'PLAYSHOLDR: <em class="placeholder">&amp;&quot;&lt;&gt;</em>', 'PLAYSHOLDR: <em class="placeholder">&amp;&quot;&lt;&gt;</em>',
'{{ token|placeholder }} was successfully translated and prefixed with "%".' '{{ token|placeholder }} was successfully translated and prefixed with "%".'
); );
$this->assertRaw( $this->assertRaw(
'DIS complex token HAZ LENGTH OV: 3. IT CONTAYNZ: <em class="placeholder">12345</em> AN &amp;&quot;&lt;&gt;. LETS PAS TEH BAD TEXT THRU: &"<>.', 'DIS complex token HAZ LENGTH OV: 3. IT CONTAYNZ: <em class="placeholder">12345</em> AN &amp;&quot;&lt;&gt;.',
'{{ complex.tokens }} were successfully translated with appropriate prefixes.' '{{ complex.tokens }} were successfully translated with appropriate prefixes.'
); );
...@@ -253,14 +248,11 @@ protected function poFileContents($langcode) { ...@@ -253,14 +248,11 @@ protected function poFileContents($langcode) {
msgid "Escaped: @string" msgid "Escaped: @string"
msgstr "ESCAPEE: @string" msgstr "ESCAPEE: @string"
msgid "Pass-through: !string"
msgstr "PAS-THRU: !string"
msgid "Placeholder: %string" msgid "Placeholder: %string"
msgstr "PLAYSHOLDR: %string" msgstr "PLAYSHOLDR: %string"
msgid "This @token.name has a length of: @count. It contains: %token.numbers and @token.bad_text. Lets pass the bad text through: !token.bad_text." msgid "This @token.name has a length of: @count. It contains: %token.numbers and @token.bad_text."
msgstr "DIS @token.name HAZ LENGTH OV: @count. IT CONTAYNZ: %token.numbers AN @token.bad_text. LETS PAS TEH BAD TEXT THRU: !token.bad_text." msgstr "DIS @token.name HAZ LENGTH OV: @count. IT CONTAYNZ: %token.numbers AN @token.bad_text."
msgctxt "Lolspeak" msgctxt "Lolspeak"
msgid "I have context." msgid "I have context."
......