Commit a938ce81 authored by Dries's avatar Dries

- Patch #1191614 by Gábor Hojtsy: make t() formatter available as its own function.

parent 347045e9
......@@ -1236,15 +1236,7 @@ function drupal_unpack($obj, $field = 'data') {
* A string containing the English string to translate.
* @param $args
* An associative array of replacements to make after translation.
* Occurrences in $string of any key in $args are replaced with the
* corresponding value, after sanitization. The sanitization function depends
* on the first character of the key:
* - !variable: Inserted as is. Use this for text that has already been
* sanitized.
* - @variable: Escaped to HTML using check_plain(). Use this for anything
* displayed on a page on the site.
* - %variable: Escaped as a placeholder for user-submitted content using
* drupal_placeholder(), which shows up as <em>emphasized</em> text.
* See format_string().
* @param $options
* An associative array of additional options, with the following elements:
* - 'langcode' (defaults to the current language): The language code to
......@@ -1290,26 +1282,50 @@ function t($string, array $args = array(), array $options = array()) {
return $string;
}
else {
// Transform arguments before inserting them.
foreach ($args as $key => $value) {
switch ($key[0]) {
case '@':
// Escaped only.
$args[$key] = check_plain($value);
break;
case '%':
default:
// Escaped and placeholder.
$args[$key] = drupal_placeholder($value);
break;
return format_string($string, $args);
}
}
case '!':
// Pass-through.
}
/**
* Replace placeholders with sanitized values in a string.
*
* @param $string
* A string containing placeholders.
* @param $args
* An associative array of replacements to make. Occurrences in $string of
* any key in $args are replaced with the corresponding value, after
* sanitization. The sanitization function depends on the first character of
* the key:
* - !variable: Inserted as is. Use this for text that has already been
* sanitized.
* - @variable: Escaped to HTML using check_plain(). Use this for anything
* displayed on a page on the site.
* - %variable: Escaped as a placeholder for user-submitted content using
* drupal_placeholder(), which shows up as <em>emphasized</em> text.
*
* @see t()
* @ingroup sanitization
*/
function format_string($string, array $args = array()) {
// Transform arguments before inserting them.
foreach ($args as $key => $value) {
switch ($key[0]) {
case '@':
// Escaped only.
$args[$key] = check_plain($value);
break;
case '%':
default:
// Escaped and placeholder.
$args[$key] = drupal_placeholder($value);
break;
case '!':
// Pass-through.
}
return strtr($string, $args);
}
return strtr($string, $args);
}
/**
......
......@@ -111,6 +111,8 @@ Drupal.detachBehaviors = function (context, settings, trigger) {
/**
* Encode special characters in a plain-text string for display as HTML.
*
* @ingroup sanitization
*/
Drupal.checkPlain = function (str) {
var character, regex,
......@@ -125,6 +127,45 @@ Drupal.checkPlain = function (str) {
return str;
};
/**
* Replace placeholders with sanitized values in a string.
*
* @param str
* A string with placeholders.
* @param args
* An object of replacements pairs to make. Incidences 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:
* - !variable: inserted as is
* - @variable: escape plain text to HTML (Drupal.checkPlain)
* - %variable: escape text and theme as a placeholder for user-submitted
* content (checkPlain + Drupal.theme('placeholder'))
*
* @see Drupal.t()
* @ingroup sanitization
*/
Drupal.formatString = function(str, args) {
// Transform arguments before inserting them.
for (var key in args) {
switch (key.charAt(0)) {
// Escaped only.
case '@':
args[key] = Drupal.checkPlain(args[key]);
break;
// Pass-through.
case '!':
break;
// Escaped and placeholder.
case '%':
default:
args[key] = Drupal.theme('placeholder', args[key]);
break;
}
str = str.replace(key, args[key]);
}
return str;
}
/**
* Translate strings to the page language or a given language.
*
......@@ -135,11 +176,7 @@ Drupal.checkPlain = function (str) {
* @param args
* An object of replacements pairs to make after translation. Incidences
* 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:
* - !variable: inserted as is
* - @variable: escape plain text to HTML (Drupal.checkPlain)
* - %variable: escape text and theme as a placeholder for user-submitted
* content (checkPlain + Drupal.theme('placeholder'))
* See Drupal.formatString().
* @return
* The translated string.
*/
......@@ -150,24 +187,7 @@ Drupal.t = function (str, args) {
}
if (args) {
// Transform arguments before inserting them.
for (var key in args) {
switch (key.charAt(0)) {
// Escaped only.
case '@':
args[key] = Drupal.checkPlain(args[key]);
break;
// Pass-through.
case '!':
break;
// Escaped and placeholder.
case '%':
default:
args[key] = Drupal.theme('placeholder', args[key]);
break;
}
str = str.replace(key, args[key]);
}
str = Drupal.formatString(str, args);
}
return str;
};
......@@ -193,11 +213,7 @@ Drupal.t = function (str, args) {
* @param args
* An object of replacements pairs to make after translation. Incidences
* 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:
* - !variable: inserted as is
* - @variable: escape plain text to HTML (Drupal.checkPlain)
* - %variable: escape text and theme as a placeholder for user-submitted
* content (checkPlain + Drupal.theme('placeholder'))
* See Drupal.formatString().
* Note that you do not need to include @count in this array.
* This replacement is done automatically for the plural case.
* @return
......
......@@ -345,14 +345,14 @@ class CommonURLUnitTest extends DrupalWebTestCase {
}
/**
* Tests for the check_plain() and filter_xss() functions.
* Tests for the check_plain(), filter_xss() and format_string() functions.
*/
class CommonXssUnitTest extends DrupalUnitTestCase {
public static function getInfo() {
return array(
'name' => 'String filtering tests',
'description' => 'Confirm that check_plain(), filter_xss(), and check_url() work correctly, including invalid multi-byte sequences.',
'description' => 'Confirm that check_plain(), filter_xss(), format_string() and check_url() work correctly, including invalid multi-byte sequences.',
'group' => 'System',
);
}
......@@ -385,6 +385,22 @@ class CommonXssUnitTest extends DrupalUnitTestCase {
$this->assertEqual($text, '&lt;&gt;&amp;&quot;&#039;', 'check_plain() escapes reserved HTML characters.');
}
/**
* Test t() and format_string() replacement functionality.
*/
function testFormatStringAndT() {
foreach (array('format_string', 't') as $function) {
$text = $function('Simple text');
$this->assertEqual($text, 'Simple text', $function . ' leaves simple text alone.');
$text = $function('Escaped text: @value', array('@value' => '<script>'));
$this->assertEqual($text, 'Escaped text: &lt;script&gt;', $function . ' replaces and escapes string.');
$text = $function('Placeholder text: %value', array('%value' => '<script>'));
$this->assertEqual($text, 'Placeholder text: <em class="placeholder">&lt;script&gt;</em>', $function . ' replaces, escapes and themes string.');
$text = $function('Verbatim text: !value', array('!value' => '<script>'));
$this->assertEqual($text, 'Verbatim text: <script>', $function . ' replaces verbatim string as-is.');
}
}
/**
* Check that harmful protocols are stripped.
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment