From 1c9ddc43b59975c13cc9eb247471f9d16443cd73 Mon Sep 17 00:00:00 2001 From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org> Date: Wed, 25 Mar 2015 11:44:36 +0000 Subject: [PATCH] =?UTF-8?q?Issue=20#2454859=20by=20G=C3=A1bor=20Hojtsy,=20?= =?UTF-8?q?alexpott,=20mrjmd:=20Not=20possible=20to=20format=20plural=20an?= =?UTF-8?q?=20already=20translated=20string?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StringTranslationTrait.php | 11 ++++ .../TranslationInterface.php | 47 +++++++++++++--- .../StringTranslation/TranslationManager.php | 54 +++++++++++++------ .../src/Tests/LocalePluralFormatTest.php | 5 ++ 4 files changed, 95 insertions(+), 22 deletions(-) diff --git a/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php index 85a6e3f4c46d..ebb20e4df733 100644 --- a/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php +++ b/core/lib/Drupal/Core/StringTranslation/StringTranslationTrait.php @@ -52,6 +52,17 @@ protected function formatPlural($count, $singular, $plural, array $args = array( return $this->getStringTranslation()->formatPlural($count, $singular, $plural, $args, $options); } + /** + * Formats a translated string containing a count of items. + * + * See the + * \Drupal\Core\StringTranslation\TranslationInterface::formatPluralTranslated() + * documentation for details. + */ + protected function formatPluralTranslated($count, $translated, array $args = array(), array $options = array()) { + return $this->getStringTranslation()->formatPluralTranslated($count, $translated, $args, $options); + } + /** * Gets the string translation service. * diff --git a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php index bc560cfd5ee4..3e866bb02b97 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationInterface.php @@ -41,7 +41,7 @@ public function translate($string, array $args = array(), array $options = array * * This function ensures that the string is pluralized correctly. Since t() is * called by this function, make sure not to pass already-localized strings to - * it. + * it. See formatPluralTranslated() for that. * * For example: * @code @@ -70,19 +70,54 @@ public function translate($string, array $args = array(), array $options = array * An associative array of replacements to make after translation. Instances * of any key in this array are replaced with the corresponding value. * Based on the first character of the key, the value is escaped and/or - * themed. See format_string(). Note that you do not need to include @count - * in this array; this replacement is done automatically for the plural case. + * themed. See \Drupal\Component\Utility\String::format(). Note that you do + * not need to include @count in this array; this replacement is done + * automatically for the plural cases. * @param array $options * An associative array of additional options. See t() for allowed keys. * * @return string * A translated string. * - * @see self::translate - * @see \Drupal\Component\Utility\String + * @see self::translate() * @see t() - * @see format_string() + * @see \Drupal\Component\Utility\SafeMarkup::format() + * @see self::formatPluralTranslated */ public function formatPlural($count, $singular, $plural, array $args = array(), array $options = array()); + /** + * Formats an already translated string containing a count of items. + * + * This function ensures that the string is pluralized correctly. As opposed + * to the formatPlural() method, this method is designed to be invoked with + * a string already translated (such as with configuration translation). + * + * @param int $count + * The item count to display. + * @param string $translation + * The string containing the translation of a singular/plural pair. It may + * contain any number of possible variants (depending on the language + * translated to) separated by the value of the LOCALE_PLURAL_DELIMITER + * constant. + * @param array $args + * Associative array of replacements to make in the translation. Instances + * of any key in this array are replaced with the corresponding value. + * Based on the first character of the key, the value is escaped and/or + * themed. See \Drupal\Component\Utility\String::format(). Note that you do + * not need to include @count in this array; this replacement is done + * automatically for the plural cases. + * @param array $options + * An associative array of additional options. The 'context' key is not + * supported because the passed string is already translated. Use the + * 'langcode' key to ensure the proper plural logic is used. + * + * @return string + * The correct substring for the given $count with $args replaced. + * + * @see self::formatPlural() + * @see \Drupal\Component\Utility\SafeMarkup::format() + */ + public function formatPluralTranslated($count, $translation, 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 46012acd5354..edb391ce50e6 100644 --- a/core/lib/Drupal/Core/StringTranslation/TranslationManager.php +++ b/core/lib/Drupal/Core/StringTranslation/TranslationManager.php @@ -129,6 +129,30 @@ public function getStringTranslation($langcode, $string, $context) { * {@inheritdoc} */ public function translate($string, array $args = array(), array $options = array()) { + $string = $this->doTranslate($string, $options); + if (empty($args)) { + return SafeMarkup::set($string); + } + else { + return SafeMarkup::format($string, $args); + } + } + + /** + * 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 defaults. if (empty($options['langcode'])) { $options['langcode'] = $this->defaultLangcode; @@ -137,30 +161,27 @@ public function translate($string, array $args = array(), array $options = array $options['context'] = ''; } $translation = $this->getStringTranslation($options['langcode'], $string, $options['context']); - $string = $translation === FALSE ? $string : $translation; - - if (empty($args)) { - return SafeMarkup::set($string); - } - else { - return SafeMarkup::format($string, $args); - } + return $translation === FALSE ? $string : $translation; } /** * {@inheritdoc} */ public function formatPlural($count, $singular, $plural, array $args = array(), array $options = array()) { - $args['@count'] = $count; - // Join both forms to search a translation. $translatable_string = implode(LOCALE_PLURAL_DELIMITER, array($singular, $plural)); - // Translate as usual. - $translated_strings = $this->translate($translatable_string, $args, $options); - // Split joined translation strings into array. - $translated_array = explode(LOCALE_PLURAL_DELIMITER, $translated_strings); + $translated_strings = $this->doTranslate($translatable_string, $options); + return $this->formatPluralTranslated($count, $translated_strings, $args, $options); + } + + /** + * {@inheritdoc} + */ + public function formatPluralTranslated($count, $translation, array $args = array(), array $options = array()) { + $args['@count'] = $count; + $translated_array = explode(LOCALE_PLURAL_DELIMITER, $translation); if ($count == 1) { - return SafeMarkup::set($translated_array[0]); + return SafeMarkup::format($translated_array[0], $args); } // Get the plural index through the gettext formula. @@ -182,7 +203,8 @@ public function formatPlural($count, $singular, $plural, array $args = array(), $return = $translated_array[1]; } } - return SafeMarkup::set($return); + + return SafeMarkup::format($return, $args); } /** diff --git a/core/modules/locale/src/Tests/LocalePluralFormatTest.php b/core/modules/locale/src/Tests/LocalePluralFormatTest.php index e6b51f174506..bb8674a1657c 100644 --- a/core/modules/locale/src/Tests/LocalePluralFormatTest.php +++ b/core/modules/locale/src/Tests/LocalePluralFormatTest.php @@ -131,6 +131,11 @@ public function testGetPluralFormat() { $expected_plural_index = ($count == 1) ? 0 : $expected_plural_index; $expected_plural_string = str_replace('@count', $count, $plural_strings[$langcode][$expected_plural_index]); $this->assertIdentical(\Drupal::translation()->formatPlural($count, '1 hour', '@count hours', array(), array('langcode' => $langcode)), $expected_plural_string, 'Plural translation of 1 hours / @count hours for count ' . $count . ' in ' . $langcode . ' is ' . $expected_plural_string); + // DO NOT use translation to pass into formatPluralTranslated() this + // way. It is designed to be used with *already* translated text like + // settings from configuration. We use PHP translation here just because + // we have the expected result data in that format. + $this->assertIdentical(\Drupal::translation()->formatPluralTranslated($count, \Drupal::translation()->translate('1 hour' . LOCALE_PLURAL_DELIMITER . '@count hours', array(), array('langcode' => $langcode)), array(), array('langcode' => $langcode)), $expected_plural_string, 'Translated plural lookup of 1 hours / @count hours for count ' . $count . ' in ' . $langcode . ' is ' . $expected_plural_string); } } } -- GitLab