Merge "Clean some phpcs errors in Preferences.php"
[mediawiki.git] / maintenance / language / languages.inc
blob61ee424a9939b515eed21fc6f3e6f37a54c64101
1 <?php
2 /**
3  * Handle messages in the language files.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  * http://www.gnu.org/copyleft/gpl.html
19  *
20  * @file
21  * @ingroup MaintenanceLanguage
22  */
24 /**
25  * @ingroup MaintenanceLanguage
26  */
27 class Languages {
28         /** @var array List of languages */
29         protected $mLanguages; #
31         /** @var array Raw list of the messages in each language  */
32         protected $mRawMessages;
34         /** @var array Messages in each language (except for English), divided to groups */
35         protected $mMessages;
37         /** @var array Fallback language in each language */
38         protected $mFallback;
40         /** @var array General messages in English, divided to groups */
41         protected $mGeneralMessages;
43         /** @var array All the messages which should be exist only in the English file */
44         protected $mIgnoredMessages;
46         /** @var array All the messages which may be translated or not, depending on the language */
47         protected $mOptionalMessages;
49         /** @var array Namespace names */
50         protected $mNamespaceNames;
52         /** @var array Namespace aliases */
53         protected $mNamespaceAliases;
55         /** @var array Magic words */
56         protected $mMagicWords;
58         /** @var  array Special page aliases */
59         protected $mSpecialPageAliases;
61         /**
62          * Load the list of languages: all the Messages*.php
63          * files in the languages directory.
64          *
65          * @param $exif bool Treat the Exif messages?
66          */
67         function __construct( $exif = true ) {
68                 require __DIR__ . '/messageTypes.inc';
69                 $this->mIgnoredMessages = $wgIgnoredMessages;
70                 if ( $exif ) {
71                         $this->mOptionalMessages = array_merge( $wgOptionalMessages );
72                 } else {
73                         $this->mOptionalMessages = array_merge( $wgOptionalMessages, $wgEXIFMessages );
74                 }
76                 $this->mLanguages = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) );
77                 sort( $this->mLanguages );
78         }
80         /**
81          * Get the language list.
82          *
83          * @return array The language list.
84          */
85         public function getLanguages() {
86                 return $this->mLanguages;
87         }
89         /**
90          * Get the ignored messages list.
91          *
92          * @return array The ignored messages list.
93          */
94         public function getIgnoredMessages() {
95                 return $this->mIgnoredMessages;
96         }
98         /**
99          * Get the optional messages list.
100          *
101          * @return array The  optional messages list.
102          */
103         public function getOptionalMessages() {
104                 return $this->mOptionalMessages;
105         }
107         /**
108          * Load the language file.
109          *
110          * @param $code string The language code.
111          */
112         protected function loadFile( $code ) {
113                 if ( isset( $this->mRawMessages[$code] ) &&
114                         isset( $this->mFallback[$code] ) &&
115                         isset( $this->mNamespaceNames[$code] ) &&
116                         isset( $this->mNamespaceAliases[$code] ) &&
117                         isset( $this->mMagicWords[$code] ) &&
118                         isset( $this->mSpecialPageAliases[$code] )
119                 ) {
120                         return;
121                 }
122                 $this->mRawMessages[$code] = array();
123                 $this->mFallback[$code] = '';
124                 $this->mNamespaceNames[$code] = array();
125                 $this->mNamespaceAliases[$code] = array();
126                 $this->mMagicWords[$code] = array();
127                 $this->mSpecialPageAliases[$code] = array();
128                 $filename = Language::getMessagesFileName( $code );
129                 if ( file_exists( $filename ) ) {
130                         require $filename;
131                         if ( isset( $messages ) ) {
132                                 $this->mRawMessages[$code] = $messages;
133                         }
134                         if ( isset( $fallback ) ) {
135                                 $this->mFallback[$code] = $fallback;
136                         }
137                         if ( isset( $namespaceNames ) ) {
138                                 $this->mNamespaceNames[$code] = $namespaceNames;
139                         }
140                         if ( isset( $namespaceAliases ) ) {
141                                 $this->mNamespaceAliases[$code] = $namespaceAliases;
142                         }
143                         if ( isset( $magicWords ) ) {
144                                 $this->mMagicWords[$code] = $magicWords;
145                         }
146                         if ( isset( $specialPageAliases ) ) {
147                                 $this->mSpecialPageAliases[$code] = $specialPageAliases;
148                         }
149                 }
150         }
152         /**
153          * Load the messages for a specific language (which is not English) and divide them to
154          * groups:
155          * all - all the messages.
156          * required - messages which should be translated in order to get a complete translation.
157          * optional - messages which can be translated, the fallback translation is used if not
158          *   translated.
159          * obsolete - messages which should not be translated, either because they do not exist,
160          *   or they are ignored messages.
161          * translated - messages which are either required or optional, but translated from
162          *   English and needed.
163          *
164          * @param $code string The language code.
165          */
166         private function loadMessages( $code ) {
167                 if ( isset( $this->mMessages[$code] ) ) {
168                         return;
169                 }
170                 $this->loadFile( $code );
171                 $this->loadGeneralMessages();
172                 $this->mMessages[$code]['all'] = $this->mRawMessages[$code];
173                 $this->mMessages[$code]['required'] = array();
174                 $this->mMessages[$code]['optional'] = array();
175                 $this->mMessages[$code]['obsolete'] = array();
176                 $this->mMessages[$code]['translated'] = array();
177                 foreach ( $this->mMessages[$code]['all'] as $key => $value ) {
178                         if ( isset( $this->mGeneralMessages['required'][$key] ) ) {
179                                 $this->mMessages[$code]['required'][$key] = $value;
180                                 $this->mMessages[$code]['translated'][$key] = $value;
181                         } elseif ( isset( $this->mGeneralMessages['optional'][$key] ) ) {
182                                 $this->mMessages[$code]['optional'][$key] = $value;
183                                 $this->mMessages[$code]['translated'][$key] = $value;
184                         } else {
185                                 $this->mMessages[$code]['obsolete'][$key] = $value;
186                         }
187                 }
188         }
190         /**
191          * Load the messages for English and divide them to groups:
192          * all - all the messages.
193          * required - messages which should be translated to other languages in order to get a
194          *   complete translation.
195          * optional - messages which can be translated to other languages, but it's not required
196          *   for a complete translation.
197          * ignored - messages which should not be translated to other languages.
198          * translatable - messages which are either required or optional, but can be translated
199          *   from English.
200          */
201         private function loadGeneralMessages() {
202                 if ( isset( $this->mGeneralMessages ) ) {
203                         return;
204                 }
205                 $this->loadFile( 'en' );
206                 $this->mGeneralMessages['all'] = $this->mRawMessages['en'];
207                 $this->mGeneralMessages['required'] = array();
208                 $this->mGeneralMessages['optional'] = array();
209                 $this->mGeneralMessages['ignored'] = array();
210                 $this->mGeneralMessages['translatable'] = array();
211                 foreach ( $this->mGeneralMessages['all'] as $key => $value ) {
212                         if ( in_array( $key, $this->mIgnoredMessages ) ) {
213                                 $this->mGeneralMessages['ignored'][$key] = $value;
214                         } elseif ( in_array( $key, $this->mOptionalMessages ) ) {
215                                 $this->mGeneralMessages['optional'][$key] = $value;
216                                 $this->mGeneralMessages['translatable'][$key] = $value;
217                         } else {
218                                 $this->mGeneralMessages['required'][$key] = $value;
219                                 $this->mGeneralMessages['translatable'][$key] = $value;
220                         }
221                 }
222         }
224         /**
225          * Get all the messages for a specific language (not English), without the
226          * fallback language messages, divided to groups:
227          * all - all the messages.
228          * required - messages which should be translated in order to get a complete translation.
229          * optional - messages which can be translated, the fallback translation is used if not
230          *   translated.
231          * obsolete - messages which should not be translated, either because they do not exist,
232          *   or they are ignored messages.
233          * translated - messages which are either required or optional, but translated from
234          *   English and needed.
235          *
236          * @param $code string The language code.
237          *
238          * @return string The messages in this language.
239          */
240         public function getMessages( $code ) {
241                 $this->loadMessages( $code );
243                 return $this->mMessages[$code];
244         }
246         /**
247          * Get all the general English messages, divided to groups:
248          * all - all the messages.
249          * required - messages which should be translated to other languages in
250          *   order to get a complete translation.
251          * optional - messages which can be translated to other languages, but it's
252          *   not required for a complete translation.
253          * ignored - messages which should not be translated to other languages.
254          * translatable - messages which are either required or optional, but can be
255          *   translated from English.
256          *
257          * @return array The general English messages.
258          */
259         public function getGeneralMessages() {
260                 $this->loadGeneralMessages();
262                 return $this->mGeneralMessages;
263         }
265         /**
266          * Get fallback language code for a specific language.
267          *
268          * @param $code string The language code.
269          *
270          * @return string Fallback code.
271          */
272         public function getFallback( $code ) {
273                 $this->loadFile( $code );
275                 return $this->mFallback[$code];
276         }
278         /**
279          * Get namespace names for a specific language.
280          *
281          * @param $code string The language code.
282          *
283          * @return array Namespace names.
284          */
285         public function getNamespaceNames( $code ) {
286                 $this->loadFile( $code );
288                 return $this->mNamespaceNames[$code];
289         }
291         /**
292          * Get namespace aliases for a specific language.
293          *
294          * @param $code string The language code.
295          *
296          * @return array Namespace aliases.
297          */
298         public function getNamespaceAliases( $code ) {
299                 $this->loadFile( $code );
301                 return $this->mNamespaceAliases[$code];
302         }
304         /**
305          * Get magic words for a specific language.
306          *
307          * @param $code string The language code.
308          *
309          * @return array Magic words.
310          */
311         public function getMagicWords( $code ) {
312                 $this->loadFile( $code );
314                 return $this->mMagicWords[$code];
315         }
317         /**
318          * Get special page aliases for a specific language.
319          *
320          * @param $code string The language code.
321          *
322          * @return array Special page aliases.
323          */
324         public function getSpecialPageAliases( $code ) {
325                 $this->loadFile( $code );
327                 return $this->mSpecialPageAliases[$code];
328         }
330         /**
331          * Get the untranslated messages for a specific language.
332          *
333          * @param $code string The language code.
334          *
335          * @return array The untranslated messages for this language.
336          */
337         public function getUntranslatedMessages( $code ) {
338                 $this->loadGeneralMessages();
339                 $this->loadMessages( $code );
341                 return array_diff_key( $this->mGeneralMessages['required'], $this->mMessages[$code]['required'] );
342         }
344         /**
345          * Get the duplicate messages for a specific language.
346          *
347          * @param $code string The language code.
348          *
349          * @return array The duplicate messages for this language.
350          */
351         public function getDuplicateMessages( $code ) {
352                 $this->loadGeneralMessages();
353                 $this->loadMessages( $code );
354                 $duplicateMessages = array();
355                 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
356                         if ( $this->mGeneralMessages['translatable'][$key] == $value ) {
357                                 $duplicateMessages[$key] = $value;
358                         }
359                 }
361                 return $duplicateMessages;
362         }
364         /**
365          * Get the obsolete messages for a specific language.
366          *
367          * @param $code string The language code.
368          *
369          * @return array The obsolete messages for this language.
370          */
371         public function getObsoleteMessages( $code ) {
372                 $this->loadGeneralMessages();
373                 $this->loadMessages( $code );
375                 return $this->mMessages[$code]['obsolete'];
376         }
378         /**
379          * Get the messages whose variables do not match the original ones.
380          *
381          * @param $code string The language code.
382          *
383          * @return array The messages whose variables do not match the original ones.
384          */
385         public function getMessagesWithMismatchVariables( $code ) {
386                 $this->loadGeneralMessages();
387                 $this->loadMessages( $code );
388                 $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' );
389                 $mismatchMessages = array();
390                 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
391                         $missing = false;
392                         foreach ( $variables as $var ) {
393                                 if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
394                                         !preg_match( "/$var/sU", $value )
395                                 ) {
396                                         $missing = true;
397                                 }
398                                 if ( !preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
399                                         preg_match( "/$var/sU", $value )
400                                 ) {
401                                         $missing = true;
402                                 }
403                         }
404                         if ( $missing ) {
405                                 $mismatchMessages[$key] = $value;
406                         }
407                 }
409                 return $mismatchMessages;
410         }
412         /**
413          * Get the messages which do not use plural.
414          *
415          * @param $code string The language code.
416          *
417          * @return array The messages which do not use plural in this language.
418          */
419         public function getMessagesWithoutPlural( $code ) {
420                 $this->loadGeneralMessages();
421                 $this->loadMessages( $code );
422                 $messagesWithoutPlural = array();
423                 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
424                         if ( stripos( $this->mGeneralMessages['translatable'][$key], '{{plural:' ) !== false &&
425                                 stripos( $value, '{{plural:' ) === false
426                         ) {
427                                 $messagesWithoutPlural[$key] = $value;
428                         }
429                 }
431                 return $messagesWithoutPlural;
432         }
434         /**
435          * Get the empty messages.
436          *
437          * @param $code string The language code.
438          *
439          * @return array The empty messages for this language.
440          */
441         public function getEmptyMessages( $code ) {
442                 $this->loadGeneralMessages();
443                 $this->loadMessages( $code );
444                 $emptyMessages = array();
445                 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
446                         if ( $value === '' || $value === '-' ) {
447                                 $emptyMessages[$key] = $value;
448                         }
449                 }
451                 return $emptyMessages;
452         }
454         /**
455          * Get the messages with trailing whitespace.
456          *
457          * @param $code string The language code.
458          *
459          * @return array The messages with trailing whitespace in this language.
460          */
461         public function getMessagesWithWhitespace( $code ) {
462                 $this->loadGeneralMessages();
463                 $this->loadMessages( $code );
464                 $messagesWithWhitespace = array();
465                 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
466                         if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) {
467                                 $messagesWithWhitespace[$key] = $value;
468                         }
469                 }
471                 return $messagesWithWhitespace;
472         }
474         /**
475          * Get the non-XHTML messages.
476          *
477          * @param $code string The language code.
478          *
479          * @return array The non-XHTML messages for this language.
480          */
481         public function getNonXHTMLMessages( $code ) {
482                 $this->loadGeneralMessages();
483                 $this->loadMessages( $code );
484                 $wrongPhrases = array(
485                         '<hr *\\?>',
486                         '<br *\\?>',
487                         '<hr/>',
488                         '<br/>',
489                         '<hr>',
490                         '<br>',
491                 );
492                 $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu';
493                 $nonXHTMLMessages = array();
494                 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
495                         if ( preg_match( $wrongPhrases, $value ) ) {
496                                 $nonXHTMLMessages[$key] = $value;
497                         }
498                 }
500                 return $nonXHTMLMessages;
501         }
503         /**
504          * Get the messages which include wrong characters.
505          *
506          * @param $code string The language code.
507          *
508          * @return array The messages which include wrong characters in this language.
509          */
510         public function getMessagesWithWrongChars( $code ) {
511                 $this->loadGeneralMessages();
512                 $this->loadMessages( $code );
513                 $wrongChars = array(
514                         '[LRM]' => "\xE2\x80\x8E",
515                         '[RLM]' => "\xE2\x80\x8F",
516                         '[LRE]' => "\xE2\x80\xAA",
517                         '[RLE]' => "\xE2\x80\xAB",
518                         '[POP]' => "\xE2\x80\xAC",
519                         '[LRO]' => "\xE2\x80\xAD",
520                         '[RLO]' => "\xE2\x80\xAB",
521                         '[ZWSP]' => "\xE2\x80\x8B",
522                         '[NBSP]' => "\xC2\xA0",
523                         '[WJ]' => "\xE2\x81\xA0",
524                         '[BOM]' => "\xEF\xBB\xBF",
525                         '[FFFD]' => "\xEF\xBF\xBD",
526                 );
527                 $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu';
528                 $wrongCharsMessages = array();
529                 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
530                         if ( preg_match( $wrongRegExp, $value ) ) {
531                                 foreach ( $wrongChars as $viewableChar => $hiddenChar ) {
532                                         $value = str_replace( $hiddenChar, $viewableChar, $value );
533                                 }
534                                 $wrongCharsMessages[$key] = $value;
535                         }
536                 }
538                 return $wrongCharsMessages;
539         }
541         /**
542          * Get the messages which include dubious links.
543          *
544          * @param $code string The language code.
545          *
546          * @return array The messages which include dubious links in this language.
547          */
548         public function getMessagesWithDubiousLinks( $code ) {
549                 $this->loadGeneralMessages();
550                 $this->loadMessages( $code );
551                 $tc = Title::legalChars() . '#%{}';
552                 $messages = array();
553                 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
554                         $matches = array();
555                         preg_match_all( "/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu", $value, $matches );
556                         $numMatches = count( $matches[0] );
557                         for ( $i = 0; $i < $numMatches; $i++ ) {
558                                 if ( preg_match( "/.*project.*/isDu", $matches[1][$i] ) ) {
559                                         $messages[$key][] = $matches[0][$i];
560                                 }
561                         }
563                         if ( isset( $messages[$key] ) ) {
564                                 $messages[$key] = implode( $messages[$key], ", " );
565                         }
566                 }
568                 return $messages;
569         }
571         /**
572          * Get the messages which include unbalanced brackets.
573          *
574          * @param $code string The language code.
575          *
576          * @return array The messages which include unbalanced brackets in this language.
577          */
578         public function getMessagesWithUnbalanced( $code ) {
579                 $this->loadGeneralMessages();
580                 $this->loadMessages( $code );
581                 $messages = array();
582                 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
583                         $a = $b = $c = $d = 0;
584                         foreach ( preg_split( '//', $value ) as $char ) {
585                                 switch ( $char ) {
586                                         case '[':
587                                                 $a++;
588                                                 break;
589                                         case ']':
590                                                 $b++;
591                                                 break;
592                                         case '{':
593                                                 $c++;
594                                                 break;
595                                         case '}':
596                                                 $d++;
597                                                 break;
598                                 }
599                         }
601                         if ( $a !== $b || $c !== $d ) {
602                                 $messages[$key] = "$a, $b, $c, $d";
603                         }
604                 }
606                 return $messages;
607         }
609         /**
610          * Get the untranslated namespace names.
611          *
612          * @param $code string The language code.
613          *
614          * @return array The untranslated namespace names in this language.
615          */
616         public function getUntranslatedNamespaces( $code ) {
617                 $this->loadFile( 'en' );
618                 $this->loadFile( $code );
619                 $namespacesDiff = array_diff_key( $this->mNamespaceNames['en'], $this->mNamespaceNames[$code] );
620                 if ( isset( $namespacesDiff[NS_MAIN] ) ) {
621                         unset( $namespacesDiff[NS_MAIN] );
622                 }
624                 return $namespacesDiff;
625         }
627         /**
628          * Get the project talk namespace names with no $1.
629          *
630          * @param $code string The language code.
631          *
632          * @return array The problematic project talk namespaces in this language.
633          */
634         public function getProblematicProjectTalks( $code ) {
635                 $this->loadFile( $code );
636                 $namespaces = array();
638                 # Check default namespace name
639                 if ( isset( $this->mNamespaceNames[$code][NS_PROJECT_TALK] ) ) {
640                         $default = $this->mNamespaceNames[$code][NS_PROJECT_TALK];
641                         if ( strpos( $default, '$1' ) === false ) {
642                                 $namespaces[$default] = 'default';
643                         }
644                 }
646                 # Check namespace aliases
647                 foreach ( $this->mNamespaceAliases[$code] as $key => $value ) {
648                         if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === false ) {
649                                 $namespaces[$key] = '';
650                         }
651                 }
653                 return $namespaces;
654         }
656         /**
657          * Get the untranslated magic words.
658          *
659          * @param $code string The language code.
660          *
661          * @return array The untranslated magic words in this language.
662          */
663         public function getUntranslatedMagicWords( $code ) {
664                 $this->loadFile( 'en' );
665                 $this->loadFile( $code );
666                 $magicWords = array();
667                 foreach ( $this->mMagicWords['en'] as $key => $value ) {
668                         if ( !isset( $this->mMagicWords[$code][$key] ) ) {
669                                 $magicWords[$key] = $value[1];
670                         }
671                 }
673                 return $magicWords;
674         }
676         /**
677          * Get the obsolete magic words.
678          *
679          * @param $code string The language code.
680          *
681          * @return array The obsolete magic words in this language.
682          */
683         public function getObsoleteMagicWords( $code ) {
684                 $this->loadFile( 'en' );
685                 $this->loadFile( $code );
686                 $magicWords = array();
687                 foreach ( $this->mMagicWords[$code] as $key => $value ) {
688                         if ( !isset( $this->mMagicWords['en'][$key] ) ) {
689                                 $magicWords[$key] = $value[1];
690                         }
691                 }
693                 return $magicWords;
694         }
696         /**
697          * Get the magic words that override the original English magic word.
698          *
699          * @param $code string The language code.
700          *
701          * @return array The overriding magic words in this language.
702          */
703         public function getOverridingMagicWords( $code ) {
704                 $this->loadFile( 'en' );
705                 $this->loadFile( $code );
706                 $magicWords = array();
707                 foreach ( $this->mMagicWords[$code] as $key => $local ) {
708                         if ( !isset( $this->mMagicWords['en'][$key] ) ) {
709                                 # Unrecognized magic word
710                                 continue;
711                         }
712                         $en = $this->mMagicWords['en'][$key];
713                         array_shift( $local );
714                         array_shift( $en );
715                         foreach ( $en as $word ) {
716                                 if ( !in_array( $word, $local ) ) {
717                                         $magicWords[$key] = $word;
718                                         break;
719                                 }
720                         }
721                 }
723                 return $magicWords;
724         }
726         /**
727          * Get the magic words which do not match the case-sensitivity of the original words.
728          *
729          * @param $code string The language code.
730          *
731          * @return array The magic words whose case does not match in this language.
732          */
733         public function getCaseMismatchMagicWords( $code ) {
734                 $this->loadFile( 'en' );
735                 $this->loadFile( $code );
736                 $magicWords = array();
737                 foreach ( $this->mMagicWords[$code] as $key => $local ) {
738                         if ( !isset( $this->mMagicWords['en'][$key] ) ) {
739                                 # Unrecognized magic word
740                                 continue;
741                         }
742                         if ( $local[0] != $this->mMagicWords['en'][$key][0] ) {
743                                 $magicWords[$key] = $local[0];
744                         }
745                 }
747                 return $magicWords;
748         }
750         /**
751          * Get the untranslated special page names.
752          *
753          * @param $code string The language code.
754          *
755          * @return array The untranslated special page names in this language.
756          */
757         public function getUntraslatedSpecialPages( $code ) {
758                 $this->loadFile( 'en' );
759                 $this->loadFile( $code );
760                 $specialPageAliases = array();
761                 foreach ( $this->mSpecialPageAliases['en'] as $key => $value ) {
762                         if ( !isset( $this->mSpecialPageAliases[$code][$key] ) ) {
763                                 $specialPageAliases[$key] = $value[0];
764                         }
765                 }
767                 return $specialPageAliases;
768         }
770         /**
771          * Get the obsolete special page names.
772          *
773          * @param $code string The language code.
774          *
775          * @return array The obsolete special page names in this language.
776          */
777         public function getObsoleteSpecialPages( $code ) {
778                 $this->loadFile( 'en' );
779                 $this->loadFile( $code );
780                 $specialPageAliases = array();
781                 foreach ( $this->mSpecialPageAliases[$code] as $key => $value ) {
782                         if ( !isset( $this->mSpecialPageAliases['en'][$key] ) ) {
783                                 $specialPageAliases[$key] = $value[0];
784                         }
785                 }
787                 return $specialPageAliases;
788         }
791 class ExtensionLanguages extends Languages {
792         /**
793          * @var MessageGroup
794          */
795         private $mMessageGroup;
797         /**
798          * Load the messages group.
799          * @param $group MessageGroup The messages group.
800          */
801         function __construct( MessageGroup $group ) {
802                 $this->mMessageGroup = $group;
804                 $this->mIgnoredMessages = $this->mMessageGroup->getIgnored();
805                 $this->mOptionalMessages = $this->mMessageGroup->getOptional();
806         }
808         /**
809          * Get the extension name.
810          *
811          * @return string The extension name.
812          */
813         public function name() {
814                 return $this->mMessageGroup->getLabel();
815         }
817         /**
818          * Load the language file.
819          *
820          * @param $code string The language code.
821          */
822         protected function loadFile( $code ) {
823                 if ( !isset( $this->mRawMessages[$code] ) ) {
824                         $this->mRawMessages[$code] = $this->mMessageGroup->load( $code );
825                         if ( empty( $this->mRawMessages[$code] ) ) {
826                                 $this->mRawMessages[$code] = array();
827                         }
828                 }
829         }