2 * Methods for transforming message syntax.
9 $.extend( mw
.language
, {
12 * Plural form transformations, needed for some languages.
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
19 convertPlural: function ( count
, forms
, explicitPluralForms
) {
23 if ( explicitPluralForms
&& ( explicitPluralForms
[ count
] !== undefined ) ) {
24 return explicitPluralForms
[ count
];
27 if ( !forms
|| forms
.length
=== 0 ) {
31 pluralRules
= mw
.language
.getData( mw
.config
.get( 'wgUserLanguage' ), 'pluralRules' );
34 return ( count
=== 1 ) ? forms
[ 0 ] : forms
[ 1 ];
36 pluralFormIndex
= mw
.cldr
.getPluralForm( count
, pluralRules
);
37 pluralFormIndex
= Math
.min( pluralFormIndex
, forms
.length
- 1 );
38 return forms
[ pluralFormIndex
];
42 * Pads an array to a specific length by copying the last one element.
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
49 preConvertPlural: function ( forms
, count
) {
50 while ( forms
.length
< count
) {
51 forms
.push( forms
[ forms
.length
- 1 ] );
57 * Provides an alternative text depending on specified gender.
59 * Usage in message text: `{{gender:[gender|user object]|masculine|feminine|neutral}}`.
60 * If second or third parameter are not specified, masculine is used.
62 * These details may be overridden per language.
64 * @param {string} gender 'male', 'female', or anything else for neutral.
65 * @param {Array} forms List of gender forms
68 gender: function ( gender
, forms
) {
69 if ( !forms
|| forms
.length
=== 0 ) {
72 forms
= mw
.language
.preConvertPlural( forms
, 2 );
73 if ( gender
=== 'male' ) {
76 if ( gender
=== 'female' ) {
79 return ( forms
.length
=== 3 ) ? forms
[ 2 ] : forms
[ 0 ];
83 * Grammatical transformations, needed for inflected languages.
84 * Invoked by putting `{{grammar:case|word}}` in a message.
86 * The rules can be defined in $wgGrammarForms global or computed
87 * dynamically by overriding this method per language.
89 * @param {string} word
90 * @param {string} form
93 convertGrammar: function ( word
, form
) {
94 var userLanguage
, forms
, transformations
,
95 patterns
, i
, rule
, sourcePattern
, regexp
, replacement
;
97 userLanguage
= mw
.config
.get( 'wgUserLanguage' );
99 forms
= mw
.language
.getData( userLanguage
, 'grammarForms' );
100 if ( forms
&& forms
[ form
] ) {
101 return forms
[ form
][ word
];
104 transformations
= mw
.language
.getData( userLanguage
, 'grammarTransformations' );
106 if ( !( transformations
&& transformations
[ form
] ) ) {
110 patterns
= transformations
[ form
];
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
];
119 for ( i
= 0; i
< patterns
.length
; i
++ ) {
120 rule
= patterns
[ i
];
121 sourcePattern
= rule
[ 0 ];
123 if ( sourcePattern
=== '@metadata' ) {
127 regexp
= new RegExp( sourcePattern
);
128 replacement
= rule
[ 1 ];
130 if ( word
.match( regexp
) ) {
131 return word
.replace( regexp
, replacement
);
139 * Turn a list of string into a simple list using commas and 'and'.
141 * See Language::listToText in languages/Language.php
143 * @param {string[]} list
146 listToText: function ( list
) {
150 for ( ; i
< list
.length
; 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' );
161 setSpecialCharacters: function ( data
) {
162 this.specialCharacters
= data
;
166 * Formats language tags according the BCP47 standard.
167 * See LanguageCode::bcp47 for the PHP implementation.
169 * @param {string} languageTag Well-formed language tag
172 bcp47: function ( languageTag
) {
174 isFirstSegment
= true,
176 segments
= languageTag
.split( '-' );
178 formatted
= segments
.map( function ( segment
) {
181 // when previous segment is x, it is a private segment and should be lc
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
192 newSegment
= segment
.toLowerCase();
195 isPrivate
= segment
.toLowerCase() === 'x';
196 isFirstSegment
= false;
201 return formatted
.join( '-' );