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 {
* 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);
}
}
......@@ -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);
}
}
......@@ -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;
}
/**
......
......@@ -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()
......
......@@ -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);
}
/**
......
......@@ -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.
......
......@@ -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;
......
......@@ -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));
}
}
......@@ -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);
}
/**
......
......@@ -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));
}
}
......@@ -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));
}
}
......@@ -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));
}
}
......@@ -40,8 +40,6 @@ function testT() {
$this->assertEqual($text, 'Escaped text: &lt;script&gt;', 't replaces and escapes string.');
$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.');
$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() {
'{{ 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">&amp;&quot;&lt;&gt;</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 &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.'
);
......@@ -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."
......
......@@ -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>
......
......@@ -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()]);
}
}
......
......@@ -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);
}
}
......@@ -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">&lt;script&gt;</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&amp;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&amp;bar">giraffe</a>', 'Support for filtering bad protocols', TRUE];
......
......@@ -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,
),
......
......@@ -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));
}
}
......@@ -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 &lt;script&gt;', TRUE),
array(2, 'Singular', '@count %arg', array('%arg' => '<script>'), array(), '2 <em class="placeholder">&lt;script&gt;</em>', TRUE),
array(2, 'Singular', '@count !arg', array('!arg' => '<script>'), array(), '2 <script>', FALSE),
[2, 'Singular', '@count @arg', array('@arg' => '<script>'), array(), '2 &lt;script&gt;'],
[2, 'Singular', '@count %arg', array('%arg' => '<script>'), array(), '2 <em class="placeholder">&lt;script&gt;</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);
}