Merge "ApiQueryInfo: fix query limits for testactions"
[lhc/web/wiklou.git] / resources / src / mediawiki.language / mediawiki.language.js
1 /*
2 * Methods for transforming message syntax.
3 */
4 ( function ( mw, $ ) {
5
6 /**
7 * @class mw.language
8 */
9 $.extend( mw.language, {
10
11 /**
12 * Plural form transformations, needed for some languages.
13 *
14 * @param {number} count Non-localized quantifier
15 * @param {Array} forms List of plural forms
16 * @param {Object} [explicitPluralForms] List of explicit plural forms
17 * @return {string} Correct form for quantifier in this language
18 */
19 convertPlural: function ( count, forms, explicitPluralForms ) {
20 var pluralRules,
21 pluralFormIndex = 0;
22
23 if ( explicitPluralForms && ( explicitPluralForms[ count ] !== undefined ) ) {
24 return explicitPluralForms[ count ];
25 }
26
27 if ( !forms || forms.length === 0 ) {
28 return '';
29 }
30
31 pluralRules = mw.language.getData( mw.config.get( 'wgUserLanguage' ), 'pluralRules' );
32 if ( !pluralRules ) {
33 // default fallback.
34 return ( count === 1 ) ? forms[ 0 ] : forms[ 1 ];
35 }
36 pluralFormIndex = mw.cldr.getPluralForm( count, pluralRules );
37 pluralFormIndex = Math.min( pluralFormIndex, forms.length - 1 );
38 return forms[ pluralFormIndex ];
39 },
40
41 /**
42 * Pads an array to a specific length by copying the last one element.
43 *
44 * @private
45 * @param {Array} forms Number of forms given to convertPlural
46 * @param {number} count Number of forms required
47 * @return {Array} Padded array of forms
48 */
49 preConvertPlural: function ( forms, count ) {
50 while ( forms.length < count ) {
51 forms.push( forms[ forms.length - 1 ] );
52 }
53 return forms;
54 },
55
56 /**
57 * Provides an alternative text depending on specified gender.
58 *
59 * Usage in message text: `{{gender:[gender|user object]|masculine|feminine|neutral}}`.
60 * If second or third parameter are not specified, masculine is used.
61 *
62 * These details may be overridden per language.
63 *
64 * @param {string} gender 'male', 'female', or anything else for neutral.
65 * @param {Array} forms List of gender forms
66 * @return {string}
67 */
68 gender: function ( gender, forms ) {
69 if ( !forms || forms.length === 0 ) {
70 return '';
71 }
72 forms = mw.language.preConvertPlural( forms, 2 );
73 if ( gender === 'male' ) {
74 return forms[ 0 ];
75 }
76 if ( gender === 'female' ) {
77 return forms[ 1 ];
78 }
79 return ( forms.length === 3 ) ? forms[ 2 ] : forms[ 0 ];
80 },
81
82 /**
83 * Grammatical transformations, needed for inflected languages.
84 * Invoked by putting `{{grammar:case|word}}` in a message.
85 *
86 * The rules can be defined in $wgGrammarForms global or computed
87 * dynamically by overriding this method per language.
88 *
89 * @param {string} word
90 * @param {string} form
91 * @return {string}
92 */
93 convertGrammar: function ( word, form ) {
94 var userLanguage, forms, transformations,
95 patterns, i, rule, sourcePattern, regexp, replacement;
96
97 userLanguage = mw.config.get( 'wgUserLanguage' );
98
99 forms = mw.language.getData( userLanguage, 'grammarForms' );
100 if ( forms && forms[ form ] ) {
101 return forms[ form ][ word ];
102 }
103
104 transformations = mediaWiki.language.getData( userLanguage, 'grammarTransformations' );
105
106 if ( !( transformations && transformations[ form ] ) ) {
107 return word;
108 }
109
110 patterns = transformations[ form ];
111
112 // Some names of grammar rules are aliases for other rules.
113 // In such cases the value is a string rather than object,
114 // so load the actual rules.
115 if ( typeof patterns === 'string' ) {
116 patterns = transformations[ patterns ];
117 }
118
119 for ( i = 0; i < patterns.length; i++ ) {
120 rule = patterns[ i ];
121 sourcePattern = rule[ 0 ];
122
123 if ( sourcePattern === '@metadata' ) {
124 continue;
125 }
126
127 regexp = new RegExp( sourcePattern );
128 replacement = rule[ 1 ];
129
130 if ( word.match( regexp ) ) {
131 return word.replace( regexp, replacement );
132 }
133 }
134
135 return word;
136 },
137
138 /**
139 * Turn a list of string into a simple list using commas and 'and'.
140 *
141 * See Language::listToText in languages/Language.php
142 *
143 * @param {string[]} list
144 * @return {string}
145 */
146 listToText: function ( list ) {
147 var text = '',
148 i = 0;
149
150 for ( ; i < list.length; i++ ) {
151 text += list[ i ];
152 if ( list.length - 2 === i ) {
153 text += mw.msg( 'and' ) + mw.msg( 'word-separator' );
154 } else if ( list.length - 1 !== i ) {
155 text += mw.msg( 'comma-separator' );
156 }
157 }
158 return text;
159 },
160
161 setSpecialCharacters: function ( data ) {
162 this.specialCharacters = data;
163 },
164
165 /**
166 * Formats language tags according the BCP47 standard.
167 * See LanguageCode::bcp47 for the PHP implementation.
168 *
169 * @param {string} languageTag Well-formed language tag
170 * @return {string}
171 */
172 bcp47: function ( languageTag ) {
173 var formatted,
174 isFirstSegment = true,
175 isPrivate = false,
176 segments = languageTag.split( '-' );
177
178 formatted = segments.map( function ( segment ) {
179 var newSegment;
180
181 // when previous segment is x, it is a private segment and should be lc
182 if ( isPrivate ) {
183 newSegment = segment.toLowerCase();
184 // ISO 3166 country code
185 } else if ( segment.length === 2 && !isFirstSegment ) {
186 newSegment = segment.toUpperCase();
187 // ISO 15924 script code
188 } else if ( segment.length === 4 && !isFirstSegment ) {
189 newSegment = segment.charAt( 0 ).toUpperCase() + segment.substring( 1 ).toLowerCase();
190 // Use lowercase for other cases
191 } else {
192 newSegment = segment.toLowerCase();
193 }
194
195 isPrivate = segment.toLowerCase() === 'x';
196 isFirstSegment = false;
197
198 return newSegment;
199 } );
200
201 return formatted.join( '-' );
202 }
203 } );
204
205 }( mediaWiki, jQuery ) );