3 * Handle messages in the language files.
6 * @subpackage Maintenance
9 require_once( 'messageTypes.inc' );
12 protected $mLanguages; # List of languages
13 protected $mRawMessages; # Raw list of the messages in each language
14 protected $mMessages; # Messages in each language (except for English), divided to groups
15 protected $mGeneralMessages; # General messages in English, divided to groups
16 protected $mIgnoredMessages; # All the messages which should be exist only in the English file
17 protected $mOptionalMessages; # All the messages which may be translated or not, depending on the language
20 * Load the list of languages: all the Messages*.php
21 * files in the languages directory.
23 * @param $exif Treat the EXIF messages?
25 function __construct( $exif = true ) {
26 global $wgIgnoredMessages, $wgOptionalMessages, $wgEXIFMessages;
27 $this->mIgnoredMessages = $wgIgnoredMessages;
29 $this->mOptionalMessages = array_merge( $wgOptionalMessages );
31 $this->mOptionalMessages = array_merge( $wgOptionalMessages, $wgEXIFMessages );
34 $this->mLanguages = array_keys( Language::getLanguageNames( true ) );
35 sort( $this->mLanguages );
39 * Get the language list.
41 * @return The language list.
43 public function getLanguages() {
44 return $this->mLanguages;
48 * Get the ignored messages list.
50 * @return The ignored messages list.
52 public function getIgnoredMessages() {
53 return $this->mIgnoredMessages;
57 * Get the optional messages list.
59 * @return The optional messages list.
61 public function getOptionalMessages() {
62 return $this->mOptionalMessages;
66 * Load the raw messages for a specific langauge from the messages file.
68 * @param $code The langauge code.
70 protected function loadRawMessages( $code ) {
71 if ( isset( $this->mRawMessages[$code] ) ) {
74 $filename = Language::getMessagesFileName( $code );
75 if ( file_exists( $filename ) ) {
77 if ( isset( $messages ) ) {
78 $this->mRawMessages[$code] = $messages;
80 $this->mRawMessages[$code] = array();
83 $this->mRawMessages[$code] = array();
88 * Load the messages for a specific language (which is not English) and divide them to groups:
89 * all - all the messages.
90 * required - messages which should be translated in order to get a complete translation.
91 * optional - messages which can be translated, the fallback translation is used if not translated.
92 * obsolete - messages which should not be translated, either because they are not exist, or they are ignored messages.
93 * translated - messages which are either required or optional, but translated from English and needed.
95 * @param $code The language code.
97 private function loadMessages( $code ) {
98 if ( isset( $this->mMessages[$code] ) ) {
101 $this->loadRawMessages( $code );
102 $this->loadGeneralMessages();
103 $this->mMessages[$code]['all'] = $this->mRawMessages[$code];
104 $this->mMessages[$code]['required'] = array();
105 $this->mMessages[$code]['optional'] = array();
106 $this->mMessages[$code]['obsolete'] = array();
107 $this->mMessages[$code]['translated'] = array();
108 foreach ( $this->mMessages[$code]['all'] as $key => $value ) {
109 if ( isset( $this->mGeneralMessages['required'][$key] ) ) {
110 $this->mMessages[$code]['required'][$key] = $value;
111 $this->mMessages[$code]['translated'][$key] = $value;
112 } else if ( isset( $this->mGeneralMessages['optional'][$key] ) ) {
113 $this->mMessages[$code]['optional'][$key] = $value;
114 $this->mMessages[$code]['translated'][$key] = $value;
116 $this->mMessages[$code]['obsolete'][$key] = $value;
122 * Load the messages for English and divide them to groups:
123 * all - all the messages.
124 * required - messages which should be translated to other languages in order to get a complete translation.
125 * optional - messages which can be translated to other languages, but it's not required for a complete translation.
126 * ignored - messages which should not be translated to other languages.
127 * translatable - messages which are either required or optional, but can be translated from English.
129 private function loadGeneralMessages() {
130 if ( isset( $this->mGeneralMessages ) ) {
133 $this->loadRawMessages( 'en' );
134 $this->mGeneralMessages['all'] = $this->mRawMessages['en'];
135 $this->mGeneralMessages['required'] = array();
136 $this->mGeneralMessages['optional'] = array();
137 $this->mGeneralMessages['ignored'] = array();
138 $this->mGeneralMessages['translatable'] = array();
139 foreach ( $this->mGeneralMessages['all'] as $key => $value ) {
140 if ( in_array( $key, $this->mIgnoredMessages ) ) {
141 $this->mGeneralMessages['ignored'][$key] = $value;
142 } else if ( in_array( $key, $this->mOptionalMessages ) ) {
143 $this->mGeneralMessages['optional'][$key] = $value;
144 $this->mGeneralMessages['translatable'][$key] = $value;
146 $this->mGeneralMessages['required'][$key] = $value;
147 $this->mGeneralMessages['translatable'][$key] = $value;
153 * Get all the messages for a specific langauge (not English), without the
154 * fallback language messages, divided to groups:
155 * all - all the messages.
156 * required - messages which should be translated in order to get a complete translation.
157 * optional - messages which can be translated, the fallback translation is used if not translated.
158 * obsolete - messages which should not be translated, either because they are not exist, or they are ignored messages.
159 * translated - messages which are either required or optional, but translated from English and needed.
161 * @param $code The langauge code.
163 * @return The messages in this language.
165 public function getMessages( $code ) {
166 $this->loadMessages( $code );
167 return $this->mMessages[$code];
171 * Get all the general English messages, divided to groups:
172 * all - all the messages.
173 * required - messages which should be translated to other languages in order to get a complete translation.
174 * optional - messages which can be translated to other languages, but it's not required for a complete translation.
175 * ignored - messages which should not be translated to other languages.
176 * translatable - messages which are either required or optional, but can be translated from English.
178 * @return The general English messages.
180 public function getGeneralMessages() {
181 $this->loadGeneralMessages();
182 return $this->mGeneralMessages;
186 * Get the untranslated messages for a specific language.
188 * @param $code The langauge code.
190 * @return The untranslated messages for this language.
192 public function getUntranslatedMessages( $code ) {
193 $this->loadGeneralMessages();
194 $this->loadMessages( $code );
195 $requiredGeneralMessages = array_keys( $this->mGeneralMessages['required'] );
196 $requiredMessages = array_keys( $this->mMessages[$code]['required'] );
197 $untranslatedMessages = array();
198 foreach ( array_diff( $requiredGeneralMessages, $requiredMessages ) as $key ) {
199 $untranslatedMessages[$key] = $this->mGeneralMessages['required'][$key];
201 return $untranslatedMessages;
205 * Get the duplicate messages for a specific language.
207 * @param $code The langauge code.
209 * @return The duplicate messages for this language.
211 public function getDuplicateMessages( $code ) {
212 $this->loadGeneralMessages();
213 $this->loadMessages( $code );
214 $duplicateMessages = array();
215 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
216 if ( $this->mGeneralMessages['translatable'][$key] == $value ) {
217 $duplicateMessages[$key] = $value;
220 return $duplicateMessages;
224 * Get the messages which do not use some variables.
226 * @param $code The langauge code.
228 * @return The messages which do not use some variables in this language.
230 public function getMessagesWithoutVariables( $code ) {
231 $this->loadGeneralMessages();
232 $this->loadMessages( $code );
233 $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' );
234 $messagesWithoutVariables = array();
235 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
237 foreach ( $variables as $var ) {
238 if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
239 !preg_match( "/$var/sU", $value ) ) {
244 $messagesWithoutVariables[$key] = $value;
247 return $messagesWithoutVariables;
251 * Get the empty messages.
253 * @param $code The langauge code.
255 * @return The empty messages for this language.
257 public function getEmptyMessages( $code ) {
258 $this->loadGeneralMessages();
259 $this->loadMessages( $code );
260 $emptyMessages = array();
261 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
262 if ( $value === '' || $value === '-' ) {
263 $emptyMessages[$key] = $value;
266 return $emptyMessages;
270 * Get the messages with trailing whitespace.
272 * @param $code The langauge code.
274 * @return The messages with trailing whitespace in this language.
276 public function getMessagesWithWhitespace( $code ) {
277 $this->loadGeneralMessages();
278 $this->loadMessages( $code );
279 $messagesWithWhitespace = array();
280 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
281 if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) {
282 $messagesWithWhitespace[$key] = $value;
285 return $messagesWithWhitespace;
289 * Get the non-XHTML messages.
291 * @param $code The langauge code.
293 * @return The non-XHTML messages for this language.
295 public function getNonXHTMLMessages( $code ) {
296 $this->loadGeneralMessages();
297 $this->loadMessages( $code );
298 $wrongPhrases = array(
304 $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu';
305 $nonXHTMLMessages = array();
306 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
307 if ( preg_match( $wrongPhrases, $value ) ) {
308 $nonXHTMLMessages[$key] = $value;
311 return $nonXHTMLMessages;
315 * Get the messages which include wrong characters.
317 * @param $code The langauge code.
319 * @return The messages which include wrong characters in this language.
321 public function getMessagesWithWrongChars( $code ) {
322 $this->loadGeneralMessages();
323 $this->loadMessages( $code );
325 '[LRM]' => "\xE2\x80\x8E",
326 '[RLM]' => "\xE2\x80\x8F",
327 '[LRE]' => "\xE2\x80\xAA",
328 '[RLE]' => "\xE2\x80\xAB",
329 '[POP]' => "\xE2\x80\xAC",
330 '[LRO]' => "\xE2\x80\xAD",
331 '[RLO]' => "\xE2\x80\xAB",
332 '[ZWSP]'=> "\xE2\x80\x8B",
333 '[NBSP]'=> "\xC2\xA0",
334 '[WJ]' => "\xE2\x81\xA0",
335 '[BOM]' => "\xEF\xBB\xBF",
336 '[FFFD]'=> "\xEF\xBF\xBD",
338 $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu';
339 $wrongCharsMessages = array();
340 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
341 if ( preg_match( $wrongRegExp, $value ) ) {
342 foreach ( $wrongChars as $viewableChar => $hiddenChar ) {
343 $value = str_replace( $hiddenChar, $viewableChar, $value );
345 $wrongCharsMessages[$key] = $value;
348 return $wrongCharsMessages;
352 * Output a messages list
354 * @param $messages The messages list
355 * @param $code The language code
356 * @param $text The text to show before the list (optional)
357 * @param $level The display level (optional)
358 * @param $links Show links (optional)
359 * @param $wikilang The langauge of the wiki to display the list in, for the links (optional)
361 public function outputMessagesList( $messages, $code, $text = '', $level = 2, $links = false, $wikilang = null ) {
362 if ( count( $messages ) == 0 ) {
369 echo "[messages are hidden]\n";
371 foreach ( $messages as $key => $value ) {
373 $displayKey = ucfirst( $key );
374 if ( !isset( $wikilang ) ) {
376 $wikilang = $wgContLang->getCode();
378 if ( $code == $wikilang ) {
379 $displayKey = "[[MediaWiki:$displayKey|$key]]";
381 $displayKey = "[[MediaWiki:$displayKey/$code|$key]]";
387 echo "* $displayKey\n";
389 echo "* $displayKey: '$value'\n";