TranslatableMarkup.php

Same filename and directory in other branches
  1. 9 core/lib/Drupal/Core/StringTranslation/TranslatableMarkup.php
  2. 8.9.x core/lib/Drupal/Core/StringTranslation/TranslatableMarkup.php
  3. 10 core/lib/Drupal/Core/StringTranslation/TranslatableMarkup.php

Namespace

Drupal\Core\StringTranslation

File

core/lib/Drupal/Core/StringTranslation/TranslatableMarkup.php

View source
<?php

namespace Drupal\Core\StringTranslation;

use Drupal\Component\Render\FormattableMarkup;
use Drupal\Component\Utility\ToStringTrait;

/**
 * Provides translatable markup class.
 *
 * This object, when cast to a string, will return the formatted, translated
 * string. Avoid casting it to a string yourself, because it is preferable to
 * let the rendering system do the cast as late as possible in the rendering
 * process, so that this object itself can be put, untranslated, into render
 * caches and thus the cache can be shared between different language contexts.
 *
 * @see \Drupal\Component\Render\FormattableMarkup
 * @see \Drupal\Core\StringTranslation\TranslationManager::translateString()
 * @see \Drupal\Core\Annotation\Translation
 */
class TranslatableMarkup extends FormattableMarkup {
    use ToStringTrait;
    
    /**
     * The translated markup without placeholder replacements.
     *
     * @var string
     */
    protected $translatedMarkup;
    
    /**
     * The translation options.
     *
     * @var array
     */
    protected $options;
    
    /**
     * The string translation service.
     *
     * @var \Drupal\Core\StringTranslation\TranslationInterface
     */
    protected $stringTranslation;
    
    /**
     * Constructs a new class instance.
     *
     * When possible, use the
     * \Drupal\Core\StringTranslation\StringTranslationTrait $this->t(). Otherwise
     * create a new \Drupal\Core\StringTranslation\TranslatableMarkup object
     * directly.
     *
     * Calling the trait's t() method or instantiating a new TranslatableMarkup
     * object serves two purposes:
     * - At run-time it translates user-visible text into the appropriate
     *   language.
     * - Static analyzers detect calls to t() and new TranslatableMarkup, and add
     *   the first argument (the string to be translated) to the database of
     *   strings that need translation. These strings are expected to be in
     *   English, so the first argument should always be in English.
     * To allow the site to be localized, it is important that all human-readable
     * text that will be displayed on the site or sent to a user is made available
     * in one of the ways supported by the
     * @link https://www.drupal.org/node/322729 Localization API @endlink.
     * See the @link https://www.drupal.org/node/322729 Localization API @endlink
     * pages for more information, including recommendations on how to break up or
     * not break up strings for translation.
     *
     * @section sec_translating_vars Translating Variables
     * $string should always be an English literal string.
     *
     * $string should never contain a variable, such as:
     * @code
     * new TranslatableMarkup($text)
     * @endcode
     * There are several reasons for this:
     * - Using a variable for $string that is user input is a security risk.
     * - Using a variable for $string that has even guaranteed safe text (for
     *   example, user interface text provided literally in code), will not be
     *   picked up by the localization static text processor. (The parameter could
     *   be a variable if the entire string in $text has been passed into t() or
     *   new TranslatableMarkup() elsewhere as the first argument, but that
     *   strategy is not recommended.)
     *
     * It is especially important never to call new TranslatableMarkup($user_text)
     * or t($user_text) where $user_text is some text that a user entered -- doing
     * that can lead to cross-site scripting and other security problems. However,
     * you can use variable substitution in your string, to put variable text such
     * as user names or link URLs into translated text. Variable substitution
     * looks like this:
     * @code
     * new TranslatableMarkup("@name's blog", ['@name' => $account->getDisplayName()]);
     * @endcode
     * Basically, you can put placeholders like @name into your string, and the
     * method will substitute the sanitized values at translation time. (See the
     * Localization API pages referenced above and the documentation of
     * \Drupal\Component\Render\FormattableMarkup::placeholderFormat()
     * for details about how to safely and correctly define variables in your
     * string.) Translators can then rearrange the string as necessary for the
     * language (e.g., in Spanish, it might be "blog de @name").
     *
     * @param string $string
     *   A string containing the English text to translate.
     * @param array $arguments
     *   (optional) An associative array of replacements to make after
     *   translation. Based on the first character of the key, the value is
     *   escaped and/or themed. See
     *   \Drupal\Component\Render\FormattableMarkup::placeholderFormat() for
     *   details.
     * @param array $options
     *   (optional) An associative array of additional options, with the following
     *   elements:
     *   - 'langcode' (defaults to the current language): A language code, to
     *     translate to a language other than what is used to display the page.
     *   - 'context' (defaults to the empty context): The context the source
     *     string belongs to.
     * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
     *   (optional) The string translation service.
     *
     * @throws \InvalidArgumentException
     *   Exception thrown when $string is not a string.
     *
     * @see \Drupal\Component\Render\FormattableMarkup::placeholderFormat()
     * @see \Drupal\Core\StringTranslation\StringTranslationTrait::t()
     *
     * @ingroup sanitization
     */
    public function __construct($string, array $arguments = [], array $options = [], ?TranslationInterface $string_translation = NULL) {
        if (!is_string($string)) {
            $message = $string instanceof TranslatableMarkup ? '$string ("' . $string->getUntranslatedString() . '") must be a string.' : '$string ("' . (string) $string . '") must be a string.';
            throw new \InvalidArgumentException($message);
        }
        parent::__construct($string, $arguments);
        $this->options = $options;
        $this->stringTranslation = $string_translation;
    }
    
    /**
     * Gets the untranslated string value stored in this translated string.
     *
     * @return string
     *   The string stored in this wrapper.
     */
    public function getUntranslatedString() {
        return $this->string;
    }
    
    /**
     * Gets a specific option from this translated string.
     *
     * @param string $name
     *   Option name.
     *
     * @return mixed
     *   The value of this option or empty string of option is not set.
     */
    public function getOption($name) {
        return $this->options[$name] ?? '';
    }
    
    /**
     * Gets all options from this translated string.
     *
     * @return mixed[]
     *   The array of options.
     */
    public function getOptions() {
        return $this->options;
    }
    
    /**
     * Gets all arguments from this translated string.
     *
     * @return mixed[]
     *   The array of arguments.
     */
    public function getArguments() {
        return $this->arguments;
    }
    
    /**
     * Renders the object as a string.
     *
     * @return string
     *   The translated string.
     */
    public function render() {
        if (!isset($this->translatedMarkup)) {
            $this->translatedMarkup = $this->getStringTranslation()
                ->translateString($this);
        }
        // Handle any replacements.
        if ($args = $this->getArguments()) {
            return $this->placeholderFormat($this->translatedMarkup, $args);
        }
        return $this->translatedMarkup;
    }
    
    /**
     * Magic __sleep() method to avoid serializing the string translator.
     */
    public function __sleep() : array {
        return [
            'string',
            'arguments',
            'options',
        ];
    }
    
    /**
     * 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;
    }
    
    /**
     * Returns the string length.
     *
     * @return int
     *   The length of the string.
     */
    public function count() : int {
        return mb_strlen($this->render());
    }

}

Classes

Title Deprecated Summary
TranslatableMarkup Provides translatable markup class.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.