Issue #2557113 by stefan.r, alexpott, dawehner, joelpittet, cilefen, lauriii, plach, catch, chx, xjm: Make t() return a TranslationWrapper object to remove reliance on a static, unpredictable safe list
parent
cead42ce15
commit
e7a7de9f8c
|
@ -13,6 +13,7 @@ use Drupal\Component\Utility\Unicode;
|
|||
use Drupal\Core\DrupalKernel;
|
||||
use Drupal\Core\Extension\ExtensionDiscovery;
|
||||
use Drupal\Core\Logger\RfcLogLevel;
|
||||
use Drupal\Core\Render\SafeString;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\Core\Utility\Error;
|
||||
|
@ -490,9 +491,9 @@ function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE)
|
|||
$_SESSION['messages'][$type] = array();
|
||||
}
|
||||
|
||||
// Convert strings which are in the safe markup list to SafeString objects.
|
||||
if (is_string($message) && SafeMarkup::isSafe($message)) {
|
||||
$message = \Drupal\Core\Render\SafeString::create($message);
|
||||
// Convert strings which are safe to the simplest SafeString objects.
|
||||
if (!($message instanceof SafeString) && SafeMarkup::isSafe($message)) {
|
||||
$message = SafeString::create((string) $message);
|
||||
}
|
||||
|
||||
// Do not use strict type checking so that equivalent string and
|
||||
|
|
|
@ -25,6 +25,7 @@ use Drupal\Core\Language\LanguageInterface;
|
|||
use Drupal\Core\Render\SafeString;
|
||||
use Drupal\Core\Render\Renderer;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||
use Drupal\Core\Url;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -260,7 +261,7 @@ function check_url($uri) {
|
|||
* Optional language code to translate to a language other than what is used
|
||||
* to display the page.
|
||||
*
|
||||
* @return
|
||||
* @return \Drupal\Core\StringTranslation\TranslationWrapper
|
||||
* A translated string representation of the size.
|
||||
*/
|
||||
function format_size($size, $langcode = NULL) {
|
||||
|
@ -269,16 +270,7 @@ function format_size($size, $langcode = NULL) {
|
|||
}
|
||||
else {
|
||||
$size = $size / Bytes::KILOBYTE; // Convert bytes to kilobytes.
|
||||
$units = array(
|
||||
t('@size KB', array(), array('langcode' => $langcode)),
|
||||
t('@size MB', array(), array('langcode' => $langcode)),
|
||||
t('@size GB', array(), array('langcode' => $langcode)),
|
||||
t('@size TB', array(), array('langcode' => $langcode)),
|
||||
t('@size PB', array(), array('langcode' => $langcode)),
|
||||
t('@size EB', array(), array('langcode' => $langcode)),
|
||||
t('@size ZB', array(), array('langcode' => $langcode)),
|
||||
t('@size YB', array(), array('langcode' => $langcode)),
|
||||
);
|
||||
$units = ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
foreach ($units as $unit) {
|
||||
if (round($size, 2) >= Bytes::KILOBYTE) {
|
||||
$size = $size / Bytes::KILOBYTE;
|
||||
|
@ -287,7 +279,26 @@ function format_size($size, $langcode = NULL) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
return str_replace('@size', round($size, 2), $unit);
|
||||
$args = ['@size' => round($size, 2)];
|
||||
$options = ['langcode' => $langcode];
|
||||
switch ($unit) {
|
||||
case 'KB':
|
||||
return new TranslationWrapper('@size KB', $args, $options);
|
||||
case 'MB':
|
||||
return new TranslationWrapper('@size MB', $args, $options);
|
||||
case 'GB':
|
||||
return new TranslationWrapper('@size GB', $args, $options);
|
||||
case 'TB':
|
||||
return new TranslationWrapper('@size TB', $args, $options);
|
||||
case 'PB':
|
||||
return new TranslationWrapper('@size PB', $args, $options);
|
||||
case 'EB':
|
||||
return new TranslationWrapper('@size EB', $args, $options);
|
||||
case 'ZB':
|
||||
return new TranslationWrapper('@size ZB', $args, $options);
|
||||
case 'YB':
|
||||
return new TranslationWrapper('@size YB', $args, $options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ class PoItem {
|
|||
strpos($this->_source, LOCALE_PLURAL_DELIMITER) !== FALSE) {
|
||||
$this->setSource(explode(LOCALE_PLURAL_DELIMITER, $this->_source));
|
||||
$this->setTranslation(explode(LOCALE_PLURAL_DELIMITER, $this->_translation));
|
||||
$this->setPlural(count($this->_translation) > 1);
|
||||
$this->setPlural(count($this->_source) > 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Component\Utility\PlaceholderTrait.
|
||||
*/
|
||||
|
||||
namespace Drupal\Component\Utility;
|
||||
|
||||
/**
|
||||
* Offers functionality for formatting strings using placeholders.
|
||||
*/
|
||||
trait PlaceholderTrait {
|
||||
|
||||
/**
|
||||
* Formats a string by replacing variable placeholders.
|
||||
*
|
||||
* @param string $string
|
||||
* A string containing placeholders.
|
||||
* @param array $args
|
||||
* An associative array of replacements to make.
|
||||
* @param bool &$safe
|
||||
* A boolean indicating whether the string is safe or not (optional).
|
||||
*
|
||||
* @return string
|
||||
* The string with the placeholders replaced.
|
||||
*
|
||||
* @see \Drupal\Component\Utility\SafeMarkup::format()
|
||||
* @see \Drupal\Core\StringTranslation\TranslationWrapper::render()
|
||||
*/
|
||||
protected static function placeholderFormat($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] = '<em class="placeholder">' . $value . '</em>';
|
||||
break;
|
||||
|
||||
case '!':
|
||||
// Pass-through.
|
||||
if (!SafeMarkup::isSafe($value)) {
|
||||
$safe = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return strtr($string, $args);
|
||||
}
|
||||
|
||||
}
|
|
@ -31,6 +31,7 @@ namespace Drupal\Component\Utility;
|
|||
* @see theme_render
|
||||
*/
|
||||
class SafeMarkup {
|
||||
use PlaceholderTrait;
|
||||
|
||||
/**
|
||||
* The list of safe strings.
|
||||
|
@ -204,40 +205,12 @@ class SafeMarkup {
|
|||
*/
|
||||
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] = '<em class="placeholder">' . $value . '</em>';
|
||||
break;
|
||||
|
||||
case '!':
|
||||
// Pass-through.
|
||||
if (!static::isSafe($value)) {
|
||||
$safe = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output = strtr($string, $args);
|
||||
$output = static::placeholderFormat($string, $args, $safe);
|
||||
if ($safe) {
|
||||
static::$safeStrings[$output]['html'] = TRUE;
|
||||
}
|
||||
|
||||
return $output;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -945,9 +945,6 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
|
||||
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 @@ class EntityManager extends DefaultPluginManager implements EntityManagerInterfa
|
|||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,13 +33,24 @@ interface TranslationInterface {
|
|||
* what is used to display the page.
|
||||
* - 'context': The context the source string belongs to.
|
||||
*
|
||||
* @return string
|
||||
* @return string|\Drupal\Core\StringTranslation\TranslationWrapper
|
||||
* The translated string.
|
||||
*
|
||||
* @see \Drupal\Component\Utility\SafeMarkup::format()
|
||||
*/
|
||||
public function translate($string, array $args = array(), array $options = array());
|
||||
|
||||
/**
|
||||
* Translates a TranslationWrapper object to a string.
|
||||
*
|
||||
* @param \Drupal\Core\StringTranslation\TranslationWrapper $translated_string
|
||||
* A TranslationWrapper object.
|
||||
*
|
||||
* @return string
|
||||
* The translated string.
|
||||
*/
|
||||
public function translateString(TranslationWrapper $translated_string);
|
||||
|
||||
/**
|
||||
* Formats a string containing a count of items.
|
||||
*
|
||||
|
|
|
@ -140,21 +140,27 @@ class TranslationManager implements TranslationInterface, TranslatorInterface {
|
|||
* {@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);
|
||||
$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 TranslationWrapper($string, $args, $options, $this);
|
||||
return $safe ? $wrapper : (string) $wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function translateString(TranslationWrapper $translated_string) {
|
||||
return $this->doTranslate($translated_string->getUntranslatedString(), $translated_string->getOptions());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -172,13 +178,11 @@ class TranslationManager implements TranslationInterface, TranslatorInterface {
|
|||
* The translated string.
|
||||
*/
|
||||
protected function doTranslate($string, array $options = array()) {
|
||||
// Merge in defaults.
|
||||
if (empty($options['langcode'])) {
|
||||
$options['langcode'] = $this->defaultLangcode;
|
||||
}
|
||||
if (empty($options['context'])) {
|
||||
$options['context'] = '';
|
||||
}
|
||||
// Merge in options defaults.
|
||||
$options = $options + [
|
||||
'langcode' => $this->defaultLangcode,
|
||||
'context' => '',
|
||||
];
|
||||
$translation = $this->getStringTranslation($options['langcode'], $string, $options['context']);
|
||||
return $translation === FALSE ? $string : $translation;
|
||||
}
|
||||
|
|
|
@ -7,21 +7,25 @@
|
|||
|
||||
namespace Drupal\Core\StringTranslation;
|
||||
|
||||
use Drupal\Component\Utility\PlaceholderTrait;
|
||||
use Drupal\Component\Utility\SafeStringInterface;
|
||||
use Drupal\Component\Utility\ToStringTrait;
|
||||
|
||||
/**
|
||||
* Provides a class to wrap a translatable string.
|
||||
* Provides translatable string class.
|
||||
*
|
||||
* This class can be used to delay translating strings until the translation
|
||||
* system is ready. This is useful for using translation in very low level
|
||||
* subsystems like entity definition and stream wrappers.
|
||||
* This class delays translating strings until rendering them.
|
||||
*
|
||||
* This is useful for using translation in very low level subsystems like entity
|
||||
* definition and stream wrappers.
|
||||
*
|
||||
* @see \Drupal\Core\StringTranslation\TranslationManager::translate()
|
||||
* @see \Drupal\Core\StringTranslation\TranslationManager::translateString()
|
||||
* @see \Drupal\Core\Annotation\Translation
|
||||
*/
|
||||
class TranslationWrapper implements SafeStringInterface {
|
||||
|
||||
use StringTranslationTrait;
|
||||
use PlaceholderTrait;
|
||||
use ToStringTrait;
|
||||
|
||||
/**
|
||||
|
@ -31,6 +35,13 @@ class TranslationWrapper implements SafeStringInterface {
|
|||
*/
|
||||
protected $string;
|
||||
|
||||
/**
|
||||
* The translated string without placeholder replacements.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $translatedString;
|
||||
|
||||
/**
|
||||
* The translation arguments.
|
||||
*
|
||||
|
@ -45,6 +56,13 @@ class TranslationWrapper implements SafeStringInterface {
|
|||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* The string translation service.
|
||||
*
|
||||
* @var \Drupal\Core\StringTranslation\TranslationInterface
|
||||
*/
|
||||
protected $stringTranslation;
|
||||
|
||||
/**
|
||||
* Constructs a new class instance.
|
||||
*
|
||||
|
@ -57,11 +75,14 @@ class TranslationWrapper implements SafeStringInterface {
|
|||
* (optional) An array with placeholder replacements, keyed by placeholder.
|
||||
* @param array $options
|
||||
* (optional) An array of additional options.
|
||||
* @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
|
||||
* (optional) The string translation service.
|
||||
*/
|
||||
public function __construct($string, array $arguments = array(), array $options = array()) {
|
||||
public function __construct($string, array $arguments = array(), array $options = array(), TranslationInterface $string_translation = NULL) {
|
||||
$this->string = $string;
|
||||
$this->arguments = $arguments;
|
||||
$this->options = $options;
|
||||
$this->stringTranslation = $string_translation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,6 +117,17 @@ class TranslationWrapper implements SafeStringInterface {
|
|||
public function getOptions() {
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -103,7 +135,18 @@ class TranslationWrapper implements SafeStringInterface {
|
|||
* The translated string.
|
||||
*/
|
||||
public function render() {
|
||||
return $this->t($this->string, $this->arguments, $this->options);
|
||||
if (!isset($this->translatedString)) {
|
||||
$this->translatedString = $this->getStringTranslation()->translateString($this);
|
||||
}
|
||||
|
||||
// Handle any replacements.
|
||||
// @todo https://www.drupal.org/node/2509218 Note that the argument
|
||||
// replacement is not stored so that different sanitization strategies can
|
||||
// be used in different contexts.
|
||||
if ($args = $this->getArguments()) {
|
||||
return $this->placeholderFormat($this->translatedString, $args);
|
||||
}
|
||||
return $this->translatedString;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,5 +166,18 @@ class TranslationWrapper implements SafeStringInterface {
|
|||
return $this->__toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string translation service.
|
||||
*
|
||||
* @return \Drupal\Core\StringTranslation\TranslationInterface
|
||||
* The string translation service.
|
||||
*/
|
||||
protected function getStringTranslation() {
|
||||
if (!$this->stringTranslation) {
|
||||
$this->stringTranslation = \Drupal::service('string_translation');
|
||||
}
|
||||
|
||||
return $this->stringTranslation;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -109,7 +109,8 @@ class Attribute implements \ArrayAccess, \IteratorAggregate, SafeStringInterface
|
|||
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;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
namespace Drupal\Core\Validation;
|
||||
|
||||
use Drupal\Component\Utility\SafeStringInterface;
|
||||
|
||||
/**
|
||||
* Translates strings using Drupal's translation system.
|
||||
*
|
||||
|
@ -73,8 +75,14 @@ class DrupalTranslator implements TranslatorInterface {
|
|||
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) {
|
||||
|
|
|
@ -16,6 +16,7 @@ use Drupal\Core\TypedData\Type\IntegerInterface;
|
|||
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 @@ class PrimitiveTypeConstraintValidator extends ConstraintValidator {
|
|||
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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -298,8 +298,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']);
|
||||
|
|
|
@ -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".
|
||||
|
|
|
@ -82,8 +82,6 @@ class NegotiationBrowserForm extends ConfigFormBase {
|
|||
}
|
||||
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(),
|
||||
);
|
||||
|
|
|
@ -641,7 +641,7 @@ function locale_form_language_admin_overview_form_alter(&$form, FormStateInterfa
|
|||
}
|
||||
}
|
||||
|
||||
array_splice($form['languages']['#header'], -1, 0, t('Interface translation'));
|
||||
array_splice($form['languages']['#header'], -1, 0, ['translation-interface' => t('Interface translation')]);
|
||||
|
||||
foreach ($languages as $langcode => $language) {
|
||||
$stats[$langcode] += array(
|
||||
|
|
|
@ -94,8 +94,6 @@ class ImportForm extends FormBase {
|
|||
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(),
|
||||
);
|
||||
|
|
|
@ -64,7 +64,7 @@ class LocaleTranslationUiTest extends WebTestBase {
|
|||
);
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
|
||||
// Add string.
|
||||
t($name, array(), array('langcode' => $langcode));
|
||||
t($name, array(), array('langcode' => $langcode))->render();
|
||||
// Reset locale cache.
|
||||
$this->container->get('string_translation')->reset();
|
||||
$this->assertRaw('"edit-languages-' . $langcode . '-weight"', 'Language code found.');
|
||||
|
@ -237,9 +237,10 @@ class LocaleTranslationUiTest extends WebTestBase {
|
|||
|
||||
// Retrieve the source string of the first string available in the
|
||||
// {locales_source} table and translate it.
|
||||
$source = db_select('locales_source', 'l')
|
||||
->fields('l', array('source'))
|
||||
->condition('l.source', '%.js%', 'LIKE')
|
||||
$query = db_select('locales_source', 's');
|
||||
$query->addJoin('INNER', 'locales_location', 'l', 's.lid = l.lid');
|
||||
$source = $query->fields('s', array('source'))
|
||||
->condition('l.type', 'javascript')
|
||||
->range(0, 1)
|
||||
->execute()
|
||||
->fetchField();
|
||||
|
@ -302,7 +303,7 @@ class LocaleTranslationUiTest extends WebTestBase {
|
|||
);
|
||||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
|
||||
// Add string.
|
||||
t($name, array(), array('langcode' => $langcode));
|
||||
t($name, array(), array('langcode' => $langcode))->render();
|
||||
// Reset locale cache.
|
||||
$search = array(
|
||||
'string' => $name,
|
||||
|
@ -361,7 +362,7 @@ class LocaleTranslationUiTest extends WebTestBase {
|
|||
$this->drupalPostForm('admin/config/regional/language/add', $edit, t('Add custom language'));
|
||||
|
||||
// Add string.
|
||||
t($name, array(), array('langcode' => $langcode));
|
||||
t($name, array(), array('langcode' => $langcode))->render();
|
||||
// Reset locale cache.
|
||||
$this->container->get('string_translation')->reset();
|
||||
$this->drupalLogout();
|
||||
|
|
|
@ -806,6 +806,8 @@ trait AssertContentTrait {
|
|||
preg_match('@<title>(.*)</title>@', $this->getRawContent(), $matches);
|
||||
if (isset($matches[1])) {
|
||||
$actual = $matches[1];
|
||||
$actual = $this->castSafeStrings($actual);
|
||||
$title = $this->castSafeStrings($title);
|
||||
if (!$message) {
|
||||
$message = SafeMarkup::format('Page title @actual is equal to @expected.', array(
|
||||
'@actual' => var_export($actual, TRUE),
|
||||
|
|
|
@ -44,7 +44,7 @@ class NameMungingTest extends FileTestBase {
|
|||
$this->config('system.file')->set('allow_insecure_uploads', 0)->save();
|
||||
$munged_name = file_munge_filename($this->name, '', TRUE);
|
||||
$messages = drupal_get_messages();
|
||||
$this->assertTrue(in_array(t('For security reasons, your upload has been renamed to %filename.', array('%filename' => $munged_name)), $messages['status']), 'Alert properly set when a file is renamed.');
|
||||
$this->assertTrue(in_array(strtr('For security reasons, your upload has been renamed to <em class="placeholder">%filename</em>.', array('%filename' => $munged_name)), $messages['status']), 'Alert properly set when a file is renamed.');
|
||||
$this->assertNotEqual($munged_name, $this->name, format_string('The new filename (%munged) has been modified from the original (%original)', array('%munged' => $munged_name, '%original' => $this->name)));
|
||||
}
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ class FormTest extends WebTestBase {
|
|||
// 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.
|
||||
|
|
|
@ -78,7 +78,7 @@ class MockBlockManager extends PluginManagerBase {
|
|||
'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->createContextDefinition('entity:user', t('User')),
|
||||
),
|
||||
));
|
||||
|
||||
|
@ -87,7 +87,7 @@ class MockBlockManager extends PluginManagerBase {
|
|||
'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->createContextDefinition('entity:user', t('User'), FALSE),
|
||||
),
|
||||
));
|
||||
|
||||
|
@ -102,8 +102,8 @@ class MockBlockManager extends PluginManagerBase {
|
|||
'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->createContextDefinition('entity:user', t('User')),
|
||||
'node' => $this->createContextDefinition('entity:node', t('Node')),
|
||||
),
|
||||
));
|
||||
|
||||
|
@ -118,4 +118,24 @@ class MockBlockManager extends PluginManagerBase {
|
|||
// 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.
|
||||
*
|
||||
* @param string $data_type
|
||||
* The required data type.
|
||||
* @param mixed string|null $label
|
||||
* The label of this context definition for the UI.
|
||||
* @param bool $required
|
||||
* Whether the context definition is required.
|
||||
*
|
||||
* @return \Drupal\Core\Plugin\Context\ContextDefinition
|
||||
*/
|
||||
protected function createContextDefinition($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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,6 +140,11 @@ function update_page_top() {
|
|||
$status = update_requirements('runtime');
|
||||
foreach (array('core', 'contrib') as $report_type) {
|
||||
$type = 'update_' . $report_type;
|
||||
// hook_requirements() supports render arrays therefore we need to render
|
||||
// them before using drupal_set_message().
|
||||
if (isset($status[$type]['description']) && is_array($status[$type]['description'])) {
|
||||
$status[$type]['description'] = \Drupal::service('renderer')->renderPlain($status[$type]['description']);
|
||||
}
|
||||
if (!empty($verbose)) {
|
||||
if (isset($status[$type]['severity'])) {
|
||||
if ($status[$type]['severity'] == REQUIREMENT_ERROR) {
|
||||
|
|
|
@ -535,7 +535,7 @@ class UserCancelTest extends WebTestBase {
|
|||
$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() . '</em> has been deleted.') !== FALSE);
|
||||
$user_storage->resetCache(array($account->id()));
|
||||
$status = $status && !$user_storage->load($account->id());
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ use Drupal\Core\Language\LanguageInterface;
|
|||
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;
|
||||
|
@ -561,7 +562,14 @@ abstract class PluginBase extends ComponentPluginBase implements ContainerFactor
|
|||
// 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]);
|
||||
|
|
|
@ -52,8 +52,6 @@ abstract class TokenizeAreaPluginBase extends AreaPluginBase {
|
|||
|
||||
// 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) {
|
||||
|
|
|
@ -1725,9 +1725,6 @@ abstract class DisplayPluginBase extends PluginBase implements DisplayPluginInte
|
|||
);
|
||||
|
||||
$options = array();
|
||||
// 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 $arg => $handler) {
|
||||
$options[$optgroup_arguments]["{{ arguments.$arg }}"] = $this->t('@argument title', array('@argument' => $handler->adminLabel()));
|
||||
|
|
|
@ -862,8 +862,6 @@ abstract class FieldPluginBase extends HandlerBase implements FieldHandlerInterf
|
|||
|
||||
// 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) {
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\KernelTests\Core\Common\DrupalSetMessageTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\KernelTests\Core\Common;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* @covers ::drupal_set_message
|
||||
* @group PHPUnit
|
||||
*/
|
||||
class DrupalSetMessageTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* The basic functionality of drupal_set_message().
|
||||
*/
|
||||
public function testDrupalSetMessage() {
|
||||
drupal_set_message(t('A message: @foo', ['@foo' => 'bar']));
|
||||
$messages = drupal_get_messages();
|
||||
$this->assertInstanceOf('Drupal\Core\Render\SafeString', $messages['status'][0]);
|
||||
$this->assertEquals('A message: bar', (string) $messages['status'][0]);
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
// Clear session to prevent global leakage.
|
||||
unset($_SESSION['messages']);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
}
|
|
@ -45,9 +45,6 @@ class TranslationTest extends UnitTestCase {
|
|||
$options = isset($values['context']) ? array(
|
||||
'context' => $values['context'],
|
||||
) : array();
|
||||
$this->translationManager->expects($this->once())
|
||||
->method('translate')
|
||||
->with($values['value'], $arguments, $options);
|
||||
|
||||
$annotation = new Translation($values);
|
||||
|
||||
|
|
|
@ -71,11 +71,10 @@ class ContextualLinkDefaultTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetTitle() {
|
||||
$title = 'Example';
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title, [], [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with($title, array(), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated'));
|
||||
|
||||
$this->setupContextualLinkDefault();
|
||||
|
@ -87,11 +86,10 @@ class ContextualLinkDefaultTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetTitleWithContext() {
|
||||
$title = 'Example';
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context'), $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with($title, array(), array('context' => 'context'))
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated with context'));
|
||||
|
||||
$this->setupContextualLinkDefault();
|
||||
|
@ -103,11 +101,10 @@ class ContextualLinkDefaultTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetTitleWithTitleArguments() {
|
||||
$title = 'Example @test';
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array('@test' => 'value')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array('@test' => 'value'), [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with($title, array('@test' => 'value'), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example value'));
|
||||
|
||||
$this->setupContextualLinkDefault();
|
||||
|
|
|
@ -83,11 +83,10 @@ class LocalActionDefaultTest extends UnitTestCase {
|
|||
* @see \Drupal\Core\Menu\LocalTaskDefault::getTitle()
|
||||
*/
|
||||
public function testGetTitle() {
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example'))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example', [], [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with('Example', array(), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated'));
|
||||
|
||||
$this->setupLocalActionDefault();
|
||||
|
@ -100,11 +99,10 @@ class LocalActionDefaultTest extends UnitTestCase {
|
|||
* @see \Drupal\Core\Menu\LocalTaskDefault::getTitle()
|
||||
*/
|
||||
public function testGetTitleWithContext() {
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example', array(), array('context' => 'context')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example', array(), array('context' => 'context'), $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with('Example', array(), array('context' => 'context'))
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated with context'));
|
||||
|
||||
$this->setupLocalActionDefault();
|
||||
|
@ -115,11 +113,10 @@ class LocalActionDefaultTest extends UnitTestCase {
|
|||
* Tests the getTitle method with title arguments.
|
||||
*/
|
||||
public function testGetTitleWithTitleArguments() {
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value'), [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with('Example @test', array('@test' => 'value'), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example value'));
|
||||
|
||||
$this->setupLocalActionDefault();
|
||||
|
|
|
@ -233,11 +233,10 @@ class LocalTaskDefaultTest extends UnitTestCase {
|
|||
* @covers ::getTitle
|
||||
*/
|
||||
public function testGetTitle() {
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example'))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example', [], [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with('Example', array(), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated'));
|
||||
|
||||
$this->setupLocalTaskDefault();
|
||||
|
@ -249,11 +248,10 @@ class LocalTaskDefaultTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetTitleWithContext() {
|
||||
$title = 'Example';
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context'), $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with($title, array(), array('context' => 'context'))
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated with context'));
|
||||
|
||||
$this->setupLocalTaskDefault();
|
||||
|
@ -264,12 +262,10 @@ class LocalTaskDefaultTest extends UnitTestCase {
|
|||
* @covers ::getTitle
|
||||
*/
|
||||
public function testGetTitleWithTitleArguments() {
|
||||
$title = 'Example @test';
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value'), [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with($title, array('@test' => 'value'), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example value'));
|
||||
|
||||
$this->setupLocalTaskDefault();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\Tests\Core\StringTranslation {
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\SafeStringInterface;
|
||||
use Drupal\Core\StringTranslation\TranslationManager;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
|
@ -59,6 +60,44 @@ class TranslationManagerTest extends UnitTestCase {
|
|||
$this->assertEquals(SafeMarkup::isSafe($result), $safe);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translation using placeholders.
|
||||
*
|
||||
* @param string $string
|
||||
* A string containing the English string to translate.
|
||||
* @param array $args
|
||||
* 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 TranslationWrapper object to be returned.
|
||||
*
|
||||
* @dataProvider providerTestTranslatePlaceholder
|
||||
*/
|
||||
public function testTranslatePlaceholder($string, array $args = array(), $expected_string, $returns_translation_wrapper) {
|
||||
$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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test data for translate().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
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],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class TestTranslationManager extends TranslationManager {
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\Tests\Core\StringTranslation;
|
||||
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -55,9 +56,11 @@ class TranslationWrapperTest extends UnitTestCase {
|
|||
* @covers ::__toString
|
||||
*/
|
||||
public function testToString() {
|
||||
$translation = $this->getMock(TranslationInterface::class);
|
||||
|
||||
$string = 'May I have an exception please?';
|
||||
$text = $this->getMockBuilder('Drupal\Core\StringTranslation\TranslationWrapper')
|
||||
->setConstructorArgs([$string])
|
||||
$text = $this->getMockBuilder(TranslationWrapper::class)
|
||||
->setConstructorArgs([$string, [], [], $translation])
|
||||
->setMethods(['_die'])
|
||||
->getMock();
|
||||
$text
|
||||
|
@ -65,11 +68,12 @@ class TranslationWrapperTest extends UnitTestCase {
|
|||
->method('_die')
|
||||
->willReturn('');
|
||||
|
||||
$translation = $this->prophesize(TranslationInterface::class);
|
||||
$translation->translate($string, [], [])->will(function () {
|
||||
$translation
|
||||
->method('translateString')
|
||||
->with($text)
|
||||
->willReturnCallback(function () {
|
||||
throw new \Exception('Yes you may.');
|
||||
});
|
||||
$text->setStringTranslation($translation->reveal());
|
||||
|
||||
// We set a custom error handler because of https://github.com/sebastianbergmann/phpunit/issues/487
|
||||
set_error_handler([$this, 'errorHandler']);
|
||||
|
|
|
@ -16,6 +16,7 @@ use Drupal\Core\TypedData\Plugin\DataType\Uri;
|
|||
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 @@ class PrimitiveTypeConstraintValidatorTest extends UnitTestCase {
|
|||
$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];
|
||||
|
|
|
@ -12,6 +12,8 @@ use Drupal\Component\Utility\Random;
|
|||
use Drupal\Component\Utility\SafeMarkup;
|
||||
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.
|
||||
|
@ -20,6 +22,8 @@ use Drupal\Core\DependencyInjection\ContainerBuilder;
|
|||
*/
|
||||
abstract class UnitTestCase extends \PHPUnit_Framework_TestCase {
|
||||
|
||||
use PlaceholderTrait;
|
||||
|
||||
/**
|
||||
* The random generator.
|
||||
*
|
||||
|
@ -214,7 +218,17 @@ abstract class UnitTestCase extends \PHPUnit_Framework_TestCase {
|
|||
$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, $translation);
|
||||
// Pretend everything is not safe.
|
||||
// @todo https://www.drupal.org/node/2570037 return the wrapper instead.
|
||||
return (string) $wrapper;
|
||||
});
|
||||
$translation->expects($this->any())
|
||||
->method('translateString')
|
||||
->willReturnCallback(function (TranslationWrapper $wrapper) {
|
||||
return $wrapper->getUntranslatedString();
|
||||
});
|
||||
$translation->expects($this->any())
|
||||
->method('formatPlural')
|
||||
->willReturnCallback(function ($count, $singular, $plural, array $args = [], array $options = []) {
|
||||
|
|
Loading…
Reference in New Issue