diff --git a/core/lib/Drupal/Component/Utility/PlaceholderTrait.php b/core/lib/Drupal/Component/Utility/PlaceholderTrait.php index f5bcb399666a59e28fcb451ce20c8dd3bff21a4d..e2db26b3ecb17234752cc1909c04ff1559703df5 100644 --- a/core/lib/Drupal/Component/Utility/PlaceholderTrait.php +++ b/core/lib/Drupal/Component/Utility/PlaceholderTrait.php @@ -50,15 +50,6 @@ trait PlaceholderTrait { * Url::fromUri($user_input)->toString() (which either throws an exception * or returns a well-formed URL) before passing the result into a * ":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 * The string with the placeholders replaced. @@ -72,24 +63,13 @@ trait PlaceholderTrait { * @see \Drupal\Component\Utility\UrlHelper::stripDangerousProtocols() * @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. foreach ($args as $key => $value) { switch ($key[0]) { case '@': // Escaped only. - if (!SafeMarkup::isSafe($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>'; + $args[$key] = static::placeholderEscape($value); break; case ':': @@ -100,14 +80,28 @@ protected static function placeholderFormat($string, array $args, &$safe = TRUE) $args[$key] = Html::escape(UrlHelper::stripDangerousProtocols($value)); break; - case '!': - // Pass-through. - if (!SafeMarkup::isSafe($value)) { - $safe = FALSE; - } + case '%': + default: + // Escaped and placeholder. + $args[$key] = '<em class="placeholder">' . static::placeholderEscape($value) . '</em>'; + break; } } + 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); + } + } diff --git a/core/lib/Drupal/Component/Utility/SafeMarkup.php b/core/lib/Drupal/Component/Utility/SafeMarkup.php index a8c95764041f0747b078dfcbdb8f1f4ca5b73448..6f42d13020c61992f53b3ff048961335acadb43d 100644 --- a/core/lib/Drupal/Component/Utility/SafeMarkup.php +++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php @@ -183,20 +183,7 @@ public static function checkPlain($text) { * Use \Drupal\Component\Utility\FormattableString. */ public static function format($string, array $args) { - // If the string has arguments that start with '!' we consider it unsafe - // 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; + return new FormattableString($string, $args); } } diff --git a/core/lib/Drupal/Core/StringTranslation/PluralTranslatableString.php b/core/lib/Drupal/Core/StringTranslation/PluralTranslatableString.php index b9e79e5a3e16bdfe618da3017779ba6c4447b169..46225df6d4cad53ca1c1d61a55a38f20072a75bb 100644 --- a/core/lib/Drupal/Core/StringTranslation/PluralTranslatableString.php +++ b/core/lib/Drupal/Core/StringTranslation/PluralTranslatableString.php @@ -8,7 +8,6 @@ namespace Drupal\Core\StringTranslation; use Drupal\Component\Utility\PlaceholderTrait; -use Drupal\Component\Utility\SafeMarkup; /** * A class to hold plural translatable strings. @@ -107,21 +106,9 @@ public function __construct($count, $singular, $plural, array $args = [], array * A PluralTranslatableString object. */ 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->translatedString = $translated_string; - return $safe ? $plural : (string) $plural; + return $plural; } /** diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php index f9ff9ef8fb0d491a569f65732cc709adb213fe59..195a5a1d58ae1c94e4920808c3419a53cc2d0db0 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php @@ -33,7 +33,7 @@ interface TranslationInterface { * what is used to display the page. * - 'context': The context the source string belongs to. * - * @return string|\Drupal\Core\StringTranslation\TranslatableString + * @return \Drupal\Core\StringTranslation\TranslatableString * The translated string. * * @see \Drupal\Component\Utility\SafeMarkup::format() diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php index c7bad70ee1fc2b2a4dbf43aa6d66b0bc43c659bc..ec16db217ba6d699512d466663af11f2cccc2527 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php @@ -110,20 +110,7 @@ public function getStringTranslation($langcode, $string, $context) { * {@inheritdoc} */ public function translate($string, array $args = array(), array $options = array()) { - $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; - } - } - $wrapper = new TranslatableString($string, $args, $options, $this); - return $safe ? $wrapper : (string) $wrapper; + return new TranslatableString($string, $args, $options, $this); } /** @@ -161,20 +148,7 @@ protected function doTranslate($string, array $options = array()) { * {@inheritdoc} */ public function formatPlural($count, $singular, $plural, array $args = array(), array $options = array()) { - $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 PluralTranslatableString($count, $singular, $plural, $args, $options, $this); - return $safe ? $plural : (string) $plural; + return new PluralTranslatableString($count, $singular, $plural, $args, $options, $this); } /** diff --git a/core/lib/Drupal/Core/Template/TwigExtension.php b/core/lib/Drupal/Core/Template/TwigExtension.php index 360eed8d19432cb9c577e1c52284dcf535af5775..552ef547ed033bd33931d525e42738d4a12c33cd 100644 --- a/core/lib/Drupal/Core/Template/TwigExtension.php +++ b/core/lib/Drupal/Core/Template/TwigExtension.php @@ -154,7 +154,6 @@ public function getFilters() { // "raw" filter and give it identifiable names. These filters should only // be used in "trans" tags. // @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)), // Replace twig's escape filter with our own. diff --git a/core/lib/Drupal/Core/Template/TwigNodeTrans.php b/core/lib/Drupal/Core/Template/TwigNodeTrans.php index a7b723ad05839ed42dd041deef76b867bebfad22..757b94b4cc2a7cc2a1357c2a46e7911274b32b95 100644 --- a/core/lib/Drupal/Core/Template/TwigNodeTrans.php +++ b/core/lib/Drupal/Core/Template/TwigNodeTrans.php @@ -136,9 +136,6 @@ protected function compileString(\Twig_NodeInterface $body) { $argPrefix = '@'; while ($args instanceof \Twig_Node_Expression_Filter) { switch ($args->getNode('filter')->getAttribute('value')) { - case 'passthrough': - $argPrefix = '!'; - break; case 'placeholder': $argPrefix = '%'; break; diff --git a/core/modules/book/tests/src/Unit/BookUninstallValidatorTest.php b/core/modules/book/tests/src/Unit/BookUninstallValidatorTest.php index d3748c263d0d435ced5cf3277267af99f17931ea..651c6ce909588fca7d2d5f112bba0ac443e4ac8f 100644 --- a/core/modules/book/tests/src/Unit/BookUninstallValidatorTest.php +++ b/core/modules/book/tests/src/Unit/BookUninstallValidatorTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\book\Unit; +use Drupal\simpletest\AssertHelperTrait; use Drupal\Tests\UnitTestCase; /** @@ -15,6 +16,8 @@ */ class BookUninstallValidatorTest extends UnitTestCase { + use AssertHelperTrait; + /** * @var \Drupal\book\BookUninstallValidator|\PHPUnit_Framework_MockObject_MockObject */ @@ -44,7 +47,7 @@ public function testValidateNotBook() { $module = 'not_book'; $expected = []; $reasons = $this->bookUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -61,7 +64,7 @@ public function testValidateEntityQueryWithoutResults() { $module = 'book'; $expected = []; $reasons = $this->bookUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -78,7 +81,7 @@ public function testValidateEntityQueryWithResults() { $module = 'book'; $expected = ['To uninstall Book, delete all content that has the Book content type']; $reasons = $this->bookUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -94,7 +97,7 @@ public function testValidateOutlineStorage() { $module = 'book'; $expected = ['To uninstall Book, delete all content that is part of a book']; $reasons = $this->bookUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } } diff --git a/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php b/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php index 796012fbc624898b40a608992ee574f41ccb21ae..fce0d674bc8e1f40af67a33045a21c2075acc693 100644 --- a/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php +++ b/core/modules/config_translation/tests/src/Unit/ConfigNamesMapperTest.php @@ -140,7 +140,7 @@ protected function setUp() { */ public function testGetTitle() { $result = $this->configNamesMapper->getTitle(); - $this->assertSame($this->pluginDefinition['title'], $result); + $this->assertSame($this->pluginDefinition['title'], (string) $result); } /** @@ -397,7 +397,7 @@ public function testPopulateFromRequest() { */ public function testGetTypeLabel() { $result = $this->configNamesMapper->getTypeLabel(); - $this->assertSame($this->pluginDefinition['title'], $result); + $this->assertSame($this->pluginDefinition['title'], (string) $result); } /** @@ -624,7 +624,7 @@ public function providerTestHasTranslation() { */ public function testGetTypeName() { $result = $this->configNamesMapper->getTypeName(); - $this->assertSame('Settings', $result); + $this->assertSame('Settings', (string) $result); } /** diff --git a/core/modules/field/tests/src/Unit/FieldUninstallValidatorTest.php b/core/modules/field/tests/src/Unit/FieldUninstallValidatorTest.php index ea9e0c89f6843a657c894ab22e2837b02e07e0e0..5f7a16d6f4e819ee3eead617366253ff7f9da9db 100644 --- a/core/modules/field/tests/src/Unit/FieldUninstallValidatorTest.php +++ b/core/modules/field/tests/src/Unit/FieldUninstallValidatorTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\field\Unit; +use Drupal\simpletest\AssertHelperTrait; use Drupal\Tests\UnitTestCase; /** @@ -15,6 +16,8 @@ */ class FieldUninstallValidatorTest extends UnitTestCase { + use AssertHelperTrait; + /** * @var \Drupal\field\FieldUninstallValidator|\PHPUnit_Framework_MockObject_MockObject */ @@ -43,7 +46,7 @@ public function testValidateNoStorages() { $module = $this->randomMachineName(); $expected = []; $reasons = $this->fieldUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -63,7 +66,7 @@ public function testValidateDeleted() { $module = $this->randomMachineName(); $expected = ['Fields pending deletion']; $reasons = $this->fieldUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -83,7 +86,7 @@ public function testValidateNoDeleted() { $module = $this->randomMachineName(); $expected = ['Fields type(s) in use']; $reasons = $this->fieldUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } } diff --git a/core/modules/filter/tests/src/Unit/FilterUninstallValidatorTest.php b/core/modules/filter/tests/src/Unit/FilterUninstallValidatorTest.php index 4a4f7bac36d8fd65b6243ab38958c588674dd19b..8416d7e619525fd5d5eecae69b0f80159d6f829b 100644 --- a/core/modules/filter/tests/src/Unit/FilterUninstallValidatorTest.php +++ b/core/modules/filter/tests/src/Unit/FilterUninstallValidatorTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\filter\Unit; +use Drupal\simpletest\AssertHelperTrait; use Drupal\Tests\UnitTestCase; /** @@ -15,6 +16,8 @@ */ class FilterUninstallValidatorTest extends UnitTestCase { + use AssertHelperTrait; + /** * @var \Drupal\filter\FilterUninstallValidator|\PHPUnit_Framework_MockObject_MockObject */ @@ -45,7 +48,7 @@ public function testValidateNoPlugins() { $module = $this->randomMachineName(); $expected = []; $reasons = $this->filterUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -67,7 +70,7 @@ public function testValidateNoFormats() { $module = $this->randomMachineName(); $expected = []; $reasons = $this->filterUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -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>' ]; $reasons = $this->filterUninstallValidator->validate($this->randomMachineName()); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } } diff --git a/core/modules/forum/tests/src/Unit/ForumUninstallValidatorTest.php b/core/modules/forum/tests/src/Unit/ForumUninstallValidatorTest.php index 560a872834e48d5581688e9519bbde1aa5281a7b..11639bc95799359f4fe6e36119f8594ea6bab846 100644 --- a/core/modules/forum/tests/src/Unit/ForumUninstallValidatorTest.php +++ b/core/modules/forum/tests/src/Unit/ForumUninstallValidatorTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\forum\Unit; +use Drupal\simpletest\AssertHelperTrait; use Drupal\Tests\UnitTestCase; /** @@ -15,6 +16,8 @@ */ class ForumUninstallValidatorTest extends UnitTestCase { + use AssertHelperTrait; + /** * @var \Drupal\forum\ForumUninstallValidator|\PHPUnit_Framework_MockObject_MockObject */ @@ -46,7 +49,7 @@ public function testValidateNotForum() { $module = 'not_forum'; $expected = []; $reasons = $this->forumUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -69,7 +72,7 @@ public function testValidate() { $module = 'forum'; $expected = []; $reasons = $this->forumUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -94,7 +97,7 @@ public function testValidateHasForumNodes() { 'To uninstall Forum, first delete all <em>Forum</em> content', ]; $reasons = $this->forumUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -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', ]; $reasons = $this->forumUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -163,7 +166,7 @@ public function testValidateHasTermsForVocabularyWithNodesNoAccess() { 'To uninstall Forum, first delete all <em class="placeholder">Vocabulary label</em> terms', ]; $reasons = $this->forumUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -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', ]; $reasons = $this->forumUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } /** @@ -230,7 +233,7 @@ public function testValidateHasTermsForVocabularyNoAccess() { 'To uninstall Forum, first delete all <em class="placeholder">Vocabulary label</em> terms', ]; $reasons = $this->forumUninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } } diff --git a/core/modules/system/src/Tests/Common/XssUnitTest.php b/core/modules/system/src/Tests/Common/XssUnitTest.php index 2890f5537c6f9fbea192b7e28c71cf564039d24a..a02bada701ef021b6b5b100c4bfd60d13b75c9f0 100644 --- a/core/modules/system/src/Tests/Common/XssUnitTest.php +++ b/core/modules/system/src/Tests/Common/XssUnitTest.php @@ -40,8 +40,6 @@ function testT() { $this->assertEqual($text, 'Escaped text: <script>', 't replaces and escapes string.'); $text = t('Placeholder text: %value', array('%value' => '<script>')); $this->assertEqual($text, 'Placeholder text: <em class="placeholder"><script></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.'); } /** diff --git a/core/modules/system/src/Tests/Theme/TwigTransTest.php b/core/modules/system/src/Tests/Theme/TwigTransTest.php index 21aef18c0c22acb976c1a3459c12e254ffd5bf46..ac970cd267c5db796a5cca46d4343a34a9fd9605 100644 --- a/core/modules/system/src/Tests/Theme/TwigTransTest.php +++ b/core/modules/system/src/Tests/Theme/TwigTransTest.php @@ -138,18 +138,13 @@ protected function assertTwigTransTags() { '{{ token }} was successfully translated and prefixed with "@".' ); - $this->assertRaw( - 'PAS-THRU: &"<>', - '{{ token|passthrough }} was successfully translated and prefixed with "!".' - ); - $this->assertRaw( 'PLAYSHOLDR: <em class="placeholder">&"<></em>', '{{ token|placeholder }} was successfully translated and prefixed with "%".' ); $this->assertRaw( - 'DIS complex token HAZ LENGTH OV: 3. IT CONTAYNZ: <em class="placeholder">12345</em> AN &"<>. LETS PAS TEH BAD TEXT THRU: &"<>.', + 'DIS complex token HAZ LENGTH OV: 3. IT CONTAYNZ: <em class="placeholder">12345</em> AN &"<>.', '{{ complex.tokens }} were successfully translated with appropriate prefixes.' ); @@ -253,14 +248,11 @@ protected function poFileContents($langcode) { msgid "Escaped: @string" msgstr "ESCAPEE: @string" -msgid "Pass-through: !string" -msgstr "PAS-THRU: !string" - msgid "Placeholder: %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." -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." +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." msgctxt "Lolspeak" msgid "I have context." diff --git a/core/modules/system/tests/modules/twig_theme_test/templates/twig_theme_test.trans.html.twig b/core/modules/system/tests/modules/twig_theme_test/templates/twig_theme_test.trans.html.twig index 9623ba546d21c94b27025f5f3d7bc14459d1d0d7..dc08db39d13f98af083577ae2bde74ff7698f096 100644 --- a/core/modules/system/tests/modules/twig_theme_test/templates/twig_theme_test.trans.html.twig +++ b/core/modules/system/tests/modules/twig_theme_test/templates/twig_theme_test.trans.html.twig @@ -47,11 +47,6 @@ Escaped: {{ string }} {% endtrans %} </div> -<div> - {% trans %} - Pass-through: {{ string|passthrough }} - {% endtrans %} -</div> <div> {% trans %} Placeholder: {{ string|placeholder }} @@ -63,7 +58,7 @@ {% set count = token|length %} <div> {% trans %} - This {{ token.name }} has a length of: {{ count }}. It contains: {{ token.numbers|placeholder }} and {{ token.bad_text }}. Lets pass the bad text through: {{ token.bad_text|passthrough }}. + This {{ token.name }} has a length of: {{ count }}. It contains: {{ token.numbers|placeholder }} and {{ token.bad_text }}. {% endtrans %} </div> diff --git a/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php b/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php index 57f5ced2ba1525a43ac28b936d60d501dcb14264..ae4973ca9b55dbaafe24d63559e15d136b2a937d 100644 --- a/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php +++ b/core/modules/user/src/Plugin/Validation/Constraint/UserMailRequired.php @@ -34,7 +34,7 @@ class UserMailRequired extends Constraint implements ConstraintValidatorInterfac * * @var string */ - public $message = '!name field is required.'; + public $message = '@name field is required.'; /** * @var \Symfony\Component\Validator\ExecutionContextInterface @@ -73,7 +73,7 @@ public function validate($items, Constraint $constraint) { $required = !(!$existing_value && \Drupal::currentUser()->hasPermission('administer users')); if ($required && (!isset($items) || $items->isEmpty())) { - $this->context->addViolation($this->message, ['!name' => Html::escape($account->getFieldDefinition('mail')->getLabel())]); + $this->context->addViolation($this->message, ['@name' => $account->getFieldDefinition('mail')->getLabel()]); } } diff --git a/core/modules/user/tests/src/Unit/PermissionHandlerTest.php b/core/modules/user/tests/src/Unit/PermissionHandlerTest.php index 5ac0f1be1081395ffd661fea0ff68f26ee713931..1b155e0a716b20550799700d150f36c637aed130 100644 --- a/core/modules/user/tests/src/Unit/PermissionHandlerTest.php +++ b/core/modules/user/tests/src/Unit/PermissionHandlerTest.php @@ -8,6 +8,9 @@ namespace Drupal\Tests\user\Unit; use Drupal\Core\Extension\Extension; +use Drupal\Core\StringTranslation\PluralTranslatableString; +use Drupal\Core\StringTranslation\TranslatableString; +use Drupal\Core\StringTranslation\TranslationInterface; use Drupal\Tests\UnitTestCase; use Drupal\user\PermissionHandler; use org\bovigo\vfs\vfsStream; @@ -40,7 +43,7 @@ class PermissionHandlerTest extends UnitTestCase { /** * The mocked string translation. * - * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject + * @var \Drupal\Tests\user\Unit\TestTranslationManager */ protected $stringTranslation; @@ -57,7 +60,7 @@ class PermissionHandlerTest extends UnitTestCase { protected function setUp() { parent::setUp(); - $this->stringTranslation = $this->getStringTranslationStub(); + $this->stringTranslation = new TestTranslationManager(); $this->controllerResolver = $this->getMock('Drupal\Core\Controller\ControllerResolverInterface'); } @@ -407,3 +410,31 @@ public function titleDescriptionRestrictAccess() { } } + +/** + * Implements a translation manager in tests. + */ +class TestTranslationManager implements TranslationInterface { + + /** + * {@inheritdoc} + */ + public function translate($string, array $args = array(), array $options = array()) { + return new TranslatableString($string, $args, $options, $this); + } + + /** + * {@inheritdoc} + */ + public function translateString(TranslatableString $translated_string) { + return $translated_string->getUntranslatedString(); + } + + /** + * {@inheritdoc} + */ + public function formatPlural($count, $singular, $plural, array $args = array(), array $options = array()) { + return new PluralTranslatableString($count, $singular, $plural, $args, $options, $this); + } + +} diff --git a/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php index 12f201256f90b303d7327d34d2be4a999a668cf3..279bdd49806d685f5a209fa5873d3669f40ae725 100644 --- a/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php +++ b/core/tests/Drupal/Tests/Component/Utility/SafeMarkupTest.php @@ -231,8 +231,6 @@ function providerFormat() { $tests[] = array('Escaped text: @value', array('@value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Escaped text: <span>Safe HTML</span>', 'SafeMarkup::format does not escape an already safe string.', TRUE); $tests[] = array('Placeholder text: %value', array('%value' => '<script>'), 'Placeholder text: <em class="placeholder"><script></em>', 'SafeMarkup::format replaces, escapes and themes string.', TRUE); $tests[] = array('Placeholder text: %value', array('%value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Placeholder text: <em class="placeholder"><span>Safe HTML</span></em>', 'SafeMarkup::format does not escape an already safe string themed as a placeholder.', TRUE); - $tests[] = array('Verbatim text: !value', array('!value' => '<script>'), 'Verbatim text: <script>', 'SafeMarkup::format replaces verbatim string as-is.', FALSE); - $tests[] = array('Verbatim text: !value', array('!value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Verbatim text: <span>Safe HTML</span>', 'SafeMarkup::format replaces verbatim string as-is.', TRUE); $tests['javascript-protocol-url'] = ['Simple text <a href=":url">giraffe</a>', [':url' => 'javascript://example.com?foo&bar'], 'Simple text <a href="//example.com?foo&bar">giraffe</a>', 'Support for filtering bad protocols', TRUE]; $tests['external-url'] = ['Simple text <a href=":url">giraffe</a>', [':url' => 'http://example.com?foo&bar'], 'Simple text <a href="http://example.com?foo&bar">giraffe</a>', 'Support for filtering bad protocols', TRUE]; diff --git a/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php b/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php index f06254c2abbe6601d316f8f43a8ad234f4cc50eb..b0379a18989920d8c6dda7c68bf54731806dcc30 100644 --- a/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php +++ b/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php @@ -66,9 +66,9 @@ public function providerTestGet() { $random_html_entity = '&' . $random; $data[] = array( array( - 'value' => 'Foo !bar @baz %qux', + 'value' => 'Foo @bar @baz %qux', 'arguments' => array( - '!bar' => $random, + '@bar' => $random, '@baz' => $random_html_entity, '%qux' => $random_html_entity, ), diff --git a/core/tests/Drupal/Tests/Core/Extension/RequiredModuleUninstallValidatorTest.php b/core/tests/Drupal/Tests/Core/Extension/RequiredModuleUninstallValidatorTest.php index a5f6fbba7f7a99e49bc69e5dcde4491ae16a3dd8..74ea1ddb8fcbbbfa0a719ac5a3186a46600ca8cf 100644 --- a/core/tests/Drupal/Tests/Core/Extension/RequiredModuleUninstallValidatorTest.php +++ b/core/tests/Drupal/Tests/Core/Extension/RequiredModuleUninstallValidatorTest.php @@ -7,6 +7,7 @@ namespace Drupal\Tests\Core\Extension; +use Drupal\simpletest\AssertHelperTrait; use Drupal\Tests\UnitTestCase; /** @@ -15,6 +16,8 @@ */ class RequiredModuleUninstallValidatorTest extends UnitTestCase { + use AssertHelperTrait; + /** * @var \Drupal\Core\Extension\RequiredModuleUninstallValidator|\PHPUnit_Framework_MockObject_MockObject */ @@ -73,7 +76,7 @@ public function testValidateRequired() { $expected = ["The $module module is required"]; $reasons = $this->uninstallValidator->validate($module); - $this->assertSame($expected, $reasons); + $this->assertSame($expected, $this->castSafeStrings($reasons)); } } diff --git a/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php index 7eaa99dc63664966b770aa8bbd1b4277b0a69600..730437b560af5becf86dfbdd4fffea554bef1ef4 100644 --- a/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php @@ -25,6 +25,9 @@ class TranslationManagerTest extends UnitTestCase { */ protected $translationManager; + /** + * {@inheritdoc} + */ protected function setUp() { $this->translationManager = new TestTranslationManager(); } @@ -35,19 +38,18 @@ protected function setUp() { */ public function providerTestFormatPlural() { return array( - array(1, 'Singular', '@count plural', array(), array(), 'Singular', TRUE), - array(2, 'Singular', '@count plural', array(), array(), '2 plural', TRUE), + [1, 'Singular', '@count plural', array(), array(), 'Singular'], + [2, 'Singular', '@count plural', array(), array(), '2 plural'], // @todo support locale_get_plural - array(2, 'Singular', '@count @arg', array('@arg' => '<script>'), array(), '2 <script>', TRUE), - array(2, 'Singular', '@count %arg', array('%arg' => '<script>'), array(), '2 <em class="placeholder"><script></em>', TRUE), - array(2, 'Singular', '@count !arg', array('!arg' => '<script>'), array(), '2 <script>', FALSE), + [2, 'Singular', '@count @arg', array('@arg' => '<script>'), array(), '2 <script>'], + [2, 'Singular', '@count %arg', array('%arg' => '<script>'), array(), '2 <em class="placeholder"><script></em>'], ); } /** * @dataProvider providerTestFormatPlural */ - public function testFormatPlural($count, $singular, $plural, array $args = array(), array $options = array(), $expected, $safe) { + public function testFormatPlural($count, $singular, $plural, array $args = array(), array $options = array(), $expected) { $translator = $this->getMock('\Drupal\Core\StringTranslation\Translator\TranslatorInterface'); $translator->expects($this->once()) ->method('getStringTranslation') @@ -57,7 +59,7 @@ public function testFormatPlural($count, $singular, $plural, array $args = array $this->translationManager->addTranslator($translator); $result = $this->translationManager->formatPlural($count, $singular, $plural, $args, $options); $this->assertEquals($expected, $result); - $this->assertEquals(SafeMarkup::isSafe($result), $safe); + $this->assertTrue(SafeMarkup::isSafe($result)); } /** @@ -69,20 +71,13 @@ public function testFormatPlural($count, $singular, $plural, array $args = array * An associative array of replacements to make after translation. * @param string $expected_string * The expected translated string value. - * @param bool $returns_translation_wrapper - * Whether we are expecting a TranslatableString object to be returned. * * @dataProvider providerTestTranslatePlaceholder */ - public function testTranslatePlaceholder($string, array $args = array(), $expected_string, $returns_translation_wrapper) { + public function testTranslatePlaceholder($string, array $args = array(), $expected_string) { $actual = $this->translationManager->translate($string, $args); - if ($returns_translation_wrapper) { - $this->assertInstanceOf(SafeStringInterface::class, $actual); - } - else { - $this->assertInternalType('string', $actual); - } - $this->assertEquals($expected_string, $actual); + $this->assertInstanceOf(SafeStringInterface::class, $actual); + $this->assertEquals($expected_string, (string) $actual); } /** @@ -92,10 +87,10 @@ public function testTranslatePlaceholder($string, array $args = array(), $expect */ public function providerTestTranslatePlaceholder() { return [ - ['foo @bar', ['@bar' => 'bar'], 'foo bar', TRUE], - ['bar !baz', ['!baz' => 'baz'], 'bar baz', FALSE], - ['bar @bar !baz', ['@bar' => 'bar', '!baz' => 'baz'], 'bar bar baz', FALSE], - ['bar !baz @bar', ['!baz' => 'baz', '@bar' => 'bar'], 'bar baz bar', FALSE], + ['foo @bar', ['@bar' => 'bar'], 'foo bar'], + ['bar %baz', ['%baz' => 'baz'], 'bar <em class="placeholder">baz</em>'], + ['bar @bar %baz', ['@bar' => 'bar', '%baz' => 'baz'], 'bar bar <em class="placeholder">baz</em>'], + ['bar %baz @bar', ['%baz' => 'baz', '@bar' => 'bar'], 'bar <em class="placeholder">baz</em> bar'], ]; } } diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php index 9d805be233693533c0ee7debc6643ac17e8449b7..5b950d47a9581469f7082c4c9c6e843a77544e29 100644 --- a/core/tests/Drupal/Tests/UnitTestCase.php +++ b/core/tests/Drupal/Tests/UnitTestCase.php @@ -221,10 +221,7 @@ public function getStringTranslationStub() { $translation->expects($this->any()) ->method('translate') ->willReturnCallback(function ($string, array $args = array(), array $options = array()) use ($translation) { - $wrapper = new TranslatableString($string, $args, $options, $translation); - // Pretend everything is not safe. - // @todo https://www.drupal.org/node/2570037 return the wrapper instead. - return (string) $wrapper; + return new TranslatableString($string, $args, $options, $translation); }); $translation->expects($this->any()) ->method('translateString')