';
}
- var info = t('files', '{dirs} and {files}', infoVars);
+ var info = t('files', '{dirs} and {files}', infoVars, null, {'escape': false});
var $summary = $('
'+info+''+filterInfo+'
'+fileSize+'
');
diff --git a/core/js/l10n.js b/core/js/l10n.js
index 0c66058432..60ffa94919 100644
--- a/core/js/l10n.js
+++ b/core/js/l10n.js
@@ -62,8 +62,8 @@ OC.L10N = {
* Register an app's translation bundle.
*
* @param {String} appName name of the app
- * @param {Object} strings bundle
- * @param {{Function|String}} [pluralForm] optional plural function or plural string
+ * @param {Object} bundle
+ * @param {Function|String} [pluralForm] optional plural function or plural string
*/
register: function(appName, bundle, pluralForm) {
this._bundles[appName] = bundle || {};
@@ -129,9 +129,17 @@ OC.L10N = {
* @param {string} text the string to translate
* @param [vars] map of placeholder key to value
* @param {number} [count] number to replace %n with
+ * @param {array} [options] options array
+ * @param {bool} [options.escape=true] enable/disable auto escape of placeholders (by default enabled)
* @return {string}
*/
- translate: function(app, text, vars, count) {
+ translate: function(app, text, vars, count, options) {
+ var defaultOptions = {
+ escape: true
+ },
+ allOptions = options || {};
+ _.defaults(allOptions, defaultOptions);
+
// TODO: cache this function to avoid inline recreation
// of the same function over and over again in case
// translate() is used in a loop
@@ -139,7 +147,15 @@ OC.L10N = {
return text.replace(/%n/g, count).replace(/{([^{}]*)}/g,
function (a, b) {
var r = vars[b];
- return typeof r === 'string' || typeof r === 'number' ? r : a;
+ if(typeof r === 'string' || typeof r === 'number') {
+ if(allOptions.escape) {
+ return escapeHTML(r);
+ } else {
+ return r;
+ }
+ } else {
+ return a;
+ }
}
);
};
@@ -160,13 +176,15 @@ OC.L10N = {
/**
* Translate a plural string
* @param {string} app the id of the app for which to translate the string
- * @param {string} text_singular the string to translate for exactly one object
- * @param {string} text_plural the string to translate for n objects
+ * @param {string} textSingular the string to translate for exactly one object
+ * @param {string} textPlural the string to translate for n objects
* @param {number} count number to determine whether to use singular or plural
* @param [vars] map of placeholder key to value
+ * @param {array} [options] options array
+ * @param {bool} [options.escape=true] enable/disable auto escape of placeholders (by default enabled)
* @return {string} Translated string
*/
- translatePlural: function(app, textSingular, textPlural, count, vars) {
+ translatePlural: function(app, textSingular, textPlural, count, vars, options) {
var identifier = '_' + textSingular + '_::_' + textPlural + '_';
var bundle = this._bundles[app] || {};
var value = bundle[identifier];
@@ -174,15 +192,15 @@ OC.L10N = {
var translation = value;
if ($.isArray(translation)) {
var plural = this._pluralFunctions[app](count);
- return this.translate(app, translation[plural.plural], vars, count);
+ return this.translate(app, translation[plural.plural], vars, count, options);
}
}
if(count === 1) {
- return this.translate(app, textSingular, vars, count);
+ return this.translate(app, textSingular, vars, count, options);
}
else{
- return this.translate(app, textPlural, vars, count);
+ return this.translate(app, textPlural, vars, count, options);
}
}
};
diff --git a/core/js/share.js b/core/js/share.js
index 00d1dab519..2692ff60b5 100644
--- a/core/js/share.js
+++ b/core/js/share.js
@@ -255,7 +255,7 @@ OC.Share={
message = this._formatSharedByOwner(owner);
}
else if (recipients) {
- message = t('core', 'Shared with {recipients}', {recipients: escapeHTML(recipients)});
+ message = t('core', 'Shared with {recipients}', {recipients: recipients});
}
action.html(' ' + message + '').prepend(img);
if (owner) {
@@ -355,9 +355,9 @@ OC.Share={
var html = '
';
if (data !== false && data.reshare !== false && data.reshare.uid_owner !== undefined) {
if (data.reshare.share_type == OC.Share.SHARE_TYPE_GROUP) {
- html += ''+t('core', 'Shared with you and the group {group} by {owner}', {group: escapeHTML(data.reshare.share_with), owner: escapeHTML(data.reshare.displayname_owner)})+'';
+ html += ''+t('core', 'Shared with you and the group {group} by {owner}', {group: data.reshare.share_with, owner: data.reshare.displayname_owner})+'';
} else {
- html += ''+t('core', 'Shared with you by {owner}', {owner: escapeHTML(data.reshare.displayname_owner)})+'';
+ html += ''+t('core', 'Shared with you by {owner}', {owner: data.reshare.displayname_owner})+'';
}
html += ' ';
}
@@ -395,7 +395,7 @@ OC.Share={
var defaultExpireMessage = '';
if ((itemType === 'folder' || itemType === 'file') && oc_appconfig.core.defaultExpireDateEnforced) {
- defaultExpireMessage = t('core', 'The public link will expire no later than {days} days after it is created', {'days': escapeHTML(oc_appconfig.core.defaultExpireDate)}) + ' ';
+ defaultExpireMessage = t('core', 'The public link will expire no later than {days} days after it is created', {'days': oc_appconfig.core.defaultExpireDate}) + ' ';
}
html += '';
@@ -622,7 +622,7 @@ OC.Share={
if (collectionList.length > 0) {
$(collectionList).append(', '+shareWithDisplayName);
} else {
- var html = '
'+t('core', 'Shared in {item} with {user}', {'item': escapeHTML(item), user: escapeHTML(shareWithDisplayName)})+'
';
+ var html = '
'+t('core', 'Shared in {item} with {user}', {'item': item, user: shareWithDisplayName})+'
';
$('#shareWithList').prepend(html);
}
} else {
diff --git a/core/js/tests/specs/l10nSpec.js b/core/js/tests/specs/l10nSpec.js
index cf7c8b11b1..bafc7746d6 100644
--- a/core/js/tests/specs/l10nSpec.js
+++ b/core/js/tests/specs/l10nSpec.js
@@ -42,6 +42,16 @@ describe('OC.L10N tests', function() {
t(TEST_APP, 'Hello {name}, the weather is {weather}', {name: 'Steve', weather: t(TEST_APP, 'sunny')})
).toEqual('Hallo Steve, das Wetter ist sonnig');
});
+ it('returns text with escaped placeholder', function() {
+ expect(
+ t(TEST_APP, 'Hello {name}', {name: 'Steve'})
+ ).toEqual('Hello <strong>Steve</strong>');
+ });
+ it('returns text with not escaped placeholder', function() {
+ expect(
+ t(TEST_APP, 'Hello {name}', {name: 'Steve'}, null, {escape: false})
+ ).toEqual('Hello Steve');
+ });
});
describe('plurals', function() {
function checkPlurals() {
diff --git a/settings/js/users/deleteHandler.js b/settings/js/users/deleteHandler.js
index 942bae91cd..fcad39dd4c 100644
--- a/settings/js/users/deleteHandler.js
+++ b/settings/js/users/deleteHandler.js
@@ -201,7 +201,7 @@ DeleteHandler.prototype.deleteEntry = function(keepNotification) {
dh.removeCallback(dh.oidToDelete);
dh.canceled = true;
} else {
- OC.dialogs.alert(result.data.message, t('settings', 'Unable to delete {objName}', {objName: escapeHTML(dh.oidToDelete)}));
+ OC.dialogs.alert(result.data.message, t('settings', 'Unable to delete {objName}', {objName: dh.oidToDelete}));
dh.undoCallback(dh.oidToDelete);
}
}