Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / core / lib / Drupal / Core / StringTranslation / TranslatableMarkup.php
1 <?php
2
3 namespace Drupal\Core\StringTranslation;
4
5 use Drupal\Component\Render\FormattableMarkup;
6 use Drupal\Component\Utility\ToStringTrait;
7 use Drupal\Component\Utility\Unicode;
8
9 /**
10  * Provides translatable markup class.
11  *
12  * This object, when cast to a string, will return the formatted, translated
13  * string. Avoid casting it to a string yourself, because it is preferable to
14  * let the rendering system do the cast as late as possible in the rendering
15  * process, so that this object itself can be put, untranslated, into render
16  * caches and thus the cache can be shared between different language contexts.
17  *
18  * @see \Drupal\Component\Render\FormattableMarkup
19  * @see \Drupal\Core\StringTranslation\TranslationManager::translateString()
20  * @see \Drupal\Core\Annotation\Translation
21  */
22 class TranslatableMarkup extends FormattableMarkup {
23
24   use ToStringTrait;
25
26   /**
27    * The translated markup without placeholder replacements.
28    *
29    * @var string
30    */
31   protected $translatedMarkup;
32
33   /**
34    * The translation options.
35    *
36    * @var array
37    */
38   protected $options;
39
40   /**
41    * The string translation service.
42    *
43    * @var \Drupal\Core\StringTranslation\TranslationInterface
44    */
45   protected $stringTranslation;
46
47   /**
48    * Constructs a new class instance.
49    *
50    * When possible, use the
51    * \Drupal\Core\StringTranslation\StringTranslationTrait $this->t(). Otherwise
52    * create a new \Drupal\Core\StringTranslation\TranslatableMarkup object
53    * directly.
54    *
55    * Calling the trait's t() method or instantiating a new TranslatableMarkup
56    * object serves two purposes:
57    * - At run-time it translates user-visible text into the appropriate
58    *   language.
59    * - Static analyzers detect calls to t() and new TranslatableMarkup, and add
60    *   the first argument (the string to be translated) to the database of
61    *   strings that need translation. These strings are expected to be in
62    *   English, so the first argument should always be in English.
63    * To allow the site to be localized, it is important that all human-readable
64    * text that will be displayed on the site or sent to a user is made available
65    * in one of the ways supported by the
66    * @link https://www.drupal.org/node/322729 Localization API @endlink.
67    * See the @link https://www.drupal.org/node/322729 Localization API @endlink
68    * pages for more information, including recommendations on how to break up or
69    * not break up strings for translation.
70    *
71    * @section sec_translating_vars Translating Variables
72    * $string should always be an English literal string.
73    *
74    * $string should never contain a variable, such as:
75    * @code
76    * new TranslatableMarkup($text)
77    * @endcode
78    * There are several reasons for this:
79    * - Using a variable for $string that is user input is a security risk.
80    * - Using a variable for $string that has even guaranteed safe text (for
81    *   example, user interface text provided literally in code), will not be
82    *   picked up by the localization static text processor. (The parameter could
83    *   be a variable if the entire string in $text has been passed into t() or
84    *   new TranslatableMarkup() elsewhere as the first argument, but that
85    *   strategy is not recommended.)
86    *
87    * It is especially important never to call new TranslatableMarkup($user_text)
88    * or t($user_text) where $user_text is some text that a user entered -- doing
89    * that can lead to cross-site scripting and other security problems. However,
90    * you can use variable substitution in your string, to put variable text such
91    * as user names or link URLs into translated text. Variable substitution
92    * looks like this:
93    * @code
94    * new TranslatableMarkup("@name's blog", array('@name' => $account->getDisplayName()));
95    * @endcode
96    * Basically, you can put placeholders like @name into your string, and the
97    * method will substitute the sanitized values at translation time. (See the
98    * Localization API pages referenced above and the documentation of
99    * \Drupal\Component\Render\FormattableMarkup::placeholderFormat()
100    * for details about how to safely and correctly define variables in your
101    * string.) Translators can then rearrange the string as necessary for the
102    * language (e.g., in Spanish, it might be "blog de @name").
103    *
104    * @param string $string
105    *   A string containing the English text to translate.
106    * @param array $arguments
107    *   (optional) An associative array of replacements to make after
108    *   translation. Based on the first character of the key, the value is
109    *   escaped and/or themed. See
110    *   \Drupal\Component\Render\FormattableMarkup::placeholderFormat() for
111    *   details.
112    * @param array $options
113    *   (optional) An associative array of additional options, with the following
114    *   elements:
115    *   - 'langcode' (defaults to the current language): A language code, to
116    *     translate to a language other than what is used to display the page.
117    *   - 'context' (defaults to the empty context): The context the source
118    *     string belongs to.
119    * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
120    *   (optional) The string translation service.
121    *
122    * @throws \InvalidArgumentException
123    *   Exception thrown when $string is not a string.
124    *
125    * @see \Drupal\Component\Render\FormattableMarkup::placeholderFormat()
126    * @see \Drupal\Core\StringTranslation\StringTranslationTrait::t()
127    *
128    * @ingroup sanitization
129    */
130   public function __construct($string, array $arguments = [], array $options = [], TranslationInterface $string_translation = NULL) {
131     if (!is_string($string)) {
132       $message = $string instanceof TranslatableMarkup ? '$string ("' . $string->getUntranslatedString() . '") must be a string.' : '$string ("' . (string) $string . '") must be a string.';
133       throw new \InvalidArgumentException($message);
134     }
135     parent::__construct($string, $arguments);
136     $this->options = $options;
137     $this->stringTranslation = $string_translation;
138   }
139
140   /**
141    * Gets the untranslated string value stored in this translated string.
142    *
143    * @return string
144    *   The string stored in this wrapper.
145    */
146   public function getUntranslatedString() {
147     return $this->string;
148   }
149
150   /**
151    * Gets a specific option from this translated string.
152    *
153    * @param string $name
154    *   Option name.
155    *
156    * @return mixed
157    *   The value of this option or empty string of option is not set.
158    */
159   public function getOption($name) {
160     return isset($this->options[$name]) ? $this->options[$name] : '';
161   }
162
163   /**
164    * Gets all options from this translated string.
165    *
166    * @return mixed[]
167    *   The array of options.
168    */
169   public function getOptions() {
170     return $this->options;
171   }
172
173   /**
174    * Gets all arguments from this translated string.
175    *
176    * @return mixed[]
177    *   The array of arguments.
178    */
179   public function getArguments() {
180     return $this->arguments;
181   }
182
183   /**
184    * Renders the object as a string.
185    *
186    * @return string
187    *   The translated string.
188    */
189   public function render() {
190     if (!isset($this->translatedMarkup)) {
191       $this->translatedMarkup = $this->getStringTranslation()->translateString($this);
192     }
193
194     // Handle any replacements.
195     if ($args = $this->getArguments()) {
196       return $this->placeholderFormat($this->translatedMarkup, $args);
197     }
198     return $this->translatedMarkup;
199   }
200
201   /**
202    * Magic __sleep() method to avoid serializing the string translator.
203    */
204   public function __sleep() {
205     return ['string', 'arguments', 'options'];
206   }
207
208   /**
209    * Gets the string translation service.
210    *
211    * @return \Drupal\Core\StringTranslation\TranslationInterface
212    *   The string translation service.
213    */
214   protected function getStringTranslation() {
215     if (!$this->stringTranslation) {
216       $this->stringTranslation = \Drupal::service('string_translation');
217     }
218
219     return $this->stringTranslation;
220   }
221
222   /**
223    * Returns the string length.
224    *
225    * @return int
226    *   The length of the string.
227    */
228   public function count() {
229     return Unicode::strlen($this->render());
230   }
231
232 }