Javascript Rails-like inflector
The only part of ActiveSupport's Inflector class I implemented are the ones I needed. I implemented even fewer of Rails' Inflector-based functions.
Stick all this in a file, such as "inflector.js".
1 /* 2 * This script depends on no outside libraries. 3 */ 4 5 Inflector = { 6 /* 7 * The order of all these lists has been reversed from the way 8 * ActiveSupport had them to keep the correct priority. 9 */ 10 Inflections: { 11 plural: [ 12 [/(quiz)$/i, "$1zes" ], 13 [/^(ox)$/i, "$1en" ], 14 [/([m|l])ouse$/i, "$1ice" ], 15 [/(matr|vert|ind)ix|ex$/i, "$1ices" ], 16 [/(x|ch|ss|sh)$/i, "$1es" ], 17 [/([^aeiouy]|qu)y$/i, "$1ies" ], 18 [/(hive)$/i, "$1s" ], 19 [/(?:([^f])fe|([lr])f)$/i, "$1$2ves"], 20 [/sis$/i, "ses" ], 21 [/([ti])um$/i, "$1a" ], 22 [/(buffal|tomat)o$/i, "$1oes" ], 23 [/(bu)s$/i, "$1ses" ], 24 [/(alias|status)$/i, "$1es" ], 25 [/(octop|vir)us$/i, "$1i" ], 26 [/(ax|test)is$/i, "$1es" ], 27 [/s$/i, "s" ], 28 [/$/, "s" ] 29 ], 30 singular: [ 31 [/(quiz)zes$/i, "$1" ], 32 [/(matr)ices$/i, "$1ix" ], 33 [/(vert|ind)ices$/i, "$1ex" ], 34 [/^(ox)en/i, "$1" ], 35 [/(alias|status)es$/i, "$1" ], 36 [/(octop|vir)i$/i, "$1us" ], 37 [/(cris|ax|test)es$/i, "$1is" ], 38 [/(shoe)s$/i, "$1" ], 39 [/(o)es$/i, "$1" ], 40 [/(bus)es$/i, "$1" ], 41 [/([m|l])ice$/i, "$1ouse" ], 42 [/(x|ch|ss|sh)es$/i, "$1" ], 43 [/(m)ovies$/i, "$1ovie" ], 44 [/(s)eries$/i, "$1eries"], 45 [/([^aeiouy]|qu)ies$/i, "$1y" ], 46 [/([lr])ves$/i, "$1f" ], 47 [/(tive)s$/i, "$1" ], 48 [/(hive)s$/i, "$1" ], 49 [/([^f])ves$/i, "$1fe" ], 50 [/(^analy)ses$/i, "$1sis" ], 51 [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, "$1$2sis"], 52 [/([ti])a$/i, "$1um" ], 53 [/(n)ews$/i, "$1ews" ], 54 [/s$/i, "" ] 55 ], 56 irregular: [ 57 ['move', 'moves' ], 58 ['sex', 'sexes' ], 59 ['child', 'children'], 60 ['man', 'men' ], 61 ['person', 'people' ] 62 ], 63 uncountable: [ 64 "sheep", 65 "fish", 66 "series", 67 "species", 68 "money", 69 "rice", 70 "information", 71 "equipment" 72 ] 73 }, 74 ordinalize: function(number) { 75 if (11 <= parseInt(number) % 100 && parseInt(number) % 100 <= 13) { 76 return number + "th"; 77 } else { 78 switch (parseInt(number) % 10) { 79 case 1: return number + "st"; 80 case 2: return number + "nd"; 81 case 3: return number + "rd"; 82 default: return number + "th"; 83 } 84 } 85 }, 86 pluralize: function(word) { 87 for (var i = 0; i < Inflector.Inflections.uncountable.length; i++) { 88 var uncountable = Inflector.Inflections.uncountable[i]; 89 if (word.toLowerCase == uncountable) { 90 return uncountable; 91 } 92 } 93 for (var i = 0; i < Inflector.Inflections.irregular.length; i++) { 94 var singular = Inflector.Inflections.irregular[i][0]; 95 var plural = Inflector.Inflections.irregular[i][1]; 96 if ((word.toLowerCase == singular) || (word == plural)) { 97 return plural; 98 } 99 } 100 for (var i = 0; i < Inflector.Inflections.plural.length; i++) { 101 var regex = Inflector.Inflections.plural[i][0]; 102 var replace_string = Inflector.Inflections.plural[i][1]; 103 if (regex.test(word)) { 104 return word.replace(regex, replace_string); 105 } 106 } 107 } 108 } 109 110 function ordinalize(number) { 111 return Inflector.ordinalize(number); 112 } 113 114 /* 115 * Javascript doesn't have optional parameters or overloading so I had to use 116 * the ever popular pseudo options hash object technique. 117 * required properties: 118 * count Number of objects to pluralize 119 * singular Singular noun for the objects 120 * optional property: 121 * plural Plural (probably irregular) noun for the objects 122 * examples: 123 * pluralize({ count: total_count, singular: "Issue" }) 124 * pluralize({ count: total_count, singular: "Goose", plural: "Geese" }) 125 */ 126 function pluralize(options) { 127 return options.count + " " + (1 == parseInt(options.count) ? 128 options.singular : 129 options.plural || Inflector.pluralize(options.singular)); 130 }