MediaWiki  1.23.0
languages.inc
Go to the documentation of this file.
1 <?php
27 class Languages {
29  protected $mLanguages; #
30 
32  protected $mRawMessages;
33 
35  protected $mMessages;
36 
38  protected $mFallback;
39 
41  protected $mGeneralMessages;
42 
44  protected $mIgnoredMessages;
45 
47  protected $mOptionalMessages;
48 
50  protected $mNamespaceNames;
51 
53  protected $mNamespaceAliases;
54 
56  protected $mMagicWords;
57 
59  protected $mSpecialPageAliases;
60 
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  }
75 
76  $this->mLanguages = array_keys( Language::fetchLanguageNames( null, 'mwfile' ) );
77  sort( $this->mLanguages );
78  }
79 
85  public function getLanguages() {
86  return $this->mLanguages;
87  }
88 
94  public function getIgnoredMessages() {
95  return $this->mIgnoredMessages;
96  }
97 
103  public function getOptionalMessages() {
104  return $this->mOptionalMessages;
105  }
106 
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 
129  $jsonfilename = Language::getJsonMessagesFileName( $code );
130  if ( file_exists( $jsonfilename ) ) {
131  $json = Language::getLocalisationCache()->readJSONFile( $jsonfilename );
132  $this->mRawMessages[$code] = $json['messages'];
133  }
134 
135  $filename = Language::getMessagesFileName( $code );
136  if ( file_exists( $filename ) ) {
137  require $filename;
138  if ( isset( $fallback ) ) {
139  $this->mFallback[$code] = $fallback;
140  }
141  if ( isset( $namespaceNames ) ) {
142  $this->mNamespaceNames[$code] = $namespaceNames;
143  }
144  if ( isset( $namespaceAliases ) ) {
145  $this->mNamespaceAliases[$code] = $namespaceAliases;
146  }
147  if ( isset( $magicWords ) ) {
148  $this->mMagicWords[$code] = $magicWords;
149  }
150  if ( isset( $specialPageAliases ) ) {
151  $this->mSpecialPageAliases[$code] = $specialPageAliases;
152  }
153  }
154  }
155 
170  private function loadMessages( $code ) {
171  if ( isset( $this->mMessages[$code] ) ) {
172  return;
173  }
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;
188  } else {
189  $this->mMessages[$code]['obsolete'][$key] = $value;
190  }
191  }
192  }
193 
205  private function loadGeneralMessages() {
206  if ( isset( $this->mGeneralMessages ) ) {
207  return;
208  }
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;
221  } else {
222  $this->mGeneralMessages['required'][$key] = $value;
223  $this->mGeneralMessages['translatable'][$key] = $value;
224  }
225  }
226  }
227 
244  public function getMessages( $code ) {
245  $this->loadMessages( $code );
246 
247  return $this->mMessages[$code];
248  }
249 
263  public function getGeneralMessages() {
264  $this->loadGeneralMessages();
265 
266  return $this->mGeneralMessages;
267  }
268 
276  public function getFallback( $code ) {
277  $this->loadFile( $code );
278 
279  return $this->mFallback[$code];
280  }
281 
289  public function getNamespaceNames( $code ) {
290  $this->loadFile( $code );
291 
292  return $this->mNamespaceNames[$code];
293  }
294 
302  public function getNamespaceAliases( $code ) {
303  $this->loadFile( $code );
304 
305  return $this->mNamespaceAliases[$code];
306  }
307 
315  public function getMagicWords( $code ) {
316  $this->loadFile( $code );
317 
318  return $this->mMagicWords[$code];
319  }
320 
328  public function getSpecialPageAliases( $code ) {
329  $this->loadFile( $code );
330 
331  return $this->mSpecialPageAliases[$code];
332  }
333 
341  public function getUntranslatedMessages( $code ) {
342  $this->loadGeneralMessages();
343  $this->loadMessages( $code );
344 
345  return array_diff_key( $this->mGeneralMessages['required'], $this->mMessages[$code]['required'] );
346  }
347 
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;
362  }
363  }
364 
365  return $duplicateMessages;
366  }
367 
375  public function getObsoleteMessages( $code ) {
376  $this->loadGeneralMessages();
377  $this->loadMessages( $code );
378 
379  return $this->mMessages[$code]['obsolete'];
380  }
381 
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 ) {
395  $missing = false;
396  foreach ( $variables as $var ) {
397  if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
398  !preg_match( "/$var/sU", $value )
399  ) {
400  $missing = true;
401  }
402  if ( !preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
403  preg_match( "/$var/sU", $value )
404  ) {
405  $missing = true;
406  }
407  }
408  if ( $missing ) {
409  $mismatchMessages[$key] = $value;
410  }
411  }
412 
413  return $mismatchMessages;
414  }
415 
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
430  ) {
431  $messagesWithoutPlural[$key] = $value;
432  }
433  }
434 
435  return $messagesWithoutPlural;
436  }
437 
445  public function getEmptyMessages( $code ) {
446  $this->loadGeneralMessages();
447  $this->loadMessages( $code );
448  $emptyMessages = array();
449  foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
450  if ( $value === '' || $value === '-' ) {
451  $emptyMessages[$key] = $value;
452  }
453  }
454 
455  return $emptyMessages;
456  }
457 
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;
472  }
473  }
474 
475  return $messagesWithWhitespace;
476  }
477 
485  public function getNonXHTMLMessages( $code ) {
486  $this->loadGeneralMessages();
487  $this->loadMessages( $code );
488  $wrongPhrases = array(
489  '<hr *\\?>',
490  '<br *\\?>',
491  '<hr/>',
492  '<br/>',
493  '<hr>',
494  '<br>',
495  );
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;
501  }
502  }
503 
504  return $nonXHTMLMessages;
505  }
506 
514  public function getMessagesWithWrongChars( $code ) {
515  $this->loadGeneralMessages();
516  $this->loadMessages( $code );
517  $wrongChars = array(
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",
530  );
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 );
537  }
538  $wrongCharsMessages[$key] = $value;
539  }
540  }
541 
542  return $wrongCharsMessages;
543  }
544 
552  public function getMessagesWithDubiousLinks( $code ) {
553  $this->loadGeneralMessages();
554  $this->loadMessages( $code );
555  $tc = Title::legalChars() . '#%{}';
556  $messages = array();
557  foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
558  $matches = array();
559  preg_match_all( "/\[\[([{$tc}]+)(?:\\|(.+?))?]]/sDu", $value, $matches );
560  $numMatches = count( $matches[0] );
561  for ( $i = 0; $i < $numMatches; $i++ ) {
562  if ( preg_match( "/.*project.*/isDu", $matches[1][$i] ) ) {
563  $messages[$key][] = $matches[0][$i];
564  }
565  }
566 
567  if ( isset( $messages[$key] ) ) {
568  $messages[$key] = implode( $messages[$key], ", " );
569  }
570  }
571 
572  return $messages;
573  }
574 
582  public function getMessagesWithUnbalanced( $code ) {
583  $this->loadGeneralMessages();
584  $this->loadMessages( $code );
585  $messages = array();
586  foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
587  $a = $b = $c = $d = 0;
588  foreach ( preg_split( '//', $value ) as $char ) {
589  switch ( $char ) {
590  case '[':
591  $a++;
592  break;
593  case ']':
594  $b++;
595  break;
596  case '{':
597  $c++;
598  break;
599  case '}':
600  $d++;
601  break;
602  }
603  }
604 
605  if ( $a !== $b || $c !== $d ) {
606  $messages[$key] = "$a, $b, $c, $d";
607  }
608  }
609 
610  return $messages;
611  }
612 
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] );
626  }
627 
628  return $namespacesDiff;
629  }
630 
638  public function getProblematicProjectTalks( $code ) {
639  $this->loadFile( $code );
640  $namespaces = array();
641 
642  # Check default namespace name
643  if ( isset( $this->mNamespaceNames[$code][NS_PROJECT_TALK] ) ) {
644  $default = $this->mNamespaceNames[$code][NS_PROJECT_TALK];
645  if ( strpos( $default, '$1' ) === false ) {
646  $namespaces[$default] = 'default';
647  }
648  }
649 
650  # Check namespace aliases
651  foreach ( $this->mNamespaceAliases[$code] as $key => $value ) {
652  if ( $value == NS_PROJECT_TALK && strpos( $key, '$1' ) === false ) {
653  $namespaces[$key] = '';
654  }
655  }
656 
657  return $namespaces;
658  }
659 
667  public function getUntranslatedMagicWords( $code ) {
668  $this->loadFile( 'en' );
669  $this->loadFile( $code );
670  $magicWords = array();
671  foreach ( $this->mMagicWords['en'] as $key => $value ) {
672  if ( !isset( $this->mMagicWords[$code][$key] ) ) {
673  $magicWords[$key] = $value[1];
674  }
675  }
676 
677  return $magicWords;
678  }
679 
687  public function getObsoleteMagicWords( $code ) {
688  $this->loadFile( 'en' );
689  $this->loadFile( $code );
690  $magicWords = array();
691  foreach ( $this->mMagicWords[$code] as $key => $value ) {
692  if ( !isset( $this->mMagicWords['en'][$key] ) ) {
693  $magicWords[$key] = $value[1];
694  }
695  }
696 
697  return $magicWords;
698  }
699 
707  public function getOverridingMagicWords( $code ) {
708  $this->loadFile( 'en' );
709  $this->loadFile( $code );
710  $magicWords = array();
711  foreach ( $this->mMagicWords[$code] as $key => $local ) {
712  if ( !isset( $this->mMagicWords['en'][$key] ) ) {
713  # Unrecognized magic word
714  continue;
715  }
716  $en = $this->mMagicWords['en'][$key];
717  array_shift( $local );
718  array_shift( $en );
719  foreach ( $en as $word ) {
720  if ( !in_array( $word, $local ) ) {
721  $magicWords[$key] = $word;
722  break;
723  }
724  }
725  }
726 
727  return $magicWords;
728  }
729 
737  public function getCaseMismatchMagicWords( $code ) {
738  $this->loadFile( 'en' );
739  $this->loadFile( $code );
740  $magicWords = array();
741  foreach ( $this->mMagicWords[$code] as $key => $local ) {
742  if ( !isset( $this->mMagicWords['en'][$key] ) ) {
743  # Unrecognized magic word
744  continue;
745  }
746  if ( $local[0] != $this->mMagicWords['en'][$key][0] ) {
747  $magicWords[$key] = $local[0];
748  }
749  }
750 
751  return $magicWords;
752  }
753 
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] ) ) {
767  $specialPageAliases[$key] = $value[0];
768  }
769  }
770 
771  return $specialPageAliases;
772  }
773 
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] ) ) {
787  $specialPageAliases[$key] = $value[0];
788  }
789  }
790 
791  return $specialPageAliases;
792  }
793 }
794 
795 class ExtensionLanguages extends Languages {
799  private $mMessageGroup;
800 
805  function __construct( MessageGroup $group ) {
806  $this->mMessageGroup = $group;
807 
808  $this->mIgnoredMessages = $this->mMessageGroup->getIgnored();
809  $this->mOptionalMessages = $this->mMessageGroup->getOptional();
810  }
811 
817  public function name() {
818  return $this->mMessageGroup->getLabel();
819  }
820 
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();
831  }
832  }
833  }
834 }
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
$fallback
$fallback
Definition: MessagesAb.php:12
Language\getMessagesFileName
static getMessagesFileName( $code)
Definition: Language.php:4085
$messages
$messages
Definition: LogTests.i18n.php:8
NS_MAIN
const NS_MAIN
Definition: Defines.php:79
Language\getLocalisationCache
static getLocalisationCache()
Get the LocalisationCache instance.
Definition: Language.php:443
Language\fetchLanguageNames
static fetchLanguageNames( $inLanguage=null, $include='mw')
Get an array of language names, indexed by code.
Definition: Language.php:875
$specialPageAliases
$specialPageAliases
Definition: MessagesAb.php:58
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
$namespaceNames
$namespaceNames
Definition: MessagesAb.php:14
$magicWords
magicword txt Magic Words are some phrases used in the wikitext They are used for two that looks like templates but that don t accept any parameter *Parser functions(like {{fullurl:...}}, {{#special:...}}) $magicWords['en']
Definition: magicword.txt:33
$matches
if(!defined( 'MEDIAWIKI')) if(!isset( $wgVersion)) $matches
Definition: NoLocalSettings.php:33
$value
$value
Definition: styleTest.css.php:45
NS_PROJECT_TALK
const NS_PROJECT_TALK
Definition: Defines.php:84
$namespaceAliases
$namespaceAliases
Definition: MessagesAb.php:33
$namespaces
namespace and then decline to actually register it & $namespaces
Definition: hooks.txt:815
$wgIgnoredMessages
$wgIgnoredMessages
Ignored messages, which should exist only in the English messages file.
Definition: messageTypes.inc:25
$wgEXIFMessages
$wgEXIFMessages
Exif messages, which may be set as optional in several checks, but are generally mandatory.
Definition: messageTypes.inc:506
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
Language\getJsonMessagesFileName
static getJsonMessagesFileName( $code)
Definition: Language.php:4097
name
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at name
Definition: design.txt:12
Title\legalChars
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition: Title.php:529
$wgOptionalMessages
$wgOptionalMessages
Optional messages, which may be translated only if changed in the target language.
Definition: messageTypes.inc:279