Index: docs/export-0.4.xsd =================================================================== --- docs/export-0.4.xsd (revision 0) +++ docs/export-0.4.xsd (revision 0) @@ -0,0 +1,320 @@ + + + + + + + MediaWiki's page export format + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + MediaWiki's page export format + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: includes/api/ApiQuerySiteinfo.php =================================================================== --- includes/api/ApiQuerySiteinfo.php (revision 47769) +++ includes/api/ApiQuerySiteinfo.php (working copy) @@ -148,7 +148,8 @@ foreach( $wgContLang->getFormattedNamespaces() as $ns => $title ) { $data[$ns] = array( - 'id' => $ns + 'id' => $ns, + 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive', ); ApiResult :: setContent( $data[$ns], $title ); $canonical = MWNamespace::getCanonicalName( $ns ); Index: includes/DefaultSettings.php =================================================================== --- includes/DefaultSettings.php (revision 47769) +++ includes/DefaultSettings.php (working copy) @@ -200,10 +200,10 @@ * thumbScriptUrl The URL for thumb.php (optional, not recommended) * transformVia404 Whether to skip media file transformation on parse and rely on a 404 * handler instead. - * initialCapital Equivalent to $wgCapitalLinks, determines whether filenames implicitly - * start with a capital letter. The current implementation may give incorrect - * description page links when the local $wgCapitalLinks and initialCapital - * are mismatched. + * initialCapital Equivalent to $wgCapitalLinks (or $wgCapitalLinkOverrides[NS_FILE], + * determines whether filenames implicitly start with a capital letter. + * The current implementation may give incorrect description page links + * when the local $wgCapitalLinks and initialCapital are mismatched. * pathDisclosureProtection * May be 'paranoid' to remove all parameters from error messages, 'none' to * leave the paths in unchanged, or 'simple' to replace paths with @@ -2239,6 +2239,19 @@ * same place as links in the middle of a sentence using a lowercase initial. */ $wgCapitalLinks = true; + + +/** + * @since 1.15 - This can now be set per-namespace. Some special namespaces (such + * as Special, see Namespace::$alwaysCapitalizedNamespaces for the full list) must be + * true by default (and setting them has no effect), due to various things that + * require them to be so. Also, since Talk namespaces need to directly mirror their + * associated content namespaces, the values for those are ignored in favor of the + * subject namespace's setting. Setting for NS_MEDIA is taken automatically from + * NS_FILE. + * EX: $wgCapitalLinkOverrides[ NS_FILE ] = false; + */ +$wgCapitalLinkOverrides = array(); /** * List of interwiki prefixes for wikis we'll accept as sources for @@ -3163,7 +3176,7 @@ * 'Main_Page' => 'noindex,follow', * # "Project", not the actual project name! * 'Project:X' => 'index,follow', - * # Needs to be "Abc", not "abc" (unless $wgCapitalLinks is false)! + * # Needs to be "Abc", not "abc" (unless $wgCapitalLinks is false for that namespace)! * 'abc' => 'noindex,nofollow' * ); */ Index: includes/Export.php =================================================================== --- includes/Export.php (revision 47769) +++ includes/Export.php (working copy) @@ -336,7 +336,7 @@ * @return string */ function schemaVersion() { - return "0.3"; // FIXME: upgrade to 0.4 when updated XSD is ready, for the revision deletion bits + return "0.4"; // FIXME: upgrade to 0.5 when updated XSD is ready, for the revision deletion bits } /** @@ -401,7 +401,11 @@ global $wgContLang; $spaces = "\n"; foreach( $wgContLang->getFormattedNamespaces() as $ns => $title ) { - $spaces .= ' ' . Xml::element( 'namespace', array( 'key' => $ns ), $title ) . "\n"; + $spaces .= ' ' . + Xml::element( 'namespace', + array( 'key' => $ns, + 'case' => MWNamespace::isCapitalized( $ns ) ? 'first-letter' : 'case-sensitive', + ), $title ) . "\n"; } $spaces .= " "; return $spaces; Index: includes/filerepo/FileRepo.php =================================================================== --- includes/filerepo/FileRepo.php (revision 47769) +++ includes/filerepo/FileRepo.php (working copy) @@ -29,7 +29,7 @@ $this->name = $info['name']; // Optional settings - $this->initialCapital = true; // by default + $this->initialCapital = MWNamespace::isCapitalized( NS_FILE ); // by default foreach ( array( 'descBaseUrl', 'scriptDirUrl', 'articleUrl', 'fetchDescription', 'thumbScriptUrl', 'initialCapital', 'pathDisclosureProtection', 'descriptionCacheExpiry', 'apiThumbCacheExpiry', 'hashLevels' ) as $var ) @@ -213,13 +213,9 @@ * Get the name of an image from its title object */ function getNameFromTitle( $title ) { - global $wgCapitalLinks; - if ( $this->initialCapital != $wgCapitalLinks ) { + if ( $this->initialCapital != MWNamespace::isCapitalized( NS_FILE ) ) { global $wgContLang; - $name = $title->getUserCaseDBKey(); - if ( $this->initialCapital ) { - $name = $wgContLang->ucfirst( $name ); - } + $name = Title::capitalize( $title->getUserCaseDBKey(), NS_FILE ); } else { $name = $title->getDBkey(); } Index: includes/Import.php =================================================================== --- includes/Import.php (revision 47769) +++ includes/Import.php (working copy) @@ -399,7 +399,7 @@ wfDebug( "WikiImporter XML error: $err\n" ); } - function handleXmlNamespace ( $parser, $data, $prefix=false, $uri=false ) { + function handleXml ( $parser, $data, $prefix=false, $uri=false ) { if( preg_match( '/www.mediawiki.org/',$prefix ) ) { $prefix = str_replace( '/','\/',$prefix ); $this->mXmlNamespace='/^'.$prefix.':/'; @@ -411,8 +411,8 @@ return(preg_replace($this->mXmlNamespace,'',$name,1)); } else { - return($name); - } + return($name); + } } # -------------- Index: includes/Namespace.php =================================================================== --- includes/Namespace.php (revision 47769) +++ includes/Namespace.php (working copy) @@ -46,6 +46,13 @@ class MWNamespace { /** + * These namespaces should always be first-letter capitalized, now and + * forevermore. Historically, they could've probably been lowercased too, + * but some things are just too ingrained now. :) + */ + private static $alwaysCapitalizedNamespaces = array( NS_SPECIAL, NS_MEDIAWIKI ); + + /** * Can pages in the given namespace be moved? * * @param $index Int: namespace index @@ -181,5 +188,31 @@ global $wgNamespacesWithSubpages; return !empty( $wgNamespacesWithSubpages[$index] ); } + + /** + * Is the namespace first-letter capitalized? + * + * @param $index int Index to check + * @return bool + */ + public static function isCapitalized( $index ) { + global $wgCapitalLinks, $wgCapitalLinkOverrides; + // Turn NS_MEDIA into NS_FILE + $index = $index === NS_MEDIA ? NS_FILE : $index; + + // Make sure to get the subject of our namespace + $index = self::getSubject( $index ); + + // Some namespaces are special and should always be upper case + if ( in_array( $index, self::$alwaysCapitalizedNamespaces ) ) { + return true; + } + if ( isset( $wgCapitalLinkOverrides[ $index ] ) ) { + // $wgCapitalLinkOverrides is explicitly set + return $wgCapitalLinkOverrides[ $index ]; + } + // Default to the global setting + return $wgCapitalLinks; + } } Index: includes/Setup.php =================================================================== --- includes/Setup.php (revision 47769) +++ includes/Setup.php (working copy) @@ -87,7 +87,6 @@ 'hashLevels' => $wgHashedUploadDirectory ? 2 : 0, 'thumbScriptUrl' => $wgThumbnailScriptPath, 'transformVia404' => !$wgGenerateThumbnailOnParse, - 'initialCapital' => $wgCapitalLinks, 'deletedDir' => $wgFileStore['deleted']['directory'], 'deletedHashLevels' => $wgFileStore['deleted']['hash'] ); Index: includes/specials/SpecialCategories.php =================================================================== --- includes/specials/SpecialCategories.php (revision 47769) +++ includes/specials/SpecialCategories.php (working copy) @@ -35,10 +35,8 @@ parent::__construct(); $from = str_replace( ' ', '_', $from ); if( $from !== '' ) { - global $wgCapitalLinks, $wgContLang; - if( $wgCapitalLinks ) { - $from = $wgContLang->ucfirst( $from ); - } + global $wgContLang; + $from = Title::capitalize( $from, NS_CATEGORY ); $this->mOffset = $from; } } Index: includes/specials/SpecialUpload.php =================================================================== --- includes/specials/SpecialUpload.php (revision 47769) +++ includes/specials/SpecialUpload.php (working copy) @@ -511,10 +511,7 @@ $warning = ''; $comparableName = str_replace( ' ', '_', $basename ); - global $wgCapitalLinks, $wgContLang; - if ( $wgCapitalLinks ) { - $comparableName = $wgContLang->ucfirst( $comparableName ); - } + $comparableName = Title::capitalize( $comparableName, NS_FILE ); if( $comparableName !== $filtered ) { $warning .= '
  • '.wfMsgHtml( 'badfilename', htmlspecialchars( $this->mDestName ) ).'
  • '; Index: includes/specials/SpecialWithoutinterwiki.php =================================================================== --- includes/specials/SpecialWithoutinterwiki.php (revision 47769) +++ includes/specials/SpecialWithoutinterwiki.php (working copy) @@ -75,13 +75,11 @@ } function wfSpecialWithoutinterwiki() { - global $wgRequest, $wgContLang, $wgCapitalLinks; + global $wgRequest, $wgContLang; list( $limit, $offset ) = wfCheckLimits(); - if( $wgCapitalLinks ) { - $prefix = $wgContLang->ucfirst( $wgRequest->getVal( 'prefix' ) ); - } else { - $prefix = $wgRequest->getVal( 'prefix' ); - } + // Only searching the mainspace anyway + $prefix = Title::capitalize( $wgRequest->getVal( 'prefix' ), NS_MAIN ); + $wip = new WithoutInterwikiPage(); $wip->setPrefix( $prefix ); $wip->doQuery( $offset, $limit ); Index: includes/Title.php =================================================================== --- includes/Title.php (revision 47769) +++ includes/Title.php (working copy) @@ -471,6 +471,18 @@ } return $name; } + + /** + * Capitalize a text if it belongs to a namespace that capitalizes + */ + public static function capitalize( $text, $ns = NS_MAIN ) { + global $wgContLang; + + if ( MWNamespace::isCapitalized( $ns ) ) + return $wgContLang->ucfirst( $text ); + else + return $text; + } /** * Returns the URL associated with an interwiki prefix @@ -2164,7 +2176,7 @@ * @return \type{\bool} true on success */ private function secureAndSplit() { - global $wgContLang, $wgLocalInterwiki, $wgCapitalLinks; + global $wgContLang, $wgLocalInterwiki; # Initialisation static $rxTc = false; @@ -2340,8 +2352,8 @@ * site might be case-sensitive. */ $this->mUserCaseDBKey = $dbkey; - if( $wgCapitalLinks && $this->mInterwiki == '') { - $dbkey = $wgContLang->ucfirst( $dbkey ); + if ( $this->mInterwiki == '') { + $dbkey = Title::capitalize( $dbkey, $this->mNamespace ); } /** Index: includes/User.php =================================================================== --- includes/User.php (revision 47769) +++ includes/User.php (working copy) @@ -502,7 +502,7 @@ || User::isIP( $name ) || strpos( $name, '/' ) !== false || strlen( $name ) > $wgMaxNameChars - || $name != $wgContLang->ucfirst( $name ) ) { + || ( $name != Title::capitalize( $name, NS_USER ) ) ) { wfDebugLog( 'username', __METHOD__ . ": '$name' invalid due to empty, IP, slash, length, or lowercase" ); return false; @@ -648,9 +648,8 @@ */ static function getCanonicalName( $name, $validate = 'valid' ) { # Force usernames to capital - global $wgContLang; - $name = $wgContLang->ucfirst( $name ); - + $name = Title::capitalize( $name, NS_USER ); + # Reject names containing '#'; these will be cleaned up # with title normalisation, but then it's too late to # check elsewhere