3 * Handle messages in the language files.
6 * @subpackage Maintenance
9 require_once( 'messageTypes.inc' );
12 private $mLanguages; # List of languages
13 private $mRawMessages; # Raw list of the messages in each language
14 private $mMessages; # Messages in each language (except for English), divided to groups
15 private $mGeneralMessages; # General messages in English, divided to groups
16 private $mIgnoredMessages; # All the messages which should be exist only in the English file
17 private $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 * Load the raw messages for a specific langauge from the messages file.
50 * @param $code The langauge code.
52 private function loadRawMessages( $code ) {
53 if ( isset( $this->mRawMessages[$code] ) ) {
56 $filename = Language::getMessagesFileName( $code );
57 if ( file_exists( $filename ) ) {
59 if ( isset( $messages ) ) {
60 $this->mRawMessages[$code] = $messages;
62 $this->mRawMessages[$code] = array();
65 $this->mRawMessages[$code] = array();
70 * Load the messages for a specific language (which is not English) and divide them to groups:
71 * all - all the messages.
72 * required - messages which should be translated in order to get a complete translation.
73 * optional - messages which can be translated, the fallback translation is used if not translated.
74 * obsolete - messages which should not be translated, either because they are not exist, or they are ignored messages.
75 * translated - messages which are either required or optional, but translated from English and needed.
77 * @param $code The language code.
79 private function loadMessages( $code ) {
80 if ( isset( $this->mMessages[$code] ) ) {
83 $this->loadRawMessages( $code );
84 $this->loadGeneralMessages();
85 $this->mMessages[$code]['all'] = $this->mRawMessages[$code];
86 $this->mMessages[$code]['required'] = array();
87 $this->mMessages[$code]['optional'] = array();
88 $this->mMessages[$code]['obsolete'] = array();
89 $this->mMessages[$code]['translated'] = array();
90 foreach ( $this->mMessages[$code]['all'] as $key => $value ) {
91 if ( isset( $this->mGeneralMessages['required'][$key] ) ) {
92 $this->mMessages[$code]['required'][$key] = $value;
93 $this->mMessages[$code]['translated'][$key] = $value;
94 } else if ( isset( $this->mGeneralMessages['optional'][$key] ) ) {
95 $this->mMessages[$code]['optional'][$key] = $value;
96 $this->mMessages[$code]['translated'][$key] = $value;
98 $this->mMessages[$code]['obsolete'][$key] = $value;
104 * Load the messages for English and divide them to groups:
105 * all - all the messages.
106 * required - messages which should be translated to other languages in order to get a complete translation.
107 * optional - messages which can be translated to other languages, but it's not required for a complete translation.
108 * ignored - messages which should not be translated to other languages.
109 * translatable - messages which are either required or optional, but can be translated from English.
111 private function loadGeneralMessages() {
112 if ( isset( $this->mGeneralMessages ) ) {
115 $this->loadRawMessages( 'en' );
116 $this->mGeneralMessages['all'] = $this->mRawMessages['en'];
117 $this->mGeneralMessages['required'] = array();
118 $this->mGeneralMessages['optional'] = array();
119 $this->mGeneralMessages['ignored'] = array();
120 $this->mGeneralMessages['translatable'] = array();
121 foreach ( $this->mGeneralMessages['all'] as $key => $value ) {
122 if ( in_array( $key, $this->mIgnoredMessages ) ) {
123 $this->mGeneralMessages['ignored'][$key] = $value;
124 } else if ( in_array( $key, $this->mOptionalMessages ) ) {
125 $this->mGeneralMessages['optional'][$key] = $value;
126 $this->mGeneralMessages['translatable'][$key] = $value;
128 $this->mGeneralMessages['required'][$key] = $value;
129 $this->mGeneralMessages['translatable'][$key] = $value;
135 * Get all the messages for a specific langauge (not English), without the
136 * fallback language messages, divided to groups:
137 * all - all the messages.
138 * required - messages which should be translated in order to get a complete translation.
139 * optional - messages which can be translated, the fallback translation is used if not translated.
140 * obsolete - messages which should not be translated, either because they are not exist, or they are ignored messages.
141 * translated - messages which are either required or optional, but translated from English and needed.
143 * @param $code The langauge code.
145 * @return The messages in this language.
147 public function getMessages( $code ) {
148 $this->loadMessages( $code );
149 return $this->mMessages[$code];
153 * Get all the general English messages, divided to groups:
154 * all - all the messages.
155 * required - messages which should be translated to other languages in order to get a complete translation.
156 * optional - messages which can be translated to other languages, but it's not required for a complete translation.
157 * ignored - messages which should not be translated to other languages.
158 * translatable - messages which are either required or optional, but can be translated from English.
160 * @return The general English messages.
162 public function getGeneralMessages() {
163 $this->loadGeneralMessages();
164 return $this->mGeneralMessages;
168 * Get the untranslated messages for a specific language.
170 * @param $code The langauge code.
172 * @return The untranslated messages for this language.
174 public function getUntranslatedMessages( $code ) {
175 $this->loadGeneralMessages();
176 $this->loadMessages( $code );
177 $requiredGeneralMessages = array_keys( $this->mGeneralMessages['required'] );
178 $requiredMessages = array_keys( $this->mMessages[$code]['required'] );
179 $untranslatedMessages = array();
180 foreach ( array_diff( $requiredGeneralMessages, $requiredMessages ) as $key ) {
181 $untranslatedMessages[$key] = $this->mGeneralMessages['required'][$key];
183 return $untranslatedMessages;
187 * Get the duplicate messages for a specific language.
189 * @param $code The langauge code.
191 * @return The duplicate messages for this language.
193 public function getDuplicateMessages( $code ) {
194 $this->loadGeneralMessages();
195 $this->loadMessages( $code );
196 $duplicateMessages = array();
197 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
198 if ( $this->mGeneralMessages['translatable'][$key] == $value ) {
199 $duplicateMessages[$key] = $value;
202 return $duplicateMessages;
206 * Get the messages which do not use some variables.
208 * @param $code The langauge code.
210 * @return The messages which do not use some variables in this language.
212 public function getMessagesWithoutVariables( $code ) {
213 $this->loadGeneralMessages();
214 $this->loadMessages( $code );
215 $variables = array( '\$1', '\$2', '\$3', '\$4', '\$5', '\$6', '\$7', '\$8', '\$9' );
216 $messagesWithoutVariables = array();
217 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
219 foreach ( $variables as $var ) {
220 if ( preg_match( "/$var/sU", $this->mGeneralMessages['translatable'][$key] ) &&
221 !preg_match( "/$var/sU", $value ) ) {
226 $messagesWithoutVariables[$key] = $value;
229 return $messagesWithoutVariables;
233 * Get the empty messages.
235 * @param $code The langauge code.
237 * @return The empty messages for this language.
239 public function getEmptyMessages( $code ) {
240 $this->loadGeneralMessages();
241 $this->loadMessages( $code );
242 $emptyMessages = array();
243 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
244 if ( $value === '' || $value === '-' ) {
245 $emptyMessages[$key] = $value;
248 return $emptyMessages;
252 * Get the messages with trailing whitespace.
254 * @param $code The langauge code.
256 * @return The messages with trailing whitespace in this language.
258 public function getMessagesWithWhitespace( $code ) {
259 $this->loadGeneralMessages();
260 $this->loadMessages( $code );
261 $messagesWithWhitespace = array();
262 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
263 if ( $this->mGeneralMessages['translatable'][$key] !== '' && $value !== rtrim( $value ) ) {
264 $messagesWithWhitespace[$key] = $value;
267 return $messagesWithWhitespace;
271 * Get the non-XHTML messages.
273 * @param $code The langauge code.
275 * @return The non-XHTML messages for this language.
277 public function getNonXHTMLMessages( $code ) {
278 $this->loadGeneralMessages();
279 $this->loadMessages( $code );
280 $wrongPhrases = array(
286 $wrongPhrases = '~(' . implode( '|', $wrongPhrases ) . ')~sDu';
287 $nonXHTMLMessages = array();
288 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
289 if ( preg_match( $wrongPhrases, $value ) ) {
290 $nonXHTMLMessages[$key] = $value;
293 return $nonXHTMLMessages;
297 * Get the messages which include wrong characters.
299 * @param $code The langauge code.
301 * @return The messages which include wrong characters in this language.
303 public function getMessagesWithWrongChars( $code ) {
304 $this->loadGeneralMessages();
305 $this->loadMessages( $code );
307 '[LRM]' => "\xE2\x80\x8E",
308 '[RLM]' => "\xE2\x80\x8F",
309 '[LRE]' => "\xE2\x80\xAA",
310 '[RLE]' => "\xE2\x80\xAB",
311 '[POP]' => "\xE2\x80\xAC",
312 '[LRO]' => "\xE2\x80\xAD",
313 '[RLO]' => "\xE2\x80\xAB",
314 '[ZWSP]'=> "\xE2\x80\x8B",
315 '[NBSP]'=> "\xC2\xA0",
316 '[WJ]' => "\xE2\x81\xA0",
317 '[BOM]' => "\xEF\xBB\xBF",
318 '[FFFD]'=> "\xEF\xBF\xBD",
320 $wrongRegExp = '/(' . implode( '|', array_values( $wrongChars ) ) . ')/sDu';
321 $wrongCharsMessages = array();
322 foreach ( $this->mMessages[$code]['translated'] as $key => $value ) {
323 if ( preg_match( $wrongRegExp, $value ) ) {
324 foreach ( $wrongChars as $viewableChar => $hiddenChar ) {
325 $value = str_replace( $hiddenChar, $viewableChar, $value );
327 $wrongCharsMessages[$key] = $value;
330 return $wrongCharsMessages;
334 * Output a messages list
336 * @param $messages The messages list
337 * @param $code The language code
338 * @param $text The text to show before the list (optional)
339 * @param $level The display level (optional)
340 * @param $links Show links (optional)
341 * @param $wikilang The langauge of the wiki to display the list in, for the links (optional)
343 public function outputMessagesList( $messages, $code, $text = '', $level = 2, $links = false, $wikilang = null ) {
344 if ( count( $messages ) == 0 ) {
351 echo "[messages are hidden]\n";
353 foreach ( $messages as $key => $value ) {
355 $displayKey = ucfirst( $key );
356 if ( !isset( $wikilang ) ) {
358 $wikilang = $wgContLang->getCode();
360 if ( $code == $wikilang ) {
361 $displayKey = "[[MediaWiki:$displayKey|$key]]";
363 $displayKey = "[[MediaWiki:$displayKey/$code|$key]]";
369 echo "* $displayKey\n";
371 echo "* $displayKey: '$value'\n";