From 04966aa03b9854fcb32f4aea9c1e2f285ea197e3 Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Tue, 27 Oct 2015 12:46:40 +0000 Subject: [PATCH] =?UTF-8?q?Issue=20#2578377=20by=20YesCT,=20jhodgdon,=20G?= =?UTF-8?q?=C3=A1bor=20Hojtsy,=20alexpott,=20herom,=20xjm:=20Make=20transl?= =?UTF-8?q?atable=20docs=20consolidated=20and=20better=20for=20developers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/includes/bootstrap.inc | 71 ++++++--------- .../StringTranslationTrait.php | 36 +++++++- .../StringTranslation/TranslatableMarkup.php | 87 ++++++++++++++++--- .../TranslationInterface.php | 36 +++++--- .../StringTranslation/TranslationManager.php | 2 +- core/misc/drupal.js | 2 +- .../TranslationManagerTest.php | 2 +- 7 files changed, 159 insertions(+), 77 deletions(-) diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc index 019beafa7216..289d5a935057 100644 --- a/core/includes/bootstrap.inc +++ b/core/includes/bootstrap.inc @@ -258,56 +258,39 @@ function drupal_get_path($type, $name) { /** * Translates a string to the current language or to a given language. * - * The t() function serves two purposes. First, at run-time it translates - * user-visible text into the appropriate language. Second, various mechanisms - * that figure out what text needs to be translated work off t() -- the text - * inside t() calls is added to the database of strings to be translated. - * 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 passed through the t() function, or a related function. 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 - * You should never use t() to translate variables, such as calling t($text) - * unless the text that the variable holds has been passed through t() - * elsewhere (e.g., $text is one of several translated literal strings in an - * array). It is especially important never to call 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 - * $text = t("@name's blog", array('@name' => $account->getDisplayName())); - * @endcode - * Basically, you can put variables like @name into your string, and t() will - * substitute their sanitized values at translation time. (See the - * Localization API pages referenced above and the documentation of - * \Drupal\Component\Utility\SafeMarkup::format() for details about how to - * 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 - * A string containing the English string to translate. - * @param $args - * 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\Utility\SafeMarkup::format() for details. - * @param $options - * An associative array of additional options, with the following elements: - * - 'langcode' (defaults to the current language): The language code to + * In order for strings to be localized, make them available in one of the ways + * supported by the + * @link https://www.drupal.org/node/322729 Localization API @endlink. When + * possible, use the \Drupal\Core\StringTranslation\StringTranslationTrait + * $this->t(). Otherwise create a new + * \Drupal\Core\StringTranslation\TranslatableMarkup object directly. + * + * See \Drupal\Core\StringTranslation\TranslatableMarkup::__construct() for + * important security information and usage guidelines. + * + * @param string $string + * A string containing the English text to translate. + * @param array $args + * (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. * * @return \Drupal\Core\StringTranslation\TranslatableMarkup - * An object that, when cast to a string, will yield the translated string. + * An object that, when cast to a string, returns the translated string. + * + * @see \Drupal\Component\Render\FormattableMarkup::placeholderFormat() + * @see \Drupal\Core\StringTranslation\StringTranslationTrait::t() + * @see \Drupal\Core\StringTranslation\TranslatableMarkup::__construct() * - * @see \Drupal\Component\Utility\SafeMarkup::format() * @ingroup sanitization */ function t($string, array $args = array(), array $options = array()) { diff --git a/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php index 53e1f6f54cfd..aae4d4535ae6 100644 --- a/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php +++ b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php @@ -36,11 +36,39 @@ trait StringTranslationTrait { /** * Translates a string to the current language or to a given language. * - * See the t() documentation for details. + * See \Drupal\Core\StringTranslation\TranslatableMarkup::__construct() for + * important security information and usage guidelines. * - * Never call $this->t($user_text) where $user_text is text that a user - * entered; doing so can lead to cross-site scripting and other security - * problems. + * In order for strings to be localized, make them available in one of the + * ways supported by the + * @link https://www.drupal.org/node/322729 Localization API @endlink. When + * possible, use the \Drupal\Core\StringTranslation\StringTranslationTrait + * $this->t(). Otherwise create a new + * \Drupal\Core\StringTranslation\TranslatableMarkup object. + * + * @param string $string + * A string containing the English text to translate. + * @param array $args + * (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. + * + * @return \Drupal\Core\StringTranslation\TranslatableMarkup + * An object that, when cast to a string, returns the translated string. + * + * @see \Drupal\Component\Render\FormattableMarkup::placeholderFormat() + * @see \Drupal\Core\StringTranslation\TranslatableMarkup::__construct() + * + * @ingroup sanitization */ protected function t($string, array $args = array(), array $options = array()) { return $this->getStringTranslation()->translate($string, $args, $options); diff --git a/core/lib/Drupal/Core/StringTranslation/TranslatableMarkup.php b/core/lib/Drupal/Core/StringTranslation/TranslatableMarkup.php index 13d3a64b2eb9..024c3a42a303 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslatableMarkup.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslatableMarkup.php @@ -13,13 +13,13 @@ /** * Provides translatable markup class. * - * This class delays translation until rendering. + * 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. * - * This is useful for using translation in very low level subsystems like entity - * definition and stream wrappers. - * - * @see \Drupal\Component\Render\FormattableMarkup::placeholderFormat() - * @see \Drupal\Core\StringTranslation\TranslationManager::translate() + * @see \Drupal\Component\Render\FormattableMarkup * @see \Drupal\Core\StringTranslation\TranslationManager::translateString() * @see \Drupal\Core\Annotation\Translation */ @@ -58,17 +58,75 @@ class TranslatableMarkup extends FormattableMarkup { /** * Constructs a new class instance. * - * Parses values passed into this class through the t() function in Drupal and - * handles an optional context for the string. + * 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", array('@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 - * The string that is to be translated. + * A string containing the English text to translate. * @param array $arguments - * (optional) An array with placeholder replacements, keyed by placeholder. - * See \Drupal\Component\Render\FormattableMarkup::placeholderFormat() for - * additional information about placeholders. + * (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 array of additional 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. * @@ -76,6 +134,9 @@ class TranslatableMarkup extends FormattableMarkup { * 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(), array $options = array(), TranslationInterface $string_translation = NULL) { if (!is_string($string)) { diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php index 1944ecbc3fde..cbee36f72fa8 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php @@ -17,26 +17,36 @@ interface TranslationInterface { /** * Translates a string to the current language or to a given language. * - * Never call translate($user_text) where $user_text is text that a user - * entered; doing so can lead to cross-site scripting and other security - * problems. + * Never call this translate() method directly. In order for strings to be + * localized, make them available in one of the ways supported by the + * @link https://www.drupal.org/node/322729 Localization API @endlink. When + * possible, use the \Drupal\Core\StringTranslation\StringTranslationTrait + * $this->t(). Otherwise create a new + * \Drupal\Core\StringTranslation\TranslatableMarkup object. * * @param string $string - * A string containing the English string to translate. + * A string containing the English text to translate. * @param array $args - * 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\Utility\SafeMarkup::format() for details. + * (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 - * 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. + * (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. * * @return \Drupal\Core\StringTranslation\TranslatableMarkup - * An object that, when cast to a string, will yield the translated string. + * An object that, when cast to a string, returns the translated string. * - * @see \Drupal\Component\Utility\SafeMarkup::format() + * @see \Drupal\Component\Render\FormattableMarkup::placeholderFormat() + * @see \Drupal\Core\StringTranslation\TranslatableMarkup::__construct() + * + * @ingroup sanitization */ public function translate($string, array $args = array(), array $options = array()); diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php index 9d3966b02c1b..e9962d6eb527 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php @@ -123,7 +123,7 @@ public function translateString(TranslatableMarkup $translated_string) { * Translates a string to the current language or to a given language. * * @param string $string - * A string containing the English string to translate. + * A string containing the English text 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 diff --git a/core/misc/drupal.js b/core/misc/drupal.js index f1f7d6f5dcc8..f19fc431499f 100644 --- a/core/misc/drupal.js +++ b/core/misc/drupal.js @@ -362,7 +362,7 @@ if (window.jQuery) { * See the documentation of the server-side t() function for further details. * * @param {string} str - * A string containing the English string to translate. + * A string containing the English text to translate. * @param {Object.<string, string>} [args] * An object of replacements pairs to make after translation. Incidences * of any key in this array are replaced with the corresponding value. diff --git a/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php index 305963daaa91..1a99bbf3a801 100644 --- a/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php +++ b/core/tests/Drupal/Tests/Core/StringTranslation/TranslationManagerTest.php @@ -66,7 +66,7 @@ public function testFormatPlural($count, $singular, $plural, array $args = array * Tests translation using placeholders. * * @param string $string - * A string containing the English string to translate. + * A string containing the English text to translate. * @param array $args * An associative array of replacements to make after translation. * @param string $expected_string -- GitLab