From 02e740fe262d4b240fbd3ea663945870637d4b6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=A6Max?= Date: Sat, 19 Jul 2014 00:47:40 +0300 Subject: [PATCH] Implemented pluralization mechanism (p11n:) --- libs/dojox/jtlc/CHT.js | 10 ++++-- libs/dojox/jtlc/CHT/p11nAlgorithm.js | 51 ++++++++++++++++++++++++++++ libs/dojox/jtlc/CHT/tags.js | 40 ++++++++++++++++++++++ 3 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 libs/dojox/jtlc/CHT/p11nAlgorithm.js diff --git a/libs/dojox/jtlc/CHT.js b/libs/dojox/jtlc/CHT.js index bcd773e..3934952 100644 --- a/libs/dojox/jtlc/CHT.js +++ b/libs/dojox/jtlc/CHT.js @@ -1,4 +1,5 @@ -// Copyright (C) 2010-2014 Adstream Holdings +// Copyright (C) 2013-2014 12 Quarters Consulting +// Copyright (C) 2010-2013 Adstream Holdings // All rights reserved. // Redistribution and use are permitted under the modified BSD license // available at https://github.com/MaxMotovilov/adstream-js-frameworks/wiki/License @@ -9,6 +10,7 @@ dojo.require( "dojox.jtlc.CHT.scanner" ); dojo.require( "dojox.jtlc.CHT.instance" ); dojo.require( "dojox.jtlc.CHT.elements" ); dojo.require( "dojox.jtlc.CHT.tags" ); +dojo.require( "dojox.jtlc.CHT.p11nAlgorithm" ); dojo.require( "dojox.jtlc.qplus" ); @@ -54,6 +56,9 @@ dojo.declare( 'dojox.jtlc.CHT', dj._qplusL, { if( !settings.tags ) settings.tags = this.tags; + if( !settings.p11nAlgorithm ) + settings.p11nAlgorithm = this.p11nAlgorithm; + this.qplus = new dj.qplus( settings ); }, @@ -547,7 +552,8 @@ dojo.declare( 'dojox.jtlc.CHT', dj._qplusL, { // at this point, dojox.jtlc.CHT.tags and dojox.jtlc.CHT.elements are not yet overwritten! tags: dojo.delegate( dj.qplus.prototype.tags, dj.CHT.tags ), - elements: dj.CHT.elements + elements: dj.CHT.elements, + p11nAlgorithm: dj.CHT.p11nAlgorithm }); })(); diff --git a/libs/dojox/jtlc/CHT/p11nAlgorithm.js b/libs/dojox/jtlc/CHT/p11nAlgorithm.js new file mode 100644 index 0000000..5646c33 --- /dev/null +++ b/libs/dojox/jtlc/CHT/p11nAlgorithm.js @@ -0,0 +1,51 @@ +// Copyright (C) 2014 12 Quarters Consulting +// All rights reserved. +// Redistribution and use are permitted under the modified BSD license +// available at https://github.com/MaxMotovilov/adstream-js-frameworks/wiki/License + +dojo.provide( "dojox.jtlc.CHT.p11nAlgorithm" ); + +dojox.jtlc.CHT.p11nAlgorithm = (function(){ + + // Based on https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_and_Plurals + + var rules = { + // FIXME: add all other locales + en: 1, es: 1, it: 1, de:1, pt: 1, 'pt-br': 2, fr: 2, ru: 7, uk: 7, be: 7 + }, + + algorithms = [ + function() { return 0 }, + function( n ) { return n==1 ? 0 : 1 }, + function( n ) { return n==0 || n==1 ? 0 : 1 }, + function( n ) { return n==0 ? 0 : n!=11 && n%10==1 ? 1 : 2 }, + function( n ) { return n==1 || n==11 ? 0 : n==2 || n==12 ? 1 : inRange( 3, n, 10 ) || inRange( 13, n, 19 ) ? 2 : 3 }, + function( n ) { return n==1 ? 0 : n==0 || inRange( 1, n%100, 19 ) ? 1 : 2 }, + function( n ) { return n%10==1 && n!=11 ? 0 : n%10==0 || inRange( 11, n%100, 19 ) ? 1 : 2 }, + function( n ) { return n%10==1 && n!=11 ? 0 : inRange( 2, n%10, 4 ) && !inRange( 12, n, 14 ) ? 1 : 2 }, + function( n ) { return n==1 ? 0 : inRange( 2, n, 4 ) ? 1 : 2 }, + function( n ) { return n==1 ? 0 : inRange( 2, n%10, 4 ) && !inRange( 12, n, 14 ) ? 1 : 2 }, + function( n ) { return n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3 }, + function( n ) { return n==1 ? 0 : n==2 ? 1 : inRange( 3, n, 6 ) ? 2 : inRange( 7, n, 10 ) ? 3 : 4 }, + function( n ) { return n==0 ? 5 : n==1 ? 0 : n==2 ? 1 : inRange( 3, n%100, 10 ) ? 2 : inRange( 0, n%100, 2 ) ? 4 : 3 }, + function( n ) { return n==1 ? 0 : n==0 || inRange( 1, n%100, 10 ) ? 1 : inRange( 11, n%100, 19 ) ? 2 : 3 }, + function( n ) { return n%10==1 ? 0 : n%10==2 ? 1 : 2 }, + function( n ) { return n%10==1 && n!=11 ? 0 : 1 }, + function( n ) { return n==1 ? 0 : n%10==1 && !{11:1, 71:1, 91:1}[n] ? 1 : n%10==2 && !{12:1, 72:1, 92:1}[n] ? 2 : + {3:1, 4:1, 9:1}[n%10] && !{13:1, 14:1, 19:1, 73:1, 74:1, 79:1, 93:1, 94:1, 99:1}[n] ? 3 : n%1000000==0 ? 4 : 5 } + ]; + + function inRange( a, b, c ) { + return a <= b && b <= c; + } + + return function( value, words ) { + var n = Number( value ); + if( Number.isNaN( n ) ) + throw Error( "p11nAlgorithm: \"" + value + "\" is not a number" ); + n = Math.round( Math.abs( n ) ); + + var i = algorithms[ rules[dojo.locale.toLowerCase()] || rules[dojo.locale.substr(0,2).toLowerCase()] || 0 ]( value ); + return words[i] || words[0]; + } +})(); \ No newline at end of file diff --git a/libs/dojox/jtlc/CHT/tags.js b/libs/dojox/jtlc/CHT/tags.js index a0bf176..7d3010e 100644 --- a/libs/dojox/jtlc/CHT/tags.js +++ b/libs/dojox/jtlc/CHT/tags.js @@ -1,3 +1,4 @@ +// Copyright (C) 2013-2014 12 Quarters Consulting // Copyright (C) 2010-2012 Adstream Holdings // All rights reserved. // Redistribution and use are permitted under the modified BSD license @@ -35,6 +36,10 @@ dojo.require( 'dojox.jtlc.tags' ); return v.join( ' ' ); } + function isLowerCase(c) { + return c == c.toLowerCase(); + } + dj.CHT._declareTag( 'foreachBody', { constructor: function( body, input ) { @@ -149,6 +154,41 @@ dojo.require( 'dojox.jtlc.tags' ); } } ) ); + dj.CHT._declareTag( 'p11n', { + constructor: function( words, arg ) { + if( typeof words !== 'string' ) + throw Error( "p11n() expects a string, not " + words.toString() ); + this.words = words.replace( /^\s*|\s*$/g, '' ).replace( /\s*\+\s*/g, '+' ); + if( this.words.indexOf( '+' ) < 0 ) { + if( "sS".indexOf( this.words.charAt( this.words.length-1 ) ) ) + this.words = this.words.substr(0,this.words.length-1) + '+' + this.words; + else + this.words += '+' + this.words + ( isLowerCase( this.words.charAt( this.words.length-1 ) ) ? 's' : 'S' ); + } + if( arg ) this.arg = arg; + }, + + compile: function( self ) { + var d = this.i18nDictionary; + if( self.arg ) this.compile( self.arg ); + else this.generator(); + + this._pluralizeFunction = this._pluralizeFunction || this.addGlobal( this.p11nAlgorithm ); + + this.expressions.push( + this._pluralizeFunction + '(' + + this.popExpression() + ',[' + + ( + d && self.words in d ? d[self.words] : self.words + ).replace( /^\s*|\s*$/g, '' ) + .split( /\s*\+\s*/g ) + .map( dj.stringLiteral ) + .join(',') + + '])' + ); + } + } ); + var escapeTag = dojo.declare( null, { constructor: function( arg ) { this.arg = arg;