From 4f625f2e7daee4e0fe1bb62034e3cbfc61c971f7 Mon Sep 17 00:00:00 2001 From: Santhosh Thottingal Date: Mon, 6 Jul 2015 12:56:31 +0530 Subject: [PATCH] Support backslash based escaping for placeholders The simpleParse method of parser, which get invoked if message contains only placeholders, was not supporting escaped placeholders(\\$10) The light weight versio of jquery.i18n when parser.js not included also has the same fix now. Add support for that and add tests. Updated the documentation in README.md too Fixes issue #74 --- README.md | 7 ++++++- src/jquery.i18n.js | 16 +++++++++++----- src/jquery.i18n.parser.js | 11 ++++++++--- test/i18n/test-en.json | 3 ++- test/jquery.i18n.test.js | 7 ++++++- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index da82c2b..9e5de74 100644 --- a/README.md +++ b/README.md @@ -313,7 +313,12 @@ var message = "Welcome, $1"; $.i18n(message, 'Alice'); // This gives "Welcome, Alice" ``` - +To escape the $ sign, use double blackslash in json file. Example: +```javascript +{ + "messageKey": "Price of {{PLURAL:$1|an item|$1 items}} is $2, you get \\$2 discount." +} +``` ## Plurals To make the syntax of sentence correct, plural forms are required. jquery.i18n support plural forms in the message using the syntax `{{PLURAL:$1|pluralform1|pluralform2|...}}` diff --git a/src/jquery.i18n.js b/src/jquery.i18n.js index 7ac8ba8..4633c4f 100644 --- a/src/jquery.i18n.js +++ b/src/jquery.i18n.js @@ -142,7 +142,7 @@ source = 'i18n/' + $.i18n().locale + '.json'; locale = $.i18n().locale; } - if ( typeof source === 'string' && + if ( typeof source === 'string' && source.split( '.' ).pop() !== 'json' ) { // Load specified locale then check for fallbacks when directory is specified in load() @@ -260,16 +260,22 @@ $.i18n.parser = { // The default parser only handles variable substitution parse: function ( message, parameters ) { - return message.replace( /\$(\d+)/g, function ( str, match ) { - var index = parseInt( match, 10 ) - 1; - return parameters[ index ] !== undefined ? parameters[ index ] : '$' + match; + return message.replace( /(\\?\$\d+)/g, function ( str, match ) { + var index; + + if ( match[ 0 ] === '\\' ) { + // Escaped. + return match.slice( 1 ); + } + index = parseInt( match.slice( 1 ), 10 ) - 1; + return parameters[ index ] !== undefined ? parameters[ index ] : match; } ); }, emitter: {} }; $.i18n.fallbacks = {}; $.i18n.debug = false; - $.i18n.log = function ( /* arguments */ ) { + $.i18n.log = function () { if ( window.console && $.i18n.debug ) { window.console.log.apply( window.console, arguments ); } diff --git a/src/jquery.i18n.parser.js b/src/jquery.i18n.parser.js index 8a9ca19..0619500 100644 --- a/src/jquery.i18n.parser.js +++ b/src/jquery.i18n.parser.js @@ -27,10 +27,15 @@ constructor: MessageParser, simpleParse: function ( message, parameters ) { - return message.replace( /\$(\d+)/g, function ( str, match ) { - var index = parseInt( match, 10 ) - 1; + return message.replace( /(\\?\$\d+)/g, function ( str, match ) { + var index; - return parameters[ index ] !== undefined ? parameters[ index ] : '$' + match; + if ( match[ 0 ] === '\\' ) { + // Escaped. + return match.slice( 1 ); + } + index = parseInt( match.slice( 1 ), 10 ) - 1; + return parameters[ index ] !== undefined ? parameters[ index ] : match; } ); }, diff --git a/test/i18n/test-en.json b/test/i18n/test-en.json index 0f65888..cf6844d 100644 --- a/test/i18n/test-en.json +++ b/test/i18n/test-en.json @@ -1,5 +1,6 @@ { "message_1": "ONE", "message_2": "TWO", - "message_3": "THREE" + "message_3": "THREE", + "message_4": "Total \\$1 of \\$1500" } diff --git a/test/jquery.i18n.test.js b/test/jquery.i18n.test.js index fe32b72..fa9284b 100644 --- a/test/jquery.i18n.test.js +++ b/test/jquery.i18n.test.js @@ -34,7 +34,7 @@ } } ); - QUnit.test( 'Message parse tests (en)', 14, function ( assert ) { + QUnit.test( 'Message parse tests (en)', 16, function ( assert ) { var pluralAndGenderMessage, pluralAndGenderMessageWithLessParaMS, pluralAndGenderMessageWithCase, @@ -49,6 +49,7 @@ QUnit.start(); assert.strictEqual( i18n.locale, 'en', 'Locale is English' ); assert.strictEqual( $.i18n( 'message_1' ), 'ONE', 'Simple message' ); + assert.strictEqual( $.i18n( 'message_4', 5 ), 'Total $1 of $1500', 'Parameter replacement escaped' ); } ); assert.strictEqual( $.i18n( 'This message key does not exist' ), @@ -56,6 +57,10 @@ 'This message key does not exist' ); assert.strictEqual( $.i18n( 'Hello $1', 'Bob' ), 'Hello Bob', 'Parameter replacement' ); + assert.strictEqual( + $.i18n( 'Price of {{PLURAL:$1|an item|$1 items}} is $2, you get \\$2 discount', 5, 2000 ), + 'Price of 5 items is 2000, you get $2 discount', 'Parameter replacement with dollar sign escaped, not parsed using simplePaser' + ); pluralAndGenderMessage = '$1 has $2 {{plural:$2|kitten|kittens}}. ' + '{{gender:$3|He|She}} loves to play with {{plural:$2|it|them}}.'; pluralAndGenderMessageWithLessParaMS = '$1 has $2 {{plural:$2|kitten}}. ' +