diff --git a/core/lib/Drupal/Component/Utility/PlaceholderTrait.php b/core/lib/Drupal/Component/Utility/PlaceholderTrait.php new file mode 100644 index 0000000..072393c --- /dev/null +++ b/core/lib/Drupal/Component/Utility/PlaceholderTrait.php @@ -0,0 +1,65 @@ + $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] = '' . $value . ''; + break; + + case '!': + // Pass-through. + if (!SafeMarkup::isSafe($value)) { + $safe = FALSE; + } + } + } + + $output = strtr($string, $args); + return [$output, $safe]; + } + +} diff --git a/core/lib/Drupal/Component/Utility/SafeMarkup.php b/core/lib/Drupal/Component/Utility/SafeMarkup.php index 3020bbe..dc91b41 100644 --- a/core/lib/Drupal/Component/Utility/SafeMarkup.php +++ b/core/lib/Drupal/Component/Utility/SafeMarkup.php @@ -31,6 +31,7 @@ * @see theme_render */ class SafeMarkup { + use PlaceholderTrait; /** * The list of safe strings. @@ -203,41 +204,12 @@ public static function checkPlain($text) { * @see t() */ public static function format($string, array $args) { - $safe = TRUE; - - // 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] = '' . $value . ''; - break; - - case '!': - // Pass-through. - if (!static::isSafe($value)) { - $safe = FALSE; - } - } - } - - $output = strtr($string, $args); + list($output, $safe) = static::placeholderFormat($string, $args); if ($safe) { static::$safeStrings[$output]['html'] = TRUE; } - return $output; + } } diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php index dd3c8f0..9d749fb 100644 --- a/core/lib/Drupal/Core/Entity/EntityManager.php +++ b/core/lib/Drupal/Core/Entity/EntityManager.php @@ -945,9 +945,6 @@ public function getEntityTypeLabels($group = FALSE) { foreach ($definitions as $entity_type_id => $definition) { if ($group) { - // We cast the optgroup label to string as array keys must not be - // objects and t() may return a TranslationWrapper once issue #2557113 - // lands. $options[(string) $definition->getGroupLabel()][$entity_type_id] = $definition->getLabel(); } else { @@ -963,8 +960,6 @@ public function getEntityTypeLabels($group = FALSE) { // Make sure that the 'Content' group is situated at the top. $content = $this->t('Content', array(), array('context' => 'Entity type group')); - // We cast the optgroup label to string as array keys must not be objects - // and t() may return a TranslationWrapper once issue #2557113 lands. $options = array((string) $content => $options[(string) $content]) + $options; } diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php index c3e2f68..b0b04d9 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php @@ -41,6 +41,24 @@ public function translate($string, array $args = array(), array $options = array()); /** + * Translates a string to the current language or to a given language. + * + * @param string $string + * A string containing the English string to translate. + * @param array $options + * An associative array of additional options, with the following elements: + * - 'langcode': The language code to translate to a language other than + * what is used to display the page. + * - 'context': The context the source string belongs to. + * + * @return string + * The translated string. + * + * @internal This method is for internal use only. Use ::translate() instead. + */ + public function translateToString($string, array $options = array()); + + /** * Formats a string containing a count of items. * * This function ensures that the string is pluralized correctly. Since t() is diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php index af6aa2b..fcd3b56 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php @@ -140,38 +140,13 @@ public function getStringTranslation($langcode, $string, $context) { * {@inheritdoc} */ public function translate($string, array $args = array(), array $options = array()) { - $string = $this->doTranslate($string, $options); - if (empty($args)) { - // We add the string to the safe list as opposed to making it an object - // implementing SafeStringInterface as we may need to call __toString() - // on the object before render time, at which point the string ceases to - // be safe, and working around this would require significant rework. - // Adding this string to the safe list is assumed to be safe because - // translate() should only be called with strings defined in code. - // @see \Drupal\Core\StringTranslation\TranslationInterface::translate() - SafeMarkup::setMultiple([$string => ['html' => TRUE]]); - return $string; - } - else { - return SafeMarkup::format($string, $args); - } + return new TranslationWrapper($string, $args, $options); } /** - * Translates a string to the current language or to a given language. - * - * @param string $string - * A string containing the English string to translate. - * @param array $options - * An associative array of additional options, with the following elements: - * - 'langcode': The language code to translate to a language other than - * what is used to display the page. - * - 'context': The context the source string belongs to. - * - * @return string - * The translated string. + * {@inheritdoc} */ - protected function doTranslate($string, array $options = array()) { + public function translateToString($string, array $options = array()) { // Merge in defaults. if (empty($options['langcode'])) { $options['langcode'] = $this->defaultLangcode; @@ -188,7 +163,7 @@ protected function doTranslate($string, array $options = array()) { */ public function formatPlural($count, $singular, $plural, array $args = array(), array $options = array()) { $translatable_string = implode(LOCALE_PLURAL_DELIMITER, array($singular, $plural)); - $translated_strings = $this->doTranslate($translatable_string, $options); + $translated_strings = $this->translateToString($translatable_string, $options); return $this->formatPluralTranslated($count, $translated_strings, $args, $options); } diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationWrapper.php b/core/lib/Drupal/Core/StringTranslation/TranslationWrapper.php index 10e9b12..536778c 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationWrapper.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationWrapper.php @@ -7,8 +7,11 @@ namespace Drupal\Core\StringTranslation; +use Drupal\Component\Utility\Html; +use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\SafeStringInterface; use Drupal\Component\Utility\ToStringTrait; +use Drupal\Component\Utility\PlaceholderTrait; /** * Provides a class to wrap a translatable string. @@ -21,6 +24,7 @@ */ class TranslationWrapper implements SafeStringInterface { + use PlaceholderTrait; use StringTranslationTrait; use ToStringTrait; @@ -103,7 +107,12 @@ public function getOptions() { * The translated string. */ public function render() { - return $this->t($this->string, $this->arguments, $this->options); + $string = $this->getStringTranslation()->translateToString($this->string, $this->options); + if (!empty($this->arguments)) { + list($string, $safe) = static::placeholderFormat($string, $this->arguments); + // @todo make sure the output from placeholderFormat() is always safe + } + return $string; } /** @@ -123,5 +132,4 @@ public function jsonSerialize() { return $this->__toString(); } - } diff --git a/core/lib/Drupal/Core/Template/Attribute.php b/core/lib/Drupal/Core/Template/Attribute.php index cc0d591..76d7c6a 100644 --- a/core/lib/Drupal/Core/Template/Attribute.php +++ b/core/lib/Drupal/Core/Template/Attribute.php @@ -109,7 +109,8 @@ protected function createAttributeValue($name, $value) { elseif (is_bool($value)) { $value = new AttributeBoolean($name, $value); } - elseif (!is_object($value)) { + // As a development aid, we allow the value to be a safe string object. + elseif (!is_object($value) || $value instanceof SafeStringInterface) { $value = new AttributeString($name, $value); } return $value; diff --git a/core/lib/Drupal/Core/Validation/DrupalTranslator.php b/core/lib/Drupal/Core/Validation/DrupalTranslator.php index a2bbf5b..dfbef68 100644 --- a/core/lib/Drupal/Core/Validation/DrupalTranslator.php +++ b/core/lib/Drupal/Core/Validation/DrupalTranslator.php @@ -7,6 +7,8 @@ namespace Drupal\Core\Validation; +use Drupal\Component\Utility\SafeStringInterface; + /** * Translates strings using Drupal's translation system. * @@ -73,8 +75,13 @@ public function getLocale() { protected function processParameters(array $parameters) { $return = array(); foreach ($parameters as $key => $value) { + // We allow the values in the parameters to be safe string objects. This can be + // useful when we want to use parameter values that are TranslationWrappers. + if ($value instanceof SafeStringInterface) { + $value = (string) $value; + } if (is_object($value)) { - // t() does not work will objects being passed as replacement strings. + // t() does not work with objects being passed as replacement strings. } // Check for symfony replacement patterns in the form "{{ name }}". elseif (strpos($key, '{{ ') === 0 && strrpos($key, ' }}') == strlen($key) - 3) { diff --git a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php index d873820..6fa8771 100644 --- a/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php +++ b/core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidator.php @@ -16,6 +16,7 @@ use Drupal\Core\TypedData\Type\StringInterface; use Drupal\Core\TypedData\Type\UriInterface; use Drupal\Core\TypedData\Validation\TypedDataAwareValidatorTrait; +use Drupal\Component\Utility\SafeStringInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; @@ -49,7 +50,7 @@ public function validate($value, Constraint $constraint) { if ($typed_data instanceof IntegerInterface && filter_var($value, FILTER_VALIDATE_INT) === FALSE) { $valid = FALSE; } - if ($typed_data instanceof StringInterface && !is_scalar($value)) { + if ($typed_data instanceof StringInterface && !is_scalar($value) && !($value instanceof SafeStringInterface)) { $valid = FALSE; } // Ensure that URIs comply with http://tools.ietf.org/html/rfc3986, which diff --git a/core/modules/ckeditor/ckeditor.admin.inc b/core/modules/ckeditor/ckeditor.admin.inc index d5bb690..9120763 100644 --- a/core/modules/ckeditor/ckeditor.admin.inc +++ b/core/modules/ckeditor/ckeditor.admin.inc @@ -117,8 +117,6 @@ function template_preprocess_ckeditor_settings_toolbar(&$variables) { $variables['active_buttons'] = array(); foreach ($active_buttons as $row_number => $button_row) { foreach ($button_groups[$row_number] as $group_name) { - // We cast the group name to string as array keys must not be objects - // and t() may return a TranslationWrapper once issue #2557113 lands. $group_name = (string) $group_name; $variables['active_buttons'][$row_number][$group_name] = array( 'group_name_class' => Html::getClass($group_name), diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 596542f..4720e36 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -299,8 +299,6 @@ function comment_form_field_ui_field_storage_add_form_alter(&$form, FormStateInt $form['#title'] = \Drupal::service('comment.manager')->getFieldUIPageTitle($route_match->getParameter('commented_entity_type'), $route_match->getParameter('field_name')); } if (!_comment_entity_uses_integer_id($form_state->get('entity_type_id'))) { - // We cast the optgroup label to string as array keys must not be objects - // and t() will return a TranslationWrapper once issue #2557113 lands. $optgroup = (string) t('General'); // You cannot use comment fields on entity types with non-integer IDs. unset($form['add']['new_storage_type']['#options'][$optgroup]['comment']); diff --git a/core/modules/entity_reference/entity_reference.module b/core/modules/entity_reference/entity_reference.module index 908e0e5..ae4cc03 100644 --- a/core/modules/entity_reference/entity_reference.module +++ b/core/modules/entity_reference/entity_reference.module @@ -126,8 +126,6 @@ function entity_reference_field_config_presave(FieldConfigInterface $field) { * Implements hook_form_FORM_ID_alter() for 'field_ui_field_storage_add_form'. */ function entity_reference_form_field_ui_field_storage_add_form_alter(array &$form) { - // We cast the optgroup label to string as array keys must not be objects - // and t() may return a TranslationWrapper once issue #2557113 lands. $optgroup = (string) t('Reference'); // Move the "Entity reference" option to the end of the list and rename it to // "Other". diff --git a/core/modules/language/src/Form/NegotiationBrowserForm.php b/core/modules/language/src/Form/NegotiationBrowserForm.php index 111f35a..5fa186a 100644 --- a/core/modules/language/src/Form/NegotiationBrowserForm.php +++ b/core/modules/language/src/Form/NegotiationBrowserForm.php @@ -82,8 +82,6 @@ public function buildForm(array $form, FormStateInterface $form_state) { } else { $language_options = array( - // We cast the optgroup labels to string as array keys must not be objects - // and t() may return a TranslationWrapper once issue #2557113 lands. (string) $this->t('Existing languages') => $existing_languages, (string) $this->t('Languages not yet added') => $this->languageManager->getStandardLanguageListWithoutConfigured(), ); diff --git a/core/modules/locale/src/Form/ImportForm.php b/core/modules/locale/src/Form/ImportForm.php index 86aecc3..f3007f6 100644 --- a/core/modules/locale/src/Form/ImportForm.php +++ b/core/modules/locale/src/Form/ImportForm.php @@ -94,8 +94,6 @@ public function buildForm(array $form, FormStateInterface $form_state) { else { $default = key($existing_languages); $language_options = array( - // We cast the optgroup labels to string as array keys must not be objects - // and t() may return a TranslationWrapper once issue #2557113 lands. (string) $this->t('Existing languages') => $existing_languages, (string) $this->t('Languages not yet added') => $this->languageManager->getStandardLanguageListWithoutConfigured(), ); diff --git a/core/modules/locale/src/Tests/LocaleImportFunctionalTest.php b/core/modules/locale/src/Tests/LocaleImportFunctionalTest.php index 05af294..02e364b 100644 --- a/core/modules/locale/src/Tests/LocaleImportFunctionalTest.php +++ b/core/modules/locale/src/Tests/LocaleImportFunctionalTest.php @@ -238,8 +238,10 @@ public function testLanguageContext() { 'langcode' => 'hr', )); - $this->assertIdentical(t('May', array(), array('langcode' => 'hr', 'context' => 'Long month name')), 'Svibanj', 'Long month name context is working.'); - $this->assertIdentical(t('May', array(), array('langcode' => 'hr')), 'Svi.', 'Default context is working.'); + // We cast the return value of t() to string so as to retrieve the translated + // value, rendered as a string. + $this->assertIdentical((string) t('May', array(), array('langcode' => 'hr', 'context' => 'Long month name')), 'Svibanj', 'Long month name context is working.'); + $this->assertIdentical((string) t('May', array(), array('langcode' => 'hr')), 'Svi.', 'Default context is working.'); } /** @@ -254,7 +256,7 @@ public function testEmptyMsgstr() { )); $this->assertRaw(t('One translation file imported. %number translations were added, %update translations were updated and %delete translations were removed.', array('%number' => 1, '%update' => 0, '%delete' => 0)), 'The translation file was successfully imported.'); - $this->assertIdentical(t('Operations', array(), array('langcode' => $langcode)), 'Műveletek', 'String imported and translated.'); + $this->assertIdentical((string) t('Operations', array(), array('langcode' => $langcode)), 'Műveletek', 'String imported and translated.'); // Try importing a .po file. $this->importPoFile($this->getPoFileWithEmptyMsgstr(), array( diff --git a/core/modules/locale/src/Tests/LocaleTranslationUiTest.php b/core/modules/locale/src/Tests/LocaleTranslationUiTest.php index 6c35b18..a708311 100644 --- a/core/modules/locale/src/Tests/LocaleTranslationUiTest.php +++ b/core/modules/locale/src/Tests/LocaleTranslationUiTest.php @@ -64,7 +64,7 @@ public function testStringTranslation() { ); $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language')); // Add string. - t($name, array(), array('langcode' => $langcode)); + (string) t($name, array(), array('langcode' => $langcode)); // Reset locale cache. $this->container->get('string_translation')->reset(); $this->assertRaw('"edit-languages-' . $langcode . '-weight"', 'Language code found.'); @@ -302,7 +302,7 @@ public function testStringValidation() { ); $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language')); // Add string. - t($name, array(), array('langcode' => $langcode)); + (string) t($name, array(), array('langcode' => $langcode)); // Reset locale cache. $search = array( 'string' => $name, @@ -361,7 +361,7 @@ public function testStringSearch() { $this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language')); // Add string. - t($name, array(), array('langcode' => $langcode)); + (string) t($name, array(), array('langcode' => $langcode)); // Reset locale cache. $this->container->get('string_translation')->reset(); $this->drupalLogout(); diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php index 62e4c9f..285865b 100644 --- a/core/modules/simpletest/src/TestBase.php +++ b/core/modules/simpletest/src/TestBase.php @@ -658,10 +658,6 @@ protected function assertNotNull($value, $message = '', $group = 'Other') { * TRUE if the assertion succeeded, FALSE otherwise. */ protected function assertEqual($first, $second, $message = '', $group = 'Other') { - // We cast objects implementing SafeStringInterface to string ourself so as - // to not rely on PHP casting them to string depending on what we're - // comparing with. - $this->castSafeStrings($first, $second); return $this->assert($first == $second, $message ? $message : SafeMarkup::format('Value @first is equal to value @second.', array('@first' => var_export($first, TRUE), '@second' => var_export($second, TRUE))), $group); } diff --git a/core/modules/system/src/Tests/Form/FormTest.php b/core/modules/system/src/Tests/Form/FormTest.php index e89b78f..b02cbdc 100644 --- a/core/modules/system/src/Tests/Form/FormTest.php +++ b/core/modules/system/src/Tests/Form/FormTest.php @@ -144,7 +144,7 @@ function testRequiredFields() { // Select elements are going to have validation errors with empty // input, since those are illegal choices. Just make sure the // error is not "field is required". - $this->assertTrue((empty($errors[$element]) || strpos('field is required', $errors[$element]) === FALSE), "Optional '$type' field '$element' is not treated as a required element"); + $this->assertTrue((empty($errors[$element]) || strpos('field is required', (string) $errors[$element]) === FALSE), "Optional '$type' field '$element' is not treated as a required element"); } else { // Make sure there is *no* form error for this element. diff --git a/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php b/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php index e435c0a..df66b7f 100644 --- a/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php +++ b/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php @@ -78,7 +78,7 @@ public function __construct() { 'label' => t('User name'), 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserNameBlock', 'context' => array( - 'user' => new ContextDefinition('entity:user', t('User')), + 'user' => $this->createContextDefinitionWithStringLabel('entity:user', t('User')), ), )); @@ -87,7 +87,7 @@ public function __construct() { 'label' => t('User name optional'), 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserNameBlock', 'context' => array( - 'user' => new ContextDefinition('entity:user', t('User'), FALSE), + 'user' => $this->createContextDefinitionWithStringLabel('entity:user', t('User'), FALSE), ), )); @@ -102,8 +102,8 @@ public function __construct() { 'label' => t('Complex context'), 'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockComplexContextBlock', 'context' => array( - 'user' => new ContextDefinition('entity:user', t('User')), - 'node' => new ContextDefinition('entity:node', t('Node')), + 'user' => $this->createContextDefinitionWithStringLabel('entity:user', t('User')), + 'node' => $this->createContextDefinitionWithStringLabel('entity:node', t('Node')), ), )); @@ -118,4 +118,17 @@ public function __construct() { // specified), so we provide it the discovery object. $this->factory = new ReflectionFactory($this->discovery); } + + /** + * Creates a new context definition with a label that is cast to string. + * + * @return \Drupal\Core\Plugin\Context\ContextDefinition + */ + protected function createContextDefinitionWithStringLabel($data_type, $label, $required = TRUE) { + // We cast the label to string for testing purposes only, as it may be + // a TranslationWrapper and we will do assertEqual() checks on arrays that + // include ContextDefinition objects, and var_export() has problems + // printing TranslationWrapper objects. + return new ContextDefinition($data_type, (string) $label, $required); + } } diff --git a/core/modules/user/src/Tests/UserCancelTest.php b/core/modules/user/src/Tests/UserCancelTest.php index 5357013..648f56f 100644 --- a/core/modules/user/src/Tests/UserCancelTest.php +++ b/core/modules/user/src/Tests/UserCancelTest.php @@ -535,7 +535,7 @@ function testMassUserCancelByAdmin() { $this->drupalPostForm(NULL, NULL, t('Cancel accounts')); $status = TRUE; foreach ($users as $account) { - $status = $status && (strpos($this->content, t('%name has been deleted.', array('%name' => $account->getUsername()))) !== FALSE); + $status = $status && (strpos($this->content, $account->getUsername() . ' has been deleted.') !== FALSE); $user_storage->resetCache(array($account->id())); $status = $status && !$user_storage->load($account->id()); } diff --git a/core/modules/views/src/Plugin/views/PluginBase.php b/core/modules/views/src/Plugin/views/PluginBase.php index 49b7f1d..66661df 100644 --- a/core/modules/views/src/Plugin/views/PluginBase.php +++ b/core/modules/views/src/Plugin/views/PluginBase.php @@ -15,6 +15,7 @@ use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Plugin\PluginBase as ComponentPluginBase; use Drupal\Core\Render\Element; +use Drupal\Core\StringTranslation\TranslationWrapper; use Drupal\views\Plugin\views\display\DisplayPluginBase; use Drupal\views\ViewExecutable; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -552,7 +553,14 @@ protected function listLanguages($flags = LanguageInterface::STATE_ALL, array $c // Since this is not a real language, surround it by '***LANGUAGE_...***', // like the negotiated languages below. if ($flags & LanguageInterface::STATE_SITE_DEFAULT) { - $list[PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT] = $this->t($languages[LanguageInterface::LANGCODE_SITE_DEFAULT]->getName()); + $name = $languages[LanguageInterface::LANGCODE_SITE_DEFAULT]->getName(); + // The language name may have already been translated, no need to + // translate it again. + // @see Drupal\Core\Language::filterLanguages(). + if (!$name instanceof TranslationWrapper) { + $name = $this->t($name); + } + $list[PluginBase::VIEWS_QUERY_LANGUAGE_SITE_DEFAULT] = $name; // Remove site default language from $languages so it's not added // twice with the real languages below. unset($languages[LanguageInterface::LANGCODE_SITE_DEFAULT]); diff --git a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php index 7c26932..75d6529 100644 --- a/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php +++ b/core/modules/views/src/Plugin/views/area/TokenizeAreaPluginBase.php @@ -52,8 +52,6 @@ public function tokenForm(&$form, FormStateInterface $form_state) { // Get a list of the available fields and arguments for token replacement. $options = array(); - // We cast the optgroup labels to string as array keys must not be objects - // and t() may return a TranslationWrapper once issue #2557113 lands. $optgroup_arguments = (string) t('Arguments'); $optgroup_fields = (string) t('Fields'); foreach ($this->view->display_handler->getHandlers('field') as $field => $handler) { diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php index 4ed8f55..1d089c8 100644 --- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php +++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php @@ -1726,9 +1726,6 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { $options = array(); $count = 0; // This lets us prepare the key as we want it printed. - // We cast the optgroup label to string as array keys must not be - // objects and t() may return a TranslationWrapper once issue #2557113 - // lands. $optgroup_arguments = (string) t('Arguments'); foreach ($this->view->display_handler->getHandlers('argument') as $handler) { $options[$optgroup_arguments]['%' . ++$count] = $this->t('@argument title', array('@argument' => $handler->adminLabel())); diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php index baa11ab..e22cab3 100644 --- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php +++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php @@ -862,8 +862,6 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { // Setup the tokens for fields. $previous = $this->getPreviousFieldLabels(); - // We cast the optgroup labels to string as array keys must not be objects - // and t() may return a TranslationWrapper once issue #2557113 lands. $optgroup_arguments = (string) t('Arguments'); $optgroup_fields = (string) t('Fields'); foreach ($previous as $id => $label) { diff --git a/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php b/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php index be8cca3..f9dfc4f 100644 --- a/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php +++ b/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php @@ -46,8 +46,8 @@ public function testGet(array $values, $expected) { 'context' => $values['context'], ) : array(); $this->translationManager->expects($this->once()) - ->method('translate') - ->with($values['value'], $arguments, $options); + ->method('translateToString') + ->with($values['value'], $options); $annotation = new Translation($values); diff --git a/core/tests/Drupal/Tests/Core/Menu/ContextualLinkDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/ContextualLinkDefaultTest.php index ac92088..837ed8b 100644 --- a/core/tests/Drupal/Tests/Core/Menu/ContextualLinkDefaultTest.php +++ b/core/tests/Drupal/Tests/Core/Menu/ContextualLinkDefaultTest.php @@ -74,8 +74,8 @@ public function testGetTitle() { $this->pluginDefinition['title'] = (new TranslationWrapper($title)) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translate') - ->with($title, array(), array()) + ->method('translateToString') + ->with($title, array()) ->will($this->returnValue('Example translated')); $this->setupContextualLinkDefault(); @@ -90,8 +90,8 @@ public function testGetTitleWithContext() { $this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translate') - ->with($title, array(), array('context' => 'context')) + ->method('translateToString') + ->with($title, array('context' => 'context')) ->will($this->returnValue('Example translated with context')); $this->setupContextualLinkDefault(); @@ -106,8 +106,8 @@ public function testGetTitleWithTitleArguments() { $this->pluginDefinition['title'] = (new TranslationWrapper($title, array('@test' => 'value'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translate') - ->with($title, array('@test' => 'value'), array()) + ->method('translateToString') + ->with($title, array()) ->will($this->returnValue('Example value')); $this->setupContextualLinkDefault(); diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php index 02d4578..52d49e4 100644 --- a/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php +++ b/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php @@ -86,8 +86,8 @@ public function testGetTitle() { $this->pluginDefinition['title'] = (new TranslationWrapper('Example')) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translate') - ->with('Example', array(), array()) + ->method('translateToString') + ->with('Example', array()) ->will($this->returnValue('Example translated')); $this->setupLocalActionDefault(); @@ -103,8 +103,8 @@ public function testGetTitleWithContext() { $this->pluginDefinition['title'] = (new TranslationWrapper('Example', array(), array('context' => 'context'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translate') - ->with('Example', array(), array('context' => 'context')) + ->method('translateToString') + ->with('Example', array('context' => 'context')) ->will($this->returnValue('Example translated with context')); $this->setupLocalActionDefault(); @@ -118,8 +118,8 @@ public function testGetTitleWithTitleArguments() { $this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translate') - ->with('Example @test', array('@test' => 'value'), array()) + ->method('translateToString') + ->with('Example @test', array()) ->will($this->returnValue('Example value')); $this->setupLocalActionDefault(); diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php index 6e393a8..59732ff 100644 --- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php +++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php @@ -236,8 +236,8 @@ public function testGetTitle() { $this->pluginDefinition['title'] = (new TranslationWrapper('Example')) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translate') - ->with('Example', array(), array()) + ->method('translateToString') + ->with('Example', array()) ->will($this->returnValue('Example translated')); $this->setupLocalTaskDefault(); @@ -252,8 +252,8 @@ public function testGetTitleWithContext() { $this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translate') - ->with($title, array(), array('context' => 'context')) + ->method('translateToString') + ->with($title, array('context' => 'context')) ->will($this->returnValue('Example translated with context')); $this->setupLocalTaskDefault(); @@ -268,8 +268,8 @@ public function testGetTitleWithTitleArguments() { $this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translate') - ->with($title, array('@test' => 'value'), array()) + ->method('translateToString') + ->with($title, array()) ->will($this->returnValue('Example value')); $this->setupLocalTaskDefault(); diff --git a/core/tests/Drupal/Tests/Core/StringTranslation/TranslationWrapperTest.php b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationWrapperTest.php index 3facf38..7b051cd 100644 --- a/core/tests/Drupal/Tests/Core/StringTranslation/TranslationWrapperTest.php +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationWrapperTest.php @@ -66,7 +66,7 @@ public function testToString() { ->willReturn(''); $translation = $this->prophesize(TranslationInterface::class); - $translation->translate($string, [], [])->will(function () { + $translation->translateToString($string, [])->will(function () { throw new \Exception('Yes you may.'); }); $text->setStringTranslation($translation->reveal()); diff --git a/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php b/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php index 2bcb318..0707fa3 100644 --- a/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php +++ b/core/tests/Drupal/Tests/Core/Validation/Plugin/Validation/Constraint/PrimitiveTypeConstraintValidatorTest.php @@ -16,6 +16,7 @@ use Drupal\Core\TypedData\PrimitiveInterface; use Drupal\Core\Validation\Plugin\Validation\Constraint\PrimitiveTypeConstraint; use Drupal\Core\Validation\Plugin\Validation\Constraint\PrimitiveTypeConstraintValidator; +use Drupal\Core\StringTranslation\TranslationWrapper; use Drupal\Tests\UnitTestCase; /** @@ -63,6 +64,7 @@ public function provideTestValidate() { $data[] = [new IntegerData(DataDefinition::create('integer')), 1.5, FALSE]; $data[] = [new IntegerData(DataDefinition::create('integer')), 'test', FALSE]; $data[] = [new StringData(DataDefinition::create('string')), 'test', TRUE]; + $data[] = [new StringData(DataDefinition::create('string')), new TranslationWrapper('test'), TRUE]; // It is odd that 1 is a valid string. // $data[] = [$this->getMock('Drupal\Core\TypedData\Type\StringInterface'), 1, FALSE]; $data[] = [new StringData(DataDefinition::create('string')), [], FALSE]; diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php index 3433c94..11dd14d 100644 --- a/core/tests/Drupal/Tests/UnitTestCase.php +++ b/core/tests/Drupal/Tests/UnitTestCase.php @@ -220,6 +220,11 @@ public function getStringTranslationStub() { ->willReturnCallback(function ($count, $singular, $plural, array $args = [], array $options = []) { return $count === 1 ? SafeMarkup::format($singular, $args) : SafeMarkup::format($plural, $args + ['@count' => $count]); }); + $translation->expects($this->any()) + ->method('translateToString') + ->willReturnCallback(function ($string, array $options = []) { + return $string; + }); return $translation; }