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".
/* * This script depends on no outside libraries. */ Inflector = { /* * The order of all these lists has been reversed from the way * ActiveSupport had them to keep the correct priority. */ Inflections: { plural: [ [/(quiz)$/i, "$1zes" ], [/^(ox)$/i, "$1en" ], [/([m|l])ouse$/i, "$1ice" ], [/(matr|vert|ind)ix|ex$/i, "$1ices" ], [/(x|ch|ss|sh)$/i, "$1es" ], [/([^aeiouy]|qu)y$/i, "$1ies" ], [/(hive)$/i, "$1s" ], [/(?:([^f])fe|([lr])f)$/i, "$1$2ves"], [/sis$/i, "ses" ], [/([ti])um$/i, "$1a" ], [/(buffal|tomat)o$/i, "$1oes" ], [/(bu)s$/i, "$1ses" ], [/(alias|status)$/i, "$1es" ], [/(octop|vir)us$/i, "$1i" ], [/(ax|test)is$/i, "$1es" ], [/s$/i, "s" ], [/$/, "s" ] ], singular: [ [/(quiz)zes$/i, "$1" ], [/(matr)ices$/i, "$1ix" ], [/(vert|ind)ices$/i, "$1ex" ], [/^(ox)en/i, "$1" ], [/(alias|status)es$/i, "$1" ], [/(octop|vir)i$/i, "$1us" ], [/(cris|ax|test)es$/i, "$1is" ], [/(shoe)s$/i, "$1" ], [/(o)es$/i, "$1" ], [/(bus)es$/i, "$1" ], [/([m|l])ice$/i, "$1ouse" ], [/(x|ch|ss|sh)es$/i, "$1" ], [/(m)ovies$/i, "$1ovie" ], [/(s)eries$/i, "$1eries"], [/([^aeiouy]|qu)ies$/i, "$1y" ], [/([lr])ves$/i, "$1f" ], [/(tive)s$/i, "$1" ], [/(hive)s$/i, "$1" ], [/([^f])ves$/i, "$1fe" ], [/(^analy)ses$/i, "$1sis" ], [/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, "$1$2sis"], [/([ti])a$/i, "$1um" ], [/(n)ews$/i, "$1ews" ], [/s$/i, "" ] ], irregular: [ ['move', 'moves' ], ['sex', 'sexes' ], ['child', 'children'], ['man', 'men' ], ['person', 'people' ] ], uncountable: [ "sheep", "fish", "series", "species", "money", "rice", "information", "equipment" ] }, ordinalize: function(number) { if (11 <= parseInt(number) % 100 && parseInt(number) % 100 <= 13) { return number + "th"; } else { switch (parseInt(number) % 10) { case 1: return number + "st"; case 2: return number + "nd"; case 3: return number + "rd"; default: return number + "th"; } } }, pluralize: function(word) { for (var i = 0; i < Inflector.Inflections.uncountable.length; i++) { var uncountable = Inflector.Inflections.uncountable[i]; if (word.toLowerCase == uncountable) { return uncountable; } } for (var i = 0; i < Inflector.Inflections.irregular.length; i++) { var singular = Inflector.Inflections.irregular[i][0]; var plural = Inflector.Inflections.irregular[i][1]; if ((word.toLowerCase == singular) || (word == plural)) { return plural; } } for (var i = 0; i < Inflector.Inflections.plural.length; i++) { var regex = Inflector.Inflections.plural[i][0]; var replace_string = Inflector.Inflections.plural[i][1]; if (regex.test(word)) { return word.replace(regex, replace_string); } } } } function ordinalize(number) { return Inflector.ordinalize(number); } /* * Javascript doesn't have optional parameters or overloading so I had to use * the ever popular pseudo options hash object technique. * required properties: * count Number of objects to pluralize * singular Singular noun for the objects * optional property: * plural Plural (probably irregular) noun for the objects * examples: * pluralize({ count: total_count, singular: "Issue" }) * pluralize({ count: total_count, singular: "Goose", plural: "Geese" }) */ function pluralize(options) { return options.count + " " + (1 == parseInt(options.count) ? options.singular : options.plural || Inflector.pluralize(options.singular)); }