3 * Handle messages in the language files.
5 * @addtogroup Maintenance
8 require_once( 'messageTypes.inc' );
11 protected $mLanguages; # List of languages
12 protected $mRawMessages; # Raw list of the messages in each language
13 protected $mMessages; # Messages in each language (except for English), divided to groups
14 protected $mGeneralMessages; # General messages in English, divided to groups
15 protected $mIgnoredMessages; # All the messages which should be exist only in the English file
16 protected $mOptionalMessages; # All the messages which may be translated or not, depending on the language
19 * Load the list of languages: all the Messages*.php
20 * files in the languages directory.
22 * @param $exif Treat the EXIF messages?
24 function __construct( $exif = true ) {
25 global $wgIgnoredMessages, $wgOptionalMessages, $wgEXIFMessages;
26 $this->mIgnoredMessages = $wgIgnoredMessages;
28 $this->mOptionalMessages = array_merge( $wgOptionalMessages );
30 $this->mOptionalMessages = array_merge( $wgOptionalMessages, $wgEXIFMessages );
33 $this->mLanguages = array_keys( Language::getLanguageNames( true ) );
34 sort( $this->mLanguages );
38 * Get the language list.
40 * @return The language list.
42 public function getLanguages() {
43 return $this->mLanguages;
47 * Get the ignored messages list.
49 * @return The ignored messages list.
51 public function getIgnoredMessages() {
52 return $this->mIgnoredMessages;
56 * Get the optional messages list.
58 * @return The optional messages list.
60 public function getOptionalMessages() {
61 return $this->mOptionalMessages;
65 * Load the raw messages for a specific langauge from the messages file.
67 * @param $code The langauge code.
69 protected function loadRawMessages( $code ) {
70 if ( isset( $this->mRawMessages[$code] ) ) {
73 $filename = Language::getMessagesFileName( $code );
74 if ( file_exists( $filename ) ) {
76 if ( isset( $messages ) ) {
77 $this->mRawMessages[$code] = $messages;
79 $this->mRawMessages[$code] = array();
82 $this->mRawMessages[$code] = array();
87 * Load the messages for a specific language (which is not English) and divide them to groups:
88 * all - all the messages.
89 * required - messages which should be translated in order to get a complete translation.
90 * optional - messages which can be translated, the fallback translation is used if not translated.
91 * obsolete - messages which should not be translated, either because they are not exist, or they are ignored messages.
92 * translated - messages which are either required or optional, but translated from English and needed.
94 * @param $code The language code.
96 private function loadMessages( $code ) {
97 if ( isset( $this->mMessages[$code] ) ) {
100 $this->loadRawMessages( $code );
101 $this->loadGeneralMessages();
102 $this->mMessages[$code]['all'] = $this->mRawMessages[$code];
103 $this->mMessages[$code]['required'] = array();
104 $this->mMessages[$code]['optional'] = array();
105 $this->mMessages[$code]['obsolete'] = array();
106 $this->mMessages[$code]['translated'] = array();
107 foreach ( $this->mMessages[$code]['all'] as $key => $value ) {
108 if ( isset( $this->mGeneralMessages['required'][$key] ) ) {
109 $this->mMessages[$code]['required'][$key] = $value;
110 $this->mMessages[$code]['translated'][$key] = $value;
111 } else if ( isset( $this->mGeneralMessages['optional'][$key] ) ) {
112 $this->mMessages[$code]['optional'][$key] = $value;
113 $this->mMessages[$code]['translated'][$key] = $value;
115 $this->mMessages[$code]['obsolete'][$key] = $value;
121 * Load the messages for English and divide them to groups:
122 * all - all the messages.
123 * required - messages which should be translated to other languages in order to get a complete translation.
124 * optional - messages which can be translated to other languages, but it's not required for a complete translation.
125 * ignored - messages which should not be translated to other languages.
126 * translatable - messages which are either required or optional, but can be translated from English.
128 private function loadGeneralMessages() {
129 if ( isset( $this->mGeneralMessages ) ) {
132 $this->loadRawMessages( 'en' );
133 $this->mGeneralMessages['all'] = $this->mRawMessages['en'];
134 $this->mGeneralMessages['required'] = array();
135 $this->mGeneralMessages['optional'] = array();
136 $this->mGeneralMessages['ignored'] = array();
137 $this->mGeneralMessages['translatable'] = array();
138 foreach ( $this->mGeneralMessages['all'] as $key => $value ) {
139 if ( in_array( $key, $this->mIgnoredMessages ) ) {
140 $this->mGeneralMessages['ignored'][$key] = $value;
141 } else if ( in_array( $key, $this->mOptionalMessages ) ) {
142 $this->mGeneralMessages['optional'][$key] = $value;
143 $this->mGeneralMessages['translatable'][$key] = $value;
145 $this->mGeneralMessages['required'][$key] = $value;
146 $this->mGeneralMessages['translatable'][$key] = $value;
152 * Get all the messages for a specific langauge (not English), without the
153 * fallback language messages, divided to groups:
154 * all - all the messages.
155 * required - messages which should be translated in order to get a complete translation.
156 * optional - messages which can be translated, the fallback translation is used if not translated.
157 * obsolete - messages which should not be translated, either because they are not exist, or they are ignored messages.
158 * translated - messages which are either required or optional, but translated from English and needed.
160 * @param $code The langauge code.
162 * @return The messages in this language.
164 public function getMessages( $code ) {
165 $this->loadMessages( $code );
166 return $this->mMessages[$code];
170 * Get all the general English messages, divided to groups:
171 * all - all the messages.
172 * required - messages which should be translated to other languages in order to get a complete translation.
173 * optional - messages which can be translated to other languages, but it's not required for a complete translation.
174 * ignored - messages which should not be translated to other languages.
175 * translatable - messages which are either required or optional, but can be translated from English.
177 * @return The general English messages.
179 public function getGeneralMessages() {
180 $this->loadGeneralMessages();
181 return $this->mGeneralMessages;
185 * Get the untranslated messages for a specific language.
187 * @param $code The langauge code.
189 * @return The untranslated messages for this language.
191 public function getUntranslatedMessages( $code ) {
192 $this->loadGeneralMessages();
193 $this->loadMessages( $code );
194 $requiredGeneralMessages = array_keys( $this->mGeneralMessages['required'] );
195 $requiredMessages = array_keys( $this->mMessages[$code]['required'] );
196 $untranslatedMessages = array();
197 foreach ( array_diff( $requiredGeneralMessages, $requiredMessages ) as $key ) {
198 $untranslatedMessages[$key] = $this->mGeneralMessages['required'][$key];
200 return $untranslatedMessages;
204 * Get the duplicate messages for a specific language.
206 * @param $code The langauge code.
208 * @return The duplicate messages for this language.
210 public function getDuplicateMessages( $code ) {
211 $this->loadGeneralMessages();
212 $this->loadMessages( $code );
213 $duplicateMessages = array();
214 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
215 if ( $this->mGeneralMessages['translatable'][$key] == $value ) {
216 $duplicateMessages[$key] = $value;
219 return $duplicateMessages;
223 * Get the messages which do not use some variables.
225 * @param $code The langauge code.
227 * @return The messages which do not use some variables in this language.
229 public function getMessagesWithoutVariables( $code ) {
230 $this->loadGeneralMessages();
231 $this->loadMessages( $code );
232 $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' );
233 $messagesWithoutVariables = array();
234 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
236 foreach ( $variables as $var ) {
237 if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
238 !preg_match( "/$var/sU", $value ) ) {
243 $messagesWithoutVariables[$key] = $value;
246 return $messagesWithoutVariables;
250 * Get the empty messages.
252 * @param $code The langauge code.
254 * @return The empty messages for this language.
256 public function getEmptyMessages( $code ) {
257 $this->loadGeneralMessages();
258 $this->loadMessages( $code );
259 $emptyMessages = array();
260 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
261 if ( $value === '' || $value === '-' ) {
262 $emptyMessages[$key] = $value;
265 return $emptyMessages;
269 * Get the messages with trailing whitespace.
271 * @param $code The langauge code.
273 * @return The messages with trailing whitespace in this language.
275 public function getMessagesWithWhitespace( $code ) {
276 $this->loadGeneralMessages();
277 $this->loadMessages( $code );
278 $messagesWithWhitespace = array();
279 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
280 if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) {
281 $messagesWithWhitespace[$key] = $value;
284 return $messagesWithWhitespace;
288 * Get the non-XHTML messages.
290 * @param $code The langauge code.
292 * @return The non-XHTML messages for this language.
294 public function getNonXHTMLMessages( $code ) {
295 $this->loadGeneralMessages();
296 $this->loadMessages( $code );
297 $wrongPhrases = array(
303 $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu';
304 $nonXHTMLMessages = array();
305 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
306 if ( preg_match( $wrongPhrases, $value ) ) {
307 $nonXHTMLMessages[$key] = $value;
310 return $nonXHTMLMessages;
314 * Get the messages which include wrong characters.
316 * @param $code The langauge code.
318 * @return The messages which include wrong characters in this language.
320 public function getMessagesWithWrongChars( $code ) {
321 $this->loadGeneralMessages();
322 $this->loadMessages( $code );
324 '[LRM]' => "\xE2\x80\x8E",
325 '[RLM]' => "\xE2\x80\x8F",
326 '[LRE]' => "\xE2\x80\xAA",
327 '[RLE]' => "\xE2\x80\xAB",
328 '[POP]' => "\xE2\x80\xAC",
329 '[LRO]' => "\xE2\x80\xAD",
330 '[RLO]' => "\xE2\x80\xAB",
331 '[ZWSP]'=> "\xE2\x80\x8B",
332 '[NBSP]'=> "\xC2\xA0",
333 '[WJ]' => "\xE2\x81\xA0",
334 '[BOM]' => "\xEF\xBB\xBF",
335 '[FFFD]'=> "\xEF\xBF\xBD",
337 $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu';
338 $wrongCharsMessages = array();
339 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
340 if ( preg_match( $wrongRegExp, $value ) ) {
341 foreach ( $wrongChars as $viewableChar => $hiddenChar ) {
342 $value = str_replace( $hiddenChar, $viewableChar, $value );
344 $wrongCharsMessages[$key] = $value;
347 return $wrongCharsMessages;
351 * Output a messages list
353 * @param $messages The messages list
354 * @param $code The language code
355 * @param $text The text to show before the list (optional)
356 * @param $level The display level (optional)
357 * @param $links Show links (optional)
358 * @param $wikilang The langauge of the wiki to display the list in, for the links (optional)
360 public function outputMessagesList( $messages, $code, $text = '', $level = 2, $links = false, $wikilang = null ) {
361 if ( count( $messages ) == 0 ) {
368 echo "[messages are hidden]\n";
370 foreach ( $messages as $key => $value ) {
372 $displayKey = ucfirst( $key );
373 if ( !isset( $wikilang ) ) {
375 $wikilang = $wgContLang->getCode();
377 if ( $code == $wikilang ) {
378 $displayKey = "[[MediaWiki:$displayKey|$key]]";
380 $displayKey = "[[MediaWiki:$displayKey/$code|$key]]";
386 echo "* $displayKey\n";
388 echo "* $displayKey: '$value'\n";