3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.util.Inflector
18 * <p>General purpose inflector class that {@link #pluralize pluralizes}, {@link #singularize singularizes} and
19 * {@link #ordinalize ordinalizes} words. Sample usage:</p>
22 //turning singular words into plurals
23 Ext.util.Inflector.pluralize('word'); //'words'
24 Ext.util.Inflector.pluralize('person'); //'people'
25 Ext.util.Inflector.pluralize('sheep'); //'sheep'
27 //turning plurals into singulars
28 Ext.util.Inflector.singularize('words'); //'word'
29 Ext.util.Inflector.singularize('people'); //'person'
30 Ext.util.Inflector.singularize('sheep'); //'sheep'
32 //ordinalizing numbers
33 Ext.util.Inflector.ordinalize(11); //"11th"
34 Ext.util.Inflector.ordinalize(21); //"21th"
35 Ext.util.Inflector.ordinalize(1043); //"1043rd"
38 * <p><u>Customization</u></p>
40 * <p>The Inflector comes with a default set of US English pluralization rules. These can be augmented with additional
41 * rules if the default rules do not meet your application's requirements, or swapped out entirely for other languages.
42 * Here is how we might add a rule that pluralizes "ox" to "oxen":</p>
45 Ext.util.Inflector.plural(/^(ox)$/i, "$1en");
48 * <p>Each rule consists of two items - a regular expression that matches one or more rules, and a replacement string.
49 * In this case, the regular expression will only match the string "ox", and will replace that match with "oxen".
50 * Here's how we could add the inverse rule:</p>
53 Ext.util.Inflector.singular(/^(ox)en$/i, "$1");
56 * <p>Note that the ox/oxen rules are present by default.</p>
61 Ext.define('Ext.util.Inflector', {
63 /* Begin Definitions */
71 * The registered plural tuples. Each item in the array should contain two items - the first must be a regular
72 * expression that matchers the singular form of a word, the second must be a String that replaces the matched
73 * part of the regular expression. This is managed by the {@link #plural} method.
78 [(/(quiz)$/i), "$1zes" ],
79 [(/^(ox)$/i), "$1en" ],
80 [(/([m|l])ouse$/i), "$1ice" ],
81 [(/(matr|vert|ind)ix|ex$/i), "$1ices" ],
82 [(/(x|ch|ss|sh)$/i), "$1es" ],
83 [(/([^aeiouy]|qu)y$/i), "$1ies" ],
84 [(/(hive)$/i), "$1s" ],
85 [(/(?:([^f])fe|([lr])f)$/i), "$1$2ves"],
87 [(/([ti])um$/i), "$1a" ],
88 [(/(buffal|tomat|potat)o$/i), "$1oes" ],
89 [(/(bu)s$/i), "$1ses" ],
90 [(/(alias|status|sex)$/i), "$1es" ],
91 [(/(octop|vir)us$/i), "$1i" ],
92 [(/(ax|test)is$/i), "$1es" ],
93 [(/^person$/), "people" ],
95 [(/^(child)$/), "$1ren" ],
102 * The set of registered singular matchers. Each item in the array should contain two items - the first must be a
103 * regular expression that matches the plural form of a word, the second must be a String that replaces the
104 * matched part of the regular expression. This is managed by the {@link #singular} method.
105 * @property singulars
109 [(/(quiz)zes$/i), "$1" ],
110 [(/(matr)ices$/i), "$1ix" ],
111 [(/(vert|ind)ices$/i), "$1ex" ],
112 [(/^(ox)en/i), "$1" ],
113 [(/(alias|status)es$/i), "$1" ],
114 [(/(octop|vir)i$/i), "$1us" ],
115 [(/(cris|ax|test)es$/i), "$1is" ],
116 [(/(shoe)s$/i), "$1" ],
117 [(/(o)es$/i), "$1" ],
118 [(/(bus)es$/i), "$1" ],
119 [(/([m|l])ice$/i), "$1ouse" ],
120 [(/(x|ch|ss|sh)es$/i), "$1" ],
121 [(/(m)ovies$/i), "$1ovie" ],
122 [(/(s)eries$/i), "$1eries"],
123 [(/([^aeiouy]|qu)ies$/i), "$1y" ],
124 [(/([lr])ves$/i), "$1f" ],
125 [(/(tive)s$/i), "$1" ],
126 [(/(hive)s$/i), "$1" ],
127 [(/([^f])ves$/i), "$1fe" ],
128 [(/(^analy)ses$/i), "$1sis" ],
129 [(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i), "$1$2sis"],
130 [(/([ti])a$/i), "$1um" ],
131 [(/(n)ews$/i), "$1ews" ],
132 [(/people$/i), "person" ],
138 * The registered uncountable words
139 * @property uncountable
159 * Adds a new singularization rule to the Inflector. See the intro docs for more information
160 * @param {RegExp} matcher The matcher regex
161 * @param {String} replacer The replacement string, which can reference matches from the matcher argument
163 singular: function(matcher, replacer) {
164 this.singulars.unshift([matcher, replacer]);
168 * Adds a new pluralization rule to the Inflector. See the intro docs for more information
169 * @param {RegExp} matcher The matcher regex
170 * @param {String} replacer The replacement string, which can reference matches from the matcher argument
172 plural: function(matcher, replacer) {
173 this.plurals.unshift([matcher, replacer]);
177 * Removes all registered singularization rules
179 clearSingulars: function() {
184 * Removes all registered pluralization rules
186 clearPlurals: function() {
191 * Returns true if the given word is transnumeral (the word is its own singular and plural form - e.g. sheep, fish)
192 * @param {String} word The word to test
193 * @return {Boolean} True if the word is transnumeral
195 isTransnumeral: function(word) {
196 return Ext.Array.indexOf(this.uncountable, word) != -1;
200 * Returns the pluralized form of a word (e.g. Ext.util.Inflector.pluralize('word') returns 'words')
201 * @param {String} word The word to pluralize
202 * @return {String} The pluralized form of the word
204 pluralize: function(word) {
205 if (this.isTransnumeral(word)) {
209 var plurals = this.plurals,
210 length = plurals.length,
213 for (i = 0; i < length; i++) {
217 if (regex == word || (regex.test && regex.test(word))) {
218 return word.replace(regex, tuple[1]);
226 * Returns the singularized form of a word (e.g. Ext.util.Inflector.singularize('words') returns 'word')
227 * @param {String} word The word to singularize
228 * @return {String} The singularized form of the word
230 singularize: function(word) {
231 if (this.isTransnumeral(word)) {
235 var singulars = this.singulars,
236 length = singulars.length,
239 for (i = 0; i < length; i++) {
240 tuple = singulars[i];
243 if (regex == word || (regex.test && regex.test(word))) {
244 return word.replace(regex, tuple[1]);
252 * Returns the correct {@link Ext.data.Model Model} name for a given string. Mostly used internally by the data
254 * @param {String} word The word to classify
255 * @return {String} The classified version of the word
257 classify: function(word) {
258 return Ext.String.capitalize(this.singularize(word));
262 * Ordinalizes a given number by adding a prefix such as 'st', 'nd', 'rd' or 'th' based on the last digit of the
263 * number. 21 -> 21st, 22 -> 22nd, 23 -> 23rd, 24 -> 24th etc
264 * @param {Number} number The number to ordinalize
265 * @return {String} The ordinalized number
267 ordinalize: function(number) {
268 var parsed = parseInt(number, 10),
270 mod100 = parsed % 100;
272 //11 through 13 are a special case
273 if (11 <= mod100 && mod100 <= 13) {
274 return number + "th";
277 case 1 : return number + "st";
278 case 2 : return number + "nd";
279 case 3 : return number + "rd";
280 default: return number + "th";
285 //aside from the rules above, there are a number of words that have irregular pluralization so we add them here
293 ellipsis: 'ellipses',
294 paralysis: 'paralyses',
296 appendix: 'appendices',
305 criterion: 'criteria',
306 curriculum: 'curricula',
308 memorandum: 'memoranda',
309 phenomenon: 'phenomena',
316 vertebra: 'vertebrae',
321 for (singular in irregulars) {
322 this.plural(singular, irregulars[singular]);
323 this.singular(irregulars[singular], singular);