http://www.bigbold.com/snippets/posts/show/3205
I have updated his implementation with two goals:
1. Add support for singularize()
2. Update to use Object.extend and add functions to String.prototype
This requires Prototype.
Sadly, the Javascript Number simple type does not allow you to 9.pluralize() // "9th" -- NO LOVE FOR YOU
1 2 pluralize(9) // "9th" 3 'dog'.pluralize() // "dogs" 4 'dog'.pluralize(4) // "4 dogs" 5 'dog'.pluralize(2, 'dogs too many') // "2 dogs too many" 6 'dogs'.singularize() // "dog" 7 'dogs'.singularize(1) // "1 dog"
Dogs suck! CATS FOREVER!
1 2 Inflector = { 3 Inflections: { 4 plural: [ 5 [/(quiz)$/i, "$1zes" ], 6 [/^(ox)$/i, "$1en" ], 7 [/([m|l])ouse$/i, "$1ice" ], 8 [/(matr|vert|ind)ix|ex$/i, "$1ices" ], 9 [/(x|ch|ss|sh)$/i, "$1es" ], 10 [/([^aeiouy]|qu)y$/i, "$1ies" ], 11 [/(hive)$/i, "$1s" ], 12 [/(?:([^f])fe|([lr])f)$/i, "$1$2ves"], 13 [/sis$/i, "ses" ], 14 [/([ti])um$/i, "$1a" ], 15 [/(buffal|tomat)o$/i, "$1oes" ], 16 [/(bu)s$/i, "$1ses" ], 17 [/(alias|status)$/i, "$1es" ], 18 [/(octop|vir)us$/i, "$1i" ], 19 [/(ax|test)is$/i, "$1es" ], 20 [/s$/i, "s" ], 21 [/$/, "s" ] 22 ], 23 singular: [ 24 [/(quiz)zes$/i, "$1" ], 25 [/(matr)ices$/i, "$1ix" ], 26 [/(vert|ind)ices$/i, "$1ex" ], 27 [/^(ox)en/i, "$1" ], 28 [/(alias|status)es$/i, "$1" ], 29 [/(octop|vir)i$/i, "$1us" ], 30 [/(cris|ax|test)es$/i, "$1is" ], 31 [/(shoe)s$/i, "$1" ], 32 [/(o)es$/i, "$1" ], 33 [/(bus)es$/i, "$1" ], 34 [/([m|l])ice$/i, "$1ouse" ], 35 [/(x|ch|ss|sh)es$/i, "$1" ], 36 [/(m)ovies$/i, "$1ovie" ], 37 [/(s)eries$/i, "$1eries"], 38 [/([^aeiouy]|qu)ies$/i, "$1y" ], 39 [/([lr])ves$/i, "$1f" ], 40 [/(tive)s$/i, "$1" ], 41 [/(hive)s$/i, "$1" ], 42 [/([^f])ves$/i, "$1fe" ], 43 [/(^analy)ses$/i, "$1sis" ], 44 [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, "$1$2sis"], 45 [/([ti])a$/i, "$1um" ], 46 [/(n)ews$/i, "$1ews" ], 47 [/s$/i, "" ] 48 ], 49 irregular: [ 50 ['move', 'moves' ], 51 ['sex', 'sexes' ], 52 ['child', 'children'], 53 ['man', 'men' ], 54 ['person', 'people' ] 55 ], 56 uncountable: [ 57 "sheep", 58 "fish", 59 "series", 60 "species", 61 "money", 62 "rice", 63 "information", 64 "equipment" 65 ] 66 }, 67 ordinalize: function(number) { 68 if (11 <= parseInt(number) % 100 && parseInt(number) % 100 <= 13) { 69 return number + "th"; 70 } else { 71 switch (parseInt(number) % 10) { 72 case 1: return number + "st"; 73 case 2: return number + "nd"; 74 case 3: return number + "rd"; 75 default: return number + "th"; 76 } 77 } 78 }, 79 pluralize: function(word) { 80 for (var i = 0; i < Inflector.Inflections.uncountable.length; i++) { 81 var uncountable = Inflector.Inflections.uncountable[i]; 82 if (word.toLowerCase == uncountable) { 83 return uncountable; 84 } 85 } 86 for (var i = 0; i < Inflector.Inflections.irregular.length; i++) { 87 var singular = Inflector.Inflections.irregular[i][0]; 88 var plural = Inflector.Inflections.irregular[i][1]; 89 if ((word.toLowerCase == singular) || (word == plural)) { 90 return plural; 91 } 92 } 93 for (var i = 0; i < Inflector.Inflections.plural.length; i++) { 94 var regex = Inflector.Inflections.plural[i][0]; 95 var replace_string = Inflector.Inflections.plural[i][1]; 96 if (regex.test(word)) { 97 return word.replace(regex, replace_string); 98 } 99 } 100 }, 101 singularize: function(word) { 102 for (var i = 0; i < Inflector.Inflections.uncountable.length; i++) { 103 var uncountable = Inflector.Inflections.uncountable[i]; 104 if (word.toLowerCase == uncountable) { 105 return uncountable; 106 } 107 } 108 for (var i = 0; i < Inflector.Inflections.irregular.length; i++) { 109 var singular = Inflector.Inflections.irregular[i][0]; 110 var plural = Inflector.Inflections.irregular[i][1]; 111 if ((word.toLowerCase == singular) || (word == plural)) { 112 return plural; 113 } 114 } 115 for (var i = 0; i < Inflector.Inflections.singular.length; i++) { 116 var regex = Inflector.Inflections.singular[i][0]; 117 var replace_string = Inflector.Inflections.singular[i][1]; 118 if (regex.test(word)) { 119 return word.replace(regex, replace_string); 120 } 121 } 122 } 123 } 124 125 function ordinalize(number) { 126 return Inflector.ordinalize(number); 127 } 128 129 Object.extend(String.prototype, { 130 pluralize: function(count, plural) { 131 if (typeof count == 'undefined') { 132 return Inflector.pluralize(this); 133 } else { 134 return count + ' ' + (1 == parseInt(count) ? this : plural || Inflector.pluralize(this)); 135 } 136 }, 137 singularize: function(count) { 138 if (typeof count == 'undefined') { 139 return Inflector.singularize(this); 140 } else { 141 return count + " " + Inflector.singularize(this); 142 } 143 } 144 });