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
|
|||
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 |
This check looks for calls to
isset(...)
orempty()
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.