From: Niklas Laxström Date: Tue, 8 Jul 2008 08:05:54 +0000 (+0000) Subject: * Move message functions to own file X-Git-Tag: 1.31.0-rc.0~46638 X-Git-Url: https://git.cyclocoop.org/%27%20.%20%24this-%3EgetSkin%28%29-%3EescapeSearchLink%28%29%20.%20%27?a=commitdiff_plain;h=60f3e72328c7b66eb46a037ac24c7ed16a52c7ec;p=lhc%2Fweb%2Fwiklou.git * Move message functions to own file * Improve documentation * Reduce code duplication * Fix the braindamage that wfMsg and friends were doing transform, but in the wrong language --- diff --git a/docs/hooks.txt b/docs/hooks.txt index d289efb906..bad937b2f4 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -868,7 +868,6 @@ $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 ae17222487..b7ac5d1375 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -11,6 +11,7 @@ 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 @@ -319,328 +320,6 @@ 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 new file mode 100644 index 0000000000..9999c44911 --- /dev/null +++ b/includes/MessageFunctions.php @@ -0,0 +1,349 @@ +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