make the summary messages optional
[lhc/web/wiklou.git] / maintenance / languages.inc
1 <?php
2 /**
3 * Handle messages in the language files.
4 *
5 * @package MediaWiki
6 * @subpackage Maintenance
7 */
8
9 class languages {
10 private $mLanguages; # List of languages
11 private $mRawMessages; # Raw list of the messages in each language
12 private $mMessages; # Messages in each language (except for English), divided to groups
13 private $mGeneralMessages; # General messages in English, divided to groups
14 private $mIgnoredMessages = array(
15 'sidebar',
16 'addsection',
17 'anonnotice',
18 'catseparator',
19 'googlesearch',
20 'exif-make-value',
21 'exif-model-value',
22 'exif-software-value',
23 'history_copyright',
24 'licenses',
25 'loginend',
26 'loginlanguagelinks',
27 'markaspatrolledlink',
28 'newarticletextanon',
29 'noarticletextanon',
30 'number_of_watching_users_RCview',
31 'pubmedurl',
32 'randompage-url',
33 'recentchanges-url',
34 'rfcurl',
35 'shareddescriptionfollows',
36 'signupend',
37 'sitenotice',
38 'sitesubtitle',
39 'sitetitle',
40 'talkpagetext',
41 'trackback',
42 'trackbackexcerpt',
43 'widthheight',
44 ); # All the messages which should be exist only in the English file
45 private $mOptionalMessages = array(
46 'imgmultigotopost',
47 'linkprefix',
48 'allpages-summary',
49 'booksources-summary',
50 'ipblocklist-summary',
51 'listusers-summary',
52 'longpages-summary',
53 'preferences-summary',
54 'specialpages-summary',
55 'whatlinkshere-summary',
56 ); # All the messages which may be translated or not, depending on the language
57 private $mEXIFMessages = array(
58 'exif-imagewidth',
59 'exif-imagelength',
60 'exif-bitspersample',
61 'exif-compression',
62 'exif-photometricinterpretation',
63 'exif-orientation',
64 'exif-samplesperpixel',
65 'exif-planarconfiguration',
66 'exif-ycbcrsubsampling',
67 'exif-ycbcrpositioning',
68 'exif-xresolution',
69 'exif-yresolution',
70 'exif-resolutionunit',
71 'exif-stripoffsets',
72 'exif-rowsperstrip',
73 'exif-stripbytecounts',
74 'exif-jpeginterchangeformat',
75 'exif-jpeginterchangeformatlength',
76 'exif-transferfunction',
77 'exif-whitepoint',
78 'exif-primarychromaticities',
79 'exif-ycbcrcoefficients',
80 'exif-referenceblackwhite',
81 'exif-datetime',
82 'exif-imagedescription',
83 'exif-make',
84 'exif-model',
85 'exif-software',
86 'exif-artist',
87 'exif-copyright',
88 'exif-exifversion',
89 'exif-flashpixversion',
90 'exif-colorspace',
91 'exif-componentsconfiguration',
92 'exif-compressedbitsperpixel',
93 'exif-pixelydimension',
94 'exif-pixelxdimension',
95 'exif-makernote',
96 'exif-usercomment',
97 'exif-relatedsoundfile',
98 'exif-datetimeoriginal',
99 'exif-datetimedigitized',
100 'exif-subsectime',
101 'exif-subsectimeoriginal',
102 'exif-subsectimedigitized',
103 'exif-exposuretime',
104 'exif-exposuretime-format',
105 'exif-fnumber',
106 'exif-fnumber-format',
107 'exif-exposureprogram',
108 'exif-spectralsensitivity',
109 'exif-isospeedratings',
110 'exif-oecf',
111 'exif-shutterspeedvalue',
112 'exif-aperturevalue',
113 'exif-brightnessvalue',
114 'exif-exposurebiasvalue',
115 'exif-maxaperturevalue',
116 'exif-subjectdistance',
117 'exif-meteringmode',
118 'exif-lightsource',
119 'exif-flash',
120 'exif-focallength',
121 'exif-focallength-format',
122 'exif-subjectarea',
123 'exif-flashenergy',
124 'exif-spatialfrequencyresponse',
125 'exif-focalplanexresolution',
126 'exif-focalplaneyresolution',
127 'exif-focalplaneresolutionunit',
128 'exif-subjectlocation',
129 'exif-exposureindex',
130 'exif-sensingmethod',
131 'exif-filesource',
132 'exif-scenetype',
133 'exif-cfapattern',
134 'exif-customrendered',
135 'exif-exposuremode',
136 'exif-whitebalance',
137 'exif-digitalzoomratio',
138 'exif-focallengthin35mmfilm',
139 'exif-scenecapturetype',
140 'exif-gaincontrol',
141 'exif-contrast',
142 'exif-saturation',
143 'exif-sharpness',
144 'exif-devicesettingdescription',
145 'exif-subjectdistancerange',
146 'exif-imageuniqueid',
147 'exif-gpsversionid',
148 'exif-gpslatituderef',
149 'exif-gpslatitude',
150 'exif-gpslongituderef',
151 'exif-gpslongitude',
152 'exif-gpsaltituderef',
153 'exif-gpsaltitude',
154 'exif-gpstimestamp',
155 'exif-gpssatellites',
156 'exif-gpsstatus',
157 'exif-gpsmeasuremode',
158 'exif-gpsdop',
159 'exif-gpsspeedref',
160 'exif-gpsspeed',
161 'exif-gpstrackref',
162 'exif-gpstrack',
163 'exif-gpsimgdirectionref',
164 'exif-gpsimgdirection',
165 'exif-gpsmapdatum',
166 'exif-gpsdestlatituderef',
167 'exif-gpsdestlatitude',
168 'exif-gpsdestlongituderef',
169 'exif-gpsdestlongitude',
170 'exif-gpsdestbearingref',
171 'exif-gpsdestbearing',
172 'exif-gpsdestdistanceref',
173 'exif-gpsdestdistance',
174 'exif-gpsprocessingmethod',
175 'exif-gpsareainformation',
176 'exif-gpsdatestamp',
177 'exif-gpsdifferential',
178 'exif-compression-1',
179 'exif-compression-6',
180 'exif-photometricinterpretation-2',
181 'exif-photometricinterpretation-6',
182 'exif-orientation-1',
183 'exif-orientation-2',
184 'exif-orientation-3',
185 'exif-orientation-4',
186 'exif-orientation-5',
187 'exif-orientation-6',
188 'exif-orientation-7',
189 'exif-orientation-8',
190 'exif-planarconfiguration-1',
191 'exif-planarconfiguration-2',
192 'exif-xyresolution-i',
193 'exif-xyresolution-c',
194 'exif-colorspace-1',
195 'exif-colorspace-ffff.h',
196 'exif-componentsconfiguration-0',
197 'exif-componentsconfiguration-1',
198 'exif-componentsconfiguration-2',
199 'exif-componentsconfiguration-3',
200 'exif-componentsconfiguration-4',
201 'exif-componentsconfiguration-5',
202 'exif-componentsconfiguration-6',
203 'exif-exposureprogram-0',
204 'exif-exposureprogram-1',
205 'exif-exposureprogram-2',
206 'exif-exposureprogram-3',
207 'exif-exposureprogram-4',
208 'exif-exposureprogram-5',
209 'exif-exposureprogram-6',
210 'exif-exposureprogram-7',
211 'exif-exposureprogram-8',
212 'exif-subjectdistance-value',
213 'exif-meteringmode-0',
214 'exif-meteringmode-1',
215 'exif-meteringmode-2',
216 'exif-meteringmode-3',
217 'exif-meteringmode-4',
218 'exif-meteringmode-5',
219 'exif-meteringmode-6',
220 'exif-meteringmode-255',
221 'exif-lightsource-0',
222 'exif-lightsource-1',
223 'exif-lightsource-2',
224 'exif-lightsource-3',
225 'exif-lightsource-4',
226 'exif-lightsource-9',
227 'exif-lightsource-10',
228 'exif-lightsource-11',
229 'exif-lightsource-12',
230 'exif-lightsource-13',
231 'exif-lightsource-14',
232 'exif-lightsource-15',
233 'exif-lightsource-17',
234 'exif-lightsource-18',
235 'exif-lightsource-19',
236 'exif-lightsource-20',
237 'exif-lightsource-21',
238 'exif-lightsource-22',
239 'exif-lightsource-23',
240 'exif-lightsource-24',
241 'exif-lightsource-255',
242 'exif-focalplaneresolutionunit-2',
243 'exif-sensingmethod-1',
244 'exif-sensingmethod-2',
245 'exif-sensingmethod-3',
246 'exif-sensingmethod-4',
247 'exif-sensingmethod-5',
248 'exif-sensingmethod-7',
249 'exif-sensingmethod-8',
250 'exif-filesource-3',
251 'exif-scenetype-1',
252 'exif-customrendered-0',
253 'exif-customrendered-1',
254 'exif-exposuremode-0',
255 'exif-exposuremode-1',
256 'exif-exposuremode-2',
257 'exif-whitebalance-0',
258 'exif-whitebalance-1',
259 'exif-scenecapturetype-0',
260 'exif-scenecapturetype-1',
261 'exif-scenecapturetype-2',
262 'exif-scenecapturetype-3',
263 'exif-gaincontrol-0',
264 'exif-gaincontrol-1',
265 'exif-gaincontrol-2',
266 'exif-gaincontrol-3',
267 'exif-gaincontrol-4',
268 'exif-contrast-0',
269 'exif-contrast-1',
270 'exif-contrast-2',
271 'exif-saturation-0',
272 'exif-saturation-1',
273 'exif-saturation-2',
274 'exif-sharpness-0',
275 'exif-sharpness-1',
276 'exif-sharpness-2',
277 'exif-subjectdistancerange-0',
278 'exif-subjectdistancerange-1',
279 'exif-subjectdistancerange-2',
280 'exif-subjectdistancerange-3',
281 'exif-gpslatitude-n',
282 'exif-gpslatitude-s',
283 'exif-gpslongitude-e',
284 'exif-gpslongitude-w',
285 'exif-gpsstatus-a',
286 'exif-gpsstatus-v',
287 'exif-gpsmeasuremode-2',
288 'exif-gpsmeasuremode-3',
289 'exif-gpsspeed-k',
290 'exif-gpsspeed-m',
291 'exif-gpsspeed-n',
292 'exif-gpsdirection-t',
293 'exif-gpsdirection-m',
294 ); # All the EXIF messages, may be set as optional if defined as such
295
296 /**
297 * Load the list of languages: all the Messages*.php
298 * files in the languages directory.
299 *
300 * @param $exif Treat the EXIF messages?
301 */
302 function __construct( $exif = true ) {
303 global $IP;
304 $dir = opendir( "$IP/languages" );
305 while ( $file = readdir( $dir ) ) {
306 if ( preg_match( "/Messages([^.]*?)\.php$/", $file, $matches ) ) {
307 $this->mLanguages[] = str_replace( '_', '-', strtolower( substr( $matches[1], 0, 1 ) ) . substr( $matches[1], 1 ) );
308 }
309 }
310 sort( $this->mLanguages );
311 if ( !$exif ) {
312 $this->mOptionalMessages = array_merge( $this->mOptionalMessages, $this->mEXIFMessages );
313 }
314 }
315
316 /**
317 * Get the language list.
318 *
319 * @return The language list.
320 */
321 public function getLanguages() {
322 return $this->mLanguages;
323 }
324
325 /**
326 * Load the raw messages for a specific langauge from the messages file.
327 *
328 * @param $code The langauge code.
329 */
330 private function loadRawMessages( $code ) {
331 if ( isset( $this->mRawMessages[$code] ) ) {
332 return;
333 }
334 global $IP;
335 $filename = Language::getFileName( "$IP/languages/Messages", $code, '.php' );
336 if ( file_exists( $filename ) ) {
337 require( $filename );
338 if ( isset( $messages ) ) {
339 $this->mRawMessages[$code] = $messages;
340 } else {
341 $this->mRawMessages[$code] = array();
342 }
343 } else {
344 $this->mRawMessages[$code] = array();
345 }
346 }
347
348 /**
349 * Load the messages for a specific language (which is not English) and divide them to groups:
350 * all - all the messages.
351 * required - messages which should be translated in order to get a complete translation.
352 * optional - messages which can be translated, the fallback translation is used if not translated.
353 * obsolete - messages which should not be translated, either because they are not exist, or they are ignored messages.
354 * translated - messages which are either required or optional, but translated from English and needed.
355 *
356 * @param $code The language code.
357 */
358 private function loadMessages( $code ) {
359 if ( isset( $this->mMessages[$code] ) ) {
360 return;
361 }
362 $this->loadRawMessages( $code );
363 $this->loadGeneralMessages();
364 $this->mMessages[$code]['all'] = $this->mRawMessages[$code];
365 $this->mMessages[$code]['required'] = array();
366 $this->mMessages[$code]['optional'] = array();
367 $this->mMessages[$code]['obsolete'] = array();
368 $this->mMessages[$code]['translated'] = array();
369 foreach ( $this->mMessages[$code]['all'] as $key => $value ) {
370 if ( isset( $this->mGeneralMessages['required'][$key] ) ) {
371 $this->mMessages[$code]['required'][$key] = $value;
372 $this->mMessages[$code]['translated'][$key] = $value;
373 } else if ( isset( $this->mGeneralMessages['optional'][$key] ) ) {
374 $this->mMessages[$code]['optional'][$key] = $value;
375 $this->mMessages[$code]['translated'][$key] = $value;
376 } else {
377 $this->mMessages[$code]['obsolete'][$key] = $value;
378 }
379 }
380 }
381
382 /**
383 * Load the messages for English and divide them to groups:
384 * all - all the messages.
385 * required - messages which should be translated to other languages in order to get a complete translation.
386 * optional - messages which can be translated to other languages, but it's not required for a complete translation.
387 * ignored - messages which should not be translated to other languages.
388 * translatable - messages which are either required or optional, but can be translated from English.
389 */
390 private function loadGeneralMessages() {
391 if ( isset( $this->mGeneralMessages ) ) {
392 return;
393 }
394 $this->loadRawMessages( 'en' );
395 $this->mGeneralMessages['all'] = $this->mRawMessages['en'];
396 $this->mGeneralMessages['required'] = array();
397 $this->mGeneralMessages['optional'] = array();
398 $this->mGeneralMessages['ignored'] = array();
399 $this->mGeneralMessages['translatable'] = array();
400 foreach ( $this->mGeneralMessages['all'] as $key => $value ) {
401 if ( in_array( $key, $this->mIgnoredMessages ) ) {
402 $this->mGeneralMessages['ignored'][$key] = $value;
403 } else if ( in_array( $key, $this->mOptionalMessages ) ) {
404 $this->mGeneralMessages['optional'][$key] = $value;
405 $this->mGeneralMessages['translatable'][$key] = $value;
406 } else {
407 $this->mGeneralMessages['required'][$key] = $value;
408 $this->mGeneralMessages['translatable'][$key] = $value;
409 }
410 }
411 }
412
413 /**
414 * Get all the messages for a specific langauge (not English), without the
415 * fallback language messages, divided to groups:
416 * all - all the messages.
417 * required - messages which should be translated in order to get a complete translation.
418 * optional - messages which can be translated, the fallback translation is used if not translated.
419 * obsolete - messages which should not be translated, either because they are not exist, or they are ignored messages.
420 * translated - messages which are either required or optional, but translated from English and needed.
421 *
422 * @param $code The langauge code.
423 *
424 * @return The messages in this language.
425 */
426 public function getMessages( $code ) {
427 $this->loadMessages( $code );
428 return $this->mMessages[$code];
429 }
430
431 /**
432 * Get all the general English messages, divided to groups:
433 * all - all the messages.
434 * required - messages which should be translated to other languages in order to get a complete translation.
435 * optional - messages which can be translated to other languages, but it's not required for a complete translation.
436 * ignored - messages which should not be translated to other languages.
437 * translatable - messages which are either required or optional, but can be translated from English.
438 *
439 * @return The general English messages.
440 */
441 public function getGeneralMessages() {
442 $this->loadGeneralMessages();
443 return $this->mGeneralMessages;
444 }
445
446 /**
447 * Get the untranslated messages for a specific language.
448 *
449 * @param $code The langauge code.
450 *
451 * @return The untranslated messages for this language.
452 */
453 public function getUntranslatedMessages( $code ) {
454 $this->loadGeneralMessages();
455 $this->loadMessages( $code );
456 $requiredGeneralMessages = array_keys( $this->mGeneralMessages['required'] );
457 $requiredMessages = array_keys( $this->mMessages[$code]['required'] );
458 $untranslatedMessages = array();
459 foreach ( array_diff( $requiredGeneralMessages, $requiredMessages ) as $key ) {
460 $untranslatedMessages[$key] = $this->mGeneralMessages['required'][$key];
461 }
462 return $untranslatedMessages;
463 }
464
465 /**
466 * Get the duplicate messages for a specific language.
467 *
468 * @param $code The langauge code.
469 *
470 * @return The duplicate messages for this language.
471 */
472 public function getDuplicateMessages( $code ) {
473 $this->loadGeneralMessages();
474 $this->loadMessages( $code );
475 $duplicateMessages = array();
476 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
477 if ( $this->mGeneralMessages['translatable'][$key] == $value ) {
478 $duplicateMessages[$key] = $value;
479 }
480 }
481 return $duplicateMessages;
482 }
483
484 /**
485 * Get the messages which do not use some variables.
486 *
487 * @param $code The langauge code.
488 *
489 * @return The messages which do not use some variables in this language.
490 */
491 public function getMessagesWithoutVariables( $code ) {
492 $this->loadGeneralMessages();
493 $this->loadMessages( $code );
494 $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' );
495 $messagesWithoutVariables = array();
496 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
497 $missing = false;
498 foreach ( $variables as $var ) {
499 if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
500 !preg_match( "/$var/sU", $value ) ) {
501 $missing = true;
502 }
503 }
504 if ( $missing ) {
505 $messagesWithoutVariables[$key] = $value;
506 }
507 }
508 return $messagesWithoutVariables;
509 }
510
511 /**
512 * Get the empty messages.
513 *
514 * @param $code The langauge code.
515 *
516 * @return The empty messages for this language.
517 */
518 public function getEmptyMessages( $code ) {
519 $this->loadGeneralMessages();
520 $this->loadMessages( $code );
521 $emptyMessages = array();
522 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
523 if ( $value === '' || $value === '-' ) {
524 $emptyMessages[$key] = $value;
525 }
526 }
527 return $emptyMessages;
528 }
529
530 /**
531 * Get the messages with trailing whitespace.
532 *
533 * @param $code The langauge code.
534 *
535 * @return The messages with trailing whitespace in this language.
536 */
537 public function getMessagesWithWhitespace( $code ) {
538 $this->loadGeneralMessages();
539 $this->loadMessages( $code );
540 $messagesWithWhitespace = array();
541 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
542 if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) {
543 $messagesWithWhitespace[$key] = $value;
544 }
545 }
546 return $messagesWithWhitespace;
547 }
548
549 /**
550 * Get the non-XHTML messages.
551 *
552 * @param $code The langauge code.
553 *
554 * @return The non-XHTML messages for this language.
555 */
556 public function getNonXHTMLMessages( $code ) {
557 $this->loadGeneralMessages();
558 $this->loadMessages( $code );
559 $wrongPhrases = array(
560 '<hr *\\?>',
561 '<br *\\?>',
562 '<hr/>',
563 '<br/>',
564 );
565 $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu';
566 $nonXHTMLMessages = array();
567 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
568 if ( preg_match( $wrongPhrases, $value ) ) {
569 $nonXHTMLMessages[$key] = $value;
570 }
571 }
572 return $nonXHTMLMessages;
573 }
574
575 /**
576 * Get the messages which include wrong characters.
577 *
578 * @param $code The langauge code.
579 *
580 * @return The messages which include wrong characters in this language.
581 */
582 public function getMessagesWithWrongChars( $code ) {
583 $this->loadGeneralMessages();
584 $this->loadMessages( $code );
585 $wrongChars = array(
586 '[LRM]' => "\xE2\x80\x8E",
587 '[RLM]' => "\xE2\x80\x8F",
588 '[LRE]' => "\xE2\x80\xAA",
589 '[RLE]' => "\xE2\x80\xAB",
590 '[POP]' => "\xE2\x80\xAC",
591 '[LRO]' => "\xE2\x80\xAD",
592 '[RLO]' => "\xE2\x80\xAB",
593 '[ZWSP]'=> "\xE2\x80\x8B",
594 '[NBSP]'=> "\xC2\xA0",
595 '[WJ]' => "\xE2\x81\xA0",
596 '[BOM]' => "\xEF\xBB\xBF",
597 '[FFFD]'=> "\xEF\xBF\xBD",
598 );
599 $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu';
600 $wrongCharsMessages = array();
601 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
602 if ( preg_match( $wrongRegExp, $value ) ) {
603 foreach ( $wrongChars as $viewableChar => $hiddenChar ) {
604 $value = str_replace( $hiddenChar, $viewableChar, $value );
605 }
606 $wrongCharsMessages[$key] = $value;
607 }
608 }
609 return $wrongCharsMessages;
610 }
611
612 /**
613 * Output a messages list
614 *
615 * @param $messages The messages list
616 * @param $code The language code
617 * @param $text The text to show before the list (optional)
618 * @param $level The display level (optional)
619 * @param $links Show links (optional)
620 * @param $wikilang The langauge of the wiki to display the list in, for the links (optional)
621 */
622 public function outputMessagesList( $messages, $code, $text = '', $level = 2, $links = false, $wikilang = null ) {
623 if ( count( $messages ) == 0 ) {
624 return;
625 }
626 if ( $text ) {
627 echo "$text\n";
628 }
629 if ( $level == 1 ) {
630 echo "[messages are hidden]\n";
631 } else {
632 foreach ( $messages as $key => $value ) {
633 if ( $links ) {
634 $displayKey = ucfirst( $key );
635 if ( !isset( $wikilang ) ) {
636 global $wgContLang;
637 $wikilang = $wgContLang->getCode();
638 }
639 if ( $code == $wikilang ) {
640 $displayKey = "[[MediaWiki:$displayKey|$key]]";
641 } else {
642 $displayKey = "[[MediaWiki:$displayKey/$code|$key]]";
643 }
644 } else {
645 $displayKey = $key;
646 }
647 if ( $level == 2 ) {
648 echo "* $displayKey\n";
649 } else {
650 echo "* $displayKey: '$value'\n";
651 }
652 }
653 }
654 }
655 }
656
657 ?>