diff -u b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php --- b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php @@ -41,24 +41,15 @@ public function translate($string, array $args = array(), array $options = array()); /** - * Translates a string to the current language or to a given language. + * Renders a TranslationWrapper object to a string. * - * @param string $string - * A string containing the English string to translate. - * @param array $args - * An associative array of replacements to make after translation. - * @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. + * @param TranslationWrapper $translated_string + * A TranslationWrapper object. * * @return string * The translated string. - * - * @internal This method is for internal use only. Use ::translate() instead. */ - public function translateToString($string, array $args = array(), array $options = array()); + public function renderTranslatedString(TranslationWrapper $translated_string); /** * Formats a string containing a count of items. diff -u b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php --- b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php @@ -154,22 +154,18 @@ break; } } - return $safe ? new TranslationWrapper($string, $args, $options) : $this->translateToString($string, $args, $options); + $wrapper = new TranslationWrapper($string, $args, $options); + return $safe ? $wrapper : $this->renderTranslatedString($wrapper); } /** * {@inheritdoc} */ - public function translateToString($string, array $args = array(), array $options = array()) { - // Merge in defaults. - if (empty($options['langcode'])) { - $options['langcode'] = $this->defaultLangcode; - } - if (empty($options['context'])) { - $options['context'] = ''; - } - $translation = $this->getStringTranslation($options['langcode'], $string, $options['context']); - $value = $translation === FALSE ? $string : $translation; + public function renderTranslatedString(TranslationWrapper $translated_string) { + $value = $this->doTranslate($translated_string->getUntranslatedString(), $translated_string->getArguments()); + + // Handle any replacements. + $args = $translated_string->getArguments(); if (!empty($args)) { $value = $this->placeholderFormat($value, $args); } @@ -181,11 +177,35 @@ */ public function formatPlural($count, $singular, $plural, array $args = array(), array $options = array()) { $translatable_string = implode(LOCALE_PLURAL_DELIMITER, array($singular, $plural)); - $translated_strings = $this->translateToString($translatable_string, array(), $options); + $translated_strings = $this->doTranslate($translatable_string, $options); return $this->formatPluralTranslated($count, $translated_strings, $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. + */ + protected function doTranslate($string, array $options = array()) { + // Merge in options defaults. + $options = $options + [ + 'langcode' => $this->defaultLangcode, + 'context' => '', + ]; + $translation = $this->getStringTranslation($options['langcode'], $string, $options['context']); + return $translation === FALSE ? $string : $translation; + } + + /** * {@inheritdoc} */ public function formatPluralTranslated($count, $translation, array $args = array(), array $options = array()) { diff -u b/core/lib/Drupal/Core/StringTranslation/TranslationWrapper.php b/core/lib/Drupal/Core/StringTranslation/TranslationWrapper.php --- b/core/lib/Drupal/Core/StringTranslation/TranslationWrapper.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationWrapper.php @@ -99,4 +99,14 @@ /** + * Gets all argments from this translation wrapper. + * + * @return mixed[] + * The array of arguments. + */ + public function getArguments() { + return $this->arguments; + } + + /** * Renders the object as a string. * @@ -107,7 +117,7 @@ if ($this->string === '') { return ''; } - return $this->getStringTranslation()->translateToString($this->string, $this->arguments, $this->options); + return $this->getStringTranslation()->renderTranslatedString($this); } /** diff -u b/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php b/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php --- b/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php +++ b/core/tests/Drupal/Tests/Core/Annotation/TranslationTest.php @@ -45,9 +45,6 @@ $options = isset($values['context']) ? array( 'context' => $values['context'], ) : array(); - $this->translationManager->expects($this->once()) - ->method('translateToString') - ->with($values['value'], $arguments, $options); $annotation = new Translation($values); diff -u b/core/tests/Drupal/Tests/Core/Menu/ContextualLinkDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/ContextualLinkDefaultTest.php --- b/core/tests/Drupal/Tests/Core/Menu/ContextualLinkDefaultTest.php +++ b/core/tests/Drupal/Tests/Core/Menu/ContextualLinkDefaultTest.php @@ -74,8 +74,8 @@ $this->pluginDefinition['title'] = (new TranslationWrapper($title)) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translateToString') - ->with($title, array(), array()) + ->method('renderTranslatedString') + ->with($this->pluginDefinition['title']) ->will($this->returnValue('Example translated')); $this->setupContextualLinkDefault(); @@ -90,8 +90,8 @@ $this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translateToString') - ->with($title, array(), array('context' => 'context')) + ->method('renderTranslatedString') + ->with($this->pluginDefinition['title']) ->will($this->returnValue('Example translated with context')); $this->setupContextualLinkDefault(); @@ -106,8 +106,8 @@ $this->pluginDefinition['title'] = (new TranslationWrapper($title, array('@test' => 'value'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translateToString') - ->with($title, array('@test' => 'value'), array()) + ->method('renderTranslatedString') + ->with($this->pluginDefinition['title']) ->will($this->returnValue('Example value')); $this->setupContextualLinkDefault(); diff -u b/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php --- b/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php +++ b/core/tests/Drupal/Tests/Core/Menu/LocalActionDefaultTest.php @@ -86,8 +86,8 @@ $this->pluginDefinition['title'] = (new TranslationWrapper('Example')) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translateToString') - ->with('Example', array(), array()) + ->method('renderTranslatedString') + ->with($this->pluginDefinition['title']) ->will($this->returnValue('Example translated')); $this->setupLocalActionDefault(); @@ -103,8 +103,8 @@ $this->pluginDefinition['title'] = (new TranslationWrapper('Example', array(), array('context' => 'context'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translateToString') - ->with('Example', array(), array('context' => 'context')) + ->method('renderTranslatedString') + ->with($this->pluginDefinition['title']) ->will($this->returnValue('Example translated with context')); $this->setupLocalActionDefault(); @@ -118,8 +118,8 @@ $this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translateToString') - ->with('Example @test', array('@test' => 'value'), array()) + ->method('renderTranslatedString') + ->with($this->pluginDefinition['title']) ->will($this->returnValue('Example value')); $this->setupLocalActionDefault(); diff -u b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php --- b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php +++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php @@ -236,8 +236,8 @@ $this->pluginDefinition['title'] = (new TranslationWrapper('Example')) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translateToString') - ->with('Example', array(), array()) + ->method('renderTranslatedString') + ->with($this->pluginDefinition['title']) ->will($this->returnValue('Example translated')); $this->setupLocalTaskDefault(); @@ -252,8 +252,8 @@ $this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translateToString') - ->with($title, array(), array('context' => 'context')) + ->method('renderTranslatedString') + ->with($this->pluginDefinition['title']) ->will($this->returnValue('Example translated with context')); $this->setupLocalTaskDefault(); @@ -264,12 +264,11 @@ * @covers ::getTitle */ public function testGetTitleWithTitleArguments() { - $title = 'Example @test'; $this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value'))) ->setStringTranslation($this->stringTranslation); $this->stringTranslation->expects($this->once()) - ->method('translateToString') - ->with($title, array('@test' => 'value'), array()) + ->method('renderTranslatedString') + ->with($this->pluginDefinition['title']) ->will($this->returnValue('Example value')); $this->setupLocalTaskDefault(); diff -u b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php --- b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php @@ -78,7 +78,7 @@ $actual = $this->translationManager->translate($string, $args); if ($returns_translation_wrapper) { $this->assertInstanceOf('Drupal\Component\Utility\SafeStringInterface', $actual); - $actual->setStringTranslation($this->getStringTranslationStub()); + $actual->setStringTranslation($this->translationManager); } else { $this->assertTrue(is_string($actual)); diff -u b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationWrapperTest.php b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationWrapperTest.php --- b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationWrapperTest.php +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationWrapperTest.php @@ -8,6 +8,7 @@ namespace Drupal\Tests\Core\StringTranslation; use Drupal\Core\StringTranslation\TranslationInterface; +use Drupal\Core\StringTranslation\TranslationWrapper; use Drupal\Tests\UnitTestCase; /** @@ -66,7 +67,7 @@ ->willReturn(''); $translation = $this->prophesize(TranslationInterface::class); - $translation->translateToString($string, [], [])->will(function () { + $translation->renderTranslatedString($text)->will(function () { throw new \Exception('Yes you may.'); }); $text->setStringTranslation($translation->reveal()); diff -u b/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php --- b/core/tests/Drupal/Tests/UnitTestCase.php +++ b/core/tests/Drupal/Tests/UnitTestCase.php @@ -13,6 +13,7 @@ use Drupal\Core\Cache\CacheTagsInvalidatorInterface; use Drupal\Core\DependencyInjection\ContainerBuilder; use Drupal\Component\Utility\PlaceholderTrait; +use Drupal\Core\StringTranslation\TranslationWrapper; /** * Provides a base class and helpers for Drupal unit tests. @@ -217,17 +218,22 @@ $translation = $this->getMock('Drupal\Core\StringTranslation\TranslationInterface'); $translation->expects($this->any()) ->method('translate') - ->will($this->returnCallback('Drupal\Component\Utility\SafeMarkup::format')); + ->willReturnCallback(function ($string, array $args = array(), array $options = array()) use ($translation) { + $wrapper = new TranslationWrapper($string, $args, $options); + $wrapper->setStringTranslation($translation); + // Pretend everything is not safe. + return (string) $wrapper; + }); + $translation->expects($this->any()) + ->method('renderTranslatedString') + ->willReturnCallback(function (TranslationWrapper $wrapper) { + return SafeMarkup::format($wrapper->getUntranslatedString(), $wrapper->getArguments()); + }); $translation->expects($this->any()) ->method('formatPlural') ->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 $args = [], array $options = []) { - return $this->placeholderFormat($string, $args); - }); return $translation; }