From 5c4377c454694015b9d34b60b7d2ad4cc9e192da Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Fri, 23 Sep 2016 14:38:34 +0200 Subject: [PATCH 1/2] Completely remove custom inlined `sprintf` implementation If someone wants to use `sprintf()`, they should use the npm module directly. --- jed.js | 180 -------------------------------------------------- test/tests.js | 85 ------------------------ 2 files changed, 265 deletions(-) diff --git a/jed.js b/jed.js index bda163b..150e405 100644 --- a/jed.js +++ b/jed.js @@ -321,191 +321,11 @@ in order to offer easy upgrades -- jsgettext.berlios.de } }); - - // We add in sprintf capabilities for post translation value interolation - // This is not internally used, so you can remove it if you have this - // available somewhere else, or want to use a different system. - - // We _slightly_ modify the normal sprintf behavior to more gracefully handle - // undefined values. - - /** - sprintf() for JavaScript 0.7-beta1 - http://www.diveintojavascript.com/projects/javascript-sprintf - - Copyright (c) Alexandru Marasteanu - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of sprintf() for JavaScript nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - var sprintf = (function() { - function get_type(variable) { - return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase(); - } - function str_repeat(input, multiplier) { - for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */} - return output.join(''); - } - - var str_format = function() { - if (!str_format.cache.hasOwnProperty(arguments[0])) { - str_format.cache[arguments[0]] = str_format.parse(arguments[0]); - } - return str_format.format.call(null, str_format.cache[arguments[0]], arguments); - }; - - str_format.format = function(parse_tree, argv) { - var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length; - for (i = 0; i < tree_length; i++) { - node_type = get_type(parse_tree[i]); - if (node_type === 'string') { - output.push(parse_tree[i]); - } - else if (node_type === 'array') { - match = parse_tree[i]; // convenience purposes only - if (match[2]) { // keyword argument - arg = argv[cursor]; - for (k = 0; k < match[2].length; k++) { - if (!arg.hasOwnProperty(match[2][k])) { - throw(sprintf('[sprintf] property "%s" does not exist', match[2][k])); - } - arg = arg[match[2][k]]; - } - } - else if (match[1]) { // positional argument (explicit) - arg = argv[match[1]]; - } - else { // positional argument (implicit) - arg = argv[cursor++]; - } - - if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) { - throw(sprintf('[sprintf] expecting number but found %s', get_type(arg))); - } - - // Jed EDIT - if ( typeof arg == 'undefined' || arg === null ) { - arg = ''; - } - // Jed EDIT - - switch (match[8]) { - case 'b': arg = arg.toString(2); break; - case 'c': arg = String.fromCharCode(arg); break; - case 'd': arg = parseInt(arg, 10); break; - case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break; - case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break; - case 'o': arg = arg.toString(8); break; - case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break; - case 'u': arg = Math.abs(arg); break; - case 'x': arg = arg.toString(16); break; - case 'X': arg = arg.toString(16).toUpperCase(); break; - } - arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg); - pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' '; - pad_length = match[6] - String(arg).length; - pad = match[6] ? str_repeat(pad_character, pad_length) : ''; - output.push(match[5] ? arg + pad : pad + arg); - } - } - return output.join(''); - }; - - str_format.cache = {}; - - str_format.parse = function(fmt) { - var _fmt = fmt, match = [], parse_tree = [], arg_names = 0; - while (_fmt) { - if ((match = /^[^\x25]+/.exec(_fmt)) !== null) { - parse_tree.push(match[0]); - } - else if ((match = /^\x25{2}/.exec(_fmt)) !== null) { - parse_tree.push('%'); - } - else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) { - if (match[2]) { - arg_names |= 1; - var field_list = [], replacement_field = match[2], field_match = []; - if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { - field_list.push(field_match[1]); - while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { - if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { - field_list.push(field_match[1]); - } - else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) { - field_list.push(field_match[1]); - } - else { - throw('[sprintf] huh?'); - } - } - } - else { - throw('[sprintf] huh?'); - } - match[2] = field_list; - } - else { - arg_names |= 2; - } - if (arg_names === 3) { - throw('[sprintf] mixing positional and named placeholders is not (yet) supported'); - } - parse_tree.push(match); - } - else { - throw('[sprintf] huh?'); - } - _fmt = _fmt.substring(match[0].length); - } - return parse_tree; - }; - - return str_format; - })(); - - var vsprintf = function(fmt, argv) { - argv.unshift(fmt); - return sprintf.apply(null, argv); - }; - Jed.parse_plural = function ( plural_forms, n ) { plural_forms = plural_forms.replace(/n/g, n); return Jed.parse_expression(plural_forms); }; - Jed.sprintf = function ( fmt, args ) { - if ( {}.toString.call( args ) == '[object Array]' ) { - return vsprintf( fmt, [].slice.call(args) ); - } - return sprintf.apply(this, [].slice.call(arguments) ); - }; - - Jed.prototype.sprintf = function () { - return Jed.sprintf.apply(this, arguments); - }; - // END sprintf Implementation - // Start the Plural forms section // This is a full plural form expression parser. It is used to avoid // running 'eval' or 'new Function' directly against the plural diff --git a/test/tests.js b/test/tests.js index 7ebc8c0..25416a1 100644 --- a/test/tests.js +++ b/test/tests.js @@ -652,94 +652,9 @@ expect( i18n.translate("test plural %1$d").ifPlural(5, "dont matta").fetch() ).to.be( "test_1_plural %1$d" ); }); - it("should take in a sprintf set of args (as array) on the plural lookup", function(){ - expect( i18n.translate("test plural %1$d").ifPlural(5, "dont matta").fetch([5]) ).to.be( "test_1_plural 5" ); - expect( i18n.translate("test plural %1$d %2$d").ifPlural(5, "dont matta %1$d %2$d").fetch([5, 6]) ).to.be( "dont matta 5 6" ); - expect( i18n.translate("test plural %1$d %2$d").ifPlural(1, "dont matta %1$d %2$d").fetch([1, 6]) ).to.be( "test plural 1 6" ); - }); - - it("should take in a sprintf set of args (as args) on the plural lookup", function(){ - expect( i18n.translate("test plural %1$d %2$d").ifPlural(5, "dont matta %1$d %2$d").fetch(5, 6) ).to.be( "dont matta 5 6" ); - expect( i18n.translate("test plural %1$d %2$d").ifPlural(1, "dont matta %1$d %2$d").fetch(1, 6) ).to.be( "test plural 1 6" ); - }); - it("should handle context information.", function () { expect(i18n.translate('test context').withContext('context').fetch() ).to.be('test_1context'); }); - - it("should be able to do all at the same time.", function () { - expect( i18n.translate("context other plural %1$d").withContext('context').onDomain('other_domain').ifPlural(5, "ignored %1$d").fetch(5) ).to.be( "context_plural_1 plural 5" ); - expect( i18n.translate("context other plural %1$d").withContext('context').onDomain('other_domain').ifPlural(1, "ignored %1$d").fetch(1) ).to.be( "context_plural_1 singular 1" ); - }); - - }); - - describe("Sprintf", function () { - var locale_data_w_context = { - "context_sprintf_test": { - "": { - "domain": "context_sprintf_test", - "lang": "en", - "plural-forms": "nplurals=2; plural=(n != 1);" - }, - "test singular": ["test_1"], - "test plural %1$d": ["test_1_singular %1$d", "test_1_plural %1$d"], - "context\u0004test context": ["test_1context"], - "test2": ["test_2"], - "zero length translation": [""], - "context\u0004test2": ["test_2context"], - "context\u0004context plural %1$d": ["context_plural_1 singular %1$d", "context_plural_1 plural %1$d"] - } - }; - - var i18n = new Jed({ - "locale_data" : locale_data_w_context, - "domain": "context_sprintf_test" - }); - - - it("should take multiple types of arrays as input", function () { - var strings = { - "blah" : "blah", - "thing%1$sbob" : "thing[one]bob", - "thing%1$s%2$sbob" : "thing[one][two]bob", - "thing%1$sasdf%2$sasdf" : "thing[one]asdf[two]asdf", - "%1$s%2$s%3$s" : "[one][two]", - "tom%1$saDick" : "tom[one]aDick" - }; - var args = ["[one]", "[two]"]; - - for (var i in strings) { - // test using new Array - expect(Jed.sprintf(i, ["[one]","[two]"])).to.be(strings[i]); - expect(i18n.sprintf(i, ["[one]","[two]"])).to.be(strings[i]); - // test using predefined array - expect(Jed.sprintf(i, args)).to.be(strings[i]); - expect(i18n.sprintf(i, args)).to.be(strings[i]); - } - }); - - - - it("should accept a single string instead of an array", function () { - // test using scalar rather than array - var strings = { - "blah" : "blah", - "" : "", - "%%" : "%", - "tom%%dick" : "tom%dick", - "thing%1$sbob" : "thing[one]bob", - "thing%1$s%2$sbob" : "thing[one]bob", - "thing%1$sasdf%2$sasdf" : "thing[one]asdfasdf", - "%1$s%2$s%3$s" : "[one]" - }; - var arg = "[one]"; - - for (var i in strings) { - expect(Jed.sprintf(i, arg)).to.be(strings[i]); - expect(i18n.sprintf(i, arg)).to.be(strings[i]); - } - }); }); })(); From e73612ef4f852cb2730825e26234d92c6e99e6ee Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Fri, 23 Sep 2016 14:42:18 +0200 Subject: [PATCH 2/2] Remove final sprintf dependency --- jed.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jed.js b/jed.js index 150e405..9c5344a 100644 --- a/jed.js +++ b/jed.js @@ -144,7 +144,7 @@ in order to offer easy upgrades -- jsgettext.berlios.de if ( {}.toString.call( sArr ) != '[object Array]' ) { sArr = [].slice.call(arguments, 0); } - return ( sArr && sArr.length ? Jed.sprintf : function(x){ return x; } )( + return ( function(x){ return x; } )( this._i18n.dcnpgettext(this._domain, this._context, this._key, this._pkey, this._val), sArr );