29 protected $mLanguages; #
32 protected $mRawMessages;
41 protected $mGeneralMessages;
44 protected $mIgnoredMessages;
47 protected $mOptionalMessages;
50 protected $mNamespaceNames;
53 protected $mNamespaceAliases;
56 protected $mMagicWords;
59 protected $mSpecialPageAliases;
67 function __construct( $exif =
true ) {
68 require __DIR__ .
'/messageTypes.inc';
77 sort( $this->mLanguages );
85 public function getLanguages() {
86 return $this->mLanguages;
94 public function getIgnoredMessages() {
95 return $this->mIgnoredMessages;
103 public function getOptionalMessages() {
104 return $this->mOptionalMessages;
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] )
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();
130 if ( file_exists( $jsonfilename ) ) {
132 $this->mRawMessages[$code] = $json[
'messages'];
136 if ( file_exists( $filename ) ) {
170 private function loadMessages( $code ) {
171 if ( isset( $this->mMessages[$code] ) ) {
174 $this->loadFile( $code );
175 $this->loadGeneralMessages();
176 $this->mMessages[$code][
'all'] = $this->mRawMessages[$code];
177 $this->mMessages[$code][
'required'] =
array();
178 $this->mMessages[$code][
'optional'] =
array();
179 $this->mMessages[$code][
'obsolete'] =
array();
180 $this->mMessages[$code][
'translated'] =
array();
181 foreach ( $this->mMessages[$code][
'all']
as $key =>
$value ) {
182 if ( isset( $this->mGeneralMessages[
'required'][$key] ) ) {
183 $this->mMessages[$code][
'required'][$key] =
$value;
184 $this->mMessages[$code][
'translated'][$key] =
$value;
185 } elseif ( isset( $this->mGeneralMessages[
'optional'][$key] ) ) {
186 $this->mMessages[$code][
'optional'][$key] =
$value;
187 $this->mMessages[$code][
'translated'][$key] =
$value;
189 $this->mMessages[$code][
'obsolete'][$key] =
$value;
205 private function loadGeneralMessages() {
206 if ( isset( $this->mGeneralMessages ) ) {
209 $this->loadFile(
'en' );
210 $this->mGeneralMessages[
'all'] = $this->mRawMessages[
'en'];
211 $this->mGeneralMessages[
'required'] =
array();
212 $this->mGeneralMessages[
'optional'] =
array();
213 $this->mGeneralMessages[
'ignored'] =
array();
214 $this->mGeneralMessages[
'translatable'] =
array();
215 foreach ( $this->mGeneralMessages[
'all']
as $key =>
$value ) {
216 if ( in_array( $key, $this->mIgnoredMessages ) ) {
217 $this->mGeneralMessages[
'ignored'][$key] =
$value;
218 } elseif ( in_array( $key, $this->mOptionalMessages ) ) {
219 $this->mGeneralMessages[
'optional'][$key] =
$value;
220 $this->mGeneralMessages[
'translatable'][$key] =
$value;
222 $this->mGeneralMessages[
'required'][$key] =
$value;
223 $this->mGeneralMessages[
'translatable'][$key] =
$value;
244 public function getMessages( $code ) {
245 $this->loadMessages( $code );
247 return $this->mMessages[$code];
263 public function getGeneralMessages() {
264 $this->loadGeneralMessages();
266 return $this->mGeneralMessages;
276 public function getFallback( $code ) {
277 $this->loadFile( $code );
279 return $this->mFallback[$code];
289 public function getNamespaceNames( $code ) {
290 $this->loadFile( $code );
292 return $this->mNamespaceNames[$code];
302 public function getNamespaceAliases( $code ) {
303 $this->loadFile( $code );
305 return $this->mNamespaceAliases[$code];
315 public function getMagicWords( $code ) {
316 $this->loadFile( $code );
318 return $this->mMagicWords[$code];
328 public function getSpecialPageAliases( $code ) {
329 $this->loadFile( $code );
331 return $this->mSpecialPageAliases[$code];
341 public function getUntranslatedMessages( $code ) {
342 $this->loadGeneralMessages();
343 $this->loadMessages( $code );
345 return array_diff_key( $this->mGeneralMessages[
'required'], $this->mMessages[$code][
'required'] );
355 public function getDuplicateMessages( $code ) {
356 $this->loadGeneralMessages();
357 $this->loadMessages( $code );
358 $duplicateMessages =
array();
359 foreach ( $this->mMessages[$code][
'translated']
as $key =>
$value ) {
360 if ( $this->mGeneralMessages[
'translatable'][$key] ==
$value ) {
361 $duplicateMessages[$key] =
$value;
365 return $duplicateMessages;
375 public function getObsoleteMessages( $code ) {
376 $this->loadGeneralMessages();
377 $this->loadMessages( $code );
379 return $this->mMessages[$code][
'obsolete'];
389 public function getMessagesWithMismatchVariables( $code ) {
390 $this->loadGeneralMessages();
391 $this->loadMessages( $code );
392 $variables =
array(
'\$1',
'\$2',
'\$3',
'\$4',
'\$5',
'\$6',
'\$7',
'\$8',
'\$9' );
393 $mismatchMessages =
array();
394 foreach ( $this->mMessages[$code][
'translated']
as $key =>
$value ) {
396 foreach ( $variables
as $var ) {
397 if ( preg_match(
"/$var/sU", $this->mGeneralMessages[
'translatable'][$key] ) &&
398 !preg_match(
"/$var/sU",
$value )
402 if ( !preg_match(
"/$var/sU", $this->mGeneralMessages[
'translatable'][$key] ) &&
403 preg_match(
"/$var/sU",
$value )
409 $mismatchMessages[$key] =
$value;
413 return $mismatchMessages;
423 public function getMessagesWithoutPlural( $code ) {
424 $this->loadGeneralMessages();
425 $this->loadMessages( $code );
426 $messagesWithoutPlural =
array();
427 foreach ( $this->mMessages[$code][
'translated']
as $key =>
$value ) {
428 if ( stripos( $this->mGeneralMessages[
'translatable'][$key],
'{{plural:' ) !==
false &&
429 stripos(
$value,
'{{plural:' ) ===
false
431 $messagesWithoutPlural[$key] =
$value;
435 return $messagesWithoutPlural;
445 public function getEmptyMessages( $code ) {
446 $this->loadGeneralMessages();
447 $this->loadMessages( $code );
448 $emptyMessages =
array();
449 foreach ( $this->mMessages[$code][
'translated']
as $key =>
$value ) {
451 $emptyMessages[$key] =
$value;
455 return $emptyMessages;
465 public function getMessagesWithWhitespace( $code ) {
466 $this->loadGeneralMessages();
467 $this->loadMessages( $code );
468 $messagesWithWhitespace =
array();
469 foreach ( $this->mMessages[$code][
'translated']
as $key =>
$value ) {
470 if ( $this->mGeneralMessages[
'translatable'][$key] !==
'' &&
$value !== rtrim(
$value ) ) {
471 $messagesWithWhitespace[$key] =
$value;
475 return $messagesWithWhitespace;
485 public function getNonXHTMLMessages( $code ) {
486 $this->loadGeneralMessages();
487 $this->loadMessages( $code );
488 $wrongPhrases =
array(
496 $wrongPhrases =
'~(' . implode(
'|', $wrongPhrases ) .
')~sDu';
497 $nonXHTMLMessages =
array();
498 foreach ( $this->mMessages[$code][
'translated']
as $key =>
$value ) {
499 if ( preg_match( $wrongPhrases,
$value ) ) {
500 $nonXHTMLMessages[$key] =
$value;
504 return $nonXHTMLMessages;
514 public function getMessagesWithWrongChars( $code ) {
515 $this->loadGeneralMessages();
516 $this->loadMessages( $code );
518 '[LRM]' =>
"\xE2\x80\x8E",
519 '[RLM]' =>
"\xE2\x80\x8F",
520 '[LRE]' =>
"\xE2\x80\xAA",
521 '[RLE]' =>
"\xE2\x80\xAB",
522 '[POP]' =>
"\xE2\x80\xAC",
523 '[LRO]' =>
"\xE2\x80\xAD",
524 '[RLO]' =>
"\xE2\x80\xAB",
525 '[ZWSP]' =>
"\xE2\x80\x8B",
526 '[NBSP]' =>
"\xC2\xA0",
527 '[WJ]' =>
"\xE2\x81\xA0",
528 '[BOM]' =>
"\xEF\xBB\xBF",
529 '[FFFD]' =>
"\xEF\xBF\xBD",
531 $wrongRegExp =
'/(' . implode(
'|', array_values( $wrongChars ) ) .
')/sDu';
532 $wrongCharsMessages =
array();
533 foreach ( $this->mMessages[$code][
'translated']
as $key =>
$value ) {
534 if ( preg_match( $wrongRegExp,
$value ) ) {
535 foreach ( $wrongChars
as $viewableChar => $hiddenChar ) {
536 $value = str_replace( $hiddenChar, $viewableChar,
$value );
538 $wrongCharsMessages[$key] =
$value;
542 return $wrongCharsMessages;
552 public function getMessagesWithDubiousLinks( $code ) {
553 $this->loadGeneralMessages();
554 $this->loadMessages( $code );
557 foreach ( $this->mMessages[$code][
'translated']
as $key =>
$value ) {
559 preg_match_all(
"/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu",
$value,
$matches );
561 for ( $i = 0; $i < $numMatches; $i++ ) {
562 if ( preg_match(
"/.*project.*/isDu",
$matches[1][$i] ) ) {
582 public function getMessagesWithUnbalanced( $code ) {
583 $this->loadGeneralMessages();
584 $this->loadMessages( $code );
586 foreach ( $this->mMessages[$code][
'translated']
as $key =>
$value ) {
587 $a = $b = $c = $d = 0;
588 foreach ( preg_split(
'//',
$value )
as $char ) {
605 if ( $a !== $b || $c !== $d ) {
620 public function getUntranslatedNamespaces( $code ) {
621 $this->loadFile(
'en' );
622 $this->loadFile( $code );
623 $namespacesDiff = array_diff_key( $this->mNamespaceNames[
'en'], $this->mNamespaceNames[$code] );
624 if ( isset( $namespacesDiff[
NS_MAIN] ) ) {
625 unset( $namespacesDiff[
NS_MAIN] );
628 return $namespacesDiff;
638 public function getProblematicProjectTalks( $code ) {
639 $this->loadFile( $code );
642 # Check default namespace name
645 if ( strpos( $default,
'$1' ) ===
false ) {
650 # Check namespace aliases
651 foreach ( $this->mNamespaceAliases[$code]
as $key =>
$value ) {
667 public function getUntranslatedMagicWords( $code ) {
668 $this->loadFile(
'en' );
669 $this->loadFile( $code );
671 foreach ( $this->mMagicWords[
'en']
as $key =>
$value ) {
672 if ( !isset( $this->mMagicWords[$code][$key] ) ) {
687 public function getObsoleteMagicWords( $code ) {
688 $this->loadFile(
'en' );
689 $this->loadFile( $code );
691 foreach ( $this->mMagicWords[$code]
as $key =>
$value ) {
692 if ( !isset( $this->mMagicWords[
'en'][$key] ) ) {
707 public function getOverridingMagicWords( $code ) {
708 $this->loadFile(
'en' );
709 $this->loadFile( $code );
711 foreach ( $this->mMagicWords[$code]
as $key => $local ) {
712 if ( !isset( $this->mMagicWords[
'en'][$key] ) ) {
713 # Unrecognized magic word
716 $en = $this->mMagicWords[
'en'][$key];
717 array_shift( $local );
719 foreach ( $en
as $word ) {
720 if ( !in_array( $word, $local ) ) {
737 public function getCaseMismatchMagicWords( $code ) {
738 $this->loadFile(
'en' );
739 $this->loadFile( $code );
741 foreach ( $this->mMagicWords[$code]
as $key => $local ) {
742 if ( !isset( $this->mMagicWords[
'en'][$key] ) ) {
743 # Unrecognized magic word
746 if ( $local[0] != $this->mMagicWords[
'en'][$key][0] ) {
761 public function getUntraslatedSpecialPages( $code ) {
762 $this->loadFile(
'en' );
763 $this->loadFile( $code );
765 foreach ( $this->mSpecialPageAliases[
'en']
as $key =>
$value ) {
766 if ( !isset( $this->mSpecialPageAliases[$code][$key] ) ) {
781 public function getObsoleteSpecialPages( $code ) {
782 $this->loadFile(
'en' );
783 $this->loadFile( $code );
785 foreach ( $this->mSpecialPageAliases[$code]
as $key =>
$value ) {
786 if ( !isset( $this->mSpecialPageAliases[
'en'][$key] ) ) {
795 class ExtensionLanguages
extends Languages {
799 private $mMessageGroup;
805 function __construct( MessageGroup $group ) {
806 $this->mMessageGroup = $group;
808 $this->mIgnoredMessages = $this->mMessageGroup->getIgnored();
809 $this->mOptionalMessages = $this->mMessageGroup->getOptional();
817 public function name() {
818 return $this->mMessageGroup->getLabel();
826 protected function loadFile( $code ) {
827 if ( !isset( $this->mRawMessages[$code] ) ) {
828 $this->mRawMessages[$code] = $this->mMessageGroup->load( $code );
829 if ( empty( $this->mRawMessages[$code] ) ) {
830 $this->mRawMessages[$code] =
array();