From 12b4eba6ef4980a74bcb8e67dc8d5dcfe4e37df1 Mon Sep 17 00:00:00 2001 From: Aryeh Gregor Date: Thu, 10 Jul 2008 19:18:00 +0000 Subject: [PATCH] Revert r37299. It's causing some extremely strange behavior that I can't pin down. Try copying the text =={{[[Navbox]]}}== into a page, where [[Template:Navbox]] is copied from enwiki. An exhibit is up at until this fix goes live. This was reported at by CapitalR; thanks to RockMFR for tracking down the revision that was causing it. As a general rule, it would be a good idea to first split the functions off into their own file without changing them, and then refactor them in a separate commit. Otherwise it's very hard to follow what's actually being changed. (git actually tracks changes to functions when they're moved across files, incidentally, which is quite awesome.) --- docs/hooks.txt | 1 + includes/GlobalFunctions.php | 323 ++++++++++++++++++++++++++++++- includes/MessageFunctions.php | 349 ---------------------------------- 3 files changed, 323 insertions(+), 350 deletions(-) delete mode 100644 includes/MessageFunctions.php diff --git a/docs/hooks.txt b/docs/hooks.txt index 05f43db5d6..2217a5ea58 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -868,6 +868,7 @@ $baseID: the revision ID this was based off, if any &$useDB: whether or not to look up the message in the database (bool) &$langCode: the language code to get the message for (string) - or - whether to use the content language (true) or site language (false) (bool) +&$transform: whether or not to expand variables and templates in the message (bool) 'OpenSearchUrls': Called when constructing the OpenSearch description XML. Hooks can alter or append to the array of URLs for search & suggestion formats. diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index def14742e6..56a313fa0f 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -11,7 +11,6 @@ if ( !defined( 'MEDIAWIKI' ) ) { require_once dirname(__FILE__) . '/LogPage.php'; require_once dirname(__FILE__) . '/normal/UtfNormalUtil.php'; require_once dirname(__FILE__) . '/XmlFunctions.php'; -require_once dirname(__FILE__) . '/MessageFunctions.php'; /** * Compatibility functions @@ -320,6 +319,328 @@ function wfReadOnlyReason() { return $wgReadOnly; } +/** + * Get a message from anywhere, for the current user language. + * + * Use wfMsgForContent() instead if the message should NOT + * change depending on the user preferences. + * + * @param $key String: lookup key for the message, usually + * defined in languages/Language.php + * + * This function also takes extra optional parameters (not + * shown in the function definition), which can by used to + * insert variable text into the predefined message. + */ +function wfMsg( $key ) { + $args = func_get_args(); + array_shift( $args ); + return wfMsgReal( $key, $args, true ); +} + +/** + * Same as above except doesn't transform the message + */ +function wfMsgNoTrans( $key ) { + $args = func_get_args(); + array_shift( $args ); + return wfMsgReal( $key, $args, true, false, false ); +} + +/** + * Get a message from anywhere, for the current global language + * set with $wgLanguageCode. + * + * Use this if the message should NOT change dependent on the + * language set in the user's preferences. This is the case for + * most text written into logs, as well as link targets (such as + * the name of the copyright policy page). Link titles, on the + * other hand, should be shown in the UI language. + * + * Note that MediaWiki allows users to change the user interface + * language in their preferences, but a single installation + * typically only contains content in one language. + * + * Be wary of this distinction: If you use wfMsg() where you should + * use wfMsgForContent(), a user of the software may have to + * customize over 70 messages in order to, e.g., fix a link in every + * possible language. + * + * @param $key String: lookup key for the message, usually + * defined in languages/Language.php + */ +function wfMsgForContent( $key ) { + global $wgForceUIMsgAsContentMsg; + $args = func_get_args(); + array_shift( $args ); + $forcontent = true; + if( is_array( $wgForceUIMsgAsContentMsg ) && + in_array( $key, $wgForceUIMsgAsContentMsg ) ) + $forcontent = false; + return wfMsgReal( $key, $args, true, $forcontent ); +} + +/** + * Same as above except doesn't transform the message + */ +function wfMsgForContentNoTrans( $key ) { + global $wgForceUIMsgAsContentMsg; + $args = func_get_args(); + array_shift( $args ); + $forcontent = true; + if( is_array( $wgForceUIMsgAsContentMsg ) && + in_array( $key, $wgForceUIMsgAsContentMsg ) ) + $forcontent = false; + return wfMsgReal( $key, $args, true, $forcontent, false ); +} + +/** + * Get a message from the language file, for the UI elements + */ +function wfMsgNoDB( $key ) { + $args = func_get_args(); + array_shift( $args ); + return wfMsgReal( $key, $args, false ); +} + +/** + * Get a message from the language file, for the content + */ +function wfMsgNoDBForContent( $key ) { + global $wgForceUIMsgAsContentMsg; + $args = func_get_args(); + array_shift( $args ); + $forcontent = true; + if( is_array( $wgForceUIMsgAsContentMsg ) && + in_array( $key, $wgForceUIMsgAsContentMsg ) ) + $forcontent = false; + return wfMsgReal( $key, $args, false, $forcontent ); +} + + +/** + * Really get a message + * @param $key String: key to get. + * @param $args + * @param $useDB Boolean + * @param $transform Boolean: Whether or not to transform the message. + * @param $forContent Boolean + * @return String: the requested message. + */ +function wfMsgReal( $key, $args, $useDB = true, $forContent=false, $transform = true ) { + wfProfileIn( __METHOD__ ); + $message = wfMsgGetKey( $key, $useDB, $forContent, $transform ); + $message = wfMsgReplaceArgs( $message, $args ); + wfProfileOut( __METHOD__ ); + return $message; +} + +/** + * This function provides the message source for messages to be edited which are *not* stored in the database. + * @param $key String: + */ +function wfMsgWeirdKey ( $key ) { + $source = wfMsgGetKey( $key, false, true, false ); + if ( wfEmptyMsg( $key, $source ) ) + return ""; + else + return $source; +} + +/** + * Fetch a message string value, but don't replace any keys yet. + * @param string $key + * @param bool $useDB + * @param string $langcode Code of the language to get the message for, or + * behaves as a content language switch if it is a + * boolean. + * @return string + * @private + */ +function wfMsgGetKey( $key, $useDB, $langCode = false, $transform = true ) { + global $wgParser, $wgContLang, $wgMessageCache, $wgLang; + + wfRunHooks('NormalizeMessageKey', array(&$key, &$useDB, &$langCode, &$transform)); + + # If $wgMessageCache isn't initialised yet, try to return something sensible. + if( is_object( $wgMessageCache ) ) { + $message = $wgMessageCache->get( $key, $useDB, $langCode ); + if ( $transform ) { + $message = $wgMessageCache->transform( $message ); + } + } else { + if( $langCode === true ) { + $lang = &$wgContLang; + } elseif( $langCode === false ) { + $lang = &$wgLang; + } else { + $validCodes = array_keys( Language::getLanguageNames() ); + if( in_array( $langCode, $validCodes ) ) { + # $langcode corresponds to a valid language. + $lang = Language::factory( $langCode ); + } else { + # $langcode is a string, but not a valid language code; use content language. + $lang =& $wgContLang; + wfDebug( 'Invalid language code passed to wfMsgGetKey, falling back to content language.' ); + } + } + + # MessageCache::get() does this already, Language::getMessage() doesn't + # ISSUE: Should we try to handle "message/lang" here too? + $key = str_replace( ' ' , '_' , $wgContLang->lcfirst( $key ) ); + + if( is_object( $lang ) ) { + $message = $lang->getMessage( $key ); + } else { + $message = false; + } + } + + return $message; +} + +/** + * Replace message parameter keys on the given formatted output. + * + * @param string $message + * @param array $args + * @return string + * @private + */ +function wfMsgReplaceArgs( $message, $args ) { + # Fix windows line-endings + # Some messages are split with explode("\n", $msg) + $message = str_replace( "\r", '', $message ); + + // Replace arguments + if ( count( $args ) ) { + if ( is_array( $args[0] ) ) { + $args = array_values( $args[0] ); + } + $replacementKeys = array(); + foreach( $args as $n => $param ) { + $replacementKeys['$' . ($n + 1)] = $param; + } + $message = strtr( $message, $replacementKeys ); + } + + return $message; +} + +/** + * Return an HTML-escaped version of a message. + * Parameter replacements, if any, are done *after* the HTML-escaping, + * so parameters may contain HTML (eg links or form controls). Be sure + * to pre-escape them if you really do want plaintext, or just wrap + * the whole thing in htmlspecialchars(). + * + * @param string $key + * @param string ... parameters + * @return string + */ +function wfMsgHtml( $key ) { + $args = func_get_args(); + array_shift( $args ); + return wfMsgReplaceArgs( htmlspecialchars( wfMsgGetKey( $key, true ) ), $args ); +} + +/** + * Return an HTML version of message + * Parameter replacements, if any, are done *after* parsing the wiki-text message, + * so parameters may contain HTML (eg links or form controls). Be sure + * to pre-escape them if you really do want plaintext, or just wrap + * the whole thing in htmlspecialchars(). + * + * @param string $key + * @param string ... parameters + * @return string + */ +function wfMsgWikiHtml( $key ) { + global $wgOut; + $args = func_get_args(); + array_shift( $args ); + return wfMsgReplaceArgs( $wgOut->parse( wfMsgGetKey( $key, true ), /* can't be set to false */ true ), $args ); +} + +/** + * Returns message in the requested format + * @param string $key Key of the message + * @param array $options Processing rules: + * parse: parses wikitext to html + * parseinline: parses wikitext to html and removes the surrounding p's added by parser or tidy + * escape: filters message through htmlspecialchars + * escapenoentities: same, but allows entity references like   through + * replaceafter: parameters are substituted after parsing or escaping + * parsemag: transform the message using magic phrases + * content: fetch message for content language instead of interface + * language: language code to fetch message for (overriden by content), its behaviour + * with parser, parseinline and parsemag is undefined. + * Behavior for conflicting options (e.g., parse+parseinline) is undefined. + */ +function wfMsgExt( $key, $options ) { + global $wgOut, $wgParser; + + $args = func_get_args(); + array_shift( $args ); + array_shift( $args ); + + if( !is_array($options) ) { + $options = array($options); + } + + if( in_array('content', $options) ) { + $forContent = true; + $langCode = true; + } elseif( array_key_exists('language', $options) ) { + $forContent = false; + $langCode = $options['language']; + $validCodes = array_keys( Language::getLanguageNames() ); + if( !in_array($options['language'], $validCodes) ) { + # Fallback to en, instead of whatever interface language we might have + $langCode = 'en'; + } + } else { + $forContent = false; + $langCode = false; + } + + $string = wfMsgGetKey( $key, /*DB*/true, $langCode, /*Transform*/false ); + + if( !in_array('replaceafter', $options) ) { + $string = wfMsgReplaceArgs( $string, $args ); + } + + if( in_array('parse', $options) ) { + $string = $wgOut->parse( $string, true, !$forContent ); + } elseif ( in_array('parseinline', $options) ) { + $string = $wgOut->parse( $string, true, !$forContent ); + $m = array(); + if( preg_match( '/^

(.*)\n?<\/p>\n?$/sU', $string, $m ) ) { + $string = $m[1]; + } + } elseif ( in_array('parsemag', $options) ) { + global $wgMessageCache; + if ( isset( $wgMessageCache ) ) { + $string = $wgMessageCache->transform( $string, !$forContent ); + } + } + + if ( in_array('escape', $options) ) { + $string = htmlspecialchars ( $string ); + } elseif ( in_array( 'escapenoentities', $options ) ) { + $string = htmlspecialchars( $string ); + $string = str_replace( '&', '&', $string ); + $string = Sanitizer::normalizeCharReferences( $string ); + } + + if( in_array('replaceafter', $options) ) { + $string = wfMsgReplaceArgs( $string, $args ); + } + + return $string; +} + + /** * Just like exit() but makes a note of it. * Commits open transactions except if the error parameter is set diff --git a/includes/MessageFunctions.php b/includes/MessageFunctions.php deleted file mode 100644 index 9999c44911..0000000000 --- a/includes/MessageFunctions.php +++ /dev/null @@ -1,349 +0,0 @@ -parse: parses wikitext to html - * parseinline: parses wikitext to html and removes the surrounding p's added by parser or tidy - * escape: filters message through htmlspecialchars - * escapenoentities: same, but allows entity references like   through - * replaceafter: parameters are substituted after parsing or escaping - * parsemag: transform the message using magic phrases - * content: fetch message for content language instead of interface - * language: language code to fetch message for (overriden by content), its behaviour - * with parse, parseinline and parsemag is undefined. - * Behavior for conflicting options (e.g., parse+parseinline) is undefined. - */ -function wfMsgExt( $key, $options ) { - $args = func_get_args(); - array_shift( $args ); - array_shift( $args ); - - if( !is_array($options) ) { - $options = array($options); - } - - $language = MessageGetter::LANG_UI; - - if( in_array('content', $options) ) { - $language = MessageGetter::LANG_CONTENT; - } elseif( array_key_exists('language', $options) ) { - $language = $options['language']; - $validCodes = array_keys( Language::getLanguageNames() ); - if( !in_array($language, $validCodes) ) { - # Fallback to en, instead of whatsever interface language we might have - $language = 'en'; - } - } - - $message = MessageGetter::get( $key, $language ); - - if( !in_array('replaceafter', $options) ) { - $message = MessageGetter::replaceArgs( $message, $args ); - } - - if( in_array('parse', $options) ) { - $message = MessageGetter::parse( $message, $language ); - } elseif ( in_array('parseinline', $options) ) { - $message = MessageGetter::parse( $message, $language, /*inline*/true ); - } elseif ( in_array('parsemag', $options) ) { - $message = MessageGetter::transform( $message, $language ); - } - - if ( in_array('escape', $options) ) { - $message = MessageGetter::escapeHtml( $message, /*allowEntities*/false ); - } elseif ( in_array( 'escapenoentities', $options ) ) { - $message = MessageGetter::escapeHtml( $message ); - } - - if( in_array('replaceafter', $options) ) { - $message = MessageGetter::replaceArgs( $message, $args ); - } - - return $message; -} - -class MessageGetter { - - const LANG_UI = false; - const LANG_CONTENT = true; - - public static function get( $key, $language = self::LANG_UI, $database = true ) { - global $wgMessageCache; - if( !is_object($wgMessageCache) ) { - throw new MWException( "Message cache not initialised\n" ); - } - - wfRunHooks('NormalizeMessageKey', array(&$key, &$database, &$language)); - - $message = $wgMessageCache->get( $key, $database, $language ); - # Fix windows line-endings - # Some messages are split with explode("\n", $msg) - $message = str_replace( "\r", '', $message ); - return $message; - - } - - public static function forContentLanguage( $key ) { - global $wgForceUIMsgAsContentMsg; - if( is_array( $wgForceUIMsgAsContentMsg ) && - in_array( $key, $wgForceUIMsgAsContentMsg ) ) { - return self::LANG_UI; - } else { - return self::LANG_CONTENT; - } - } - - public static function replaceArgs( $message, $args ) { - // Replace arguments - if ( count( $args ) ) { - if ( is_array( $args[0] ) ) { - $args = array_values( $args[0] ); - } - $replacementKeys = array(); - foreach( $args as $n => $param ) { - $replacementKeys['$' . ($n + 1)] = $param; - } - $message = strtr( $message, $replacementKeys ); - } - - return $message; - } - - /** - * @param $language LANG_UI or LANG_CONTENT. - */ - public static function transform( $message, $language = self::LANG_UI ) { - global $wgMessageCache; - // transform accepts only boolean values - if ( !is_bool($language) ) - throw new MWException( __METHOD__ . ': only ui/content language supported' ); - return $wgMessageCache->transform( $message, !$language ); - } - - /** - * @param $language LANG_UI or LANG_CONTENT. - */ - public static function parse( $message, $language = self::LANG_UI, $inline = false ) { - global $wgOut; - // parse accepts only boolean values - if ( !is_bool($language) ) - throw new MWException( __METHOD__ . ': only ui/content language supported' ); - $message = $wgOut->parse( $message, true, !$language ); - - if ( $inline ) { - $m = array(); - if( preg_match( '/^

(.*)\n?<\/p>\n?$/sU', $message, $m ) ) { - $message = $m[1]; - } - } - - return $message; - } - - public static function escapeHtml( $message, $allowEntities = true ) { - $message = htmlspecialchars( $message ); - if ( $allowEntities ) { - $message = str_replace( '&', '&', $message ); - $message = Sanitizer::normalizeCharReferences( $message ); - } - - return $message; - } - -} \ No newline at end of file -- 2.20.1