Completed
Branch master (939199)
by
unknown
39:35
created

maintenance/language/languages.inc (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
 */
23
24
/**
25
 * @ingroup MaintenanceLanguage
26
 */
27
class Languages {
28
	/** @var array List of languages */
29
	protected $mLanguages;
30
31
	/** @var array Raw list of the messages in each language */
32
	protected $mRawMessages;
33
34
	/** @var array Messages in each language (except for English), divided to groups */
35
	protected $mMessages;
36
37
	/** @var array Fallback language in each language */
38
	protected $mFallback;
39
40
	/** @var array General messages in English, divided to groups */
41
	protected $mGeneralMessages;
42
43
	/** @var array All the messages which should be exist only in the English file */
44
	protected $mIgnoredMessages;
45
46
	/** @var array All the messages which may be translated or not, depending on the language */
47
	protected $mOptionalMessages;
48
49
	/** @var array Namespace names */
50
	protected $mNamespaceNames;
51
52
	/** @var array Namespace aliases */
53
	protected $mNamespaceAliases;
54
55
	/** @var array Magic words */
56
	protected $mMagicWords;
57
58
	/** @var array Special page aliases */
59
	protected $mSpecialPageAliases;
60
61
	/**
62
	 * Load the list of languages: all the Messages*.php
63
	 * files in the languages directory.
64
	 */
65
	function __construct() {
66
		Hooks::run( 'LocalisationIgnoredOptionalMessages',
67
			[ &$this->mIgnoredMessages, &$this->mOptionalMessages ] );
68
69
		$this->mLanguages = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) );
70
		sort( $this->mLanguages );
71
	}
72
73
	/**
74
	 * Get the language list.
75
	 *
76
	 * @return array The language list.
77
	 */
78
	public function getLanguages() {
79
		return $this->mLanguages;
80
	}
81
82
	/**
83
	 * Get the ignored messages list.
84
	 *
85
	 * @return array The ignored messages list.
86
	 */
87
	public function getIgnoredMessages() {
88
		return $this->mIgnoredMessages;
89
	}
90
91
	/**
92
	 * Get the optional messages list.
93
	 *
94
	 * @return array The  optional messages list.
95
	 */
96
	public function getOptionalMessages() {
97
		return $this->mOptionalMessages;
98
	}
99
100
	/**
101
	 * Load the language file.
102
	 *
103
	 * @param string $code The language code.
104
	 */
105
	protected function loadFile( $code ) {
106
		if ( isset( $this->mRawMessages[$code] ) &&
107
			isset( $this->mFallback[$code] ) &&
108
			isset( $this->mNamespaceNames[$code] ) &&
109
			isset( $this->mNamespaceAliases[$code] ) &&
110
			isset( $this->mMagicWords[$code] ) &&
111
			isset( $this->mSpecialPageAliases[$code] )
112
		) {
113
			return;
114
		}
115
		$this->mRawMessages[$code] = [];
116
		$this->mFallback[$code] = '';
117
		$this->mNamespaceNames[$code] = [];
118
		$this->mNamespaceAliases[$code] = [];
119
		$this->mMagicWords[$code] = [];
120
		$this->mSpecialPageAliases[$code] = [];
121
122
		$jsonfilename = Language::getJsonMessagesFileName( $code );
123
		if ( file_exists( $jsonfilename ) ) {
124
			$json = Language::getLocalisationCache()->readJSONFile( $jsonfilename );
125
			$this->mRawMessages[$code] = $json['messages'];
126
		}
127
128
		$filename = Language::getMessagesFileName( $code );
129
		if ( file_exists( $filename ) ) {
130
			require $filename;
131
			if ( isset( $fallback ) ) {
0 ignored issues
show
The variable $fallback seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
132
				$this->mFallback[$code] = $fallback;
133
			}
134
			if ( isset( $namespaceNames ) ) {
135
				$this->mNamespaceNames[$code] = $namespaceNames;
136
			}
137
			if ( isset( $namespaceAliases ) ) {
138
				$this->mNamespaceAliases[$code] = $namespaceAliases;
139
			}
140
			if ( isset( $magicWords ) ) {
141
				$this->mMagicWords[$code] = $magicWords;
142
			}
143
			if ( isset( $specialPageAliases ) ) {
144
				$this->mSpecialPageAliases[$code] = $specialPageAliases;
145
			}
146
		}
147
	}
148
149
	/**
150
	 * Load the messages for a specific language (which is not English) and divide them to
151
	 * groups:
152
	 * all - all the messages.
153
	 * required - messages which should be translated in order to get a complete translation.
154
	 * optional - messages which can be translated, the fallback translation is used if not
155
	 *   translated.
156
	 * obsolete - messages which should not be translated, either because they do not exist,
157
	 *   or they are ignored messages.
158
	 * translated - messages which are either required or optional, but translated from
159
	 *   English and needed.
160
	 *
161
	 * @param string $code The language code.
162
	 */
163
	private function loadMessages( $code ) {
164
		if ( isset( $this->mMessages[$code] ) ) {
165
			return;
166
		}
167
		$this->loadFile( $code );
168
		$this->loadGeneralMessages();
169
		$this->mMessages[$code]['all'] = $this->mRawMessages[$code];
170
		$this->mMessages[$code]['required'] = [];
171
		$this->mMessages[$code]['optional'] = [];
172
		$this->mMessages[$code]['obsolete'] = [];
173
		$this->mMessages[$code]['translated'] = [];
174
		foreach ( $this->mMessages[$code]['all'] as $key => $value ) {
175
			if ( isset( $this->mGeneralMessages['required'][$key] ) ) {
176
				$this->mMessages[$code]['required'][$key] = $value;
177
				$this->mMessages[$code]['translated'][$key] = $value;
178
			} elseif ( isset( $this->mGeneralMessages['optional'][$key] ) ) {
179
				$this->mMessages[$code]['optional'][$key] = $value;
180
				$this->mMessages[$code]['translated'][$key] = $value;
181
			} else {
182
				$this->mMessages[$code]['obsolete'][$key] = $value;
183
			}
184
		}
185
	}
186
187
	/**
188
	 * Load the messages for English and divide them to groups:
189
	 * all - all the messages.
190
	 * required - messages which should be translated to other languages in order to get a
191
	 *   complete translation.
192
	 * optional - messages which can be translated to other languages, but it's not required
193
	 *   for a complete translation.
194
	 * ignored - messages which should not be translated to other languages.
195
	 * translatable - messages which are either required or optional, but can be translated
196
	 *   from English.
197
	 */
198
	private function loadGeneralMessages() {
199
		if ( isset( $this->mGeneralMessages ) ) {
200
			return;
201
		}
202
		$this->loadFile( 'en' );
203
		$this->mGeneralMessages['all'] = $this->mRawMessages['en'];
204
		$this->mGeneralMessages['required'] = [];
205
		$this->mGeneralMessages['optional'] = [];
206
		$this->mGeneralMessages['ignored'] = [];
207
		$this->mGeneralMessages['translatable'] = [];
208
		foreach ( $this->mGeneralMessages['all'] as $key => $value ) {
209
			if ( in_array( $key, $this->mIgnoredMessages ) ) {
210
				$this->mGeneralMessages['ignored'][$key] = $value;
211
			} elseif ( in_array( $key, $this->mOptionalMessages ) ) {
212
				$this->mGeneralMessages['optional'][$key] = $value;
213
				$this->mGeneralMessages['translatable'][$key] = $value;
214
			} else {
215
				$this->mGeneralMessages['required'][$key] = $value;
216
				$this->mGeneralMessages['translatable'][$key] = $value;
217
			}
218
		}
219
	}
220
221
	/**
222
	 * Get all the messages for a specific language (not English), without the
223
	 * fallback language messages, divided to groups:
224
	 * all - all the messages.
225
	 * required - messages which should be translated in order to get a complete translation.
226
	 * optional - messages which can be translated, the fallback translation is used if not
227
	 *   translated.
228
	 * obsolete - messages which should not be translated, either because they do not exist,
229
	 *   or they are ignored messages.
230
	 * translated - messages which are either required or optional, but translated from
231
	 *   English and needed.
232
	 *
233
	 * @param string $code The language code.
234
	 *
235
	 * @return string The messages in this language.
236
	 */
237
	public function getMessages( $code ) {
238
		$this->loadMessages( $code );
239
240
		return $this->mMessages[$code];
241
	}
242
243
	/**
244
	 * Get all the general English messages, divided to groups:
245
	 * all - all the messages.
246
	 * required - messages which should be translated to other languages in
247
	 *   order to get a complete translation.
248
	 * optional - messages which can be translated to other languages, but it's
249
	 *   not required for a complete translation.
250
	 * ignored - messages which should not be translated to other languages.
251
	 * translatable - messages which are either required or optional, but can be
252
	 *   translated from English.
253
	 *
254
	 * @return array The general English messages.
255
	 */
256
	public function getGeneralMessages() {
257
		$this->loadGeneralMessages();
258
259
		return $this->mGeneralMessages;
260
	}
261
262
	/**
263
	 * Get fallback language code for a specific language.
264
	 *
265
	 * @param string $code The language code.
266
	 *
267
	 * @return string Fallback code.
268
	 */
269
	public function getFallback( $code ) {
270
		$this->loadFile( $code );
271
272
		return $this->mFallback[$code];
273
	}
274
275
	/**
276
	 * Get namespace names for a specific language.
277
	 *
278
	 * @param string $code The language code.
279
	 *
280
	 * @return array Namespace names.
281
	 */
282
	public function getNamespaceNames( $code ) {
283
		$this->loadFile( $code );
284
285
		return $this->mNamespaceNames[$code];
286
	}
287
288
	/**
289
	 * Get namespace aliases for a specific language.
290
	 *
291
	 * @param string $code The language code.
292
	 *
293
	 * @return array Namespace aliases.
294
	 */
295
	public function getNamespaceAliases( $code ) {
296
		$this->loadFile( $code );
297
298
		return $this->mNamespaceAliases[$code];
299
	}
300
301
	/**
302
	 * Get magic words for a specific language.
303
	 *
304
	 * @param string $code The language code.
305
	 *
306
	 * @return array Magic words.
307
	 */
308
	public function getMagicWords( $code ) {
309
		$this->loadFile( $code );
310
311
		return $this->mMagicWords[$code];
312
	}
313
314
	/**
315
	 * Get special page aliases for a specific language.
316
	 *
317
	 * @param string $code The language code.
318
	 *
319
	 * @return array Special page aliases.
320
	 */
321
	public function getSpecialPageAliases( $code ) {
322
		$this->loadFile( $code );
323
324
		return $this->mSpecialPageAliases[$code];
325
	}
326
327
	/**
328
	 * Get the untranslated messages for a specific language.
329
	 *
330
	 * @param string $code The language code.
331
	 *
332
	 * @return array The untranslated messages for this language.
333
	 */
334
	public function getUntranslatedMessages( $code ) {
335
		$this->loadGeneralMessages();
336
		$this->loadMessages( $code );
337
338
		return array_diff_key( $this->mGeneralMessages['required'], $this->mMessages[$code]['required'] );
339
	}
340
341
	/**
342
	 * Get the duplicate messages for a specific language.
343
	 *
344
	 * @param string $code The language code.
345
	 *
346
	 * @return array The duplicate messages for this language.
347
	 */
348
	public function getDuplicateMessages( $code ) {
349
		$this->loadGeneralMessages();
350
		$this->loadMessages( $code );
351
		$duplicateMessages = [];
352
		foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
353
			if ( $this->mGeneralMessages['translatable'][$key] == $value ) {
354
				$duplicateMessages[$key] = $value;
355
			}
356
		}
357
358
		return $duplicateMessages;
359
	}
360
361
	/**
362
	 * Get the obsolete messages for a specific language.
363
	 *
364
	 * @param string $code The language code.
365
	 *
366
	 * @return array The obsolete messages for this language.
367
	 */
368
	public function getObsoleteMessages( $code ) {
369
		$this->loadGeneralMessages();
370
		$this->loadMessages( $code );
371
372
		return $this->mMessages[$code]['obsolete'];
373
	}
374
375
	/**
376
	 * Get the messages whose variables do not match the original ones.
377
	 *
378
	 * @param string $code The language code.
379
	 *
380
	 * @return array The messages whose variables do not match the original ones.
381
	 */
382
	public function getMessagesWithMismatchVariables( $code ) {
383
		$this->loadGeneralMessages();
384
		$this->loadMessages( $code );
385
		$variables = [ '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' ];
386
		$mismatchMessages = [];
387
		foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
388
			$missing = false;
389
			foreach ( $variables as $var ) {
390 View Code Duplication
				if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
391
					!preg_match( "/$var/sU", $value )
392
				) {
393
					$missing = true;
394
				}
395 View Code Duplication
				if ( !preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
396
					preg_match( "/$var/sU", $value )
397
				) {
398
					$missing = true;
399
				}
400
			}
401
			if ( $missing ) {
402
				$mismatchMessages[$key] = $value;
403
			}
404
		}
405
406
		return $mismatchMessages;
407
	}
408
409
	/**
410
	 * Get the messages which do not use plural.
411
	 *
412
	 * @param string $code The language code.
413
	 *
414
	 * @return array The messages which do not use plural in this language.
415
	 */
416
	public function getMessagesWithoutPlural( $code ) {
417
		$this->loadGeneralMessages();
418
		$this->loadMessages( $code );
419
		$messagesWithoutPlural = [];
420
		foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
421 View Code Duplication
			if ( stripos( $this->mGeneralMessages['translatable'][$key], '{{plural:' ) !== false &&
422
				stripos( $value, '{{plural:' ) === false
423
			) {
424
				$messagesWithoutPlural[$key] = $value;
425
			}
426
		}
427
428
		return $messagesWithoutPlural;
429
	}
430
431
	/**
432
	 * Get the empty messages.
433
	 *
434
	 * @param string $code The language code.
435
	 *
436
	 * @return array The empty messages for this language.
437
	 */
438
	public function getEmptyMessages( $code ) {
439
		$this->loadGeneralMessages();
440
		$this->loadMessages( $code );
441
		$emptyMessages = [];
442
		foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
443
			if ( $value === '' || $value === '-' ) {
444
				$emptyMessages[$key] = $value;
445
			}
446
		}
447
448
		return $emptyMessages;
449
	}
450
451
	/**
452
	 * Get the messages with trailing whitespace.
453
	 *
454
	 * @param string $code The language code.
455
	 *
456
	 * @return array The messages with trailing whitespace in this language.
457
	 */
458
	public function getMessagesWithWhitespace( $code ) {
459
		$this->loadGeneralMessages();
460
		$this->loadMessages( $code );
461
		$messagesWithWhitespace = [];
462
		foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
463
			if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) {
464
				$messagesWithWhitespace[$key] = $value;
465
			}
466
		}
467
468
		return $messagesWithWhitespace;
469
	}
470
471
	/**
472
	 * Get the non-XHTML messages.
473
	 *
474
	 * @param string $code The language code.
475
	 *
476
	 * @return array The non-XHTML messages for this language.
477
	 */
478
	public function getNonXHTMLMessages( $code ) {
479
		$this->loadGeneralMessages();
480
		$this->loadMessages( $code );
481
		$wrongPhrases = [
482
			'<hr *\\?>',
483
			'<br *\\?>',
484
			'<hr/>',
485
			'<br/>',
486
			'<hr>',
487
			'<br>',
488
		];
489
		$wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu';
490
		$nonXHTMLMessages = [];
491
		foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
492
			if ( preg_match( $wrongPhrases, $value ) ) {
493
				$nonXHTMLMessages[$key] = $value;
494
			}
495
		}
496
497
		return $nonXHTMLMessages;
498
	}
499
500
	/**
501
	 * Get the messages which include wrong characters.
502
	 *
503
	 * @param string $code The language code.
504
	 *
505
	 * @return array The messages which include wrong characters in this language.
506
	 */
507
	public function getMessagesWithWrongChars( $code ) {
508
		$this->loadGeneralMessages();
509
		$this->loadMessages( $code );
510
		$wrongChars = [
511
			'[LRM]' => "\xE2\x80\x8E",
512
			'[RLM]' => "\xE2\x80\x8F",
513
			'[LRE]' => "\xE2\x80\xAA",
514
			'[RLE]' => "\xE2\x80\xAB",
515
			'[POP]' => "\xE2\x80\xAC",
516
			'[LRO]' => "\xE2\x80\xAD",
517
			'[RLO]' => "\xE2\x80\xAB",
518
			'[ZWSP]' => "\xE2\x80\x8B",
519
			'[NBSP]' => "\xC2\xA0",
520
			'[WJ]' => "\xE2\x81\xA0",
521
			'[BOM]' => "\xEF\xBB\xBF",
522
			'[FFFD]' => "\xEF\xBF\xBD",
523
		];
524
		$wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu';
525
		$wrongCharsMessages = [];
526
		foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
527
			if ( preg_match( $wrongRegExp, $value ) ) {
528
				foreach ( $wrongChars as $viewableChar => $hiddenChar ) {
529
					$value = str_replace( $hiddenChar, $viewableChar, $value );
530
				}
531
				$wrongCharsMessages[$key] = $value;
532
			}
533
		}
534
535
		return $wrongCharsMessages;
536
	}
537
538
	/**
539
	 * Get the messages which include dubious links.
540
	 *
541
	 * @param string $code The language code.
542
	 *
543
	 * @return array The messages which include dubious links in this language.
544
	 */
545
	public function getMessagesWithDubiousLinks( $code ) {
546
		$this->loadGeneralMessages();
547
		$this->loadMessages( $code );
548
		$tc = Title::legalChars() . '#%{}';
549
		$messages = [];
550
		foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
551
			$matches = [];
552
			preg_match_all( "/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu", $value, $matches );
553
			$numMatches = count( $matches[0] );
554
			for ( $i = 0; $i < $numMatches; $i++ ) {
555
				if ( preg_match( "/.*project.*/isDu", $matches[1][$i] ) ) {
556
					$messages[$key][] = $matches[0][$i];
557
				}
558
			}
559
560
			if ( isset( $messages[$key] ) ) {
561
				$messages[$key] = implode( $messages[$key], ", " );
562
			}
563
		}
564
565
		return $messages;
566
	}
567
568
	/**
569
	 * Get the messages which include unbalanced brackets.
570
	 *
571
	 * @param string $code The language code.
572
	 *
573
	 * @return array The messages which include unbalanced brackets in this language.
574
	 */
575
	public function getMessagesWithUnbalanced( $code ) {
576
		$this->loadGeneralMessages();
577
		$this->loadMessages( $code );
578
		$messages = [];
579
		foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
580
			$a = $b = $c = $d = 0;
581
			foreach ( preg_split( '//', $value ) as $char ) {
582
				switch ( $char ) {
583
					case '[':
584
						$a++;
585
						break;
586
					case ']':
587
						$b++;
588
						break;
589
					case '{':
590
						$c++;
591
						break;
592
					case '}':
593
						$d++;
594
						break;
595
				}
596
			}
597
598
			if ( $a !== $b || $c !== $d ) {
599
				$messages[$key] = "$a, $b, $c, $d";
600
			}
601
		}
602
603
		return $messages;
604
	}
605
606
	/**
607
	 * Get the untranslated namespace names.
608
	 *
609
	 * @param string $code The language code.
610
	 *
611
	 * @return array The untranslated namespace names in this language.
612
	 */
613
	public function getUntranslatedNamespaces( $code ) {
614
		$this->loadFile( 'en' );
615
		$this->loadFile( $code );
616
		$namespacesDiff = array_diff_key( $this->mNamespaceNames['en'], $this->mNamespaceNames[$code] );
617
		if ( isset( $namespacesDiff[NS_MAIN] ) ) {
618
			unset( $namespacesDiff[NS_MAIN] );
619
		}
620
621
		return $namespacesDiff;
622
	}
623
624
	/**
625
	 * Get the project talk namespace names with no $1.
626
	 *
627
	 * @param string $code The language code.
628
	 *
629
	 * @return array The problematic project talk namespaces in this language.
630
	 */
631
	public function getProblematicProjectTalks( $code ) {
632
		$this->loadFile( $code );
633
		$namespaces = [];
634
635
		# Check default namespace name
636
		if ( isset( $this->mNamespaceNames[$code][NS_PROJECT_TALK] ) ) {
637
			$default = $this->mNamespaceNames[$code][NS_PROJECT_TALK];
638
			if ( strpos( $default, '$1' ) === false ) {
639
				$namespaces[$default] = 'default';
640
			}
641
		}
642
643
		# Check namespace aliases
644
		foreach ( $this->mNamespaceAliases[$code] as $key => $value ) {
645
			if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === false ) {
646
				$namespaces[$key] = '';
647
			}
648
		}
649
650
		return $namespaces;
651
	}
652
653
	/**
654
	 * Get the untranslated magic words.
655
	 *
656
	 * @param string $code The language code.
657
	 *
658
	 * @return array The untranslated magic words in this language.
659
	 */
660 View Code Duplication
	public function getUntranslatedMagicWords( $code ) {
661
		$this->loadFile( 'en' );
662
		$this->loadFile( $code );
663
		$magicWords = [];
664
		foreach ( $this->mMagicWords['en'] as $key => $value ) {
665
			if ( !isset( $this->mMagicWords[$code][$key] ) ) {
666
				$magicWords[$key] = $value[1];
667
			}
668
		}
669
670
		return $magicWords;
671
	}
672
673
	/**
674
	 * Get the obsolete magic words.
675
	 *
676
	 * @param string $code The language code.
677
	 *
678
	 * @return array The obsolete magic words in this language.
679
	 */
680 View Code Duplication
	public function getObsoleteMagicWords( $code ) {
681
		$this->loadFile( 'en' );
682
		$this->loadFile( $code );
683
		$magicWords = [];
684
		foreach ( $this->mMagicWords[$code] as $key => $value ) {
685
			if ( !isset( $this->mMagicWords['en'][$key] ) ) {
686
				$magicWords[$key] = $value[1];
687
			}
688
		}
689
690
		return $magicWords;
691
	}
692
693
	/**
694
	 * Get the magic words that override the original English magic word.
695
	 *
696
	 * @param string $code The language code.
697
	 *
698
	 * @return array The overriding magic words in this language.
699
	 */
700
	public function getOverridingMagicWords( $code ) {
701
		$this->loadFile( 'en' );
702
		$this->loadFile( $code );
703
		$magicWords = [];
704
		foreach ( $this->mMagicWords[$code] as $key => $local ) {
705
			if ( !isset( $this->mMagicWords['en'][$key] ) ) {
706
				# Unrecognized magic word
707
				continue;
708
			}
709
			$en = $this->mMagicWords['en'][$key];
710
			array_shift( $local );
711
			array_shift( $en );
712
			foreach ( $en as $word ) {
713
				if ( !in_array( $word, $local ) ) {
714
					$magicWords[$key] = $word;
715
					break;
716
				}
717
			}
718
		}
719
720
		return $magicWords;
721
	}
722
723
	/**
724
	 * Get the magic words which do not match the case-sensitivity of the original words.
725
	 *
726
	 * @param string $code The language code.
727
	 *
728
	 * @return array The magic words whose case does not match in this language.
729
	 */
730
	public function getCaseMismatchMagicWords( $code ) {
731
		$this->loadFile( 'en' );
732
		$this->loadFile( $code );
733
		$magicWords = [];
734
		foreach ( $this->mMagicWords[$code] as $key => $local ) {
735
			if ( !isset( $this->mMagicWords['en'][$key] ) ) {
736
				# Unrecognized magic word
737
				continue;
738
			}
739
			if ( $local[0] != $this->mMagicWords['en'][$key][0] ) {
740
				$magicWords[$key] = $local[0];
741
			}
742
		}
743
744
		return $magicWords;
745
	}
746
747
	/**
748
	 * Get the untranslated special page names.
749
	 *
750
	 * @param string $code The language code.
751
	 *
752
	 * @return array The untranslated special page names in this language.
753
	 */
754 View Code Duplication
	public function getUntraslatedSpecialPages( $code ) {
755
		$this->loadFile( 'en' );
756
		$this->loadFile( $code );
757
		$specialPageAliases = [];
758
		foreach ( $this->mSpecialPageAliases['en'] as $key => $value ) {
759
			if ( !isset( $this->mSpecialPageAliases[$code][$key] ) ) {
760
				$specialPageAliases[$key] = $value[0];
761
			}
762
		}
763
764
		return $specialPageAliases;
765
	}
766
767
	/**
768
	 * Get the obsolete special page names.
769
	 *
770
	 * @param string $code The language code.
771
	 *
772
	 * @return array The obsolete special page names in this language.
773
	 */
774 View Code Duplication
	public function getObsoleteSpecialPages( $code ) {
775
		$this->loadFile( 'en' );
776
		$this->loadFile( $code );
777
		$specialPageAliases = [];
778
		foreach ( $this->mSpecialPageAliases[$code] as $key => $value ) {
779
			if ( !isset( $this->mSpecialPageAliases['en'][$key] ) ) {
780
				$specialPageAliases[$key] = $value[0];
781
			}
782
		}
783
784
		return $specialPageAliases;
785
	}
786
}
787
788
class ExtensionLanguages extends Languages {
789
	/**
790
	 * @var MessageGroup
791
	 */
792
	private $mMessageGroup;
793
794
	/**
795
	 * Load the messages group.
796
	 * @param MessageGroup $group The messages group.
797
	 */
798
	function __construct( MessageGroup $group ) {
799
		$this->mMessageGroup = $group;
800
801
		$this->mIgnoredMessages = $this->mMessageGroup->getIgnored();
802
		$this->mOptionalMessages = $this->mMessageGroup->getOptional();
803
	}
804
805
	/**
806
	 * Get the extension name.
807
	 *
808
	 * @return string The extension name.
809
	 */
810
	public function name() {
811
		return $this->mMessageGroup->getLabel();
812
	}
813
814
	/**
815
	 * Load the language file.
816
	 *
817
	 * @param string $code The language code.
818
	 */
819
	protected function loadFile( $code ) {
820
		if ( !isset( $this->mRawMessages[$code] ) ) {
821
			$this->mRawMessages[$code] = $this->mMessageGroup->load( $code );
822
			if ( empty( $this->mRawMessages[$code] ) ) {
823
				$this->mRawMessages[$code] = [];
824
			}
825
		}
826
	}
827
}
828