9999c44911c14fc879019309a1f8c959e2658efb
[lhc/web/wiklou.git] / includes / MessageFunctions.php
1 <?php
2 /**
3 * Definitions of wfMsg and all it's incarnations. $key refers to the unique key
4 * of the message. Most of the messages are defined in
5 * $IP/languages/messages/MessagesEn.php with default values.
6 *
7 * Some function accept $language as parameter. It can be either be a language
8 * code, one of the array keys returned by Language::getLanguageNames(); or bool
9 * in which case true is shortcut for content language and false for interface
10 * language.
11 *
12 * Most functions take parameters for the message in variable argument list
13 * after defined parameters.
14 *
15 * Some functions do "transforming", which means {{..}} items are substituted.
16 * These include magic words for plural and grammar function. It is important
17 * to call the right function, so that these function will produce the correct
18 * results.
19 *
20 * To produce correct results two things need to be taken care of. The language
21 * information must be passed, so that correct language is called for the
22 * substition. Another thing is that variables must be substited before doing
23 * this process.
24 * @file
25 */
26
27
28 /**
29 * Equivalent to: wfMsgExt( $key, 'parsemag' );
30 * Use cases: Getting interface messages that are later passed to functions that
31 * escape their input.
32 *
33 * Use wfMsgForContent() instead if the message should NOT
34 * change depending on the user preferences.
35 */
36 function wfMsg( $key ) {
37 $args = func_get_args();
38 array_shift( $args );
39
40 $message = MessageGetter::get( $key );
41 $message = MessageGetter::replaceArgs( $message, $args );
42 $message = MessageGetter::transform( $message );
43 return $message;
44 }
45
46 /**
47 * Equivalent to: wfMsgExt( $key );
48 * Use cases: Getting interface messages that are later passed to function that
49 * parse their contents. Make sure that the function does know the correct
50 * language.
51 */
52 function wfMsgNoTrans( $key ) {
53 $args = func_get_args();
54 array_shift( $args );
55
56 $message = MessageGetter::get( $key );
57 $message = MessageGetter::replaceArgs( $message, $args );
58 return $message;
59 }
60
61 /**
62 * Use cases: Message that should NOT change dependent on the language set in
63 * the user's preferences. This is the case for most text written into logs, as
64 * well as link targets (such as the name of the copyright policy page) and else
65 * that goes back into the database. Link titles, on the other hand, should be
66 * shown in the UI language.
67 */
68 function wfMsgForContent( $key ) {
69 $args = func_get_args();
70 array_shift( $args );
71
72 $content = MessageGetter::forContentLanguage( $key );
73 $message = MessageGetter::get( $key, /*Language*/ $content );
74 $message = MessageGetter::replaceArgs( $message, $args );
75 $message = MessageGetter::transform( $message, /*Langugage*/ $content );
76 return $message;
77 }
78
79 /**
80 * Use cases: Messages for content language that are later passed to a function
81 * that parses it. Make sure the function uses the correct language for parsing.
82 * Or just for getting the raw message without conversions.
83 */
84 function wfMsgForContentNoTrans( $key ) {
85 $args = func_get_args();
86 array_shift( $args );
87
88 $content = MessageGetter::forContentLanguage( $key );
89 $message = MessageGetter::get( $key, /*Language*/ $content );
90 $message = MessageGetter::replaceArgs( $message, $args );
91 return $message;
92 }
93
94 /**
95 * Use cases: Getting messages when the database is not available. Also used in
96 * Special:Allmessages.
97 */
98 function wfMsgNoDB( $key ) {
99 $args = func_get_args();
100 array_shift( $args );
101
102 $message = MessageGetter::get( $key, MessageGetter::LANG_UI, /*DB*/false );
103 $message = MessageGetter::replaceArgs( $message, $args );
104 $message = MessageGetter::transform( $message );
105 return $message;
106 }
107
108 /**
109 * Use cases: Getting the unmodified message when database is not available,
110 * perhaps for later parsing.
111 */
112 function wfMsgNoDBForContent( $key ) {
113 $args = func_get_args();
114 array_shift( $args );
115
116 $message = MessageGetter::get( $key, /*Language*/ $content, /*DB*/false );
117 $message = MessageGetter::replaceArgs( $message, $args );
118 return $message;
119 }
120
121
122 /**
123 * Use cases: Getting messages in different languages.
124 */
125 function wfMsgReal( $key, $args, $useDB = true, $language = MessageGetter::LANG_UI, $transform = true ) {
126 $message = MessageGetter::get( $key, /*Language*/ $language, /*DB*/ $useDB );
127 $message = MessageGetter::replaceArgs( $message, $args );
128 if ( $transform )
129 $message = MessageGetter::transform( $message, /*Langugage*/ $language );
130 return $message;
131 }
132
133 /**
134 * Use cases: Getting the message content or empty string if it doesn't exist
135 * for showing as the default value when editing MediaWiki namespace.
136 */
137 function wfMsgWeirdKey ( $key ) {
138 $message = MessageGetter::get( $key, MessageGetter::LANG_UI, /*DB*/ false );
139 return wfEmptyMsg( $key, $message ) ? '' : $message;
140 }
141
142
143 // Private marked
144 function wfMsgGetKey( $key, $useDB, $language = MessageGetter::LANG_UI, $transform = true ) {
145 //wfDeprecated( __METHOD__ );
146 $message = MessageGetter::get( $key, $language, $useDB );
147
148 // Plural and grammar will go wrong here, no arguments replaced
149 if ( $transform ) {
150 wfDebug( __METHOD__ . " called with transform = true for key $key\n" );
151 $message = MessageGetter::transform( $message, $language );
152 }
153
154 return $message;
155 }
156
157 function wfMsgReplaceArgs( $message, $args ) {
158 //wfDeprecated( __METHOD__ );
159 return MessageGetter::replaceArgs( $message, $args );
160 }
161
162 /**
163 * Return an HTML-escaped version of a message.
164 * Parameter replacements, if any, are done *after* the HTML-escaping,
165 * so parameters may contain HTML (eg links or form controls). Be sure
166 * to pre-escape them if you really do want plaintext, or just wrap
167 * the whole thing in htmlspecialchars().
168 */
169 function wfMsgHtml( $key ) {
170 $args = func_get_args();
171 array_shift( $args );
172
173 $message = MessageGetter::get( $key );
174 $message = MessageGetter::escapeHtml( $message, /* Entities */ false );
175 $message = MessageGetter::replaceArgs( $message, $args );
176 return $message;
177 }
178
179 /**
180 * Return an HTML version of message
181 * Parameter replacements, if any, are done *after* parsing the wiki-text message,
182 * so parameters may contain HTML (eg links or form controls). Be sure
183 * to pre-escape them if you really do want plaintext, or just wrap
184 * the whole thing in htmlspecialchars().
185 */
186 function wfMsgWikiHtml( $key ) {
187 $args = func_get_args();
188 array_shift( $args );
189
190 $message = MessageGetter::get( $key );
191 $message = MessageGetter::parse( $message );
192 $message = MessageGetter::replaceArgs( $message, $args );
193 return $message;
194 }
195
196 /**
197 * Use cases: When the previous just aren't enough.
198 * @param $key String: Key of the message
199 * @param $options Array: Processing rules:
200 * @param $... Arguments
201 * <i>parse</i>: parses wikitext to html
202 * <i>parseinline</i>: parses wikitext to html and removes the surrounding p's added by parser or tidy
203 * <i>escape</i>: filters message through htmlspecialchars
204 * <i>escapenoentities</i>: same, but allows entity references like &nbsp; through
205 * <i>replaceafter</i>: parameters are substituted after parsing or escaping
206 * <i>parsemag</i>: transform the message using magic phrases
207 * <i>content</i>: fetch message for content language instead of interface
208 * <i>language</i>: language code to fetch message for (overriden by <i>content</i>), its behaviour
209 * with parse, parseinline and parsemag is undefined.
210 * Behavior for conflicting options (e.g., parse+parseinline) is undefined.
211 */
212 function wfMsgExt( $key, $options ) {
213 $args = func_get_args();
214 array_shift( $args );
215 array_shift( $args );
216
217 if( !is_array($options) ) {
218 $options = array($options);
219 }
220
221 $language = MessageGetter::LANG_UI;
222
223 if( in_array('content', $options) ) {
224 $language = MessageGetter::LANG_CONTENT;
225 } elseif( array_key_exists('language', $options) ) {
226 $language = $options['language'];
227 $validCodes = array_keys( Language::getLanguageNames() );
228 if( !in_array($language, $validCodes) ) {
229 # Fallback to en, instead of whatsever interface language we might have
230 $language = 'en';
231 }
232 }
233
234 $message = MessageGetter::get( $key, $language );
235
236 if( !in_array('replaceafter', $options) ) {
237 $message = MessageGetter::replaceArgs( $message, $args );
238 }
239
240 if( in_array('parse', $options) ) {
241 $message = MessageGetter::parse( $message, $language );
242 } elseif ( in_array('parseinline', $options) ) {
243 $message = MessageGetter::parse( $message, $language, /*inline*/true );
244 } elseif ( in_array('parsemag', $options) ) {
245 $message = MessageGetter::transform( $message, $language );
246 }
247
248 if ( in_array('escape', $options) ) {
249 $message = MessageGetter::escapeHtml( $message, /*allowEntities*/false );
250 } elseif ( in_array( 'escapenoentities', $options ) ) {
251 $message = MessageGetter::escapeHtml( $message );
252 }
253
254 if( in_array('replaceafter', $options) ) {
255 $message = MessageGetter::replaceArgs( $message, $args );
256 }
257
258 return $message;
259 }
260
261 class MessageGetter {
262
263 const LANG_UI = false;
264 const LANG_CONTENT = true;
265
266 public static function get( $key, $language = self::LANG_UI, $database = true ) {
267 global $wgMessageCache;
268 if( !is_object($wgMessageCache) ) {
269 throw new MWException( "Message cache not initialised\n" );
270 }
271
272 wfRunHooks('NormalizeMessageKey', array(&$key, &$database, &$language));
273
274 $message = $wgMessageCache->get( $key, $database, $language );
275 # Fix windows line-endings
276 # Some messages are split with explode("\n", $msg)
277 $message = str_replace( "\r", '', $message );
278 return $message;
279
280 }
281
282 public static function forContentLanguage( $key ) {
283 global $wgForceUIMsgAsContentMsg;
284 if( is_array( $wgForceUIMsgAsContentMsg ) &&
285 in_array( $key, $wgForceUIMsgAsContentMsg ) ) {
286 return self::LANG_UI;
287 } else {
288 return self::LANG_CONTENT;
289 }
290 }
291
292 public static function replaceArgs( $message, $args ) {
293 // Replace arguments
294 if ( count( $args ) ) {
295 if ( is_array( $args[0] ) ) {
296 $args = array_values( $args[0] );
297 }
298 $replacementKeys = array();
299 foreach( $args as $n => $param ) {
300 $replacementKeys['$' . ($n + 1)] = $param;
301 }
302 $message = strtr( $message, $replacementKeys );
303 }
304
305 return $message;
306 }
307
308 /**
309 * @param $language LANG_UI or LANG_CONTENT.
310 */
311 public static function transform( $message, $language = self::LANG_UI ) {
312 global $wgMessageCache;
313 // transform accepts only boolean values
314 if ( !is_bool($language) )
315 throw new MWException( __METHOD__ . ': only ui/content language supported' );
316 return $wgMessageCache->transform( $message, !$language );
317 }
318
319 /**
320 * @param $language LANG_UI or LANG_CONTENT.
321 */
322 public static function parse( $message, $language = self::LANG_UI, $inline = false ) {
323 global $wgOut;
324 // parse accepts only boolean values
325 if ( !is_bool($language) )
326 throw new MWException( __METHOD__ . ': only ui/content language supported' );
327 $message = $wgOut->parse( $message, true, !$language );
328
329 if ( $inline ) {
330 $m = array();
331 if( preg_match( '/^<p>(.*)\n?<\/p>\n?$/sU', $message, $m ) ) {
332 $message = $m[1];
333 }
334 }
335
336 return $message;
337 }
338
339 public static function escapeHtml( $message, $allowEntities = true ) {
340 $message = htmlspecialchars( $message );
341 if ( $allowEntities ) {
342 $message = str_replace( '&amp;', '&', $message );
343 $message = Sanitizer::normalizeCharReferences( $message );
344 }
345
346 return $message;
347 }
348
349 }