From: jenkins-bot Date: Fri, 5 Sep 2014 19:32:47 +0000 (+0000) Subject: Merge "Sanitizer::escapeId: Decode entity before replacing spaces" X-Git-Tag: 1.31.0-rc.0~14143 X-Git-Url: https://git.heureux-cyclage.org/?a=commitdiff_plain;h=eddce194b22b80f46ce578362250bb402312c7a2;hp=89ad2617e3c0bb0587c69cf15ab7def2807492da;p=lhc%2Fweb%2Fwiklou.git Merge "Sanitizer::escapeId: Decode entity before replacing spaces" --- diff --git a/RELEASE-NOTES-1.24 b/RELEASE-NOTES-1.24 index 4ae33e3e8e..288599533e 100644 --- a/RELEASE-NOTES-1.24 +++ b/RELEASE-NOTES-1.24 @@ -70,6 +70,10 @@ production. we will send rel=alternate. === New features in 1.24 === +* Added new hook WatchlistEditorBeforeFormRender, allowing subscribers to + manipulate the list of pages and/or preload lots of data at once. +* Added new argument &$link in hook WatchlistEditorBuildRemoveLine, allowing the + link to the title to be changed. * Added a new hook, "WhatLinksHereProps", to allow extensions to annotate WhatLinksHere entries. * Added a new hook, "ContentGetParserOutput", to customize parser output for @@ -177,6 +181,8 @@ production. * API token handling has been rewritten. Any API module using tokens will need to be updated. See the entry below under "Action API internal changes". * Added HTMLAutoCompleteSelectField. +* Added a new hook, "SkinPreloadExistence", to allow extensions to add titles to + link existence cache before the page is rendered. === Bug fixes in 1.24 === * (bug 50572) MediaWiki:Blockip should support gender @@ -209,6 +215,7 @@ production. * (bugs 57238, 65206) Blank pages can now be directly created. * (bug 69789) Title::getContentModel() now loads from the database when necessary instead of incorrectly returning the default content model. +* (bug 69249) wfBaseConvert() now works around PHP Bug #50175 when using GMP. === Action API changes in 1.24 === * action=parse API now supports prop=modules, which provides the list of @@ -348,6 +355,13 @@ changes to languages because of Bugzilla reports. the "headelement" template key are no longer supported. Setting $useHeadElement = false; is no longer supported and will not cause old keys like "headlinks", "skinnameclass", etc. to be defined. +* BREAKING CHANGE: The files commonElements.css, commonContent.css and + commonInterface.css (in skins/common/) have been removed. Skins may no longer + rely on their presence and include them in their style modules. ResourceLoader + modules introduced in MediaWiki 1.23 should be loaded instead: + - skins/common/commonElements.css → 'mediawiki.skinning.elements' module + - skins/common/commonContent.css → 'mediawiki.skinning.content' module + - skins/common/commonInterface.css → 'mediawiki.skinning.interface' module * The deprecated 'SpecialVersionExtensionTypes' hook was removed. * (bug 63891) Add 'X-Robots-Tag: noindex' header in action=render pages. * SpecialPage no longer supports the syntax for invoking wfSpecial*() functions. @@ -430,6 +444,12 @@ changes to languages because of Bugzilla reports. Running update.php on MySQL < v5.1 may result in heavy processing. * RSS and Atom feeds generated by MediaWiki no longer include a fallback stylesheet. It was ignored by most browsers these days anyway. +* SpecialSearchNoResults hook has been removed. SpecialSearchResults is now + called unconditionally. +* TablePager::getBody() is now 'final' and can't be overridden in subclasses. +* TablePager::getBody() is deprecated, use getBodyOutput() or getFullOutput(). +* log_page for move log entries store the original page ID, rather than that + of the new redirect page. This is not retroactive. ==== Renamed classes ==== * CLDRPluralRuleConverter_Expression to CLDRPluralRuleConverterExpression diff --git a/docs/hooks.txt b/docs/hooks.txt index 65b1675530..ec2cc785fd 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -863,6 +863,14 @@ $name: name of the special page, e.g. 'Watchlist' &$join_conds: join conditions for the tables $opts: FormOptions for this request +'LoginUserMigrated': Called during login to allow extensions the opportunity to +inform a user that their username doesn't exist for a specific reason, instead +of letting the login form give the generic error message that the account does +not exist. For example, when the account has been renamed or deleted. +$user: the User object being authenticated against. +&$msg: the message identifier for abort reason, or an array to pass a message + key and parameters. + 'Collation::factory': Called if $wgCategoryCollation is an unknown collation. $collationName: Name of the collation in question &$collationObject: Null. Replace with a subclass of the Collation class that @@ -1635,6 +1643,13 @@ $code: language code &$alldata: The localisation data from core and extensions &purgeBlobs: whether to purge/update the message blobs via MessageBlobStore::clear() +'LocalisationCacheRecacheFallback': Called for each language when merging +fallback data into the cache. +$cache: The LocalisationCache object +$code: language code +&$alldata: The localisation data from core and extensions. Note some keys may + be omitted if they won't be merged into the final result. + 'LocalisationChecksBlacklist': When fetching the blacklist of localisation checks. &$blacklist: array of checks to blacklist. See the bottom of @@ -2292,6 +2307,11 @@ $type: 'normal' or 'history' for old/diff views the MediaWiki icon but plain text instead. $skin: Skin object +'SkinPreloadExistence': Supply titles that should be added to link existence +cache before the page is rendered. +&$titles: Array of Title objects +$skin: Skin object + 'SkinSubPageSubtitle': At the beginning of Skin::subPageSubtitle(). &$subpages: Subpage links HTML $skin: Skin object @@ -2513,16 +2533,11 @@ $specialSearch: SpecialSearch object ($this) $output: $wgOut $term: Search term specified by the user -'SpecialSearchResults': Called before search result display when there are -matches. +'SpecialSearchResults': Called before search result display $term: string of search term &$titleMatches: empty or SearchResultSet object &$textMatches: empty or SearchResultSet object -'SpecialSearchNoResults': Called before search result display when there are no -matches. -$term: string of search term - 'SpecialStatsAddExtra': Add extra statistic at the end of Special:Statistics. &$extraStats: Array to save the new stats ( $extraStats[''] => ; ) @@ -2947,12 +2962,18 @@ $page: WikiPage object to be watched $user: user that watched $page: WikiPage object watched +'WatchlistEditorBeforeFormRender': Before building the Special:EditWatchlist +form, used to manipulate the list of pages or preload data based on that list. +&$watchlistInfo: array of watchlisted pages in + [namespaceId => ['title1' => 1, 'title2' => 1]] format + 'WatchlistEditorBuildRemoveLine': when building remove lines in Special:Watchlist/edit. &$tools: array of extra links $title: Title object $redirect: whether the page is a redirect $skin: Skin object +&$link: HTML link to title 'WebRequestPathInfoRouter': While building the PathRouter to parse the REQUEST_URI. diff --git a/docs/kss/styleguide-template/index.html b/docs/kss/styleguide-template/index.html index b6036b2d94..38f0dd144f 100644 --- a/docs/kss/styleguide-template/index.html +++ b/docs/kss/styleguide-template/index.html @@ -19,7 +19,7 @@
-
diff --git a/docs/kss/styleguide-template/public/kss.less b/docs/kss/styleguide-template/public/kss.less index f5ddff1253..a1d62a37ee 100644 --- a/docs/kss/styleguide-template/public/kss.less +++ b/docs/kss/styleguide-template/public/kss.less @@ -1,4 +1,3 @@ - .container { width: 100%; } @@ -7,7 +6,7 @@ nav { display: none; } -article { +.content { .example { blockquote { margin-top: 20px; @@ -25,7 +24,8 @@ body { font-family: "Nimbus Sans L", "Liberation Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif; } -.content.kss-no-margin { +.kss-no-margin { + // FIXME: Is this being used anywhere? Remove if not. margin: 0; } @@ -89,7 +89,7 @@ nav { } } -article { +.content { -webkit-flex: 1; flex: 1; @@ -154,7 +154,7 @@ article { width: auto; } - article { + .content { margin-left: 30px; } diff --git a/docs/uidesign/design.html b/docs/uidesign/design.html index a285a5b22f..51c1b55204 100644 --- a/docs/uidesign/design.html +++ b/docs/uidesign/design.html @@ -1,7 +1,7 @@ - + diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index 04802f9e97..0559a8ef8a 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -36,8 +36,12 @@ $wgAutoloadLocalClasses = array( 'AuthPluginUser' => 'includes/AuthPlugin.php', 'Autopromote' => 'includes/Autopromote.php', 'Block' => 'includes/Block.php', + 'BloomCache' => 'includes/cache/bloom/BloomCache.php', + 'BloomCacheRedis' => 'includes/cache/bloom/BloomCacheRedis.php', + 'BloomFilterTitleHasLogs' => 'includes/cache/bloom/BloomFilters.php', + 'CacheHelper' => 'includes/CacheHelper.php', 'Category' => 'includes/Category.php', - 'Categoryfinder' => 'includes/Categoryfinder.php', + 'CategoryFinder' => 'includes/CategoryFinder.php', 'CategoryViewer' => 'includes/CategoryViewer.php', 'ChangeTags' => 'includes/ChangeTags.php', 'ChannelFeed' => 'includes/Feed.php', @@ -65,6 +69,7 @@ $wgAutoloadLocalClasses = array( 'DumpPipeOutput' => 'includes/Export.php', 'EditPage' => 'includes/EditPage.php', 'EmailNotification' => 'includes/UserMailer.php', + 'EmptyBloomCache' => 'includes/cache/bloom/BloomCache.php', 'Fallback' => 'includes/Fallback.php', 'FauxRequest' => 'includes/WebRequest.php', 'FauxResponse' => 'includes/WebResponse.php', diff --git a/includes/CategoryFinder.php b/includes/CategoryFinder.php new file mode 100644 index 0000000000..9fd388352a --- /dev/null +++ b/includes/CategoryFinder.php @@ -0,0 +1,236 @@ + + * # Determines whether the article with the page_id 12345 is in both + * # "Category 1" and "Category 2" or their subcategories, respectively + * + * $cf = new CategoryFinder; + * $cf->seed( + * array( 12345 ), + * array( 'Category 1', 'Category 2' ), + * 'AND' + * ); + * $a = $cf->run(); + * print implode( ',' , $a ); + * + * + */ +class CategoryFinder { + /** @var int[] The original article IDs passed to the seed function */ + protected $articles = array(); + + /** @var array Array of DBKEY category names for categories that don't have a page */ + protected $deadend = array(); + + /** @var array Array of [ID => array()] */ + protected $parents = array(); + + /** @var array Array of article/category IDs */ + protected $next = array(); + + /** @var array Array of DBKEY category names */ + protected $targets = array(); + + /** @var array */ + protected $name2id = array(); + + /** @var string "AND" or "OR" */ + protected $mode; + + /** @var DatabaseBase Read-DB slave */ + protected $dbr; + + /** + * Initializes the instance. Do this prior to calling run(). + * @param array $articleIds Array of article IDs + * @param array $categories FIXME + * @param string $mode FIXME, default 'AND'. + * @todo FIXME: $categories/$mode + */ + public function seed( $articleIds, $categories, $mode = 'AND' ) { + $this->articles = $articleIds; + $this->next = $articleIds; + $this->mode = $mode; + + # Set the list of target categories; convert them to DBKEY form first + $this->targets = array(); + foreach ( $categories as $c ) { + $ct = Title::makeTitleSafe( NS_CATEGORY, $c ); + if ( $ct ) { + $c = $ct->getDBkey(); + $this->targets[$c] = $c; + } + } + } + + /** + * Iterates through the parent tree starting with the seed values, + * then checks the articles if they match the conditions + * @return array Array of page_ids (those given to seed() that match the conditions) + */ + public function run() { + $this->dbr = wfGetDB( DB_SLAVE ); + while ( count( $this->next ) > 0 ) { + $this->scanNextLayer(); + } + + # Now check if this applies to the individual articles + $ret = array(); + + foreach ( $this->articles as $article ) { + $conds = $this->targets; + if ( $this->check( $article, $conds ) ) { + # Matches the conditions + $ret[] = $article; + } + } + return $ret; + } + + /** + * This functions recurses through the parent representation, trying to match the conditions + * @param int $id The article/category to check + * @param array $conds The array of categories to match + * @param array $path Used to check for recursion loops + * @return bool Does this match the conditions? + */ + private function check( $id, &$conds, $path = array() ) { + // Check for loops and stop! + if ( in_array( $id, $path ) ) { + return false; + } + + $path[] = $id; + + # Shortcut (runtime paranoia): No conditions=all matched + if ( count( $conds ) == 0 ) { + return true; + } + + if ( !isset( $this->parents[$id] ) ) { + return false; + } + + # iterate through the parents + foreach ( $this->parents[$id] as $p ) { + $pname = $p->cl_to; + + # Is this a condition? + if ( isset( $conds[$pname] ) ) { + # This key is in the category list! + if ( $this->mode == 'OR' ) { + # One found, that's enough! + $conds = array(); + return true; + } else { + # Assuming "AND" as default + unset( $conds[$pname] ); + if ( count( $conds ) == 0 ) { + # All conditions met, done + return true; + } + } + } + + # Not done yet, try sub-parents + if ( !isset( $this->name2id[$pname] ) ) { + # No sub-parent + continue; + } + $done = $this->check( $this->name2id[$pname], $conds, $path ); + if ( $done || count( $conds ) == 0 ) { + # Subparents have done it! + return true; + } + } + return false; + } + + /** + * Scans a "parent layer" of the articles/categories in $this->next + */ + private function scanNextLayer() { + $profiler = new ProfileSection( __METHOD__ ); + + # Find all parents of the article currently in $this->next + $layer = array(); + $res = $this->dbr->select( + /* FROM */ 'categorylinks', + /* SELECT */ '*', + /* WHERE */ array( 'cl_from' => $this->next ), + __METHOD__ . '-1' + ); + foreach ( $res as $o ) { + $k = $o->cl_to; + + # Update parent tree + if ( !isset( $this->parents[$o->cl_from] ) ) { + $this->parents[$o->cl_from] = array(); + } + $this->parents[$o->cl_from][$k] = $o; + + # Ignore those we already have + if ( in_array( $k, $this->deadend ) ) { + continue; + } + + if ( isset( $this->name2id[$k] ) ) { + continue; + } + + # Hey, new category! + $layer[$k] = $k; + } + + $this->next = array(); + + # Find the IDs of all category pages in $layer, if they exist + if ( count( $layer ) > 0 ) { + $res = $this->dbr->select( + /* FROM */ 'page', + /* SELECT */ array( 'page_id', 'page_title' ), + /* WHERE */ array( 'page_namespace' => NS_CATEGORY, 'page_title' => $layer ), + __METHOD__ . '-2' + ); + foreach ( $res as $o ) { + $id = $o->page_id; + $name = $o->page_title; + $this->name2id[$name] = $id; + $this->next[] = $id; + unset( $layer[$name] ); + } + } + + # Mark dead ends + foreach ( $layer as $v ) { + $this->deadend[$v] = $v; + } + } +} diff --git a/includes/Categoryfinder.php b/includes/Categoryfinder.php deleted file mode 100644 index a5415afd3e..0000000000 --- a/includes/Categoryfinder.php +++ /dev/null @@ -1,241 +0,0 @@ - - * # Determines whether the article with the page_id 12345 is in both - * # "Category 1" and "Category 2" or their subcategories, respectively - * - * $cf = new Categoryfinder; - * $cf->seed( - * array( 12345 ), - * array( 'Category 1', 'Category 2' ), - * 'AND' - * ); - * $a = $cf->run(); - * print implode( ',' , $a ); - * - * - */ -class Categoryfinder { - /** @var int[] The original article IDs passed to the seed function */ - protected $articles = array(); - - /** @var array Array of DBKEY category names for categories that don't have a page */ - protected $deadend = array(); - - /** @var array Array of [ID => array()] */ - protected $parents = array(); - - /** @var array Array of article/category IDs */ - protected $next = array(); - - /** @var array Array of DBKEY category names */ - protected $targets = array(); - - /** @var array */ - protected $name2id = array(); - - /** @var string "AND" or "OR" */ - protected $mode; - - /** @var DatabaseBase Read-DB slave */ - protected $dbr; - - function __construct() { - } - - /** - * Initializes the instance. Do this prior to calling run(). - * @param array $article_ids Array of article IDs - * @param array $categories FIXME - * @param string $mode FIXME, default 'AND'. - * @todo FIXME: $categories/$mode - */ - function seed( $article_ids, $categories, $mode = 'AND' ) { - $this->articles = $article_ids; - $this->next = $article_ids; - $this->mode = $mode; - - # Set the list of target categories; convert them to DBKEY form first - $this->targets = array(); - foreach ( $categories as $c ) { - $ct = Title::makeTitleSafe( NS_CATEGORY, $c ); - if ( $ct ) { - $c = $ct->getDBkey(); - $this->targets[$c] = $c; - } - } - } - - /** - * Iterates through the parent tree starting with the seed values, - * then checks the articles if they match the conditions - * @return array Array of page_ids (those given to seed() that match the conditions) - */ - function run() { - $this->dbr = wfGetDB( DB_SLAVE ); - while ( count( $this->next ) > 0 ) { - $this->scan_next_layer(); - } - - # Now check if this applies to the individual articles - $ret = array(); - - foreach ( $this->articles as $article ) { - $conds = $this->targets; - if ( $this->check( $article, $conds ) ) { - # Matches the conditions - $ret[] = $article; - } - } - return $ret; - } - - /** - * This functions recurses through the parent representation, trying to match the conditions - * @param int $id The article/category to check - * @param array $conds The array of categories to match - * @param array $path Used to check for recursion loops - * @return bool Does this match the conditions? - */ - function check( $id, &$conds, $path = array() ) { - // Check for loops and stop! - if ( in_array( $id, $path ) ) { - return false; - } - - $path[] = $id; - - # Shortcut (runtime paranoia): No conditions=all matched - if ( count( $conds ) == 0 ) { - return true; - } - - if ( !isset( $this->parents[$id] ) ) { - return false; - } - - # iterate through the parents - foreach ( $this->parents[$id] as $p ) { - $pname = $p->cl_to; - - # Is this a condition? - if ( isset( $conds[$pname] ) ) { - # This key is in the category list! - if ( $this->mode == 'OR' ) { - # One found, that's enough! - $conds = array(); - return true; - } else { - # Assuming "AND" as default - unset( $conds[$pname] ); - if ( count( $conds ) == 0 ) { - # All conditions met, done - return true; - } - } - } - - # Not done yet, try sub-parents - if ( !isset( $this->name2id[$pname] ) ) { - # No sub-parent - continue; - } - $done = $this->check( $this->name2id[$pname], $conds, $path ); - if ( $done || count( $conds ) == 0 ) { - # Subparents have done it! - return true; - } - } - return false; - } - - /** - * Scans a "parent layer" of the articles/categories in $this->next - */ - function scan_next_layer() { - wfProfileIn( __METHOD__ ); - - # Find all parents of the article currently in $this->next - $layer = array(); - $res = $this->dbr->select( - /* FROM */ 'categorylinks', - /* SELECT */ '*', - /* WHERE */ array( 'cl_from' => $this->next ), - __METHOD__ . '-1' - ); - foreach ( $res as $o ) { - $k = $o->cl_to; - - # Update parent tree - if ( !isset( $this->parents[$o->cl_from] ) ) { - $this->parents[$o->cl_from] = array(); - } - $this->parents[$o->cl_from][$k] = $o; - - # Ignore those we already have - if ( in_array( $k, $this->deadend ) ) { - continue; - } - - if ( isset( $this->name2id[$k] ) ) { - continue; - } - - # Hey, new category! - $layer[$k] = $k; - } - - $this->next = array(); - - # Find the IDs of all category pages in $layer, if they exist - if ( count( $layer ) > 0 ) { - $res = $this->dbr->select( - /* FROM */ 'page', - /* SELECT */ array( 'page_id', 'page_title' ), - /* WHERE */ array( 'page_namespace' => NS_CATEGORY, 'page_title' => $layer ), - __METHOD__ . '-2' - ); - foreach ( $res as $o ) { - $id = $o->page_id; - $name = $o->page_title; - $this->name2id[$name] = $id; - $this->next[] = $id; - unset( $layer[$name] ); - } - } - - # Mark dead ends - foreach ( $layer as $v ) { - $this->deadend[$v] = $v; - } - - wfProfileOut( __METHOD__ ); - } -} diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 5fc73776a9..26ce83c111 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -1156,7 +1156,7 @@ $wgMimeInfoFile = 'includes/mime.info'; * Sets an external MIME detector program. The command must print only * the MIME type to standard output. * The name of the file to process will be appended to the command given here. - * If not set or NULL, mime_content_type will be used if available. + * If not set or NULL, PHP's fileinfo extension will be used if available. * * @par Example: * @code @@ -2075,6 +2075,28 @@ $wgObjectCaches = array( 'hash' => array( 'class' => 'HashBagOStuff' ), ); +/** + * Map of bloom filter store names to configuration arrays. + * + * Example: + * $wgBloomFilterStores['main'] = array( + * 'cacheId' => 'main-v1', + * 'class' => 'BloomCacheRedis', + * 'redisServers' => array( '127.0.0.1:6379' ), + * 'redisConfig' => array( 'connectTimeout' => 2 ) + * ); + * + * A primary bloom filter must be created manually. + * Example in eval.php: + * + * BloomCache::get( 'main' )->init( 'shared', 1000000000, .001 ); + * + * The size should be as large as practical given wiki size and resources. + * + * @since 1.24 + */ +$wgBloomFilterStores = array(); + /** * The expiry time for the parser cache, in seconds. * The default is 86400 (one day). diff --git a/includes/EditPage.php b/includes/EditPage.php index b83569d8fe..a14191a035 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -217,8 +217,13 @@ class EditPage { /** @var bool|stdClass */ protected $lastDelete; - /** @var bool */ - protected $mTokenOk = false; + /** @var bool + * This is public because SemanticForms uses it (bug 67522). + * However, please consider using this property publicly + * to be deprecated. + * @protected + */ + public $mTokenOk = false; /** @var bool */ protected $mTokenOkExceptSuffix = false; @@ -2425,9 +2430,7 @@ class EditPage { $wgOut->addHTML( $this->editFormTextBeforeContent ); - if ( $this->contentModel === CONTENT_MODEL_WIKITEXT && - $showToolbar && $wgUser->getOption( 'showtoolbar' ) ) - { + if ( !$this->isCssJsSubpage && $showToolbar && $wgUser->getOption( 'showtoolbar' ) ) { $wgOut->addHTML( EditPage::getEditToolbar() ); } @@ -2612,9 +2615,18 @@ class EditPage { ); } elseif ( $wgUser->isAnon() ) { if ( $this->formtype != 'preview' ) { - $wgOut->wrapWikiMsg( "
\n$1
", 'anoneditwarning' ); + $wgOut->wrapWikiMsg( + "
\n$1\n
", + array( 'anoneditwarning', + // Log-in link + '{{fullurl:Special:UserLogin|returnto={{FULLPAGENAMEE}}}}', + // Sign-up link + '{{fullurl:Special:UserLogin/signup|returnto={{FULLPAGENAMEE}}}}' ) + ); } else { - $wgOut->wrapWikiMsg( "
\n$1
", 'anonpreviewwarning' ); + $wgOut->wrapWikiMsg( "
\n$1
", + 'anonpreviewwarning' + ); } } else { if ( $this->isCssJsSubpage ) { diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index ddea620b81..cfe9a87dc1 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -3366,7 +3366,10 @@ function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1, ); if ( extension_loaded( 'gmp' ) && ( $engine == 'auto' || $engine == 'gmp' ) ) { - $result = gmp_strval( gmp_init( $input, $sourceBase ), $destBase ); + // Removing leading zeros works around broken base detection code in + // some PHP versions (see and + // ). + $result = gmp_strval( gmp_init( ltrim( $input, '0' ), $sourceBase ), $destBase ); } elseif ( extension_loaded( 'bcmath' ) && ( $engine == 'auto' || $engine == 'bcmath' ) ) { $decimal = '0'; foreach ( str_split( strtolower( $input ) ) as $char ) { diff --git a/includes/Initialize.php b/includes/Initialize.php deleted file mode 100644 index 4bc63f451d..0000000000 --- a/includes/Initialize.php +++ /dev/null @@ -1,49 +0,0 @@ -transform( $hp15 ); $thumb20 = $file->transform( $hp20 ); - if ( $thumb15 && $thumb15->getUrl() !== $thumb->getUrl() ) { + if ( $thumb15 && !$thumb15->isError() && $thumb15->getUrl() !== $thumb->getUrl() ) { $thumb->responsiveUrls['1.5'] = $thumb15->getUrl(); } - if ( $thumb20 && $thumb20->getUrl() !== $thumb->getUrl() ) { + if ( $thumb20 && !$thumb20->isError() && $thumb20->getUrl() !== $thumb->getUrl() ) { $thumb->responsiveUrls['2'] = $thumb20->getUrl(); } } diff --git a/includes/MediaWiki.php b/includes/MediaWiki.php index 0424633a93..9213c021ef 100644 --- a/includes/MediaWiki.php +++ b/includes/MediaWiki.php @@ -27,7 +27,6 @@ */ class MediaWiki { /** - * @todo Fold $output, etc, into this * @var IContextSource */ private $context; @@ -37,30 +36,6 @@ class MediaWiki { */ private $config; - /** - * @param null|WebRequest $x - * @return WebRequest - */ - public function request( WebRequest $x = null ) { - $old = $this->context->getRequest(); - if ( $x ) { - $this->context->setRequest( $x ); - } - return $old; - } - - /** - * @param null|OutputPage $x - * @return OutputPage - */ - public function output( OutputPage $x = null ) { - $old = $this->context->getOutput(); - if ( $x ) { - $this->context->setOutput( $x ); - } - return $old; - } - /** * @param IContextSource|null $context */ diff --git a/includes/MimeMagic.php b/includes/MimeMagic.php index 8f0a2af230..656c1e0846 100644 --- a/includes/MimeMagic.php +++ b/includes/MimeMagic.php @@ -898,9 +898,9 @@ class MimeMagic { /** * Internal MIME type detection. Detection is done using an external * program, if $wgMimeDetectorCommand is set. Otherwise, the fileinfo - * extension and mime_content_type are tried (in this order), if they - * are available. If the detections fails and $ext is not false, the MIME - * type is guessed from the file extension, using guessTypesForExtension. + * extension is tried if it is available. If detection fails and $ext + * is not false, the MIME type is guessed from the file extension, + * using guessTypesForExtension. * * If the MIME type is still unknown, getimagesize is used to detect the * MIME type if the file is an image. If no MIME type can be determined, @@ -927,18 +927,7 @@ class MimeMagic { $args = wfEscapeShellArg( $file ); $m = wfShellExec( "$wgMimeDetectorCommand $args" ); } elseif ( function_exists( "finfo_open" ) && function_exists( "finfo_file" ) ) { - - # This required the fileinfo extension by PECL, - # see http://pecl.php.net/package/fileinfo - # This must be compiled into PHP - # - # finfo is the official replacement for the deprecated - # mime_content_type function, see below. - # - # If you may need to load the fileinfo extension at runtime, set - # $wgLoadFileinfoExtension in LocalSettings.php - - $mime_magic_resource = finfo_open( FILEINFO_MIME ); /* return MIME type ala mimetype extension */ + $mime_magic_resource = finfo_open( FILEINFO_MIME ); if ( $mime_magic_resource ) { $m = finfo_file( $mime_magic_resource, $file ); @@ -946,21 +935,6 @@ class MimeMagic { } else { wfDebug( __METHOD__ . ": finfo_open failed on " . FILEINFO_MIME . "!\n" ); } - } elseif ( function_exists( "mime_content_type" ) ) { - - # NOTE: this function is available since PHP 4.3.0, but only if - # PHP was compiled with --with-mime-magic or, before 4.3.2, with - # --enable-mime-magic. - # - # On Windows, you must set mime_magic.magicfile in php.ini to point - # to the mime.magic file bundled with PHP; sometimes, this may even - # be needed under *nix. - # - # Also note that this has been DEPRECATED in favor of the fileinfo - # extension by PECL, see above. - # See http://www.php.net/manual/en/ref.mime-magic.php for details. - - $m = mime_content_type( $file ); } else { wfDebug( __METHOD__ . ": no magic mime detector found!\n" ); } diff --git a/includes/OutputPage.php b/includes/OutputPage.php index fbd80c955f..af90ca6da4 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -2797,7 +2797,9 @@ $templates ); } else { $links['html'] .= Html::inlineScript( - $resourceLoader->makeModuleResponse( $context, $grpModules ) + ResourceLoader::makeLoaderConditionalScript( + $resourceLoader->makeModuleResponse( $context, $grpModules ) + ) ); } $links['html'] .= "\n"; @@ -3502,6 +3504,8 @@ $templates if ( $flip === 'flip' && $this->getLanguage()->isRTL() ) { # If wanted, and the interface is right-to-left, flip the CSS $style_css = CSSJanus::transform( $style_css, true, false ); + } else { + $style_css = CSSJanus::nullTransform( $style_css ); } $this->mInlineStyles .= Html::inlineStyle( $style_css ) . "\n"; } @@ -3552,6 +3556,8 @@ $templates $previewedCSS = $this->getRequest()->getText( 'wpTextbox1' ); if ( $this->getLanguage()->getDir() !== $wgContLang->getDir() ) { $previewedCSS = CSSJanus::transform( $previewedCSS, true, false ); + } else { + $previewedCSS = CSSJanus::nullTransform( $previewedCSS ); } $otherTags .= Html::inlineStyle( $previewedCSS ) . "\n"; } else { diff --git a/includes/PrefixSearch.php b/includes/PrefixSearch.php index 35be2a9d87..295183c62a 100644 --- a/includes/PrefixSearch.php +++ b/includes/PrefixSearch.php @@ -174,6 +174,9 @@ abstract class PrefixSearch { if ( $subpageSearch !== null ) { // Try matching the full search string as a page name $specialTitle = Title::makeTitleSafe( NS_SPECIAL, $searchKey ); + if ( !$specialTitle ) { + return array(); + } $special = SpecialPageFactory::getPage( $specialTitle->getText() ); if ( $special ) { $subpages = $special->prefixSearchSubpages( $subpageSearch, $limit ); diff --git a/includes/ProtectionForm.php b/includes/ProtectionForm.php index 853e2cc412..4aa65d9403 100644 --- a/includes/ProtectionForm.php +++ b/includes/ProtectionForm.php @@ -57,16 +57,21 @@ class ProtectionForm { /** @var array Map of action to the expiry time of the existing protection */ protected $mExistingExpiry = array(); - function __construct( Page $article ) { - global $wgUser; + /** @var IContextSource */ + private $mContext; + + function __construct( Article $article ) { // Set instance variables. $this->mArticle = $article; $this->mTitle = $article->getTitle(); $this->mApplicableTypes = $this->mTitle->getRestrictionTypes(); + $this->mContext = $article->getContext(); // Check if the form should be disabled. // If it is, the form will be available in read-only to show levels. - $this->mPermErrors = $this->mTitle->getUserPermissionsErrors( 'protect', $wgUser ); + $this->mPermErrors = $this->mTitle->getUserPermissionsErrors( + 'protect', $this->mContext->getUser() + ); if ( wfReadOnly() ) { $this->mPermErrors[] = array( 'readonlytext', wfReadOnlyReason() ); } @@ -82,14 +87,15 @@ class ProtectionForm { * Loads the current state of protection into the object. */ function loadData() { - global $wgRequest, $wgUser; - - $levels = MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace(), $wgUser ); + $levels = MWNamespace::getRestrictionLevels( + $this->mTitle->getNamespace(), $this->mContext->getUser() + ); $this->mCascade = $this->mTitle->areRestrictionsCascading(); - $this->mReason = $wgRequest->getText( 'mwProtect-reason' ); - $this->mReasonSelection = $wgRequest->getText( 'wpProtectReasonSelection' ); - $this->mCascade = $wgRequest->getBool( 'mwProtect-cascade', $this->mCascade ); + $request = $this->mContext->getRequest(); + $this->mReason = $request->getText( 'mwProtect-reason' ); + $this->mReasonSelection = $request->getText( 'wpProtectReasonSelection' ); + $this->mCascade = $request->getBool( 'mwProtect-cascade', $this->mCascade ); foreach ( $this->mApplicableTypes as $action ) { // @todo FIXME: This form currently requires individual selections, @@ -106,8 +112,8 @@ class ProtectionForm { } $this->mExistingExpiry[$action] = $existingExpiry; - $requestExpiry = $wgRequest->getText( "mwProtect-expiry-$action" ); - $requestExpirySelection = $wgRequest->getVal( "wpProtectExpirySelection-$action" ); + $requestExpiry = $request->getText( "mwProtect-expiry-$action" ); + $requestExpirySelection = $request->getVal( "wpProtectExpirySelection-$action" ); if ( $requestExpiry ) { // Custom expiry takes precedence @@ -128,7 +134,7 @@ class ProtectionForm { $this->mExpirySelection[$action] = 'infinite'; } - $val = $wgRequest->getVal( "mwProtect-level-$action" ); + $val = $request->getVal( "mwProtect-level-$action" ); if ( isset( $val ) && in_array( $val, $levels ) ) { $this->mRestrictions[$action] = $val; } @@ -170,16 +176,14 @@ class ProtectionForm { * Main entry point for action=protect and action=unprotect */ function execute() { - global $wgRequest, $wgOut; - if ( MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace() ) === array( '' ) ) { throw new ErrorPageError( 'protect-badnamespace-title', 'protect-badnamespace-text' ); } - if ( $wgRequest->wasPosted() ) { + if ( $this->mContext->getRequest()->wasPosted() ) { if ( $this->save() ) { $q = $this->mArticle->isRedirect() ? 'redirect=no' : ''; - $wgOut->redirect( $this->mTitle->getFullURL( $q ) ); + $this->mContext->getOutput()->redirect( $this->mTitle->getFullURL( $q ) ); } } else { $this->show(); @@ -192,28 +196,27 @@ class ProtectionForm { * @param string $err Error message or null if there's no error */ function show( $err = null ) { - global $wgOut; - - $wgOut->setRobotPolicy( 'noindex,nofollow' ); - $wgOut->addBacklinkSubtitle( $this->mTitle ); + $out = $this->mContext->getOutput(); + $out->setRobotPolicy( 'noindex,nofollow' ); + $out->addBacklinkSubtitle( $this->mTitle ); if ( is_array( $err ) ) { - $wgOut->wrapWikiMsg( "

\n$1\n

\n", $err ); + $out->wrapWikiMsg( "

\n$1\n

\n", $err ); } elseif ( is_string( $err ) ) { - $wgOut->addHTML( "

{$err}

\n" ); + $out->addHTML( "

{$err}

\n" ); } if ( $this->mTitle->getRestrictionTypes() === array() ) { // No restriction types available for the current title // this might happen if an extension alters the available types - $wgOut->setPageTitle( wfMessage( + $out->setPageTitle( wfMessage( 'protect-norestrictiontypes-title', $this->mTitle->getPrefixedText() ) ); - $wgOut->addWikiText( wfMessage( 'protect-norestrictiontypes-text' )->text() ); + $out->addWikiText( wfMessage( 'protect-norestrictiontypes-text' )->text() ); // Show the log in case protection was possible once - $this->showLogExtract( $wgOut ); + $this->showLogExtract( $out ); // return as there isn't anything else we can do return; } @@ -227,7 +230,7 @@ class ProtectionForm { } /** @todo FIXME: i18n issue, should use formatted number. */ - $wgOut->wrapWikiMsg( + $out->wrapWikiMsg( "
\n$1\n" . $titles . "
", array( 'protect-cascadeon', count( $cascadeSources ) ) ); @@ -236,19 +239,19 @@ class ProtectionForm { # Show an appropriate message if the user isn't allowed or able to change # the protection settings at this time if ( $this->disabled ) { - $wgOut->setPageTitle( + $out->setPageTitle( wfMessage( 'protect-title-notallowed', $this->mTitle->getPrefixedText() ) ); - $wgOut->addWikiText( $wgOut->formatPermissionsErrorMessage( $this->mPermErrors, 'protect' ) ); + $out->addWikiText( $out->formatPermissionsErrorMessage( $this->mPermErrors, 'protect' ) ); } else { - $wgOut->setPageTitle( wfMessage( 'protect-title', $this->mTitle->getPrefixedText() ) ); - $wgOut->addWikiMsg( 'protect-text', + $out->setPageTitle( wfMessage( 'protect-title', $this->mTitle->getPrefixedText() ) ); + $out->addWikiMsg( 'protect-text', wfEscapeWikiText( $this->mTitle->getPrefixedText() ) ); } - $wgOut->addHTML( $this->buildForm() ); - $this->showLogExtract( $wgOut ); + $out->addHTML( $this->buildForm() ); + $this->showLogExtract( $out ); } /** @@ -257,16 +260,17 @@ class ProtectionForm { * @return bool Success */ function save() { - global $wgRequest, $wgUser, $wgOut; - # Permission check! if ( $this->disabled ) { $this->show(); return false; } - $token = $wgRequest->getVal( 'wpEditToken' ); - if ( !$wgUser->matchEditToken( $token, array( 'protect', $this->mTitle->getPrefixedDBkey() ) ) ) { + $request = $this->mContext->getRequest(); + $user = $this->mContext->getUser(); + $out = $this->mContext->getOutput(); + $token = $request->getVal( 'wpEditToken' ); + if ( !$user->matchEditToken( $token, array( 'protect', $this->mTitle->getPrefixedDBkey() ) ) ) { $this->show( array( 'sessionfailure' ) ); return false; } @@ -295,18 +299,18 @@ class ProtectionForm { } } - $this->mCascade = $wgRequest->getBool( 'mwProtect-cascade' ); + $this->mCascade = $request->getBool( 'mwProtect-cascade' ); $status = $this->mArticle->doUpdateRestrictions( $this->mRestrictions, $expiry, $this->mCascade, $reasonstr, - $wgUser + $user ); if ( !$status->isOK() ) { - $this->show( $wgOut->parseInline( $status->getWikiText() ) ); + $this->show( $out->parseInline( $status->getWikiText() ) ); return false; } @@ -327,7 +331,7 @@ class ProtectionForm { return false; } - WatchAction::doWatchOrUnwatch( $wgRequest->getCheck( 'mwProtectWatch' ), $this->mTitle, $wgUser ); + WatchAction::doWatchOrUnwatch( $request->getCheck( 'mwProtectWatch' ), $this->mTitle, $user ); return true; } @@ -338,12 +342,14 @@ class ProtectionForm { * @return string HTML form */ function buildForm() { - global $wgUser, $wgLang, $wgOut, $wgCascadingRestrictionLevels; - + $user = $this->mContext->getUser(); + $output = $this->mContext->getOutput(); + $lang = $this->mContext->getLanguage(); + $cascadingRestrictionLevels = $this->mContext->getConfig()->get( 'CascadingRestrictionLevels' ); $out = ''; if ( !$this->disabled ) { - $wgOut->addModules( 'mediawiki.legacy.protect' ); - $wgOut->addJsConfigVars( 'wgCascadeableLevels', $wgCascadingRestrictionLevels ); + $output->addModules( 'mediawiki.legacy.protect' ); + $output->addJsConfigVars( 'wgCascadeableLevels', $cascadingRestrictionLevels ); $out .= Xml::openElement( 'form', array( 'method' => 'post', 'action' => $this->mTitle->getLocalURL( 'action=protect' ), 'id' => 'mw-Protect-Form', 'onsubmit' => 'ProtectionForm.enableUnchainedInputs(true)' ) ); @@ -379,9 +385,9 @@ class ProtectionForm { $expiryFormOptions = ''; if ( $this->mExistingExpiry[$action] && $this->mExistingExpiry[$action] != 'infinity' ) { - $timestamp = $wgLang->timeanddate( $this->mExistingExpiry[$action], true ); - $d = $wgLang->date( $this->mExistingExpiry[$action], true ); - $t = $wgLang->time( $this->mExistingExpiry[$action], true ); + $timestamp = $lang->timeanddate( $this->mExistingExpiry[$action], true ); + $d = $lang->date( $this->mExistingExpiry[$action], true ); + $t = $lang->time( $this->mExistingExpiry[$action], true ); $expiryFormOptions .= Xml::option( wfMessage( 'protect-existing-expiry', $timestamp, $d, $t )->text(), @@ -508,14 +514,14 @@ class ProtectionForm { " "; # Disallow watching is user is not logged in - if ( $wgUser->isLoggedIn() ) { + if ( $user->isLoggedIn() ) { $out .= " " . Xml::checkLabel( wfMessage( 'watchthis' )->text(), 'mwProtectWatch', 'mwProtectWatch', - $wgUser->isWatched( $this->mTitle ) || $wgUser->getOption( 'watchdefault' ) ) . + $user->isWatched( $this->mTitle ) || $user->getOption( 'watchdefault' ) ) . " "; } @@ -533,7 +539,7 @@ class ProtectionForm { } $out .= Xml::closeElement( 'fieldset' ); - if ( $wgUser->isAllowed( 'editinterface' ) ) { + if ( $user->isAllowed( 'editinterface' ) ) { $title = Title::makeTitle( NS_MEDIAWIKI, 'Protect-dropdown' ); $link = Linker::link( $title, @@ -547,10 +553,10 @@ class ProtectionForm { if ( !$this->disabled ) { $out .= Html::hidden( 'wpEditToken', - $wgUser->getEditToken( array( 'protect', $this->mTitle->getPrefixedDBkey() ) ) + $user->getEditToken( array( 'protect', $this->mTitle->getPrefixedDBkey() ) ) ); $out .= Xml::closeElement( 'form' ); - $wgOut->addScript( $this->buildCleanupScript() ); + $output->addScript( $this->buildCleanupScript() ); } return $out; @@ -564,12 +570,10 @@ class ProtectionForm { * @return string HTML fragment */ function buildSelector( $action, $selected ) { - global $wgUser; - // If the form is disabled, display all relevant levels. Otherwise, // just show the ones this user can use. $levels = MWNamespace::getRestrictionLevels( $this->mTitle->getNamespace(), - $this->disabled ? null : $wgUser + $this->disabled ? null : $this->mContext->getUser() ); $id = 'mwProtect-level-' . $action; diff --git a/includes/Title.php b/includes/Title.php index 7fdeb05511..ca292eefcf 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -3931,9 +3931,13 @@ class Title { $redirectContent = null; } + // bug 57084: log_page should be the ID of the *moved* page + $oldid = $this->getArticleID(); + $logTitle = clone $this; + $logEntry = new ManualLogEntry( 'move', $logType ); $logEntry->setPerformer( $wgUser ); - $logEntry->setTarget( $this ); + $logEntry->setTarget( $logTitle ); $logEntry->setComment( $reason ); $logEntry->setParameters( array( '4::target' => $nt->getPrefixedText(), @@ -3949,8 +3953,6 @@ class Title { # Truncate for whole multibyte characters. $comment = $wgContLang->truncate( $comment, 255 ); - $oldid = $this->getArticleID(); - $dbw = wfGetDB( DB_MASTER ); $newpage = WikiPage::factory( $nt ); diff --git a/includes/User.php b/includes/User.php index 665edb973c..942ba82393 100644 --- a/includes/User.php +++ b/includes/User.php @@ -829,7 +829,7 @@ class User implements IDBAccessObject { * @param int $ts Optional timestamp to convert, default 0 for the current time */ public function expirePassword( $ts = 0 ) { - $this->load(); + $this->loadPasswords(); $timestamp = wfTimestamp( TS_MW, $ts ); $this->mPasswordExpires = $timestamp; $this->saveSettings(); @@ -3788,12 +3788,14 @@ class User implements IDBAccessObject { */ public function checkPassword( $password ) { global $wgAuth, $wgLegacyEncoding; + + $section = new ProfileSection( __METHOD__ ); + $this->loadPasswords(); // Certain authentication plugins do NOT want to save // domain passwords in a mysql database, so we should // check this (in case $wgAuth->strict() is false). - if ( $wgAuth->authenticate( $this->getName(), $password ) ) { return true; } elseif ( $wgAuth->strict() ) { diff --git a/includes/WebRequest.php b/includes/WebRequest.php index a1fa0eb775..b187c4acef 100644 --- a/includes/WebRequest.php +++ b/includes/WebRequest.php @@ -181,7 +181,12 @@ class WebRequest { continue; } $host = $parts[0]; - if ( $parts[1] === false ) { + if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) ) { + // Bug 70021: Assume that upstream proxy is running on the default + // port based on the protocol. We have no reliable way to determine + // the actual port in use upstream. + $port = $stdPort; + } elseif ( $parts[1] === false ) { if ( isset( $_SERVER['SERVER_PORT'] ) ) { $port = $_SERVER['SERVER_PORT']; } // else leave it as $stdPort diff --git a/includes/WebStart.php b/includes/WebStart.php index 84a9ae6fe7..e137628c5e 100644 --- a/includes/WebStart.php +++ b/includes/WebStart.php @@ -1,7 +1,12 @@ getOutput(); @@ -344,6 +366,7 @@ abstract class Action { /** * Returns the description that goes below the \ tag + * @since 1.17 * * @return string */ @@ -355,6 +378,8 @@ abstract class Action { * The main action entry point. Do all output for display and send it to the context * output. Do not use globals $wgOut, $wgRequest, etc, in implementations; use * $this->getOutput(), etc. + * @since 1.17 + * * @throws ErrorPageError */ abstract public function show(); diff --git a/includes/api/ApiQueryBase.php b/includes/api/ApiQueryBase.php index afb939befe..6b08fc5c87 100644 --- a/includes/api/ApiQueryBase.php +++ b/includes/api/ApiQueryBase.php @@ -576,7 +576,7 @@ abstract class ApiQueryBase extends ApiBase { * @return bool True if acceptable, false otherwise */ protected function checkRowCount() { - wfDeprecated( __METHOD__, 1.24 ); + wfDeprecated( __METHOD__, '1.24' ); $db = $this->getDB(); $this->profileDBIn(); $rowcount = $db->estimateRowCount( @@ -603,7 +603,7 @@ abstract class ApiQueryBase extends ApiBase { * @return string Page title with underscores */ public function titleToKey( $title ) { - wfDeprecated( __METHOD__, 1.24 ); + wfDeprecated( __METHOD__, '1.24' ); // Don't throw an error if we got an empty string if ( trim( $title ) == '' ) { return ''; @@ -623,7 +623,7 @@ abstract class ApiQueryBase extends ApiBase { * @return string Page title with spaces */ public function keyToTitle( $key ) { - wfDeprecated( __METHOD__, 1.24 ); + wfDeprecated( __METHOD__, '1.24' ); // Don't throw an error if we got an empty string if ( trim( $key ) == '' ) { return ''; @@ -644,7 +644,7 @@ abstract class ApiQueryBase extends ApiBase { * @return string Key part with underscores */ public function keyPartToTitle( $keyPart ) { - wfDeprecated( __METHOD__, 1.24 ); + wfDeprecated( __METHOD__, '1.24' ); return substr( $this->keyToTitle( $keyPart . 'x' ), 0, -1 ); } diff --git a/includes/api/ApiQueryInfo.php b/includes/api/ApiQueryInfo.php index 3ac9c8ac1d..d7037e3a19 100644 --- a/includes/api/ApiQueryInfo.php +++ b/includes/api/ApiQueryInfo.php @@ -458,6 +458,7 @@ class ApiQueryInfo extends ApiQueryBase { if ( $this->fld_url ) { $pageInfo['fullurl'] = wfExpandUrl( $title->getFullURL(), PROTO_CURRENT ); $pageInfo['editurl'] = wfExpandUrl( $title->getFullURL( 'action=edit' ), PROTO_CURRENT ); + $pageInfo['canonicalurl'] = wfExpandUrl( $title->getFullURL(), PROTO_CANONICAL ); } if ( $this->fld_readable && $title->userCan( 'read', $this->getUser() ) ) { $pageInfo['readable'] = ''; @@ -837,7 +838,7 @@ class ApiQueryInfo extends ApiQueryBase { ' watchers - The number of watchers, if allowed', ' notificationtimestamp - The watchlist notification timestamp of each page', ' subjectid - The page ID of the parent page for each talk page', - ' url - Gives a full URL to the page, and also an edit URL', + ' url - Gives a full URL, an edit URL, and the canonical URL for each page', ' readable - Whether the user can read this page', ' preload - Gives the text returned by EditFormPreloadText', ' displaytitle - Gives the way the page title is actually displayed', diff --git a/includes/api/ApiQuerySiteinfo.php b/includes/api/ApiQuerySiteinfo.php index 04892a1ef0..522c7c0805 100644 --- a/includes/api/ApiQuerySiteinfo.php +++ b/includes/api/ApiQuerySiteinfo.php @@ -843,7 +843,7 @@ class ApiQuerySiteinfo extends ApiQueryBase { ' fileextensions - Returns list of file extensions allowed to be uploaded', ' rightsinfo - Returns wiki rights (license) information if available', ' restrictions - Returns information on available restriction (protection) types', - ' languages - Returns a list of languages MediaWiki supports' . + ' languages - Returns a list of languages MediaWiki supports ' . "(optionally localised by using {$p}inlanguagecode)", ' skins - Returns a list of all enabled skins', ' extensiontags - Returns a list of parser extension tags', diff --git a/includes/cache/LocalisationCache.php b/includes/cache/LocalisationCache.php index bdfe51010b..bdfc75a6ef 100644 --- a/includes/cache/LocalisationCache.php +++ b/includes/cache/LocalisationCache.php @@ -843,73 +843,109 @@ class LocalisationCache { if ( $coreData['fallbackSequence'][$len - 1] !== 'en' ) { $coreData['fallbackSequence'][] = 'en'; } + } - # Load the fallback localisation item by item and merge it - foreach ( $coreData['fallbackSequence'] as $fbCode ) { - # Load the secondary localisation from the source file to - # avoid infinite cycles on cyclic fallbacks - $fbData = $this->readSourceFilesAndRegisterDeps( $fbCode, $deps ); - if ( $fbData === false ) { - continue; - } + $codeSequence = array_merge( array( $code ), $coreData['fallbackSequence'] ); - foreach ( self::$allKeys as $key ) { - if ( !isset( $fbData[$key] ) ) { - continue; - } + wfProfileIn( __METHOD__ . '-fallbacks' ); + + # Load non-JSON localisation data for extensions + $extensionData = array_combine( + $codeSequence, + array_fill( 0, count( $codeSequence ), $initialData ) ); + foreach ( $wgExtensionMessagesFiles as $extension => $fileName ) { + if ( isset( $wgMessagesDirs[$extension] ) ) { + # This extension has JSON message data; skip the PHP shim + continue; + } + + $data = $this->readPHPFile( $fileName, 'extension' ); + $used = false; - if ( is_null( $coreData[$key] ) || $this->isMergeableKey( $key ) ) { - $this->mergeItem( $key, $coreData[$key], $fbData[$key] ); + foreach ( $data as $key => $item ) { + foreach ( $codeSequence as $csCode ) { + if ( isset( $item[$csCode] ) ) { + $this->mergeItem( $key, $extensionData[$csCode][$key], $item[$csCode] ); + $used = true; } } } - } - $codeSequence = array_merge( array( $code ), $coreData['fallbackSequence'] ); + if ( $used ) { + $deps[] = new FileDependency( $fileName ); + } + } - # Load core messages and the extension localisations. - wfProfileIn( __METHOD__ . '-extensions' ); + # Load the localisation data for each fallback, then merge it into the full array $allData = $initialData; - foreach ( $wgMessagesDirs as $dirs ) { - foreach ( (array)$dirs as $dir ) { - foreach ( $codeSequence as $csCode ) { + foreach ( $codeSequence as $csCode ) { + $csData = $initialData; + + # Load core messages and the extension localisations. + foreach ( $wgMessagesDirs as $dirs ) { + foreach ( (array)$dirs as $dir ) { $fileName = "$dir/$csCode.json"; $data = $this->readJSONFile( $fileName ); foreach ( $data as $key => $item ) { - $this->mergeItem( $key, $allData[$key], $item ); + $this->mergeItem( $key, $csData[$key], $item ); } $deps[] = new FileDependency( $fileName ); } } - } - foreach ( $wgExtensionMessagesFiles as $extension => $fileName ) { - if ( isset( $wgMessagesDirs[$extension] ) ) { - # Already loaded the JSON files for this extension; skip the PHP shim - continue; + # Merge non-JSON extension data + if ( isset( $extensionData[$csCode] ) ) { + foreach ( $extensionData[$csCode] as $key => $item ) { + $this->mergeItem( $key, $csData[$key], $item ); + } } - $data = $this->readPHPFile( $fileName, 'extension' ); - $used = false; - - foreach ( $data as $key => $item ) { - if ( $this->mergeExtensionItem( $codeSequence, $key, $allData[$key], $item ) ) { - $used = true; + if ( $csCode === $code ) { + # Merge core data into extension data + foreach ( $coreData as $key => $item ) { + $this->mergeItem( $key, $csData[$key], $item ); + } + } else { + # Load the secondary localisation from the source file to + # avoid infinite cycles on cyclic fallbacks + $fbData = $this->readSourceFilesAndRegisterDeps( $csCode, $deps ); + if ( $fbData !== false ) { + # Only merge the keys that make sense to merge + foreach ( self::$allKeys as $key ) { + if ( !isset( $fbData[$key] ) ) { + continue; + } + + if ( is_null( $coreData[$key] ) || $this->isMergeableKey( $key ) ) { + $this->mergeItem( $key, $csData[$key], $fbData[$key] ); + } + } } } - if ( $used ) { - $deps[] = new FileDependency( $fileName ); + # Allow extensions an opportunity to adjust the data for this + # fallback + wfRunHooks( 'LocalisationCacheRecacheFallback', array( $this, $csCode, &$csData ) ); + + # Merge the data for this fallback into the final array + if ( $csCode === $code ) { + $allData = $csData; + } else { + foreach ( self::$allKeys as $key ) { + if ( !isset( $csData[$key] ) ) { + continue; + } + + if ( is_null( $allData[$key] ) || $this->isMergeableKey( $key ) ) { + $this->mergeItem( $key, $allData[$key], $csData[$key] ); + } + } } } - # Merge core data into extension data - foreach ( $coreData as $key => $item ) { - $this->mergeItem( $key, $allData[$key], $item ); - } - wfProfileOut( __METHOD__ . '-extensions' ); + wfProfileOut( __METHOD__ . '-fallbacks' ); # Add cache dependencies for any referenced globals $deps['wgExtensionMessagesFiles'] = new GlobalDependency( 'wgExtensionMessagesFiles' ); diff --git a/includes/cache/bloom/BloomCache.php b/includes/cache/bloom/BloomCache.php new file mode 100644 index 0000000000..236db9544c --- /dev/null +++ b/includes/cache/bloom/BloomCache.php @@ -0,0 +1,323 @@ + BloomCache) */ + protected static $instances = array(); + + /** + * @param string $id + * @return BloomCache + */ + final public static function get( $id ) { + global $wgBloomFilterStores; + + if ( !isset( self::$instances[$id] ) ) { + if ( isset( $wgBloomFilterStores[$id] ) ) { + $class = $wgBloomFilterStores[$id]['class']; + self::$instances[$id] = new $class( $wgBloomFilterStores[$id] ); + } else { + wfDebug( "No bloom filter store '$id'; using EmptyBloomCache." ); + return new EmptyBloomCache( array() ); + } + } + + return self::$instances[$id]; + } + + /** + * Create a new bloom cache instance from configuration. + * This should only be called from within BloomCache. + * + * @param array $config Parameters include: + * - cacheID : Prefix to all bloom filter names that is unique to this cache. + * It should only consist of alphanumberic, '-', and '_' characters. + * This ID is what avoids collisions if multiple logical caches + * use the same storage system, so this should be set carefully. + */ + public function __construct( array $config ) { + $this->cacheID = $config['cacheId']; + if ( !preg_match( '!^[a-zA-Z0-9-_]{1,32}$!', $this->cacheID ) ) { + throw new MWException( "Cache ID '{$this->cacheID}' is invalid." ); + } + } + + /** + * Check if a member is set in the bloom filter + * + * A member being set means that it *might* have been added. + * A member not being set means it *could not* have been added. + * + * This abstracts over isHit() to deal with filter updates and readiness. + * A class must exist with the name BloomFilter and a static public + * mergeAndCheck() method. The later takes the following arguments: + * (BloomCache $bcache, $domain, $virtualKey, array $status) + * The method should return a bool indicating whether to use the filter. + * + * The 'shared' bloom key must be used for any updates and will be used + * for the membership check if the method returns true. Since the key is shared, + * the method should never use delete(). The filter cannot be used in cases where + * membership in the filter needs to be taken away. In such cases, code *cannot* + * use this method - instead, it can directly use the other BloomCache methods + * to manage custom filters with their own keys (e.g. not 'shared'). + * + * @param string $domain + * @param string $type + * @param string $member + * @return bool True if set, false if not (also returns true on error) + */ + final public function check( $domain, $type, $member ) { + $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ ); + + if ( method_exists( "BloomFilter{$type}", 'mergeAndCheck' ) ) { + try { + $virtualKey = "$domain:$type"; + + $status = $this->getStatus( $virtualKey ); + if ( $status == false ) { + wfDebug( "Could not query virtual bloom filter '$virtualKey'." ); + return null; + } + + $useFilter = call_user_func_array( + array( "BloomFilter{$type}", 'mergeAndCheck' ), + array( $this, $domain, $virtualKey, $status ) + ); + + if ( $useFilter ) { + return ( $this->isHit( 'shared', "$virtualKey:$member" ) !== false ); + } + } catch ( MWException $e ) { + MWExceptionHandler::logException( $e ); + return true; + } + } + + return true; + } + + /** + * Inform the bloom filter of a new member in order to keep it up to date + * + * @param string $domain + * @param string $type + * @param string|array $members + * @return bool Success + */ + final public function insert( $domain, $type, $members ) { + $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ ); + + if ( method_exists( "BloomFilter{$type}", 'mergeAndCheck' ) ) { + try { + $virtualKey = "$domain:$type"; + $prefixedMembers = array(); + foreach ( (array)$members as $member ) { + $prefixedMembers[] = "$virtualKey:$member"; + } + + return $this->add( 'shared', $prefixedMembers ); + } catch ( MWException $e ) { + MWExceptionHandler::logException( $e ); + return false; + } + } + + return true; + } + + /** + * Create a new bloom filter at $key (if one does not exist yet) + * + * @param string $key + * @param integer $size Bit length [default: 1000000] + * @param float $precision [default: .001] + * @return bool Success + */ + final public function init( $key, $size = 1000000, $precision = .001 ) { + $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ ); + + return $this->doInit( "{$this->cacheID}:$key", $size, min( .1, $precision ) ); + } + + /** + * Add a member to the bloom filter at $key + * + * @param string $key + * @param string|array $members + * @return bool Success + */ + final public function add( $key, $members ) { + $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ ); + + return $this->doAdd( "{$this->cacheID}:$key", (array)$members ); + } + + /** + * Check if a member is set in the bloom filter. + * + * A member being set means that it *might* have been added. + * A member not being set means it *could not* have been added. + * + * If this returns true, then the caller usually should do the + * expensive check (whatever that may be). It can be avoided otherwise. + * + * @param string $key + * @param string $member + * @return bool|null True if set, false if not, null on error + */ + final public function isHit( $key, $member ) { + $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ ); + + return $this->doIsHit( "{$this->cacheID}:$key", $member ); + } + + /** + * Destroy a bloom filter at $key + * + * @param string $key + * @return bool Success + */ + final public function delete( $key ) { + $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ ); + + return $this->doDelete( "{$this->cacheID}:$key" ); + } + + /** + * Set the status map of the virtual bloom filter at $key + * + * @param string $virtualKey + * @param array $values Map including some of (lastID, asOfTime, epoch) + * @return bool Success + */ + final public function setStatus( $virtualKey, array $values ) { + $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ ); + + return $this->doSetStatus( "{$this->cacheID}:$virtualKey", $values ); + } + + /** + * Get the status map of the virtual bloom filter at $key + * + * The map includes: + * - lastID : the highest ID of the items merged in + * - asOfTime : UNIX timestamp that the filter is up-to-date as of + * - epoch : UNIX timestamp that filter started being populated + * Unset fields will have a null value. + * + * @param string $virtualKey + * @return array|bool False on failure + */ + final public function getStatus( $virtualKey ) { + $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ ); + + return $this->doGetStatus( "{$this->cacheID}:$virtualKey" ); + } + + /** + * Get an exclusive lock on a filter for updates + * + * @param string $virtualKey + * @return ScopedCallback|ScopedLock|null Returns null if acquisition failed + */ + public function getScopedLock( $virtualKey ) { + return null; + } + + /** + * @param string $key + * @param integer $size Bit length + * @param float $precision + * @return bool Success + */ + abstract protected function doInit( $key, $size, $precision ); + + /** + * @param string $key + * @param array $members + * @return bool Success + */ + abstract protected function doAdd( $key, array $members ); + + /** + * @param string $key + * @param string $member + * @return bool|null + */ + abstract protected function doIsHit( $key, $member ); + + /** + * @param string $key + * @return bool Success + */ + abstract protected function doDelete( $key ); + + /** + * @param string $virtualKey + * @param array $values + * @return bool Success + */ + abstract protected function doSetStatus( $virtualKey, array $values ); + + /** + * @param string $key + * @return array|bool + */ + abstract protected function doGetStatus( $key ); +} + +class EmptyBloomCache extends BloomCache { + public function __construct( array $config ) { + parent::__construct( array( 'cacheId' => 'none' ) ); + } + + protected function doInit( $key, $size, $precision ) { + return true; + } + + protected function doAdd( $key, array $members ) { + return true; + } + + protected function doIsHit( $key, $member ) { + return true; + } + + protected function doDelete( $key ) { + return true; + } + + protected function doSetStatus( $virtualKey, array $values ) { + return true; + } + + protected function doGetStatus( $virtualKey ) { + return array( 'lastID' => null, 'asOfTime' => null, 'epoch' => null ) ; + } +} diff --git a/includes/cache/bloom/BloomCacheRedis.php b/includes/cache/bloom/BloomCacheRedis.php new file mode 100644 index 0000000000..7bafc99369 --- /dev/null +++ b/includes/cache/bloom/BloomCacheRedis.php @@ -0,0 +1,370 @@ += 2.6 and should have volatile-lru or volatile-ttl + * if there is any eviction policy. It should not be allkeys-* in any case. Also, + * this can be used in a simple master/slave setup or with Redis Sentinal preferably. + * + * Some bits are based on https://github.com/ErikDubbelboer/redis-lua-scaling-bloom-filter + * but are simplified to use a single filter instead of up to 32 filters. + * + * @since 1.24 + */ +class BloomCacheRedis extends BloomCache { + /** @var RedisConnectionPool */ + protected $redisPool; + /** @var RedisLockManager */ + protected $lockMgr; + /** @var array */ + protected $servers; + /** @var integer Federate each filter into this many redis bitfield objects */ + protected $segments = 128; + + /** + * @params include: + * - redisServers : list of servers (address:) (the first is the master) + * - redisConf : additional redis configuration + * + * @param array $config + */ + public function __construct( array $config ) { + parent::__construct( $config ); + + $redisConf = $config['redisConfig']; + $redisConf['serializer'] = 'none'; // manage that in this class + $this->redisPool = RedisConnectionPool::singleton( $redisConf ); + $this->servers = $config['redisServers']; + $this->lockMgr = new RedisLockManager( array( + 'lockServers' => array( 'srv1' => $this->servers[0] ), + 'srvsByBucket' => array( 0 => array( 'srv1' ) ), + 'redisConfig' => $config['redisConfig'] + ) ); + } + + protected function doInit( $key, $size, $precision ) { + $conn = $this->getConnection( 'master' ); + if ( !$conn ) { + return false; + } + + // 80000000 items at p = .001 take up 500MB and fit into one value. + // Do not hit the 512MB redis value limit by reducing the demands. + $size = min( $size, 80000000 * $this->segments ); + $precision = max( round( $precision, 3 ), .001 ); + $epoch = microtime( true ); + + static $script = +<<script( 'load', $script ); + $conn->multi( Redis::MULTI ); + for ( $i = 0; $i < $this->segments; ++$i ) { + $res = $conn->luaEval( $script, + array( + "$key:$i:bloom-metadata", # KEYS[1] + "$key:$i:bloom-data", # KEYS[2] + ceil( $size / $this->segments ), # ARGV[1] + $precision, # ARGV[2] + $epoch # ARGV[3] + ), + 2 # number of first argument(s) that are keys + ); + } + $results = $conn->exec(); + $res = $results && !in_array( false, $results, true ); + } catch ( RedisException $e ) { + $this->handleException( $conn, $e ); + } + + return ( $res !== false ); + } + + protected function doAdd( $key, array $members ) { + $conn = $this->getConnection( 'master' ); + if ( !$conn ) { + return false; + } + + static $script = +<<script( 'load', $script ); + $conn->multi( Redis::PIPELINE ); + foreach ( $members as $member ) { + $i = $this->getSegment( $member ); + $conn->luaEval( $script, + array( + "$key:$i:bloom-metadata", # KEYS[1], + "$key:$i:bloom-data", # KEYS[2] + $member # ARGV[1] + ), + 2 # number of first argument(s) that are keys + ); + } + $results = $conn->exec(); + $res = $results && !in_array( false, $results, true ); + } catch ( RedisException $e ) { + $this->handleException( $conn, $e ); + } + + if ( $res === false ) { + wfDebug( "Could not add to the '$key' bloom filter; it may be missing." ); + } + + return ( $res !== false ); + } + + protected function doSetStatus( $virtualKey, array $values ) { + $conn = $this->getConnection( 'master' ); + if ( !$conn ) { + return null; + } + + $res = false; + try { + $res = $conn->hMSet( "$virtualKey:filter-metadata", $values ); + } catch ( RedisException $e ) { + $this->handleException( $conn, $e ); + } + + return ( $res !== false ); + } + + protected function doGetStatus( $virtualKey ) { + $conn = $this->getConnection( 'slave' ); + if ( !$conn ) { + return false; + } + + $res = false; + try { + $res = $conn->hGetAll( "$virtualKey:filter-metadata" ); + } catch ( RedisException $e ) { + $this->handleException( $conn, $e ); + } + + if ( is_array( $res ) ) { + $res['lastID'] = isset( $res['lastID'] ) ? $res['lastID'] : null; + $res['asOfTime'] = isset( $res['asOfTime'] ) ? $res['asOfTime'] : null; + $res['epoch'] = isset( $res['epoch'] ) ? $res['epoch'] : null; + } + + return $res; + } + + protected function doIsHit( $key, $member ) { + $conn = $this->getConnection( 'slave' ); + if ( !$conn ) { + return null; + } + + static $script = +<<getSegment( $member ); + $res = $conn->luaEval( $script, + array( + "$key:$i:bloom-metadata", # KEYS[1], + "$key:$i:bloom-data", # KEYS[2] + $member # ARGV[1] + ), + 2 # number of first argument(s) that are keys + ); + } catch ( RedisException $e ) { + $this->handleException( $conn, $e ); + } + + return is_int( $res ) ? (bool)$res : null; + } + + protected function doDelete( $key ) { + $conn = $this->getConnection( 'master' ); + if ( !$conn ) { + return false; + } + + $res = false; + try { + $keys = array(); + for ( $i = 0; $i < $this->segments; ++$i ) { + $keys[] = "$key:$i:bloom-metadata"; + $keys[] = "$key:$i:bloom-data"; + } + $res = $conn->delete( $keys ); + } catch ( RedisException $e ) { + $this->handleException( $conn, $e ); + } + + return ( $res !== false ); + } + + public function getScopedLock( $virtualKey ) { + $status = Status::newGood(); + return ScopedLock::factory( $this->lockMgr, + array( $virtualKey ), LockManager::LOCK_EX, $status ); + } + + /** + * @param string $member + * @return integer + */ + protected function getSegment( $member ) { + return hexdec( substr( md5( $member ), 0, 2 ) ) % $this->segments; + } + + /** + * $param string $to (master/slave) + * @return RedisConnRef|bool Returns false on failure + */ + protected function getConnection( $to ) { + if ( $to === 'master' ) { + $conn = $this->redisPool->getConnection( $this->servers[0] ); + } else { + static $lastServer = null; + + $conn = false; + if ( $lastServer ) { + $conn = $this->redisPool->getConnection( $lastServer ); + if ( $conn ) { + return $conn; // reuse connection + } + } + $servers = $this->servers; + $attempts = min( 3, count( $servers ) ); + for ( $i = 1; $i <= $attempts; ++$i ) { + $index = mt_rand( 0, count( $servers ) - 1 ); + $conn = $this->redisPool->getConnection( $servers[$index] ); + if ( $conn ) { + $lastServer = $servers[$index]; + return $conn; + } + unset( $servers[$index] ); // skip next time + } + } + + return $conn; + } + + /** + * @param RedisConnRef $conn + * @param Exception $e + */ + protected function handleException( RedisConnRef $conn, $e ) { + $this->redisPool->handleError( $conn, $e ); + } +} diff --git a/includes/cache/bloom/BloomFilters.php b/includes/cache/bloom/BloomFilters.php new file mode 100644 index 0000000000..9b710d7905 --- /dev/null +++ b/includes/cache/bloom/BloomFilters.php @@ -0,0 +1,79 @@ +getScopedLock( $virtualKey ) + : false; + + if ( $scopedLock ) { + $updates = self::merge( $bcache, $domain, $virtualKey, $status ); + if ( isset( $updates['asOfTime'] ) ) { + $age = ( microtime( true ) - $updates['asOfTime'] ); + } + } + + return ( $age < 30 ); + } + + public static function merge( + BloomCache $bcache, $domain, $virtualKey, array $status + ) { + $limit = 1000; + $dbr = wfGetDB( DB_SLAVE, array(), $domain ); + $res = $dbr->select( 'logging', + array( 'log_namespace', 'log_title', 'log_id', 'log_timestamp' ), + array( 'log_id > ' . $dbr->addQuotes( (int)$status['lastID'] ) ), + __METHOD__, + array( 'ORDER BY' => 'log_id', 'LIMIT' => $limit ) + ); + + $updates = array(); + if ( $res->numRows() > 0 ) { + $members = array(); + foreach ( $res as $row ) { + $members[] = "$virtualKey:{$row->log_namespace}:{$row->log_title}"; + } + $lastID = $row->log_id; + $lastTime = $row->log_timestamp; + if ( !$bcache->add( 'shared', $members ) ) { + return false; + } + $updates['lastID'] = $lastID; + $updates['asOfTime'] = wfTimestamp( TS_UNIX, $lastTime ); + } else { + $updates['asOfTime'] = microtime( true ); + } + + $updates['epoch'] = $status['epoch'] ?: microtime( true ); + + $bcache->setStatus( $virtualKey, $updates ); + + return $updates; + } +} diff --git a/includes/changes/ChangesList.php b/includes/changes/ChangesList.php index d3c44afed8..03d1289f4b 100644 --- a/includes/changes/ChangesList.php +++ b/includes/changes/ChangesList.php @@ -36,6 +36,9 @@ class ChangesList extends ContextSource { protected $rclistOpen; protected $rcMoveIndex; + /** @var MapCacheLRU */ + protected $watchingCache; + /** * Changeslist constructor * @@ -50,6 +53,7 @@ class ChangesList extends ContextSource { $this->skin = $obj; } $this->preCacheMessages(); + $this->watchingCache = new MapCacheLRU( 50 ); } /** @@ -458,14 +462,14 @@ class ChangesList extends ContextSource { * @return string */ protected function numberofWatchingusers( $count ) { - static $cache = array(); + $cache = $this->watchingCache; if ( $count > 0 ) { - if ( !isset( $cache[$count] ) ) { - $cache[$count] = $this->msg( 'number_of_watching_users_RCview' ) - ->numParams( $count )->escaped(); + if ( !$cache->has( $count ) ) { + $cache->set( $count, $this->msg( 'number_of_watching_users_RCview' ) + ->numParams( $count )->escaped() ); } - return $cache[$count]; + return $cache->get( $count ); } else { return ''; } diff --git a/includes/changes/OldChangesList.php b/includes/changes/OldChangesList.php index 17c5b6eb1b..b779a029c1 100644 --- a/includes/changes/OldChangesList.php +++ b/includes/changes/OldChangesList.php @@ -21,6 +21,7 @@ */ class OldChangesList extends ChangesList { + /** * Format a line using the old system (aka without any javascript). * @@ -33,10 +34,6 @@ class OldChangesList extends ChangesList { public function recentChangesLine( &$rc, $watched = false, $linenumber = null ) { wfProfileIn( __METHOD__ ); - # Should patrol-related stuff be shown? - $unpatrolled = $this->showAsUnpatrolled( $rc ); - - $s = ''; $classes = array(); // use mw-line-even/mw-line-odd class only if linenumber is given (feature from bug 14468) if ( $linenumber ) { @@ -52,20 +49,52 @@ class OldChangesList extends ChangesList { $classes[] = $watched && $rc->mAttribs['rc_timestamp'] >= $watched ? 'mw-changeslist-line-watched' : 'mw-changeslist-line-not-watched'; + $html = $this->formatChangeLine( $rc, $watched ); + + if ( $this->watchlist ) { + $classes[] = Sanitizer::escapeClass( 'watchlist-' . + $rc->mAttribs['rc_namespace'] . '-' . $rc->mAttribs['rc_title'] ); + } + + if ( !wfRunHooks( 'OldChangesListRecentChangesLine', array( &$this, &$html, $rc, &$classes ) ) ) { + wfProfileOut( __METHOD__ ); + + return false; + } + + wfProfileOut( __METHOD__ ); + + $dateheader = ''; // $html now contains only
  • ...
  • , for hooks' convenience. + $this->insertDateHeader( $dateheader, $rc->mAttribs['rc_timestamp'] ); + + return "$dateheader
  • " . $html . "
  • \n"; + } + + /** + * @param RecentChange $rc + * @param boolean $watched + * + * @return string + */ + private function formatChangeLine( RecentChange $rc, $watched ) { + $html = ''; + if ( $rc->mAttribs['rc_log_type'] ) { $logtitle = SpecialPage::getTitleFor( 'Log', $rc->mAttribs['rc_log_type'] ); - $this->insertLog( $s, $logtitle, $rc->mAttribs['rc_log_type'] ); + $this->insertLog( $html, $logtitle, $rc->mAttribs['rc_log_type'] ); // Log entries (old format) or log targets, and special pages } elseif ( $rc->mAttribs['rc_namespace'] == NS_SPECIAL ) { - list( $name, $subpage ) = SpecialPageFactory::resolveAlias( $rc->mAttribs['rc_title'] ); + list( $name, $htmlubpage ) = SpecialPageFactory::resolveAlias( $rc->mAttribs['rc_title'] ); if ( $name == 'Log' ) { - $this->insertLog( $s, $rc->getTitle(), $subpage ); + $this->insertLog( $html, $rc->getTitle(), $htmlubpage ); } // Regular entries } else { - $this->insertDiffHist( $s, $rc, $unpatrolled ); + $unpatrolled = $this->showAsUnpatrolled( $rc ); + + $this->insertDiffHist( $html, $rc, $unpatrolled ); # M, N, b and ! (minor, new, bot and unpatrolled) - $s .= $this->recentChangesFlags( + $html .= $this->recentChangesFlags( array( 'newpage' => $rc->mAttribs['rc_type'] == RC_NEW, 'minor' => $rc->mAttribs['rc_minor'], @@ -74,56 +103,40 @@ class OldChangesList extends ChangesList { ), '' ); - $this->insertArticleLink( $s, $rc, $unpatrolled, $watched ); + $this->insertArticleLink( $html, $rc, $unpatrolled, $watched ); } # Edit/log timestamp - $this->insertTimestamp( $s, $rc ); + $this->insertTimestamp( $html, $rc ); # Bytes added or removed if ( $this->getConfig()->get( 'RCShowChangedSize' ) ) { $cd = $this->formatCharacterDifference( $rc ); if ( $cd !== '' ) { - $s .= $cd . ' . . '; + $html .= $cd . ' . . '; } } if ( $rc->mAttribs['rc_type'] == RC_LOG ) { - $s .= $this->insertLogEntry( $rc ); + $html .= $this->insertLogEntry( $rc ); } else { # User tool links - $this->insertUserRelatedLinks( $s, $rc ); + $this->insertUserRelatedLinks( $html, $rc ); # LTR/RTL direction mark - $s .= $this->getLanguage()->getDirMark(); - $s .= $this->insertComment( $rc ); + $html .= $this->getLanguage()->getDirMark(); + $html .= $this->insertComment( $rc ); } # Tags - $this->insertTags( $s, $rc, $classes ); + $this->insertTags( $html, $rc, $classes ); # Rollback - $this->insertRollback( $s, $rc ); + $this->insertRollback( $html, $rc ); # For subclasses - $this->insertExtra( $s, $rc, $classes ); + $this->insertExtra( $html, $rc, $classes ); # How many users watch this page if ( $rc->numberofWatchingusers > 0 ) { - $s .= ' ' . $this->numberofWatchingusers( $rc->numberofWatchingusers ); - } - - if ( $this->watchlist ) { - $classes[] = Sanitizer::escapeClass( 'watchlist-' . - $rc->mAttribs['rc_namespace'] . '-' . $rc->mAttribs['rc_title'] ); + $html .= ' ' . $this->numberofWatchingusers( $rc->numberofWatchingusers ); } - if ( !wfRunHooks( 'OldChangesListRecentChangesLine', array( &$this, &$s, $rc, &$classes ) ) ) { - wfProfileOut( __METHOD__ ); - - return false; - } - - wfProfileOut( __METHOD__ ); - - $dateheader = ''; // $s now contains only
  • ...
  • , for hooks' convenience. - $this->insertDateHeader( $dateheader, $rc->mAttribs['rc_timestamp'] ); - - return "$dateheader
  • " . $s . "
  • \n"; + return $html; } } diff --git a/includes/content/CssContent.php b/includes/content/CssContent.php index 2673084ebe..72414585d0 100644 --- a/includes/content/CssContent.php +++ b/includes/content/CssContent.php @@ -58,7 +58,7 @@ class CssContent extends TextContent { $text = $this->getNativeData(); $pst = $wgParser->preSaveTransform( $text, $title, $user, $popts ); - return new CssContent( $pst ); + return new static( $pst ); } /** diff --git a/includes/content/CssContentHandler.php b/includes/content/CssContentHandler.php index fd326f01b1..1ab4ee2a8f 100644 --- a/includes/content/CssContentHandler.php +++ b/includes/content/CssContentHandler.php @@ -36,27 +36,8 @@ class CssContentHandler extends TextContentHandler { parent::__construct( $modelId, array( CONTENT_FORMAT_CSS ) ); } - /** - * @param string $text - * @param string $format - * - * @return CssContent - * - * @see ContentHandler::unserializeContent() - */ - public function unserializeContent( $text, $format = null ) { - $this->checkFormat( $format ); - - return new CssContent( $text ); - } - - /** - * @return CssContent A new CssContent object with empty text. - * - * @see ContentHandler::makeEmptyContent() - */ - public function makeEmptyContent() { - return new CssContent( '' ); + protected function getContentClass() { + return 'CssContent'; } /** diff --git a/includes/content/JSONContentHandler.php b/includes/content/JSONContentHandler.php index 6b7752781e..33f203661c 100644 --- a/includes/content/JSONContentHandler.php +++ b/includes/content/JSONContentHandler.php @@ -16,6 +16,8 @@ class JSONContentHandler extends TextContentHandler { /** * The class name of objects that should be created * + * @deprecated override getContentClass instead + * * @var string */ protected $contentClass = 'JSONContent'; @@ -25,25 +27,13 @@ class JSONContentHandler extends TextContentHandler { } /** - * Unserializes a JSONContent object. - * - * @param string $text Serialized form of the content - * @param null|string $format The format used for serialization - * - * @return JSONContent - */ - public function unserializeContent( $text, $format = null ) { - $this->checkFormat( $format ); - return new $this->contentClass( $text ); - } - - /** - * Creates an empty JSONContent object. + * Temporary back-compat until extensions + * are updated to override this * - * @return JSONContent + * @return string */ - public function makeEmptyContent() { - return new $this->contentClass( '' ); + protected function getContentClass() { + return $this->contentClass; } /** diff --git a/includes/content/JavaScriptContent.php b/includes/content/JavaScriptContent.php index 442b705282..0991f07683 100644 --- a/includes/content/JavaScriptContent.php +++ b/includes/content/JavaScriptContent.php @@ -57,7 +57,7 @@ class JavaScriptContent extends TextContent { $text = $this->getNativeData(); $pst = $wgParser->preSaveTransform( $text, $title, $user, $popts ); - return new JavaScriptContent( $pst ); + return new static( $pst ); } /** diff --git a/includes/content/JavaScriptContentHandler.php b/includes/content/JavaScriptContentHandler.php index 122003fe53..8d62e2a3ad 100644 --- a/includes/content/JavaScriptContentHandler.php +++ b/includes/content/JavaScriptContentHandler.php @@ -36,27 +36,8 @@ class JavaScriptContentHandler extends TextContentHandler { parent::__construct( $modelId, array( CONTENT_FORMAT_JAVASCRIPT ) ); } - /** - * @param string $text - * @param string $format - * - * @return JavaScriptContent - * - * @see ContentHandler::unserializeContent() - */ - public function unserializeContent( $text, $format = null ) { - $this->checkFormat( $format ); - - return new JavaScriptContent( $text ); - } - - /** - * @return JavaScriptContent A new JavaScriptContent object with empty text. - * - * @see ContentHandler::makeEmptyContent() - */ - public function makeEmptyContent() { - return new JavaScriptContent( '' ); + protected function getContentClass() { + return 'JavaScriptContent'; } /** diff --git a/includes/content/TextContentHandler.php b/includes/content/TextContentHandler.php index 0c9ee37577..ffe1acbd20 100644 --- a/includes/content/TextContentHandler.php +++ b/includes/content/TextContentHandler.php @@ -92,6 +92,19 @@ class TextContentHandler extends ContentHandler { return $mergedContent; } + /** + * Returns the name of the associated Content class, to + * be used when creating new objects. Override expected + * by subclasses. + * + * @since 1.24 + * + * @return string + */ + protected function getContentClass() { + return 'TextContent'; + } + /** * Unserializes a Content object of the type supported by this ContentHandler. * @@ -105,7 +118,8 @@ class TextContentHandler extends ContentHandler { public function unserializeContent( $text, $format = null ) { $this->checkFormat( $format ); - return new TextContent( $text ); + $class = $this->getContentClass(); + return new $class( $text ); } /** @@ -116,7 +130,8 @@ class TextContentHandler extends ContentHandler { * @return Content A new TextContent object with empty text. */ public function makeEmptyContent() { - return new TextContent( '' ); + $class = $this->getContentClass(); + return new $class( '' ); } } diff --git a/includes/content/WikitextContent.php b/includes/content/WikitextContent.php index 237029b0ba..d23f925d80 100644 --- a/includes/content/WikitextContent.php +++ b/includes/content/WikitextContent.php @@ -52,7 +52,7 @@ class WikitextContent extends TextContent { if ( $sect === false ) { return false; } else { - return new WikitextContent( $sect ); + return new static( $sect ); } } @@ -104,7 +104,7 @@ class WikitextContent extends TextContent { $text = $wgParser->replaceSection( $oldtext, $sectionId, $text ); } - $newContent = new WikitextContent( $text ); + $newContent = new static( $text ); wfProfileOut( __METHOD__ ); @@ -125,7 +125,7 @@ class WikitextContent extends TextContent { $text .= "\n\n"; $text .= $this->getNativeData(); - return new WikitextContent( $text ); + return new static( $text ); } /** @@ -145,7 +145,7 @@ class WikitextContent extends TextContent { $pst = $wgParser->preSaveTransform( $text, $title, $user, $popts ); rtrim( $pst ); - return ( $text === $pst ) ? $this : new WikitextContent( $pst ); + return ( $text === $pst ) ? $this : new static( $pst ); } /** @@ -164,7 +164,7 @@ class WikitextContent extends TextContent { $text = $this->getNativeData(); $plt = $wgParser->getPreloadText( $text, $title, $popts, $params ); - return new WikitextContent( $plt ); + return new static( $plt ); } /** @@ -246,7 +246,7 @@ class WikitextContent extends TextContent { '[[' . $target->getFullText() . ']]', $this->getNativeData(), 1 ); - return new WikitextContent( $newText ); + return new static( $newText ); } /** diff --git a/includes/content/WikitextContentHandler.php b/includes/content/WikitextContentHandler.php index 5ae3e25d6e..c1db1de63a 100644 --- a/includes/content/WikitextContentHandler.php +++ b/includes/content/WikitextContentHandler.php @@ -34,19 +34,8 @@ class WikitextContentHandler extends TextContentHandler { parent::__construct( $modelId, array( CONTENT_FORMAT_WIKITEXT ) ); } - public function unserializeContent( $text, $format = null ) { - $this->checkFormat( $format ); - - return new WikitextContent( $text ); - } - - /** - * @return Content A new WikitextContent object with empty text. - * - * @see ContentHandler::makeEmptyContent - */ - public function makeEmptyContent() { - return new WikitextContent( '' ); + protected function getContentClass() { + return 'WikitextContent'; } /** @@ -79,7 +68,8 @@ class WikitextContentHandler extends TextContentHandler { $redirectText .= "\n" . $text; } - return new WikitextContent( $redirectText ); + $class = $this->getContentClass(); + return new $class( $redirectText ); } /** diff --git a/includes/db/Database.php b/includes/db/Database.php index a46ee1c068..9584e466f1 100644 --- a/includes/db/Database.php +++ b/includes/db/Database.php @@ -679,8 +679,6 @@ abstract class DatabaseBase implements IDatabase, DatabaseType { * - DBO_DEBUG: output some debug info (same as debug()) * - DBO_NOBUFFER: don't buffer results (inverse of bufferResults()) * - DBO_TRX: automatically start transactions - * - DBO_DEFAULT: automatically sets DBO_TRX if not in command line mode - * and removes it in command line mode * - DBO_PERSISTENT: use persistant database connection * @return bool */ diff --git a/includes/diff/DifferenceEngine.php b/includes/diff/DifferenceEngine.php index ee918f3785..50e08ca1d2 100644 --- a/includes/diff/DifferenceEngine.php +++ b/includes/diff/DifferenceEngine.php @@ -310,11 +310,11 @@ class DifferenceEngine extends ContextSource { 'undoafter' => $this->mOldid, 'undo' => $this->mNewid ) ), - 'title' => Linker::titleAttrib( 'undo' ) + 'title' => Linker::titleAttrib( 'undo' ), ), $this->msg( 'editundo' )->text() ); - $revisionTools[] = $undoLink; + $revisionTools['mw-diff-undo'] = $undoLink; } } @@ -387,8 +387,14 @@ class DifferenceEngine extends ContextSource { wfRunHooks( 'DiffRevisionTools', array( $this->mNewRev, &$revisionTools, $this->mOldRev ) ); $formattedRevisionTools = array(); // Put each one in parentheses (poor man's button) - foreach ( $revisionTools as $tool ) { - $formattedRevisionTools[] = $this->msg( 'parentheses' )->rawParams( $tool )->escaped(); + foreach ( $revisionTools as $key => $tool ) { + $toolClass = is_string( $key ) ? $key : 'mw-diff-tool'; + $element = Html::rawElement( + 'span', + array( 'class' => $toolClass ), + $this->msg( 'parentheses' )->rawParams( $tool )->escaped() + ); + $formattedRevisionTools[] = $element; } $newRevisionHeader = $this->getRevisionHeader( $this->mNewRev, 'complete' ) . ' ' . implode( ' ', $formattedRevisionTools ); @@ -1052,8 +1058,13 @@ class DifferenceEngine extends ContextSource { $key = $title->quickUserCan( 'edit', $user ) ? 'editold' : 'viewsourceold'; $msg = $this->msg( $key )->escaped(); - $header .= ' ' . $this->msg( 'parentheses' )->rawParams( - Linker::linkKnown( $title, $msg, array(), $editQuery ) )->plain(); + $editLink = $this->msg( 'parentheses' )->rawParams( + Linker::linkKnown( $title, $msg, array( ), $editQuery ) )->plain(); + $header .= ' ' . Html::rawElement( + 'span', + array( 'class' => 'mw-diff-edit' ), + $editLink + ); if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) { $header = Html::rawElement( 'span', diff --git a/includes/filerepo/file/File.php b/includes/filerepo/file/File.php index 4fab33b9ec..ba2d4ac895 100644 --- a/includes/filerepo/file/File.php +++ b/includes/filerepo/file/File.php @@ -714,7 +714,7 @@ abstract class File { */ function canRender() { if ( !isset( $this->canRender ) ) { - $this->canRender = $this->getHandler() && $this->handler->canRender( $this ); + $this->canRender = $this->getHandler() && $this->handler->canRender( $this ) && $this->exists(); } return $this->canRender; diff --git a/includes/filerepo/file/OldLocalFile.php b/includes/filerepo/file/OldLocalFile.php index 0adcc73c62..710058fba6 100644 --- a/includes/filerepo/file/OldLocalFile.php +++ b/includes/filerepo/file/OldLocalFile.php @@ -404,4 +404,18 @@ class OldLocalFile extends LocalFile { return true; } + + /** + * If archive name is an empty string, then file does not "exist" + * + * This is the case for a couple files on Wikimedia servers where + * the old version is "lost". + */ + public function exists() { + $archiveName = $this->getArchiveName(); + if ( $archiveName === '' || !is_string( $archiveName ) ) { + return false; + } + return parent::exists(); + } } diff --git a/includes/installer/WebInstallerOutput.php b/includes/installer/WebInstallerOutput.php index f797ef9a45..3094d5571b 100644 --- a/includes/installer/WebInstallerOutput.php +++ b/includes/installer/WebInstallerOutput.php @@ -124,53 +124,55 @@ class WebInstallerOutput { * @return string */ public function getCSS() { - // Horrible, horrible hack: the installer is currently hardcoded to use the Vector skin, so load - // it here. Include instead of require, as this will work without it, it will just look bad. - // We need the 'global' statement for $wgResourceModules because the Vector skin adds the - // definitions for its RL modules there that we use implicitly below. - // @codingStandardsIgnoreStart - global $wgResourceModules; // This is NOT UNUSED! - // @codingStandardsIgnoreEnd global $wgStyleDirectory; - include_once "$wgStyleDirectory/Vector/Vector.php"; $moduleNames = array( // See SkinTemplate::setupSkinUserCss 'mediawiki.legacy.shared', // See Vector::setupSkinUserCss 'mediawiki.skinning.interface', - 'skins.vector.styles', - - 'mediawiki.legacy.config', ); - $css = ''; + if ( file_exists( "$wgStyleDirectory/Vector/Vector.php" ) ) { + // Force loading Vector skin if available as a fallback skin + // for whatever ResourceLoader wants to have as the default. + + // Include instead of require, as this will work without it, it will just look bad. + // We need the 'global' statement for $wgResourceModules because the Vector skin adds the + // definitions for its RL modules there that we use implicitly below. + + // @codingStandardsIgnoreStart + global $wgResourceModules; // This is NOT UNUSED! + // @codingStandardsIgnoreEnd + + include_once "$wgStyleDirectory/Vector/Vector.php"; + + $moduleNames[] = 'skins.vector.styles'; + } + + $moduleNames[] = 'mediawiki.legacy.config'; $resourceLoader = new ResourceLoader(); $rlContext = new ResourceLoaderContext( $resourceLoader, new FauxRequest( array( 'debug' => 'true', 'lang' => $this->getLanguageCode(), 'only' => 'styles', - 'skin' => 'vector', ) ) ); + + $styles = array(); foreach ( $moduleNames as $moduleName ) { /** @var ResourceLoaderFileModule $module */ $module = $resourceLoader->getModule( $moduleName ); - // One of the modules will be missing if Vector is unavailable - if ( !$module ) { - continue; - } // Based on: ResourceLoaderFileModule::getStyles (without the DB query) - $styles = ResourceLoader::makeCombinedStyles( $module->readStyleFiles( - $module->getStyleFiles( $rlContext ), - $module->getFlip( $rlContext ) - ) ); - - $css .= implode( "\n", $styles ); + $styles = array_merge( $styles, ResourceLoader::makeCombinedStyles( + $module->readStyleFiles( + $module->getStyleFiles( $rlContext ), + $module->getFlip( $rlContext ) + ) ) ); } - return $css; + return implode( "\n", $styles ); } /** @@ -271,8 +273,8 @@ class WebInstallerOutput { $this->getDir() ) ) . "\n"; ?>
    -
    -
    +
    +

    outputTitle(); ?>

    utf8_normalize.so eingesetzt.", "config-unicode-using-intl": "Zur Unicode-Normalisierung wird die [http://pecl.php.net/intl PECL-Erweiterung intl] eingesetzt.", "config-unicode-pure-php-warning": "'''Warnung:''' Die [http://pecl.php.net/intl PECL-Erweiterung intl] ist für die Unicode-Normalisierung nicht verfügbar, so dass stattdessen die langsame pure-PHP-Implementierung genutzt wird.\nSofern eine Website mit großer Benutzeranzahl betrieben wird, sollten weitere Informationen auf der Webseite [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-Normalisierung (en)] gelesen werden.", diff --git a/includes/installer/i18n/es.json b/includes/installer/i18n/es.json index 135a32ba0c..755c2a69fb 100644 --- a/includes/installer/i18n/es.json +++ b/includes/installer/i18n/es.json @@ -24,7 +24,8 @@ "McDutchie", "Miguel2706", "Macofe", - "AVIADOR" + "AVIADOR", + "FuzzyDice" ] }, "config-desc": "El instalador de MediaWiki", @@ -41,9 +42,9 @@ "config-session-expired": "Tus datos de sesión parecen haber expirado.\nLas sesiones están configuradas por una duración de $1.\nPuedes incrementar esto configurando session.gc_maxlifetime en php.ini.\nReiniciar el proceso de instalación.", "config-no-session": "Se han perdido los datos de sesión.\nVerifica tu php.ini y comprueba que session.save_path está establecido en un directorio apropiado.", "config-your-language": "Tu idioma:", - "config-your-language-help": "Seleccionar un idioma a usar durante el proceso de instalación.", + "config-your-language-help": "Selecciona un idioma para usar durante el proceso de instalación.", "config-wiki-language": "Idioma del wiki:", - "config-wiki-language-help": "Seleccionar el idioma en el que el wiki será escrito predominantemente.", + "config-wiki-language-help": "Selecciona el idioma en el que se escribirá predominantemente el wiki.", "config-back": "← Atrás", "config-continue": "Continuar →", "config-page-language": "Idioma", @@ -69,6 +70,7 @@ "config-env-good": "El entorno ha sido comprobado.\nPuedes instalar MediaWiki.", "config-env-bad": "El entorno ha sido comprobado.\nNo puedes instalar MediaWiki.", "config-env-php": "PHP $1 está instalado.", + "config-env-hhvm": "HHVM $1 está instalado.", "config-unicode-using-utf8": "Usando utf8_normalize.so de Brion Vibber para la normalización Unicode.", "config-unicode-using-intl": "Usando la [http://pecl.php.net/intl extensión intl PECL] para la normalización Unicode.", "config-unicode-pure-php-warning": "'''Advertencia''': La [http://pecl.php.net/intl extensión intl] no está disponible para efectuar la normalización Unicode. Utilizando la implementación más lenta en PHP.\nSi tu web tiene mucho tráfico, te recomendamos leer acerca de la [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalización Unicode].", @@ -96,48 +98,48 @@ "config-no-cache": "'''Advertencia:''' No pudo encontrarse [http://www.php.net/apc APC], [http://xcache.lighttpd.net/ XCache] o [http://www.iis.net/download/WinCacheForPhp WinCache].\nEl caché de objetos no está habilitado.", "config-mod-security": "''' Advertencia ''': Su servidor web tiene [http://modsecurity.org/ mod_security] habilitado. Si la configuración es incorrecta, puede causar problemas a MediaWiki u otro software que permita a los usuarios publicar contenido arbitrarios.\nConsulte la [http://modsecurity.org/documentation/ documentación de mod_security] o contacte con el soporte de su servidor (''host'') si encuentra errores aleatorios.", "config-diff3-bad": "GNU diff3 no se encuentra.", - "config-git": "Se encontró el ''software'' de control de versiones Git: $1.", + "config-git": "Se encontró el software de control de versiones Git: $1.", "config-git-bad": "No se encontró el software de control de versiones Git.", "config-imagemagick": "ImageMagick encontrado: $1.\nLa miniaturización de imágenes se habilitará si habilitas las cargas.", "config-gd": "Se ha encontrado una biblioteca de gráficos GD integrada.\nLa miniaturización de imágenes se habilitará si habilitas las subidas.", "config-no-scaling": "No se ha encontrado ninguma biblioteca GD o ImageMagik.\nSe inhabilitará la miniaturización de imágenes.", - "config-no-uri": "'''Error:''' No se pudo determinar el URI actual.\nSe interrumpió la instalación.", + "config-no-uri": "Error: no se pudo determinar el URI actual.\nSe interrumpió la instalación.", "config-no-cli-uri": "Aviso: No se especificó --scriptpath; se usa el valor predeterminado: $1.", "config-using-server": "Utilizando el nombre de servidor \"$1\".", - "config-using-uri": "Utilizando la dirección URL del servidor \"$1$2\".", + "config-using-uri": "Utilizando la URL del servidor \"$1$2\".", "config-uploads-not-safe": "'''Atención:''' Su directorio por defecto para las cargas, $1, es vulnerable a la ejecución de scripts arbitrarios.\nAunque MediaWiki comprueba todos los archivos cargados por si hubiese amenazas de seguridad, es altamente recomendable [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security cerrar esta vulnerabilidad de seguridad] antes de activar las cargas.", "config-no-cli-uploads-check": "'''Atención:''' Su directorio predeterminado para cargas ($1) no está comprobado para la vulnerabilidad\n de ejecución arbitraria de comandos script durante la instalación de CLI.", "config-brokenlibxml": "El sistema tiene una combinación de versiones de PHP y de libxml2 que es poco confiable y puede provocar corrupción oculta en los datos de MediaWiki y otras aplicaciones web.\nActualizar a PHP 5.2.9 o posterior y a libxml2 2.7.3 o posterior ([//bugs.php.net/bug.php?id=45996 bug reportado con PHP]).\nInstalación abortada.", "config-suhosin-max-value-length": "Suhosin está instalado y limita el parámetro length GET a $1 bytes.\nEl componente ResourceLoader (gestor de recursos) de MediaWiki trabajará en este límite, pero eso perjudicará el rendimiento.\nSi es posible, deberías establecer suhosin.get.max_value_length en el valor 1024 o superior en php.ini y establecer $wgResourceLoaderMaxQueryLength en el mismo valor en php.ini.", - "config-db-type": "Tipo de base de datos", + "config-db-type": "Tipo de base de datos:", "config-db-host": "Servidor de la base de datos:", "config-db-host-help": "Si su servidor de base de datos está en otro servidor, escriba el nombre del host o su dirección IP aquí.\nSi está utilizando alojamiento web compartido, su proveedor de alojamiento debería darle el nombre correcto del servidor de alojamiento (host) en su documentación.\nSi va a instalarlo en un servidor Windows y utiliza MySQL, el uso de \"localhost\" como nombre del servidor puede no funcionar. Si no es así, intente poner \"127.0.0.1\" como dirección IP local.\nSi utiliza PostgreSQL, deje este campo en blanco para conectarse a través de un socket de Unix.", "config-db-host-oracle": "TNS de la base de datos:", "config-db-host-oracle-help": "Introduzca un [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm nombre de conexión local] válido; un archivo tnsnames.ora debe ser visible para esta instalación.
    Si está utilizando bibliotecas de cliente 10g o más recientes también puede utilizar el método de asignación de nombres [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect].", - "config-db-wiki-settings": "Identifique este wiki", - "config-db-name": "Nombre de base de datos:", + "config-db-wiki-settings": "Identifica este wiki", + "config-db-name": "Nombre de la base de datos:", "config-db-name-help": "Elija un nombre que identifique su wiki.\nNo debe contener espacios.\n\nSi está utilizando alojamiento web compartido, su proveedor de alojamiento le dará un nombre específico de base de datos para que lo utilice, o bien le permitirá crear bases de datos a través de un panel de control.", - "config-db-name-oracle": "Esquema de base de datos:", + "config-db-name-oracle": "Esquema de la base de datos:", "config-db-account-oracle-warn": "Hay tres escenarios compatibles para la instalación de Oracle como base de datos back-end:\n\nSi desea crear una cuenta de base de datos como parte del proceso de instalación, por favor suministre una cuenta con función SYSDBA como cuenta de base de datos para la instalación y especifique las credenciales deseadas de la cuenta de acceso al web, de lo contrario puede crear manualmente la cuenta de acceso al web y suministrar sólo esa cuenta (si tiene los permisos necesarios para crear los objetos de esquema) o suministrar dos cuentas diferentes, una con privilegios de creación y otra con acceso restringido a la web\n\nLa secuencia de comandos (script) para crear una cuenta con los privilegios necesarios puede encontrarse en el directorio \"maintenance/oracle/\" de esta instalación. Tenga en cuenta que utilizando una cuenta restringida desactivará todas las capacidades de mantenimiento con la cuenta predeterminada.", "config-db-install-account": "Cuenta de usuario para instalación", - "config-db-username": "Nombre de usuario de base de datos:", - "config-db-password": "contraseña de base de datos:", + "config-db-username": "Nombre de usuario de la base de datos:", + "config-db-password": "Contraseña de la base de datos:", "config-db-password-empty": "Introduzca una contraseña para el nuevo usuario de base de datos: $1.\nAunque es posible crear usuarios sin contraseña, esto no es seguro.", "config-db-username-empty": "Debe introducir un valor para \"{{int:config-db-username}}\"", "config-db-install-username": "Introduzca el nombre de usuario que se utilizará para conectarse a la base de datos durante el proceso de instalación.\nEste no es el nombre de usuario de la cuenta de MediaWiki; Este es el nombre de usuario para la base de datos.", "config-db-install-password": "Introduzca la contraseña que se utilizará para conectarse a la base de datos durante el proceso de instalación.\nEsta no es la contraseña para la cuenta de MediaWiki; esta es la contraseña para la base de datos.", "config-db-install-help": "Ingresar el nombre de usuario y la contraseña que será usada para conectar a la base de datos durante el proceso de instalación.", "config-db-account-lock": "Usar el mismo nombre de usuario y contraseña durante operación normal", - "config-db-wiki-account": "Usar cuenta para operación normal", + "config-db-wiki-account": "Cuenta de usuario para operación normal", "config-db-wiki-help": "Introduce el nombre de usuario y la contraseña que serán usados para acceder a la base de datos durante la operación normal del wiki.\nSi esta cuenta no existe y la cuenta de instalación tiene suficientes privilegios, se creará esta cuenta de usuario con los privilegios mínimos necesarios para la operación normal del wiki.", - "config-db-prefix": "Prefijo de tablas de base de datos:", + "config-db-prefix": "Prefijo de tablas de la base de datos:", "config-db-prefix-help": "Si necesita compartir una base de datos entre múltiples wikis, o entre MediaWiki y otra aplicación web, puede optar por agregar un prefijo a todos los nombres de tabla para evitar conflictos.\nNo utilice espacios.\n\nNormalmente se deja este campo vacío.", "config-db-charset": "Conjunto de caracteres de la base de datos", "config-charset-mysql5-binary": "MySQL 4.1/5.0 binario", "config-charset-mysql5": "MySQL 4.1/5.0 UTF-8", "config-charset-mysql4": "MySQL 4.0 retrocompatible UTF-8", "config-charset-help": "'''Atención:''' Si emplea '''backwards-compatible UTF-8''' en MySQL 4.1+ y posteriormente hace copia de seguridad de la base de datos con mysqldump , puede destruir todos los caracteres no-ASCII, ¡dañando irreversiblemente sus copias de seguridad!\n\nEn '''modo binario''', MediaWiki almacena texto UTF-8 en la base de datos en campos binarios.\nEsto es más eficiente que el modo UTF-8 de MySQL, y le permite utilizar la gama completa de caracteres Unicode.\nEn ''' modo UTF-8'' ', MySQL sabrá el juego de caracteres de sus datos y puede presentarlos y convertirlos apropiadamente,\npero no le permitirá almacenar caracteres por encima del [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes plano multilingüe básico].", - "config-mysql-old": "Se necesita MySQL $1 o una versión más reciente. Tienes la versión $2.", + "config-mysql-old": "Se necesita MySQL $1 o posterior. Tienes $2.", "config-db-port": "Puerto de la base de datos:", "config-db-schema": "Esquema para MediaWiki", "config-db-schema-help": "Estos esquemas usualmente estarán bien.\nAltéralos sólo si tienes la seguridad de que necesitas hacerlo.", @@ -188,9 +190,9 @@ "config-upgrade-done": "Actualización completa.\n\nUsted puede ahora [ $1 empezar a usar su wiki].\n\nSi desea regenerar su archivo LocalSettings.php de archivo, haga clic en el botón de abajo.\nEsto '''no se recomienda''' a menos que esté teniendo problemas con su wiki.", "config-upgrade-done-no-regenerate": "Actualización completa.\n\nUsted puede ahora [$1 empezar a usar su wiki].", "config-regenerate": "Regenerar LocalSettings.php →", - "config-show-table-status": "SHOW TABLE STATUS ha fallado!", + "config-show-table-status": "¡Falló la consulta SHOW TABLE STATUS!", "config-unknown-collation": "'''Advertencia:''' La base de datos está utilizando una intercalación no reconocida.", - "config-db-web-account": "Cuenta de base de datos para acceso Web", + "config-db-web-account": "Cuenta de la base de datos para acceso web", "config-db-web-help": "Elige el usuario y contraseña que el servidor Web usará para conectarse al servidor de la base de datos durante el fincionamiento normal del wiki.", "config-db-web-account-same": "Utilizar la misma cuenta que en la instalación", "config-db-web-create": "Crear la cuenta si no existe", @@ -205,7 +207,7 @@ "config-mysql-binary": "Binario", "config-mysql-utf8": "UTF-8", "config-mysql-charset-help": "En '''modo binario''', MediaWiki almacena texto UTF-8 para la base de datos en campos binarios.\nEsto es más eficiente que el modo UTF-8 de MySQL y le permite utilizar la gama completa de caracteres Unicode.\n\nEn '''modo UTF-8''', MySQL sabrá qué conjunto de caracteres emplean sus datos y puede presentarlos y convertirlos adecuadamente, pero no le permitirá almacenar caracteres por encima del [//en.wikipedia.org/wiki/Mapping_of_Unicode_character_planes plano multilingüe básico].", - "config-mssql-auth": "Tipo de autentificación:", + "config-mssql-auth": "Tipo de autenticación:", "config-mssql-install-auth": "Seleccione el tipo de autenticación que se utilizará para conectarse a la base de datos durante el proceso de instalación.\nSi selecciona \"{{int:config-mssql-windowsauth}}\", las credenciales de cualquier usuario de el servidor web que se está ejecutando van a ser utilizadas.", "config-mssql-web-auth": "Seleccione el tipo de autenticación que utilizará el servidor web para conectarse al servidor de base de datos, durante el funcionamiento normal de la wiki.\nSi selecciona \"{{int:config-mssql-windowsauth}}\", las credenciales del usuario que sea cual sea el servidor Web se ejecuta como será utilizado.", "config-mssql-sqlauth": "Autenticación de SQL Server", @@ -215,7 +217,7 @@ "config-site-name-blank": "Ingresar un nombre de sitio.", "config-project-namespace": "Espacio de nombre de proyecto:", "config-ns-generic": "Proyecto", - "config-ns-site-name": "Igual como el nombre del wiki: $1", + "config-ns-site-name": "Igual al nombre del wiki: $1", "config-ns-other": "Otro (especificar)", "config-ns-other-default": "MiWiki", "config-project-namespace-help": "Siguiendo el ejemplo de Wikipedia, muchos wikis mantienen sus páginas de políticas separadas de sus páginas de contenido, en un \"'''espacio de nombres del proyecto'''\".\n\nTodos los títulos de página en este espacio de nombres comienzan con un determinado prefijo, que usted puede especificar aquí.\nTradicionalmente, este prefijo se deriva del nombre del wiki, pero no puede contener caracteres de puntuación como \"#\" o \":\".", @@ -224,7 +226,7 @@ "config-admin-box": "Cuenta de administrador", "config-admin-name": "Tu nombre de usuario:", "config-admin-password": "Contraseña:", - "config-admin-password-confirm": "Repita la contraseña:", + "config-admin-password-confirm": "Repite la contraseña:", "config-admin-help": "Escribe aquí el nombre de usuario que desees, como por ejemplo \"Pedro Bloggs\".\nEste es el nombre que usarás para entrar al wiki.", "config-admin-name-blank": "Introduce un nombre de usuario de administrador.", "config-admin-name-invalid": "El nombre de usuario especificado \"$1\" no es válido.\nEspecifique un nombre de usuario diferente.", @@ -247,20 +249,20 @@ "config-profile-fishbowl": "Sólo editores autorizados", "config-profile-private": "Wiki privado", "config-profile-help": "Los wikis funcionan mejor cuando dejas que los edite tanta gente como sea posible.\nEn MediaWiki, es fácil revisar los cambios recientes y revertir los daños realizados por usuarios malintencionados o novatos.\nSin embargo, muchos han encontrado que MediaWiki es útil para una amplia variedad de funciones, y a veces no es fácil convencer a todos de los beneficios de la forma wiki.\nPor lo tanto tienes la elección.\n\nEl modelo '''{{int:config-profile-wiki}}''' permite que cualquiera pueda editar, sin siquiera iniciar sesión.\nUn wiki con '''{{int:config-profile-no-anon}}''' ofrece rendición de cuentas adicional, pero puede disuadir a colaboradores.\n\nEl modelo '''{{int:config-profile-fishbowl}}''' permite editar a los usuarios autorizados, pero el público puede ver las páginas, incluyendo el historial.\nUn '''{{int:config-profile-private}}''' sólo permite ver páginas a los usuarios autorizados, el mismo grupo al que le está permitido editar.\n\nConfiguraciones más complejas de derechos de usuario están disponibles después de la instalación, consulte [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights esta entrada en el manual].", - "config-license": "Copyright and licencia:", + "config-license": "Derechos de autor y licencia:", "config-license-none": "Pie sin licencia", - "config-license-cc-by-sa": "Creative Commons Reconocimiento Compartir Igual", - "config-license-cc-by": "Creative Commons Reconocimiento", - "config-license-cc-by-nc-sa": "Creative Commons Reconocimiento Compartir Igual no comercial", + "config-license-cc-by-sa": "Creative Commons Atribución-CompartirIgual", + "config-license-cc-by": "Creative Commons Atribución", + "config-license-cc-by-nc-sa": "Creative Commons Atribución-NoComercial-CompartirIgual", "config-license-cc-0": "Creative Commons Zero (dominio público)", "config-license-gfdl": "Licencia de documentación libre de GNU 1.3 o posterior", - "config-license-pd": "Dominio Público", + "config-license-pd": "Dominio público", "config-license-cc-choose": "Selecciona una licencia personalizada de Creative Commons", "config-license-help": "Muchos wikis públicos ponen todas las contribuciones bajo una [http://freedomdefined.org/Definition licencia libre].\nEsto ayuda a crear un sentido de propiedad comunitaria y alienta la contribución a largo plazo.\nEsto no es generalmente necesario para un wiki privado o corporativo.\n\nSi deseas poder utilizar texto de Wikipedia, y deseas que Wikipedia pueda aceptar el texto copiado de tu wiki, debes elegir {{int:config-license-cc-by-sa}}.\n\nWikipedia utilizaba anteriormente la licencia de documentación libre de GNU (GFDL).\nLa GFDL es una licencia válida, pero es difícil de entender.\nTambién es difícil reutilizar el contenido licenciado bajo la GFDL.", "config-email-settings": "Configuración de correo electrónico", "config-enable-email": "Activar el envío de correos electrónicos", "config-enable-email-help": "Si quieres que el correo electrónico funcione, la [http://www.php.net/manual/en/mail.configuration.php configuración PHP de correo electrónico] debe ser la correcta.\nSi no quieres la funcionalidad de correo electrónico, puedes desactivarla aquí.", - "config-email-user": "Habilitar correo electrónico de usuario a usuario", + "config-email-user": "Habilitar correo electrónico entre usuarios", "config-email-user-help": "Permitir que todos los usuarios intercambien correos electrónicos si lo han activado en sus preferencias.", "config-email-usertalk": "Activar notificaciones de páginas de discusión de usuarios", "config-email-usertalk-help": "Permitir a los usuarios recibir notificaciones de cambios en la página de discusión de usuario, si lo han activado en sus preferencias.", @@ -319,7 +321,7 @@ "config-install-user": "Creando el usuario de la base de datos", "config-install-user-alreadyexists": "El usuario \"$1\" ya existe", "config-install-user-create-failed": "La creación del usuario \"$1\" falló: $2", - "config-install-user-grant-failed": "La concesión de permisos para el usuario \"$1\" ha fallado: $2", + "config-install-user-grant-failed": "La concesión de permisos al usuario \"$1\" falló: $2", "config-install-user-missing": "El usuario especificado \"$1\" no existe.", "config-install-user-missing-create": "El usuario especificado \"$1\" no existe.\nPor favor, haga clic en la casilla \"Crear cuenta\" que aparece a continuación si desea crearlo.", "config-install-tables": "Creando tablas", @@ -329,9 +331,9 @@ "config-install-interwiki-list": "No se pudo encontrar el archivo interwiki.list.", "config-install-interwiki-exists": "'''Advertencia''': La tabla de interwikis parece ya contener entradas.\nSe omitirá la lista predeterminada.", "config-install-stats": "Iniciando las estadísticas", - "config-install-keys": "Generación de claves secretas", + "config-install-keys": "Generando claves secretas", "config-insecure-keys": "''' Atención:'' ' {{PLURAL:$2|Una clave de seguridad generada|Las claves de seguridad generadas}} ($1) durante la instalación no {{PLURAL:$2|es totalmente segura|son totalmente seguras}}. Considere {{PLURAL:$2| cambiarla|cambiarlas}} manualmente.", - "config-install-sysop": "Creando cuenta de usuario del administrador", + "config-install-sysop": "Creando la cuenta de usuario del administrador", "config-install-subscribe-fail": "No se ha podido suscribir a mediawiki-announce: $1", "config-install-subscribe-notpossible": "cURL no está instalado y allow_url_fopen no está disponible.", "config-install-mainpage": "Creando página principal con contenido predeterminado", @@ -339,10 +341,10 @@ "config-install-mainpage-failed": "No se pudo insertar la página principal: $1", "config-install-done": "¡Felicidades!\nHas instalado MediaWiki correctamente.\n\nEl instalador ha generado un archivo LocalSettings.php.\nEste contiene toda su configuración.\n\nDeberás descargarlo y ponerlo en la base de la instalación de wiki (el mismo directorio que index.php). La descarga debería haber comenzado automáticamente.\n\nSi no comenzó la descarga, o si se ha cancelado, puedes reiniciar la descarga haciendo clic en el siguiente enlace:\n\n$3\n\nNota: Si no haces esto ahora, este archivo de configuración generado no estará disponible más tarde si sales de la instalación sin descargarlo.\n\nCuando lo hayas hecho, podrás [$2 entrar en tu wiki].", "config-download-localsettings": "Descargar archivo LocalSettings.php", - "config-help": "Ayuda", - "config-help-tooltip": "Haz clic para ampliar", + "config-help": "ayuda", + "config-help-tooltip": "haz clic para ampliar", "config-nofile": "El archivo \"$1\" no se pudo encontrar. ¿Se ha eliminado?", "config-extension-link": "¿Sabías que tu wiki admite [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensiones]?\n\nPuedes navegar por las [//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category categorías] o visitar el [//www.mediawiki.org/wiki/Extension_Matrix centro de extensiones] para ver una lista completa.", - "mainpagetext": "'''MediaWiki ha sido instalado con éxito.'''", + "mainpagetext": "MediaWiki se ha instalado con éxito.", "mainpagedocfooter": "Consulta la [//meta.wikimedia.org/wiki/Help:Contents/es guía del usuario] para obtener información sobre el uso del software wiki.\n\n== Primeros pasos ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista de ajustes de configuración]\n* [//www.mediawiki.org/wiki/Manual:FAQ/es Preguntas frecuentes sobre MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista de correo de anuncios de publicación de MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Traducir MediaWiki en tu idioma]" } diff --git a/includes/installer/i18n/et.json b/includes/installer/i18n/et.json index 13b61ed0b5..8fae026e6a 100644 --- a/includes/installer/i18n/et.json +++ b/includes/installer/i18n/et.json @@ -2,7 +2,8 @@ "@metadata": { "authors": [ "Avjoska", - "Pikne" + "Pikne", + "Boxmein" ] }, "config-information": "Teave", @@ -26,6 +27,7 @@ "config-page-upgradedoc": "Uuendamine", "config-page-existingwiki": "Olemasolev viki", "config-restart": "Jah, tee taaskäivitus", + "config-env-hhvm": "HHVM $1 on installitud.", "config-db-name": "Andmebaasi nimi:", "config-db-username": "Andmebaasi kasutajanimi:", "config-db-password": "Andmebaasi parool:", diff --git a/includes/installer/i18n/fa.json b/includes/installer/i18n/fa.json index d619cff2f6..02ffd0d1ca 100644 --- a/includes/installer/i18n/fa.json +++ b/includes/installer/i18n/fa.json @@ -6,7 +6,8 @@ "Ebraminio", "Omidh", "Pouyana", - "Reza1615" + "Reza1615", + "Alirezaaa" ] }, "config-desc": "نصب کنندهٔ ویکی‌مدیا", @@ -19,7 +20,7 @@ "config-upgrade-key-missing": "نصب موجود مدیاویکی شناسایی شده‌است.\nبرای بروزرسانی این نصب، لطفاً خط زیر را در آخر کد \nقرار دادن به نصب ارتقاء داده شده، به خط زیر لطفاً در پایین خود را LocalSettings.php قرار دهید:\n\n$1", "config-localsettings-incomplete": "وجود LocalSettings.php به نظر ناقص می‌رسد.\nمتغیر $1 تنظیم نشده‌است.\nبرای اینکه این متغیر تنظیم شود لطفاً LocalSettings.php را تغییر دهید، و \"{{int:Config-continue}}\" را کلیک کنید.", "config-localsettings-connection-error": "هنگام اتصال به پایگاه اطلاعاتی که ازتنظیمات مشخص شده درLocalSettings.php استفاده می‌کند، خطایی رخ داد. لطفاً این تنظیمات را نصب کنید و دوباره تلاش کنید.\n$1", - "config-session-error": "خطا در شروع جلسه $1", + "config-session-error": "خطا در شروع جلسه: $1", "config-session-expired": "به نظر می‌رسد اطلاعات جلسهٔ شما منقضی شده‌است.\nجلسات برای مادام العمر $1 پیکربندی شده‌اند.\nشما می‌توانید این پیکربندی را با تنظیم session.gc_maxlifetime در php.ini افزایش دهید.\nروند نصب را دوباره شروع کنید.", "config-no-session": "اطلاعات دورهٔ شما از دست رفته‌ است!\nphp.ini خود را بررسی کنید و مطمئن شوید session.save_path برای یک فهرست مناسب تنظیم شده‌است.", "config-your-language": "زبان شما:", @@ -31,26 +32,27 @@ "config-page-language": "زبان", "config-page-welcome": "به مدیاویکی خوش آمدید!", "config-page-dbconnect": "اتصال به پایگاه داده", - "config-page-upgrade": "نصب موجود را ارتقاء دهید.", - "config-page-dbsettings": "تنظیمات پایگاه اطلاعاتی", + "config-page-upgrade": "ارتقای نصب موجود", + "config-page-dbsettings": "تنظیمات پایگاه داده", "config-page-name": "نام", "config-page-options": "گزینه‌ها", "config-page-install": "نصب", "config-page-complete": "کامل!", - "config-page-restart": "نصب را دوباره شروع کنید", + "config-page-restart": "راه‌اندازی دوباره نصب", "config-page-readme": "مرا بخوان", "config-page-releasenotes": "یادداشت‌های انتشار", "config-page-copying": "تکثیر", - "config-page-upgradedoc": "ارتقا", + "config-page-upgradedoc": "ارتقاء", "config-page-existingwiki": "ویکی موجود", "config-help-restart": "آیا می‌خواهید همهٔ اطلاعات ذخیره شده‌ای که وارد کرده‌اید را پاک کنید و دوباره روند نصب را شروع کنید؟", - "config-restart": "بله ، آن دوباره راه اندازی کن", + "config-restart": "بله، دوباره راه‌اندازی کن", "config-welcome": "===بررسی‌های محیطی===\nبرای فهمیدن اینکه این محیط برای نصب مدیاویکی مناسب است، اکنون بررسی‌های اساسی انجام خواهد‌شد.\nاگر به دنبال پشتیبانی در چگونگی تکمیل نصب هستید،به یاد داشته باشید این اطلاعات را بگنجانید.", "config-copyright": "===حق چاپ و شرایط===\n$1\nاین برنامه،نرم‌افزاری آزاد است;شما می‌توانید این برنامه را دوباره توزیع کنید و/یا تحت شرایط مجوز عمومی کلی جی‌ان‌یو که توسط بنیاد نرم‌افزار آزاد منتشر شده،اصلاح کنید;یا نسخهٔ 2 مجوز، یا (به انتخاب خود) هر نسخهٔ پس از این.\nاین برنامه به امید اینکه مفید واقع‌ شود توزیع شده‌است،اما '''بدون هیچ ضمانتی'''; حتی بدون اشارهٔ ضمانتی از '''قابلیت عرضه''' یا ''' صلاحیت برای یک هدف خاص'''.\nبرای جزئیات بیشتر مجوز عمومی کلی جی‌ان‌یو را مشاهده کنید.\nشما باید یک چاپ ازمجوز عمومی کلی همراه این برنامه دریافت کنید; اگر دریافت نکردید،به بنیاد نرم‌افزار آزاد بنویسید،Inc.،خیابان فرانکلین۵۱،طبقه پنجم،بوستون، MA۰۲۱۱۰-۱۳۰،آمریکا،یا [http://www.gnu.org/copyleft/gpl.html read it online].", "config-sidebar": "* [//www.mediawiki.org صفحهٔ اصلی مدیاویکی]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents راهنمای کاربر]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Contents راهنمای مدیر]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ پرسش‌های رایج]\n----\n* مرا بخوان\n* یادداشت‌های انتشار\n* نسخه برداری\n* ارتقا", "config-env-good": "محیط بررسی شده‌است.\nشما می‌توانید مدیاویکی را نصب کنید.", "config-env-bad": "محیط بررسی شده‌است.\nشما نمی‌توانید مدیاویکی را نصب کنید.", "config-env-php": "پی‌اچ‌پی $1 نصب شده‌است.", + "config-env-hhvm": "HHVM $1 نصب شده‌است.", "config-unicode-using-utf8": "برای یونیکد عادی از Brion Vibber's utf8_normalize.so استفاده کنید.", "config-unicode-using-intl": "برای یونیکد عادی از [http://pecl.php.net/intl intl PECL extension] استفاده کنید.", "config-unicode-pure-php-warning": "'''هشدار:''' [http://pecl.php.net/intl intl PECL extension] برای کنترل یونیکد عادی در دسترس نیست،اجرای کاملاً آهسته به تعویق می‌افتد.\nاگر شما یک سایت پر‌ ترافیک را اجرا می‌کنید، باید کمی [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalization] را بخوانید.", @@ -78,8 +80,8 @@ "config-no-cache": "'''هشدار:''' [http://www.php.net/apc APC],[http://xcache.lighttpd.net/ XCache] یا [http://www.iis.net/download/WinCacheForPhp WinCache] را نتوانست پیدا کند.\nذخیره شی فعال نیست.", "config-mod-security": "'''هشدار:''' وب سرور شما [http://modsecurity.org/ mod_security] فعال است.اگر اشتباه پیکربندی شده‌‌ باشد،می تواند باعث ایجاد مشکلاتی برای مدیاویکی یا دیگر نرم‌افزاری شود که به کاربران اجازه می‌دهد پیام دلخواه ارسال کنند.\nبه [http://modsecurity.org/documentation/ mod_security documentation] مراجعه کنید یا اگر با خطاهای اتفاقی مواجه شدید با پشتیبانی میزبان خود در تماس باشید.", "config-diff3-bad": "جی‌ان‌یو دیف۳ پیدا نشد.", - "config-git": "نسخهٔ کنترل نرم‌افزار جیت پیدا شد:$1.", - "config-git-bad": "نسخه نرم‌افزار کنترل جیت پیدا نشد.", + "config-git": "کنترل نسخهٔ نرم‌افزار گیت پیدا شد: $1.", + "config-git-bad": "کنترل نسخهٔ نرم‌افزار گیت پیدا نشد.", "config-imagemagick": "ایمیج‌مجیک پیدا شد: $1.\nاگر ارسال‌ها را فعال کنید،تصویر کوچک فعال خواهد‌شد.", "config-gd": "گرافیک‌های جی‌دی ساخته‌‌ شده در کتابخانه پیدا شد.\nاگر ارسال‌ها را فعال کنید تصویر کوچک فعال خواهد‌شد.", "config-no-scaling": "کتابخانهٔ جی‌دی یا ایمیج‌مجیک نتوانست پیدا شود.\nتصویر کوچک غیر‌فعال خواهد‌شد.", @@ -104,7 +106,7 @@ "config-db-install-account": "حساب کاربری برای نصب", "config-db-username": "نام کاربری پایگاه اطلاعات:", "config-db-password": "گذرواژه پایگاه داده‌ها:", - "config-db-password-empty": "لطفاً یک رمز عبور برای کاربر جدید پایگاه اطلا‌عاتی وارد کنید: $1\nدر صورتی که ممکن است کاربران بدون رمز عبور به وجود آیند،امن نیست.", + "config-db-password-empty": "لطفاً یک رمز عبور برای کاربر تازه پایگاه اطلا‌عاتی وارد کنید: $1\nدر صورتی که ممکن است کاربران بدون رمز عبور به وجود آیند،امن نیست.", "config-db-username-empty": "شما باید یک مقدار برای \"نام کاربری {{int:config-db-username}}\" وارد کنید", "config-db-install-username": "نام کاربری را وارد کنید که برای اتصال به پایگاه اطلاعاتی در طول روند نصب استفاده خواهد‌شد.\nاین نام کاربری حساب مدیاویکی نیست; نام کاربری برای پایگاه اطلاعاتی شما است.", "config-db-install-password": "رمز عبوری را وارد کنید که برای اتصال به پایگاه اطلاعاتی در طول روند نصب استفاده خواهد‌شد.\nاین رمز عبور برای حساب مدیاویکی نیست;رمز عبور برای پایگاه اطلاعاتی شما است.", @@ -310,6 +312,8 @@ "config-install-stats": "شروع آمار", "config-install-keys": "تولید کلیدهای مخفی", "config-insecure-keys": "'''هشدار:''' {{PLURAL:$2|کلید امن|کلیدهای امن}} ($1) در طی نصب کاملاً ایمن {{PLURAL:$2|نیست|نیستند}}. تغییر دستی {{PLURAL:$2|آن|آنها}} را در نظر بگیرید.", + "config-install-updates": "جلوگیری از به روز رسانی‌های غیر ضروری در حال اجرا", + "config-install-updates-failed": "خطا: قراردادن کلیدهای به روز رسانی به داخل جداول با خطای روبرو مواجه شد: $1", "config-install-sysop": "ایجاد حساب کاربری مدیر", "config-install-subscribe-fail": "قادر تصدیق اعلام مدیاویکی نیست:$1", "config-install-subscribe-notpossible": "سی‌یوآر‌ال نصب نشده‌است و allow_url_fopen در دسترس نیست.", diff --git a/includes/installer/i18n/fr.json b/includes/installer/i18n/fr.json index ed0e08b3f6..9fd6726e9a 100644 --- a/includes/installer/i18n/fr.json +++ b/includes/installer/i18n/fr.json @@ -66,6 +66,7 @@ "config-env-good": "L’environnement a été vérifié.\nVous pouvez installer MediaWiki.", "config-env-bad": "L’environnement a été vérifié.\nVous ne pouvez pas installer MediaWiki.", "config-env-php": "PHP $1 est installé.", + "config-env-hhvm": "HHVM $1 est installé.", "config-unicode-using-utf8": "Utilisation de utf8_normalize.so par Brion Vibber pour la normalisation Unicode.", "config-unicode-using-intl": "Utilisation de [http://pecl.php.net/intl l'extension PECL intl] pour la normalisation Unicode.", "config-unicode-pure-php-warning": "Attention : L'[http://pecl.php.net/intl extension PECL intl] n'est pas disponible pour la normalisation d’Unicode, retour à la version lente implémentée en PHP.\nSi votre site web sera très fréquenté, vous devriez lire ceci : [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations ''Unicode normalization''] (en anglais).", diff --git a/includes/installer/i18n/he.json b/includes/installer/i18n/he.json index 296e068c7b..dd14e6335c 100644 --- a/includes/installer/i18n/he.json +++ b/includes/installer/i18n/he.json @@ -51,6 +51,7 @@ "config-env-good": "הסביבה שלכם נבדקה.\nאפשר להתקין מדיה־ויקי.", "config-env-bad": "הסביבה שלכם נבדקה.\nאי־אפשר להתקין מדיה־ויקי.", "config-env-php": "מותקנת PHP $1.", + "config-env-hhvm": "מותקנת HHVM $1.", "config-unicode-using-utf8": "משתמש ב־utf8_normalize.so של בריון ויבר לנרמול יוניקוד.", "config-unicode-using-intl": "משתמש ב[http://pecl.php.net/intl הרחבת intl PECL] לנרמול יוניקוד.", "config-unicode-pure-php-warning": "'''אזהרה''': [http://pecl.php.net/intl הרחבת intl PECL] אינה זמינה לטיפול בנרמול יוניקוד. משתמש ביישום PHP טהור ואטי יותר.\nאם זהו אתר בעל תעבורה גבוהה, כדאי לקרוא את המסמך הבא: [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode normalization].", diff --git a/includes/installer/i18n/it.json b/includes/installer/i18n/it.json index 908d282e0d..d3582db8fe 100644 --- a/includes/installer/i18n/it.json +++ b/includes/installer/i18n/it.json @@ -55,6 +55,7 @@ "config-env-good": "L'ambiente è stato controllato.\nÈ possibile installare MediaWiki.", "config-env-bad": "L'ambiente è stato controllato.\nNon è possibile installare MediaWiki.", "config-env-php": "PHP $1 è installato.", + "config-env-hhvm": "HHVM $1 è installato.", "config-unicode-using-utf8": "Usa Brion Vibber's utf8_normalize.so per la normalizzazione Unicode.", "config-unicode-using-intl": "Usa [http://pecl.php.net/intl l'estensione PECL intl] per la normalizzazione Unicode.", "config-unicode-pure-php-warning": "'''Attenzione:''' [http://pecl.php.net/intl l'estensione PECL intl] non è disponibile per gestire la normalizzazione Unicode, così si usa la lenta implementazione in puro PHP.\nSe esegui un sito ad alto traffico, dovresti leggere alcune considerazioni sulla [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalizzazione Unicode].", @@ -62,6 +63,8 @@ "config-no-db": "Impossibile trovare un driver adatto per il database! È necessario installare un driver per PHP.\nI seguenti formati di database sono supportati: $1.\n\nSe compili PHP autonomamente, riconfiguralo attivando un client database, per esempio utilizzando ./configure --with-mysqli.\nQualora avessi installato PHP per mezzo di un pacchetto Debian o Ubuntu, allora devi installare anche il pacchetto php5-mysql.", "config-outdated-sqlite": "'''Attenzione''': è presente SQLite $1 mentre è richiesta la versione $2, SQLite non sarà disponibile.", "config-no-fts3": "'''Attenzione''': SQLite è compilato senza il [//sqlite.org/fts3.html modulo FTS3], le funzionalità di ricerca non saranno disponibili su questo backend.", + "config-register-globals-error": "Errore: l'opzione PHP [http://php.net/register_globals register_globals] è abilitata.\nDeve essere disabilitata per continuare con l'installazione.\nVedi [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] per un aiuto su come farlo.", + "config-magic-quotes-gpc": "Fatale: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] è attivo!\nQuesta opzione danneggia i dati di input in modo imprevedibile.\nNon puoi installare o utilizzare MediaWiki, a meno che questa opzione sia disabilitata.", "config-magic-quotes-runtime": "'''Errore: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] è attivato!''' Questa opzione interferisce in modo imprevedibile con l'inserimento dei dati. Non è possibile installare o utilizzare MediaWiki a meno che questa opzione non sia disabilitata.", "config-magic-quotes-sybase": "'''Errore: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] è attivato!''' Questa opzione interferisce in modo imprevedibile con l'inserimento dei dati. Non è possibile installare o utilizzare MediaWiki a meno che questa opzione non sia disabilitata.", "config-mbstring": "'''Errore: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] è attivato!''' Questa opzione causa errori e può interferire in modo imprevedibile coi dati. Non è possibile installare o utilizzare MediaWiki a meno che questa opzione non sia disabilitata.", @@ -72,6 +75,7 @@ "config-memory-raised": "Il valore memory_limit di PHP è $1, aumentato a $2.", "config-memory-bad": "''Attenzione:''' Il valore di memory_limit di PHP è $1.\nProbabilmente è troppo basso.\nL'installazione potrebbe non riuscire!", "config-ctype": "'''Errore''': PHP deve essere compilato con il supporto per l'[http://www.php.net/manual/it/ctype.installation.php estensione Ctype].", + "config-iconv": "Fatale: PHP deve essere compilato con il supporto per l'[http://www.php.net/manual/en/iconv.installation.php estensione iconv].", "config-json": "'''Errore:''' PHP è stato compilato senza il supporto per JSON. E' necessario installare l'estensione PHP per JSON o l'estensione [http://pecl.php.net/package/jsonc PECL jsonc] prima di installare MediaWiki.\n* L'estensione PHP è inclusa in Red Hat Enterprise Linux (CentOS) 5 e 6, ma deve essere abilitata in /etc/php.ini o /etc/php.d/json.ini.\n* Alcune distribuzioni di Linux pubblicate dopo il maggio 2013 omettono l'estensione PHP, e al posto utilizzano l'estensione PECL come php5-json o php-pecl-jsonc", "config-xcache": "[http://xcache.lighttpd.net/ XCache] è installato", "config-apc": "[http://www.php.net/apc APC] è installato", @@ -91,10 +95,12 @@ "config-uploads-not-safe": "Attenzione: la directory predefinita per i caricamenti $1 è vulnerabile all'esecuzione arbitraria di script.\nAnche se MediaWiki controlla tutti i file caricati per rischi alla sicurezza, è fortemente raccomandato di [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security#Upload_security chiudere questa vulnerabilità di sicurezza] prima di abilitare i caricamenti.", "config-no-cli-uploads-check": "Attenzione: la directory predefinita per i caricamenti ($1) non è stata verificata per la vulnerabilità sull'esecuzione arbitraria di script durante l'installazione da linea di comando.", "config-brokenlibxml": "Il tuo sistema ha una combinazione di versioni di PHP e libxml2 che è difettosa e che può provocare un danneggiamento non visibile di dati in MediaWiki ed in altre applicazioni per il web.\nAggiorna a libxml2 2.7.3 o successivo ([https://bugs.php.net/bug.php?id=45996 il bug è studiato dal lato PHP]).\nInstallazione interrotta.", + "config-suhosin-max-value-length": "Suhosin è installato e limita il parametro GET length a $1 byte.\nIl componente MediaWiki ResourceLoader funzionerà aggirando questo limite, ma riducendo le prestazioni.\nSe possibile, dovresti impostare suhosin.get.max_value_length a 1024 o superiore in php.ini, ed impostare $wgResourceLoaderMaxQueryLength allo stesso valore in LocalSettings.php.", "config-db-type": "Tipo di database:", "config-db-host": "Host del database:", "config-db-host-help": "Se il server del tuo database è su un server diverso, immetti qui il nome dell'host o il suo indirizzo IP.\n\nSe stai utilizzando un web hosting condiviso, il tuo hosting provider dovrebbe fornirti il nome host corretto nella sua documentazione.\n\nSe stai installando su un server Windows con uso di MySQL, l'uso di \"localhost\" potrebbe non funzionare correttamente come nome del server. In caso di problemi, prova a impostare \"127.0.0.1\" come indirizzo IP locale.\n\nSe usi PostgreSQL, lascia questo campo vuoto per consentire di connettersi tramite un socket Unix.", "config-db-host-oracle": "TNS del database:", + "config-db-host-oracle-help": "Inserisci un valido [http://download.oracle.com/docs/cd/B28359_01/network.111/b28317/tnsnames.htm Local Connect Name]; un file tnsnames.ora deve essere visibile a questa installazione.
    Se stai usando la libreria cliente 10g o più recente puoi anche usare il metodo di denominazione [http://download.oracle.com/docs/cd/E11882_01/network.112/e10836/naming.htm Easy Connect].", "config-db-wiki-settings": "Identifica questo wiki", "config-db-name": "Nome del database:", "config-db-name-help": "Scegli un nome che identifica il tuo wiki.\nNon deve contenere spazi.\n\nSe utilizzi un web hosting condiviso, il tuo hosting provider o ti fornisce uno specifico nome di database da utilizzare, oppure ti consentirà di creare il database tramite un pannello di controllo.", @@ -129,6 +135,10 @@ "config-type-mssql": "Microsoft SQL Server", "config-support-info": "MediaWiki supporta i seguenti sistemi di database:\n\n$1\n\nSe fra quelli elencati qui sotto non vedi il sistema di database che vorresti utilizzare, seguire le istruzioni linkate sopra per abilitare il supporto.", "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] è la configurazione preferibile per MediaWiki ed è quella meglio supportata. MediaWiki funziona anche con [{{int:version-db-mariadb-url}} MariaDB] e [{{int:version-db-percona-url}} Percona Server], che sono compatibili con MySQL.([http://www.php.net/manual/en/mysqli.installation.php Come compilare PHP con supporto MySQL])", + "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL] è un popolare sistema di database open source come alternativa a MySQL. Ci possono essere alcuni bug minori in sospeso, e non è raccomandato per l'uso in un ambiente di produzione. ([http://www.php.net/manual/en/pgsql.installation.php Come compilare PHP con supporto PostgreSQL])", + "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite] è un sistema di database leggero, che è supportato molto bene. ([http://www.php.net/manual/en/pdo.installation.php Come compilare PHP con supporto SQLite], utilizza PDO)", + "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle] è un database di un'impresa commerciale. ([http://www.php.net/manual/en/oci8.installation.php Come compilare PHP con supporto OCI8])", + "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL Server] è un database di un'impresa commerciale per Windows. ([http://www.php.net/manual/en/sqlsrv.installation.php Come compilare PHP con supporto SQLSRV])", "config-header-mysql": "Impostazioni MySQL", "config-header-postgres": "Impostazioni PostgreSQL", "config-header-sqlite": "Impostazioni SQLite", @@ -148,6 +158,8 @@ "config-postgres-old": "PostgreSQL $1 o una versione successiva è necessaria, rilevata la $2.", "config-mssql-old": "Si richiede Microsoft SQL Server $1 o successivo. Tu hai la versione $2.", "config-sqlite-name-help": "Scegli un nome che identifichi il tuo wiki.\nNon utilizzare spazi o trattini.\nQuesto servirà per il nome del file di dati SQLite.", + "config-sqlite-parent-unwritable-group": "Non è possibile creare la directory dati $1, perché la directory superiore $2 non è scrivibile dal webserver.\n\nIl programma di installazione ha determinato l'utente con cui il server web è in esecuzione.\nForniscigli la possibilità di scrivere nella directory $3 per continuare.\nSu un sistema Unix/Linux:\n\n
    cd $2\nmkdir $3\nchgrp $4 $3\nchmod g+w $3
    ", + "config-sqlite-parent-unwritable-nogroup": "Non è possibile creare la directory dati $1, perché la directory superiore $2 non è scrivibile dal webserver.\n\nIl programma di installazione non ha potuto determinare l'utente con cui il server web è in esecuzione.\nFornisci ad esso (ed altri!) la possibilità di scrivere globalmente nella directory $3 per continuare.\nSu un sistema Unix/Linux:\n\n
    cd $2\nmkdir $3\nchmod a+w $3
    ", "config-sqlite-mkdir-error": "Errore durante la creazione della directory dati \"$1\".\nControlla la posizione e riprova.", "config-sqlite-dir-unwritable": "Impossibile scrivere nella directory \"$1\".\nModifica le autorizzazioni in modo che il webserver possa scrivere in essa e riprova.", "config-sqlite-connection-error": "$1.\n\nControlla la directory dati e il nome del database qui sotto, poi riprova.", @@ -168,10 +180,13 @@ "config-mysql-engine": "Storage engine:", "config-mysql-innodb": "InnoDB", "config-mysql-myisam": "MyISAM", + "config-mysql-engine-help": "InnoDB è quasi sempre l'opzione migliore, in quanto ha un buon supporto della concorrenza.\n\nMyISAM potrebbe essere più veloce nelle installazioni monoutente o in sola lettura.\nI database MyISAM tendono a danneggiarsi più spesso dei database InnoDB.", "config-mysql-charset": "Set di caratteri del database:", "config-mysql-binary": "Binario", "config-mysql-utf8": "UTF-8", "config-mssql-auth": "Tipo di autenticazione:", + "config-mssql-install-auth": "Seleziona il tipo di autenticazione che verrà utilizzato per connettersi al database durante il processo di installazione.\nSe si seleziona \"{{int:config-mssql-windowsauth}}\", saranno utilizzate le credenziali dell'utente con cui viene eseguito il server web, qualunque esso sia.", + "config-mssql-web-auth": "Seleziona il tipo di autenticazione che il server web utilizzerà per connettersi al database, durante il normale funzionamento del wiki.\nSe si seleziona \"{{int:config-mssql-windowsauth}}\", saranno utilizzate le credenziali dell'utente con cui viene eseguito il server web, qualunque esso sia.", "config-mssql-sqlauth": "Autenticazione di SQL Server", "config-mssql-windowsauth": "Autenticazione di Windows", "config-site-name": "Nome del wiki:", @@ -182,6 +197,9 @@ "config-ns-site-name": "Stesso nome del wiki: $1", "config-ns-other": "Altro (specificare)", "config-ns-other-default": "MyWiki", + "config-project-namespace-help": "Seguendo l'esempio di Wikipedia, molti wiki tengono le loro pagine con le regole separate dalle pagine di contenuto, in un \"'''namespace di progetto'''\".\nTutti i titoli delle pagine in questo namespace iniziano con un certo prefisso, che puoi indicare qui.\nSolitamente, questo prefisso deriva dal nome del wiki, ma non può contenere caratteri di punteggiatura come \"#\" o \":\".", + "config-ns-invalid": "Il namespace indicato \"$1\" non è valido.\nSpecificare un diverso namespace di progetto.", + "config-ns-conflict": "Il namespace indicato \"$1\" è in conflitto con un namespace predefinito MediaWiki.\nSpecificare un diverso namespace di progetto.", "config-admin-box": "Account amministratore", "config-admin-name": "Il tuo nome utente:", "config-admin-password": "Password:", @@ -191,7 +209,7 @@ "config-admin-name-invalid": "Il nome utente specificato \"$1\" non è valido.\nSpecificare un nome utente diverso.", "config-admin-password-blank": "Inserisci una password per l'account di amministratore.", "config-admin-password-mismatch": "Le password inserite non coincidono tra loro.", - "config-admin-email": "Indirizzo e-mail:", + "config-admin-email": "Indirizzo email:", "config-admin-email-help": "Inserisci qui un indirizzo email per poter ricevere email dagli altri utenti del wiki, reimpostare la tua password, ed essere informato delle modifiche apportate alle pagine tuoi osservati speciali. Se non ti interessa, puoi lasciare vuoto questo campo.", "config-admin-error-user": "Errore interno durante la creazione di un amministratore con il nome \"$1\".", "config-admin-error-password": "Errore interno durante l'impostazione di una password per amministratore \"$1\":
    $2
    ", @@ -219,6 +237,7 @@ "config-license-help": "Molti wiki pubblici rilasciano i loro contributi con una [http://freedomdefined.org/Definition licenza libera]. Questo aiuta a creare un senso di proprietà condivisa nella comunità e incoraggia a contribuire a lungo termine. Non è generalmente necessario per un wiki privato o aziendale.\n\nSe vuoi usare testi da Wikipedia, o desideri che Wikipedia possa essere in grado di accettare testi copiati dal tuo wiki, dovresti scegliere {{int:config-license-cc-by-sa}}.\n\nIn precedenza Wikipedia ha utilizzato la GNU Free Documentation License. La GFDL è una licenza valida, ma è di difficile comprensione e complica il riutilizzo dei contenuti.", "config-email-settings": "Impostazioni email", "config-enable-email": "Abilita la posta elettronica in uscita", + "config-enable-email-help": "Se vuoi che funzionino le email, le [http://www.php.net/manual/en/mail.configuration.php PHP's impostazioni della posta] devono essere configurate correttamente.\nSe non si desidera alcuna funzionalità di posta elettronica, puoi disabilitarla qui.", "config-email-user": "Abilita invio email fra utenti", "config-email-user-help": "Consente a tutti gli utenti di inviarsi a vicenda email, se lo hanno abilitato nelle loro preferenze.", "config-email-usertalk": "Abilita le notifiche per le pagine di discussione utente", @@ -226,14 +245,18 @@ "config-email-watchlist": "Abilita le notifiche per gli osservati speciali", "config-email-watchlist-help": "Consente agli utenti di ricevere notifiche per pagine tra gli osservati speciali, se lo hanno abilitato nelle loro preferenze.", "config-email-auth": "Abilita autenticazione via email", + "config-email-auth-help": "Se questa opzione è attivata, gli utenti dovranno confermare il loro indirizzo email utilizzando un collegamento che viene inviato ogni volta che lo impostano o lo modificano.\nSolo gli indirizzi di posta elettronica autenticati possono ricevere email da altri utenti o modificare le email di notifica.\nImpostare questa opzione è raccomandato per wiki pubblici a causa del potenziale abuso delle funzioni di posta elettronica.", "config-email-sender": "Indirizzo email di ritorno:", + "config-email-sender-help": "Inserisci l'indirizzo email da utilizzare come indirizzo di ritorno per la posta in uscita.\nQuesto è dove verranno inviati gli eventuali errori.\nMolti server di posta richiedono che almeno la parte del nome di dominio sia valido.", "config-upload-settings": "Caricamenti di immagini e file", "config-upload-enable": "Consentire il caricamento di file", + "config-upload-help": "Il caricamento di file può potenzialmente esporre il tuo server a rischi di sicurezza.\nPer ulteriori informazioni, leggi la [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Security sezione sulla sicurezza] nel manuale.\n\nPer consentire il caricamento di file, modificare la modalità nella sottodirectory images della directory principale di MediaWiki affinché il server web possa scriverci.\nPoi attivare questa opzione.", "config-upload-deleted": "Directory per i file cancellati:", "config-upload-deleted-help": "Scegli una directory in cui archiviare i file cancellati.\nIdealmente, questa non dovrebbe essere accessibile dal web.", "config-logo": "URL del logo:", "config-logo-help": "La skin predefinita di MediaWiki include lo spazio per un logo di 135 x 160 pixel sopra il menu laterale.\nCarica un'immagine di dimensioni appropriate e inserisci l'URL qui.\n\nÈ possibile utilizzare $wgStylePath o $wgScriptPath se il logo è relativo a tali percorsi.\n\nSe non si desidera un logo, lascia vuota questa casella.", "config-instantcommons": "Abilita Instant Commons", + "config-instantcommons-help": "[//www.mediawiki.org/wiki/InstantCommons Instant Commons] è una funzionalità che consente ai wiki di usare immagini, suoni e altri file multimediali che trovate sul sito [//commons.wikimedia.org/ Wikimedia Commons].\nPer fare questo, MediaWiki richiede l'accesso a Internet.\n\nPer ulteriori informazioni su questa funzionalità, incluse le istruzioni su come configurarlo per wiki diversi da Wikimedia Commons, consultare [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgForeignFileRepos il manuale].", "config-cc-error": "Il selettore di licenze Creative Commons non ha dato alcun risultato.\nInserisci manualmente il nome della licenza.", "config-cc-again": "Seleziona di nuovo...", "config-cc-not-chosen": "Scegliere quale licenza Creative Commons si desidera e cliccare su \"procedi\".", @@ -251,6 +274,12 @@ "config-memcache-badport": "I numeri di porta per memcached dovrebbero essere tra $1 e $2.", "config-extensions": "Estensioni", "config-extensions-help": "Le estensioni elencate sopra sono state rilevate nella tua directory ./extensions.\n\nQueste potrebbero richiedere ulteriore configurazione, ma è possibile attivarle ora", + "config-skins": "Skin", + "config-skins-help": "Le skin elencate sopra sono state rilevate nella tua directory ./skins. Devi attivarne almeno una e scegliere quella predefinita.", + "config-skins-use-as-default": "Usa questa skin come predefinita", + "config-skins-missing": "Non è stata trovata alcuna skin, MediaWiki userà una soluzione di ripiego finché non ne installerai una appropriata.", + "config-skins-must-enable-some": "Devi scegliere almeno una skin da attivare.", + "config-skins-must-enable-default": "La skin scelta come predefinita deve essere attivata.", "config-install-alreadydone": "'''Attenzione:''' sembra che hai già installato MediaWiki e stai tentando di installarlo nuovamente.\nProcedi alla pagina successiva.", "config-install-begin": "Premendo \"{{int:config-continue}}\", si avvierà l'installazione di MediaWiki.\nSe prima desideri apportare altre modifiche, premi \"{{int:config-back}}\".", "config-install-step-done": "fatto", @@ -264,6 +293,7 @@ "config-install-pg-plpgsql": "Controllo il linguaggio PL/pgSQL", "config-pg-no-plpgsql": "È necessario installare il linguaggio PL/pgSQL nel database $1", "config-pg-no-create-privs": "L'account indicato per l'installazione non dispone dei permessi necessari per creare un'utenza.", + "config-pg-not-in-role": "L'account indicato per l'utente web esiste già.\nL'account indicato per l'installazione non è un utente avanzato e non è un membro del ruolo degli utente web, quindi non è in grado di creare oggetti di proprietà dell'utente web.\n\nMediaWiki attualmente richiede che le tabelle siano di proprietà dell'utente web. Indica un altro account web, o fai click su \"indietro\" e specifica un utente per l'installazione opportunamente privilegiato.", "config-install-user": "Creazione di utente del database", "config-install-user-alreadyexists": "L'utente \"$1\" è già presente", "config-install-user-create-failed": "Creazione dell'utente \"$1\" non riuscita: $2", @@ -279,6 +309,8 @@ "config-install-stats": "Inizializzazione delle statistiche", "config-install-keys": "Generazione delle chiavi segrete", "config-insecure-keys": "'''Attenzione:''' {{PLURAL:$2|Una chiave sicura|Delle chiavi sicure}} ($1) {{PLURAL:$2|generata|generate}} durante l'installazione non {{PLURAL:$2|è|sono}} completamente {{PLURAL:$2|sicura|sicure}}. Considera di {{PLURAL:$2|cambiarla|cambiarle}} manualmente.", + "config-install-updates": "Impedire l'esecuzione di aggiornamenti non necessari", + "config-install-updates-failed": "Errore: l'inserimento delle chiavi di aggiornamento nelle tabelle non è riuscito con il seguente errore: $1", "config-install-sysop": "Creazione dell'account utente per l'amministratore", "config-install-subscribe-fail": "Impossibile sottoscrivere mediawiki-announce: $1", "config-install-subscribe-notpossible": "cURL non è installato e allow_url_fopen non è disponibile.", diff --git a/includes/installer/i18n/ja.json b/includes/installer/i18n/ja.json index 39ebf877cf..21fcb9d7ff 100644 --- a/includes/installer/i18n/ja.json +++ b/includes/installer/i18n/ja.json @@ -58,6 +58,7 @@ "config-env-good": "環境を確認しました。\nMediaWiki をインストールできます。", "config-env-bad": "環境を確認しました。\nMediaWiki のインストールはできません。", "config-env-php": "PHP $1がインストールされています。", + "config-env-hhvm": "HHVM $1 がインストールされています。", "config-unicode-using-utf8": "Unicode正規化に、Brion Vibberのutf8_normalize.soを使用。", "config-unicode-using-intl": "Unicode正規化に[http://pecl.php.net/intl intl PECL 拡張機能]を使用。", "config-unicode-pure-php-warning": "警告: Unicode 正規化の処理に [http://pecl.php.net/intl intl PECL 拡張機能]を利用できないため、処理が遅いピュア PHP の実装を代わりに使用しています。\n高トラフィックのサイトを運営する場合は、[//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode 正規化]をお読みください。", diff --git a/includes/installer/i18n/lb.json b/includes/installer/i18n/lb.json index 030e0c19de..4d73ca0252 100644 --- a/includes/installer/i18n/lb.json +++ b/includes/installer/i18n/lb.json @@ -44,6 +44,7 @@ "config-env-good": "Den Environement gouf nogekuckt.\nDir kënnt MediaWiki installéieren.", "config-env-bad": "Den Environnement gouf iwwerpréift.\nDir kënnt MediWiki net installéieren.", "config-env-php": "PHP $1 ass installéiert.", + "config-env-hhvm": "HHVM $1 ass installéiert.", "config-unicode-using-utf8": "Fir d'Unicode-Normalisatioun gëtt dem Brion Vibber säin utf8_normalize.so benotzt.", "config-no-db": "Et konnt kee passenden Datebank-Driver fonnt ginn! Dir musst een Datebank-Driver fir PHP installéieren.\nDës Datebank-Type ginn ënnerstëtzt: $1.\n\nWann Dir PHP selwer compiléiert hutt, da rekonfiguréiert en mat dem ageschalten Datebank-Client, zum Beispill an deem Dir ./configure --with-mysql benotzt.\nWann Dir PHP vun engem Debian oder Ubuntu Package aus installéiert hutt, da musst Dir och den php5-mysql Modul installéieren.", "config-outdated-sqlite": "'''Warnung:''' SQLite $1 ass installéiert. Allerdengs brauch MediaWiki SQLite $2 oder méi nei. SQLite ass dofir net disponibel.", diff --git a/includes/installer/i18n/mk.json b/includes/installer/i18n/mk.json index 3c40ab556a..8784521e16 100644 --- a/includes/installer/i18n/mk.json +++ b/includes/installer/i18n/mk.json @@ -47,6 +47,7 @@ "config-env-good": "Околината е проверена.\nМожете да го воспоставите МедијаВики.", "config-env-bad": "Околината е проверена.\nНе можете да го воспоставите МедијаВики.", "config-env-php": "PHP $1 е воспоставен.", + "config-env-hhvm": "HHVM $1 е воспоставен.", "config-unicode-using-utf8": "Со utf8_normalize.so за уникодна нормализација од Брајон Вибер (Brion Vibber).", "config-unicode-using-intl": "Со додатокот [http://pecl.php.net/intl intl PECL] за уникодна нормализација.", "config-unicode-pure-php-warning": "'''Предупредување''': Додатокот [http://pecl.php.net/intl intl PECL] не е достапен за врши уникодна нормализација, враќајќи се на бавна примена на чист PHP.\n\nАко имате високопрометно мрежно место, тогаш ќе треба да прочитате повеќе за [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations уникодната нормализација].", diff --git a/includes/installer/i18n/mt.json b/includes/installer/i18n/mt.json index 0a84d8734b..262a83782f 100644 --- a/includes/installer/i18n/mt.json +++ b/includes/installer/i18n/mt.json @@ -1,7 +1,8 @@ { "@metadata": { "authors": [ - "Chrisportelli" + "Chrisportelli", + "Leli Forte" ] }, "config-title": "Installazzjoni ta' MediaWiki $1", @@ -30,6 +31,7 @@ "config-page-existingwiki": "Wiki eżistenti", "config-restart": "Iva, erÄ¡a' ibda", "config-env-php": "PHP $1 huwa installat.", + "config-env-hhvm": "HHVM $1 hu installat.", "config-db-wiki-settings": "Identifika din il-wiki", "config-db-name": "Isem tad-databażi:", "config-db-install-account": "Kont tal-utent għall-installazzjoni", @@ -46,13 +48,13 @@ "config-site-name": "Isem tal-wiki:", "config-site-name-help": "Dan se jidher fil-barra tat-titlu tal-browżer u f'diversi postijiet oħra.", "config-site-name-blank": "Daħħal isem tas-sit.", - "config-project-namespace": "Spazju tal-isem tal-proÄ¡ett:", + "config-project-namespace": "Spazju tal-ismijiet tal-proÄ¡ett:", "config-ns-generic": "ProÄ¡ett", "config-ns-site-name": "L-istess bħall-isem tal-wiki: $1", "config-ns-other": "Oħrajn (speċifika)", "config-ns-other-default": "MyWiki", - "config-ns-invalid": "L-ispazju speċifikat \"$1\" huwa ħażin.\nSpeċifika spazju tal-isem tal-proÄ¡ett differenti.", - "config-ns-conflict": "L-ispazju speċifikat \"$1\" joħloq kunflitt ma' spazju tal-isem ieħor tal-MediaWiki.\nSpeċifika spazju tal-isem tal-proÄ¡ett differenti.", + "config-ns-invalid": "L-ispazju speċifikat \"$1\" huwa ħażin.\nSpeċifika spazju tal-ismijiet ta' proÄ¡ett differenti.", + "config-ns-conflict": "L-ispazju speċifikat \"$1\" joħloq kunflitt ma' spazju tal-ismijiet tal-MediaWiki predeterminat.\nSpeċifika spazju tal-ismijiet ta' proÄ¡ett differenti.", "config-admin-box": "Kont tal-amministratur", "config-admin-name": "Ismek:", "config-admin-password": "Password:", diff --git a/includes/installer/i18n/nap.json b/includes/installer/i18n/nap.json index 0bfcbe8d12..1cbe7d56b4 100644 --- a/includes/installer/i18n/nap.json +++ b/includes/installer/i18n/nap.json @@ -4,6 +4,13 @@ "C.R." ] }, + "config-desc": "'O prugramma d'istallazione 'e MediaWiki", + "config-title": "Installazione 'e MediaWiki $1", + "config-information": "Nfurmaziune", + "config-localsettings-upgrade": "È stato rilevato nu file LocalSettings.php.\nP'agghiurnà sta installazione, pe' piacere nzertàte 'o valore 'e $wgUpgradeKey dint' 'a cascia ccà abbascio.\n'O putite truvà dint'a LocalSettings.php.", + "config-localsettings-cli-upgrade": "È stato scummigliato nu file LocalSettings.php.\nPe l'agghiurnà sta installazione, secutate update.php", + "config-localsettings-key": "Chiave d'agghiurnamiento:", + "config-localsettings-badkey": "'A chiave c'avete dato nun è curretta.", "config-mssql-install-auth": "Sceglie 'o tipo d'autenticazziona ca s'ausarrà pe cunnettà â database, durante ll'operazziona d'istallazziona. Si piglie \"{{int:config-mssql-windowsauth}}\", 'e credenziale 'e qualunque fosse ll'utenza ca 'o webserver sta pruciessanno sarranno ausate.", "config-mssql-web-auth": "Sceglie 'o tipo d'autenticazziona ca 'o web server pigliarrà pe se cunnettà a 'o server 'e bbase 'e dati, durante ll'operazziona nurmale d''a wiki.\nSi piglie \"{{int:config-mssql-windowsauth}}\", 'e credenziale 'e qualunque fosse ll'utenza ca 'o webserver sta pruciessanno sarranno ausate." } diff --git a/includes/installer/i18n/nb.json b/includes/installer/i18n/nb.json index 93ddfa4c62..f3cf645495 100644 --- a/includes/installer/i18n/nb.json +++ b/includes/installer/i18n/nb.json @@ -50,6 +50,7 @@ "config-env-good": "Miljøet har blitt sjekket.\nDu kan installere MediaWiki.", "config-env-bad": "Miljøet har blitt sjekket.\nDu kan installere MediaWiki.", "config-env-php": "PHP $1 er innstallert.", + "config-env-hhvm": "HHVM $1 er installert.", "config-unicode-using-utf8": "Bruker Brion Vibbers utf8_normalize.so for Unicode-normalisering.", "config-unicode-using-intl": "Bruker [http://pecl.php.net/intl intl PECL-utvidelsen] for Unicode-normalisering.", "config-unicode-pure-php-warning": "'''Advarsel''': [http://pecl.php.net/intl intl PECL-utvidelsen] er ikke tilgjengelig for Ã¥ hÃ¥ndtere Unicode-normaliseringen, faller tilbake til en langsommere ren-PHP-implementasjon.\nOm du kjører et nettsted med høy trafikk bør du lese litt om [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-normalisering].", @@ -58,6 +59,7 @@ "config-outdated-sqlite": "'''Advarsel''': Du har SQLite $1, som er en eldre versjon enn minimumskravet SQLite $2. SQLite vil ikke være tilgjengelig.", "config-no-fts3": "'''Advarsel''': SQLite er kompilert uten [//sqlite.org/fts3.html FTS3-modulen], søkefunksjoner vil ikke være tilgjengelig pÃ¥ dette bakstykket.", "config-register-globals-error": "Feil: PHPs [http://php.net/register_globals register_globals]-valg er aktivt.\nDet mÃ¥ deaktiveres for Ã¥ kunne fortsette med installeringen.\nSe [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] for Ã¥ fÃ¥ hjelp til Ã¥ gjøre dette.", + "config-magic-quotes-gpc": "Fatalt: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] er aktiv!\nDette valget kan ødelegge inndata pÃ¥ en uforutsigelig mÃ¥te.\nDu kan ikke installere eller bruke MediaWiki uten at denne valgmuligheten er slÃ¥tt av.", "config-magic-quotes-runtime": "'''Kritisk: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] er aktiv!'''\nDette alternativet ødelegger inndata pÃ¥ en uforutsigbar mÃ¥te.\nDu kan ikke installere eller bruke MediaWiki med mindre dette alternativet deaktiveres.", "config-magic-quotes-sybase": "'''Kritisk: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] er aktiv!'''\nDette alternativet ødelegger inndata pÃ¥ en uforutsigbar mÃ¥te.\nDu kan ikke installere eller bruke MediaWiki med mindre dette alternativet deaktiveres.", "config-mbstring": "'''Kritisk: [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] er aktiv!'''\nDette alternativet fører til feil og kan ødelegge data pÃ¥ en uforutsigbar mÃ¥te.\nDu kan ikke installere eller bruke MediaWiki med mindre dette alternativet deaktiveres.", @@ -68,6 +70,7 @@ "config-memory-raised": "PHPs memory_limit er $1, økt til $2.", "config-memory-bad": "'''Advarsel:''' PHPs memory_limit er $1.\nDette er sannsynligvis for lavt.\nInstallasjonen kan mislykkes!", "config-ctype": "'''Fatal feil''': PHP mÃ¥ kompileres med støtte for [http://www.php.net/manual/en/ctype.installation.php Ctype-utvidelsen].", + "config-iconv": "Kritisk: PHP mÃ¥ kompileres med støtte for [http://www.php.net/manual/en/iconv.installation.php iconv-utvidelsen].", "config-json": "'''Alvorlig:''' PHP ble kompilert uten JSON-støtte.\nDu mÃ¥ installere enten PHP JSON-utvidelsen eller [http://pecl.php.net/package/jsonc PECL jsonc]-utvidelsen før du installere MediaWiki.\n* PHP-utvidelsen inngÃ¥r i Red Hat Enterprise Linux (CentOS) 5 and 6, men mÃ¥ aktiveres i /etc/php.ini eller /etc/php.d/json.ini.\n* Noen Linux-distribusjoner sluppet etter mai 2013 har ikke med PHP-utvidelsen, men har i stedet med PECL-utvidelsen php5-json eller php-pecl-jsonc.", "config-xcache": "[http://xcache.lighttpd.net/ XCache] er innstallert", "config-apc": "[http://www.php.net/apc APC] er innstallert", diff --git a/includes/installer/i18n/ne.json b/includes/installer/i18n/ne.json index b2d4a040e2..836e0fcb84 100644 --- a/includes/installer/i18n/ne.json +++ b/includes/installer/i18n/ne.json @@ -4,9 +4,15 @@ "Bhawani Gautam", "RajeshPandey", "सरोज कुमार ढकाल", - "Ganesh Paudel" + "Ganesh Paudel", + "बिप्लब आनन्द" ] }, + "config-information": "जानकारी", + "config-localsettings-badkey": "तपाइले दिनु भएको कुन्जी गलत छ ।", + "config-your-language": "तपाईंको भाषा:", + "config-your-language-help": "इन्स्टल गर्दा उपयोग गर्ने भाषा छान्नुहोस् ।", + "config-wiki-language": "विकि भाषाहरू", "config-page-name": "नाम", "config-page-options": "विकल्पहरु", "config-page-install": "स्थापना गर्ने", diff --git a/includes/installer/i18n/oc.json b/includes/installer/i18n/oc.json index e4bcb6e221..372058f8d8 100644 --- a/includes/installer/i18n/oc.json +++ b/includes/installer/i18n/oc.json @@ -37,7 +37,7 @@ "config-env-good": "L’environament es estat verificat.\nPodètz installar MediaWiki.", "config-env-bad": "L’environament es estat verificat.\nPodètz pas installar MediaWiki.", "config-env-php": "PHP $1 es installat.", - "config-env-php-toolow": "PHP $1 es installat.\nPasmens, MediaWiki requerís PHP $2 o superior.", + "config-env-hhvm": "HHVM $1 es installat.", "config-unicode-using-utf8": "Utilizacion de utf8_normalize.so per Brion Vibber per la normalizacion Unicode.", "config-unicode-using-intl": "Utilizacion de [http://pecl.php.net/intl l'extension PECL intl] per la normalizacion Unicode.", "config-memory-raised": "Lo paramètre memory_limit de PHP èra a $1, portat a $2.", @@ -153,20 +153,29 @@ "config-cache-options": "Paramètres per la mesa en escondedor dels objèctes :", "config-memcached-servers": "servidors per Memcached :", "config-extensions": "Extensions", + "config-skins": "Abilhatges", + "config-skins-use-as-default": "Utilizar aqueste abilhatge per defaut", "config-install-step-done": "fach", "config-install-step-failed": "fracàs", "config-install-extensions": "Inclusion de las extensions", "config-install-database": "Creacion de la banca de donadas", "config-install-schema": "Creacion d'esquèma", + "config-install-pg-schema-not-exist": "L'esquèma PostgreSQL existís pas", "config-install-pg-commit": "Validacion de las modificacions", "config-install-pg-plpgsql": "Verificacion del lengatge PL/pgSQL", "config-install-user": "Creacion d'un utilizaire de la banca de donadas", + "config-install-user-alreadyexists": "L'utilizaire « $1 » existís ja.", + "config-install-user-create-failed": "Fracàs al moment de la creacion de l'utilizaire « $1 » : $2", + "config-install-user-missing": "L'utilizaire «$1» existís pas.", "config-install-tables": "Creacion de las taulas", "config-install-stats": "Inicializacion de las estatisticas", + "config-install-keys": "Generacion de la clau secreta", + "config-install-updates": "Empachar l’execucion de las mesas a jorn inutilas", "config-install-sysop": "Creacion del compte administrator", "config-install-mainpage-failed": "Impossible d’inserir la pagina principala : $1", "config-download-localsettings": "Telecargar LocalSettings.php", "config-help": "ajuda", + "config-help-tooltip": "clicar per agrandir", "mainpagetext": "'''MediaWiki es estat installat amb succès.'''", "mainpagedocfooter": "Consultatz lo [//meta.wikimedia.org/wiki/Help:Contents/fr Guida de l'utilizaire] per mai d'entresenhas sus l'utilizacion d'aqueste logicial de wiki.\n\n== Per començar ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista dels paramètres de configuracion]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ/oc FAQ MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Lista de discussions de las distribucions de MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Adaptatz MediaWiki dins vòstra lenga]" } diff --git a/includes/installer/i18n/pl.json b/includes/installer/i18n/pl.json index 0c48ffa35b..2e7e0233bc 100644 --- a/includes/installer/i18n/pl.json +++ b/includes/installer/i18n/pl.json @@ -62,6 +62,7 @@ "config-env-good": "Środowisko oprogramowania zostało sprawdzone.\nMożesz teraz zainstalować MediaWiki.", "config-env-bad": "Środowisko oprogramowania zostało sprawdzone.\nNie możesz zainstalować MediaWiki.", "config-env-php": "Zainstalowane jest PHP w wersji $1.", + "config-env-hhvm": "Zainstalowany jest HHVM $1.", "config-unicode-using-utf8": "Korzystanie z normalizacji Unicode utf8_normalize.so napisanej przez Brion Vibbera.", "config-unicode-using-intl": "Korzystanie z [http://pecl.php.net/intl rozszerzenia intl PECL] do normalizacji Unicode.", "config-unicode-pure-php-warning": "'''Uwaga!''' [http://pecl.php.net/intl Rozszerzenie intl PECL] do obsługi normalizacji Unicode nie jest dostępne. Użyta zostanie mało wydajna zwykła implementacja w PHP.\nJeśli prowadzisz stronę o dużym natężeniu ruchu, powinieneś zapoznać się z informacjami o [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations normalizacji Unicode].", @@ -321,6 +322,7 @@ "config-install-stats": "Inicjowanie statystyki", "config-install-keys": "Generowanie tajnych kluczy", "config-insecure-keys": "'''Ostrzeżenie:''' {{PLURAL:$2|Klucz bezpieczeństwa|Klucze bezpieczeństwa|Klucze bezpieczeństwa}} ($1) utworzone podczas instalacji {{PLURAL:$2|utworzony podczas instalacji nie jest|utworzone podczas instalacji nie są|utworzone podczas instalacji nie są}} w pełni bezpieczne. Być może warto wygenerować {{PLURAL:$2|własny klucz|własne klucze|własne klucze}}.", + "config-install-updates": "Zapobieganie uruchamianiu niepotrzebnych aktualizacji", "config-install-sysop": "Tworzenie konta administratora", "config-install-subscribe-fail": "Nie można zapisać na listę „mediawiki-announce“ – $1", "config-install-subscribe-notpossible": "cURL nie jest zainstalowany, więc allow_url_fopen nie jest dostępne.", diff --git a/includes/installer/i18n/pt.json b/includes/installer/i18n/pt.json index a827fac31d..835cf9b410 100644 --- a/includes/installer/i18n/pt.json +++ b/includes/installer/i18n/pt.json @@ -59,6 +59,7 @@ "config-env-good": "O ambiente foi verificado.\nPode instalar o MediaWiki.", "config-env-bad": "O ambiente foi verificado.\nNão pode instalar o MediaWiki.", "config-env-php": "O PHP $1 está instalado.", + "config-env-hhvm": "HHVM $1 está instalado.", "config-unicode-using-utf8": "A usar o utf8_normalize.so, por Brion Vibber, para a normalização Unicode.", "config-unicode-using-intl": "A usar a [http://pecl.php.net/intl extensão intl PECL] para a normalização Unicode.", "config-unicode-pure-php-warning": "'''Aviso''': A [http://pecl.php.net/intl extensão intl PECL] não está disponível para efetuar a normalização Unicode. Irá recorrer-se à implementação em PHP puro, que é mais lenta.\nSe o seu site tem alto volume de tráfego, devia informar-se um pouco sobre a [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations/pt normalização Unicode].", diff --git a/includes/installer/i18n/qqq.json b/includes/installer/i18n/qqq.json index c879843aff..dc65dd64f1 100644 --- a/includes/installer/i18n/qqq.json +++ b/includes/installer/i18n/qqq.json @@ -270,7 +270,7 @@ "config-upload-deleted": "Prompt for the server directory into which deleted files should be moved.", "config-upload-deleted-help": "Explanation for {{msg|config-upload-deleted}}.", "config-logo": "Prompt for a link to the logo to use for the wiki.", - "config-logo-help": "", + "config-logo-help": "Help string shown to the user explaining the requirements for the wiki's logo.", "config-instantcommons": "Used as label for the checkbox.\n\nThe help message for this checkbox is:\n* {{msg-mw|Config-instantcommons-help}}", "config-instantcommons-help": "Used as help message for the checkbox which is labeled {{msg-mw|config-instantcommons}}.", "config-cc-error": "Prompt to manually enter a license when the tool fails to match.", diff --git a/includes/installer/i18n/ru.json b/includes/installer/i18n/ru.json index ccd88e8005..b8a36bef28 100644 --- a/includes/installer/i18n/ru.json +++ b/includes/installer/i18n/ru.json @@ -62,6 +62,7 @@ "config-env-good": "Проверка внешней среды была успешно проведена.\nВы можете установить MediaWiki.", "config-env-bad": "Была проведена проверка внешней среды.\nВы не можете установить MediaWiki.", "config-env-php": "Установленная версия PHP: $1.", + "config-env-hhvm": "HHVM $1 установлена.", "config-unicode-using-utf8": "Использовать Brion Vibber utf8_normalize.so для нормализации Юникода.", "config-unicode-using-intl": "Будет использовано [http://pecl.php.net/intl расширение «intl» для PECL] для нормализации Юникода.", "config-unicode-pure-php-warning": "'''Внимание!''': [http://pecl.php.net/intl расширение intl из PECL] недоступно для нормализации Юникода, будет использоваться медленная реализация на чистом PHP.\nЕсли ваш сайт работает под высокой нагрузкой, вам следует больше узнать о [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations нормализации Юникода].", diff --git a/includes/installer/i18n/sl.json b/includes/installer/i18n/sl.json index 961264d2a5..b27fcdd3bb 100644 --- a/includes/installer/i18n/sl.json +++ b/includes/installer/i18n/sl.json @@ -2,16 +2,20 @@ "@metadata": { "authors": [ "Dbc334", - "Eleassar" + "Eleassar", + "Yerpo" ] }, "config-desc": "Namestitveni program za MediaWiki", "config-title": "Namestitev MediaWiki $1", "config-information": "Informacije", + "config-localsettings-upgrade": "Zaznana je bila datoteka LocalSettings.php.\nZa nadgradnjo te inÅ¡talacije prosim vnesite vrednost $wgUpgradeKey v polje za vnos spodaj.\nNaÅ¡li jo boste v LocalSettings.php.", "config-localsettings-cli-upgrade": "Zaznana je bila datoteka LocalSettings.php.\nZa nadgradnjo te namestitve zaženite update.php", "config-localsettings-key": "Nadgraditveni ključ:", "config-localsettings-badkey": "Naveden ključ je napačen.", "config-upgrade-key-missing": "Zaznana je bila obstoječa namestitev MediaWiki.\nZa nadgradnjo te namestitve vstavite naslednjo vrstico na dno vaÅ¡e LocalSettings.php:\n\n$1", + "config-localsettings-incomplete": "Kaže, da je obstoječa datoteka LocalSettings.php nepopolna. Vrednost $1 ni nastavljena. Prosimo, nastavite to vrednost v LocalSettings.php in kliknite \"{{int:Config-continue}}\".", + "config-localsettings-connection-error": "PriÅ¡lo je do napake pri povezovanju s podatkovno zbirko z nastavitvami, določenimi v LocalSettings.php. Prosimo popravite te nastavitve in poskusite znova.\n\n$1", "config-session-error": "Napaka pri začenjanju seje: $1", "config-session-expired": "Kot kaže, so vaÅ¡i podatki seje potekli.\nSeje so konfigurirane za dobo $1.\nTo lahko povečate tako, da nastavite session.gc_maxlifetime v php.ini.\nPonovno zaženite postopek namestitve.", "config-no-session": "VaÅ¡i podatki seje so bili izgubljeni!\nPreverite vaÅ¡ php.ini in se prepričajte, da je session.save_path nastavljena na ustrezno mapo.", @@ -43,7 +47,6 @@ "config-env-good": "Okolje je pregledano.\nLahko namestite MediaWiki.", "config-env-bad": "Okolje je pregledano.\nNe morete namestiti MediaWiki.", "config-env-php": "Nameščen je PHP $1.", - "config-env-php-toolow": "Nameščen je PHP $1.\nVendar pa MediaWiki zahteva PHP $2 ali viÅ¡ji.", "config-unicode-using-utf8": "Uporaba utf8_normalize.so Briona Vibberja za normalizacijo unikoda.", "config-unicode-using-intl": "Uporaba [http://pecl.php.net/intl razÅ¡iritve PECL intl] za normalizacijo unikoda.", "config-memory-raised": "PHP-jev memory_limit je $1, dvignjen na $2.", diff --git a/includes/installer/i18n/sv.json b/includes/installer/i18n/sv.json index b46902c4fa..2bdfb10072 100644 --- a/includes/installer/i18n/sv.json +++ b/includes/installer/i18n/sv.json @@ -51,6 +51,7 @@ "config-env-good": "Miljön har kontrollerats.\nDu kan installera MediaWiki.", "config-env-bad": "Miljön har kontrollerats.\nDu kan inte installera MediaWiki.", "config-env-php": "PHP $1 är installerat.", + "config-env-hhvm": "HHVM $1 är installerat.", "config-unicode-using-utf8": "Använder Brion Vibbers utf8_normalize.so för Unicode-normalisering.", "config-unicode-using-intl": "Använder [http://pecl.php.net/intl intl PECL-tillägget] för Unicode-normalisering.", "config-unicode-pure-php-warning": "'''Varning:''' [http://pecl.php.net/intl intl PECL-tillägget] är inte tillgängligt för att hantera Unicode-normalisering, faller tillbaka till en lÃ¥ngsamt implementering i ren PHP.\nOm du driver en högtrafikerad webbplats bör du läsa lite om [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode-normalisering].", @@ -310,6 +311,8 @@ "config-install-stats": "Initierar statistik", "config-install-keys": "Genererar hemliga nycklar", "config-insecure-keys": "'''Varning:''' {{PLURAL:$2|En säkerhetsnyckel|Säkerhetsnycklar}} ($1) som generades under installationen är inte helt {{PLURAL:$2|säker|säkra}} . Överväg att ändra {{PLURAL:$2|den|dem}} manuellt.", + "config-install-updates": "Förhindra att onödiga uppdateringar körs", + "config-install-updates-failed": "Fel: Infogning av uppdateringsnycklar i tabeller misslyckades med följande fel:$1", "config-install-sysop": "Skapar administratörskonto", "config-install-subscribe-fail": "Det gick inte att prenumerera pÃ¥ mediawiki-announce: $1", "config-install-subscribe-notpossible": "cURL är inte installerad och allow_url_fopen är inte tillgänglig.", diff --git a/includes/installer/i18n/uk.json b/includes/installer/i18n/uk.json index 001a0f8d32..9eee1a7fd6 100644 --- a/includes/installer/i18n/uk.json +++ b/includes/installer/i18n/uk.json @@ -314,6 +314,7 @@ "config-install-stats": "Ініціалізація статистики", "config-install-keys": "Генерація секретних ключів", "config-insecure-keys": "'''Увага:''' {{PLURAL:$2|1=Секретний ключ|Секретні ключі}} ($1), {{PLURAL:$2|1=згенерований в процесі встановлення, недостатньо надійний|згенеровані в процесі встановлення, недостатньо надійні}}. Розгляньте можливість {{PLURAL:$2|1=його|їх}} заміни вручну.", + "config-install-updates-failed": "Помилка: Вставка оновленних ключів в таблиці не вдалося через таку помилку:$1", "config-install-sysop": "Створення облікового запису адміністратора", "config-install-subscribe-fail": "Не можливо підписатись на mediawiki-announce: $1", "config-install-subscribe-notpossible": "cURL не встановлено і опція allow_url_fopen не доступна.", diff --git a/includes/installer/i18n/zh-hans.json b/includes/installer/i18n/zh-hans.json index a4b64bceeb..9e2833e2c0 100644 --- a/includes/installer/i18n/zh-hans.json +++ b/includes/installer/i18n/zh-hans.json @@ -66,6 +66,7 @@ "config-env-good": "环境检查已经完成。您可以安装MediaWiki。", "config-env-bad": "环境检查已经完成。您不能安装MediaWiki。", "config-env-php": "PHP $1已安装。", + "config-env-hhvm": "HHVM $1已安装。", "config-unicode-using-utf8": "使用Brion Vibber的utf8_normalize.so实现Unicode正常化。", "config-unicode-using-intl": "使用[http://pecl.php.net/intl intl PECL扩展程序]标准化Unicode。", "config-unicode-pure-php-warning": "警告:因为尚未安装 [http://pecl.php.net/intl intl PECL 扩展]以处理 Unicode 正常化,故只能退而采用运行较慢的纯 PHP 实现的方法。\n如果您运行着一个高流量的站点,请参阅 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations Unicode 正常化]一文。", diff --git a/includes/installer/i18n/zh-hant.json b/includes/installer/i18n/zh-hant.json index cb6cefb4c9..c5b5a4c007 100644 --- a/includes/installer/i18n/zh-hant.json +++ b/includes/installer/i18n/zh-hant.json @@ -58,6 +58,7 @@ "config-env-good": "環境檢查已完成。\n您可以安裝 MediaWiki。", "config-env-bad": "環境檢查已完成。\n您無法安裝 MediaWiki。", "config-env-php": "PHP $1 已安裝。", + "config-env-hhvm": "HHVM $1 已安裝。", "config-unicode-using-utf8": "使用 Brion Vibber 的 utf8_normalize.so 做 Unicode 正規化。", "config-unicode-using-intl": "使用 [http://pecl.php.net/intl intl PECL 擴充套件] 做 Unicode 正規化。", "config-unicode-pure-php-warning": "警告: 無法使用 [http://pecl.php.net/intl intl PECL 擴充套件] 處理 Unicode 正規化,故回退使用純 PHP 實作的正規化程式,此方式處理速度較緩慢。\n\n如果您的網站瀏覽人次很高,您應先閱讀 [//www.mediawiki.org/wiki/Special:MyLanguage/Unicode_normalization_considerations/zh Unicode 正規化]。", @@ -171,7 +172,7 @@ "config-sqlite-cant-create-db": "無法建立資料庫檔案 $1。", "config-sqlite-fts3-downgrade": "PHP 不支援 FTS3,正在降級資料表。", "config-can-upgrade": "在資料庫中找到 MediaWiki 的資料表。\n要升級至 MediaWiki $1,請點選 繼續。", - "config-upgrade-done": "升級完成。\n\n現在您可以 [$1 開始使用您的 Wiki] 了。\n\n如果您需要重新產生 LocalSettings.php 檔案,請點擊下方按鈕。\n除非您的 Wiki 出現了問題,否則我們 不建議 您執行此操作。", + "config-upgrade-done": "升級完成。\n\n現在您可以 [$1 開始使用您的 Wiki] 了。\n\n如果您需要重新產生 LocalSettings.php 檔案,請點選下方按鈕。\n除非您的 Wiki 出現了問題,否則我們 不建議 您執行此操作。", "config-upgrade-done-no-regenerate": "升級完成。\n\n現在您可以 [$1 開始使用您的 Wiki] 了。", "config-regenerate": "重新產生 LocalSettings.php →", "config-show-table-status": "SHOW TABLE STATUS 查詢失敗!", @@ -251,7 +252,7 @@ "config-email-usertalk": "開啟使用者討論頁面通知", "config-email-usertalk-help": "若使用者在個人偏好開啟了此功能,則可收到使用者討論頁面被修改的通知。", "config-email-watchlist": "開啟監視清單通知", - "config-email-watchlist-help": "若使用者在個人偏好開啟了此功能,允許使用者收到與其監視列表有關的通知。", + "config-email-watchlist-help": "若使用者在個人偏好開啟了此功能,允許使用者收到與其監視清單有關的通知。", "config-email-auth": "開啟電子郵件身份認證", "config-email-auth-help": "若開啟此選項,使用者不論設定或者更改電子郵件地址,都必須透過收信的方式確認沒有問題。\n只有驗證過的電子郵件地址可以收到來自其他使用者或修改通知的信件。\n公開的 Wiki 會 建議 設定此選項,以防使用者濫用電子郵件功能。", "config-email-sender": "電子郵件回覆位址:", diff --git a/includes/jobqueue/JobRunner.php b/includes/jobqueue/JobRunner.php index 617a3a31df..8a708f16c8 100644 --- a/includes/jobqueue/JobRunner.php +++ b/includes/jobqueue/JobRunner.php @@ -79,20 +79,22 @@ class JobRunner { // Flush any pending DB writes for sanity wfGetLBFactory()->commitMasterChanges(); - $backoffs = $this->loadBackoffs(); // map of (type => UNIX expiry) - $startingBackoffs = $backoffs; // avoid unnecessary writes - $backoffExpireFunc = function ( $t ) { - return $t > time(); - }; + // Some jobs types should not run until a certain timestamp + $backoffs = array(); // map of (type => UNIX expiry) + $backoffDeltas = array(); // map of (type => seconds) + $wait = 'wait'; // block to read backoffs the first time $jobsRun = 0; // counter $timeMsTotal = 0; $flags = JobQueueGroup::USE_CACHE; - $startTime = microtime( true ); // time since jobs started running + $sTime = microtime( true ); // time since jobs started running $lastTime = microtime( true ); // time since last slave check do { - $backoffs = array_filter( $backoffs, $backoffExpireFunc ); + // Sync the persistent backoffs with concurrent runners + $backoffs = $this->syncBackoffDeltas( $backoffs, $backoffDeltas, $wait ); $blacklist = $noThrottle ? array() : array_keys( $backoffs ); + $wait = 'nowait'; // less important now + if ( $type === false ) { $job = $group->pop( JobQueueGroup::TYPE_DEFAULT, $flags, $blacklist ); } elseif ( in_array( $type, $blacklist ) ) { @@ -100,14 +102,26 @@ class JobRunner { } else { $job = $group->pop( $type ); // job from a single queue } + if ( $job ) { // found a job $jType = $job->getType(); + // Back off of certain jobs for a while (for throttling and for errors) + $ttw = $this->getBackoffTimeToWait( $job ); + if ( $ttw > 0 ) { + // Always add the delta for other runners in case the time running the + // job negated the backoff for each individually but not collectively. + $backoffDeltas[$jType] = isset( $backoffDeltas[$jType] ) + ? $backoffDeltas[$jType] + $ttw + : $ttw; + $backoffs = $this->syncBackoffDeltas( $backoffs, $backoffDeltas, $wait ); + } + $this->runJobsLog( $job->toString() . " STARTING" ); // Run the job... wfProfileIn( __METHOD__ . '-' . get_class( $job ) ); - $t = microtime( true ); + $sTime = microtime( true ); try { ++$jobsRun; $status = $job->run(); @@ -119,7 +133,7 @@ class JobRunner { $error = get_class( $e ) . ': ' . $e->getMessage(); MWExceptionHandler::logException( $e ); } - $timeMs = intval( ( microtime( true ) - $t ) * 1000 ); + $timeMs = intval( ( microtime( true ) - $sTime ) * 1000 ); wfProfileOut( __METHOD__ . '-' . get_class( $job ) ); $timeMsTotal += $timeMs; @@ -128,6 +142,14 @@ class JobRunner { $group->ack( $job ); // done } + // Back off of certain jobs for a while (for throttling and for errors) + if ( $status === false && mt_rand( 0, 49 ) == 0 ) { + $ttw = max( $ttw, 30 ); // too many errors + $backoffDeltas[$jType] = isset( $backoffDeltas[$jType] ) + ? $backoffDeltas[$jType] + $ttw + : $ttw; + } + if ( $status === false ) { $this->runJobsLog( $job->toString() . " t=$timeMs error={$error}" ); } else { @@ -141,21 +163,11 @@ class JobRunner { 'time' => $timeMs ); - // Back off of certain jobs for a while (for throttling and for errors) - $ttw = $this->getBackoffTimeToWait( $job ); - if ( $status === false && mt_rand( 0, 49 ) == 0 ) { - $ttw = max( $ttw, 30 ); - } - if ( $ttw > 0 ) { - $backoffs[$jType] = isset( $backoffs[$jType] ) ? $backoffs[$jType] : 0; - $backoffs[$jType] = max( $backoffs[$jType], time() + $ttw ); - } - // Break out if we hit the job count or wall time limits... if ( $maxJobs && $jobsRun >= $maxJobs ) { $response['reached'] = 'job-limit'; break; - } elseif ( $maxTime && ( microtime( true ) - $startTime ) > $maxTime ) { + } elseif ( $maxTime && ( microtime( true ) - $sTime ) > $maxTime ) { $response['reached'] = 'time-limit'; break; } @@ -177,9 +189,8 @@ class JobRunner { } while ( $job ); // stop when there are no jobs // Sync the persistent backoffs for the next runJobs.php pass - $backoffs = array_filter( $backoffs, $backoffExpireFunc ); - if ( $backoffs !== $startingBackoffs ) { - $this->syncBackoffs( $backoffs ); + if ( $backoffDeltas ) { + $this->syncBackoffDeltas( $backoffs, $backoffDeltas, 'wait' ); } $response['backoffs'] = $backoffs; @@ -221,47 +232,86 @@ class JobRunner { /** * Get the previous backoff expiries from persistent storage + * On I/O or lock acquisition failure this returns the original $backoffs. * + * @param array $backoffs Map of (job type => UNIX timestamp) + * @param string $mode Lock wait mode - "wait" or "nowait" * @return array Map of (job type => backoff expiry timestamp) */ - private function loadBackoffs() { + private function loadBackoffs( array $backoffs, $mode = 'wait' ) { $section = new ProfileSection( __METHOD__ ); - $backoffs = array(); $file = wfTempDir() . '/mw-runJobs-backoffs.json'; if ( is_file( $file ) ) { + $noblock = ( $mode === 'nowait' ) ? LOCK_NB : 0; $handle = fopen( $file, 'rb' ); - flock( $handle, LOCK_SH ); + if ( !flock( $handle, LOCK_SH | $noblock ) ) { + fclose( $handle ); + return $backoffs; // don't wait on lock + } $content = stream_get_contents( $handle ); flock( $handle, LOCK_UN ); fclose( $handle ); - $backoffs = json_decode( $content, true ) ?: array(); + $ctime = microtime( true ); + $cBackoffs = json_decode( $content, true ) ?: array(); + foreach ( $cBackoffs as $type => $timestamp ) { + if ( $timestamp < $ctime ) { + unset( $cBackoffs[$type] ); + } + } + } else { + $cBackoffs = array(); } - return $backoffs; + return $cBackoffs; } /** * Merge the current backoff expiries from persistent storage * - * @param array $backoffs Map of (job type => backoff expiry timestamp) + * The $deltas map is set to an empty array on success. + * On I/O or lock acquisition failure this returns the original $backoffs. + * + * @param array $backoffs Map of (job type => UNIX timestamp) + * @param array $deltas Map of (job type => seconds) + * @param string $mode Lock wait mode - "wait" or "nowait" + * @return array The new backoffs account for $backoffs and the latest file data */ - private function syncBackoffs( array $backoffs ) { + private function syncBackoffDeltas( array $backoffs, array &$deltas, $mode = 'wait' ) { $section = new ProfileSection( __METHOD__ ); + if ( !$deltas ) { + return $this->loadBackoffs( $backoffs, $mode ); + } + + $noblock = ( $mode === 'nowait' ) ? LOCK_NB : 0; $file = wfTempDir() . '/mw-runJobs-backoffs.json'; $handle = fopen( $file, 'wb+' ); - flock( $handle, LOCK_EX ); + if ( !flock( $handle, LOCK_EX | $noblock ) ) { + fclose( $handle ); + return $backoffs; // don't wait on lock + } + $ctime = microtime( true ); $content = stream_get_contents( $handle ); $cBackoffs = json_decode( $content, true ) ?: array(); - foreach ( $backoffs as $type => $timestamp ) { - $cBackoffs[$type] = isset( $cBackoffs[$type] ) ? $cBackoffs[$type] : 0; - $cBackoffs[$type] = max( $cBackoffs[$type], $backoffs[$type] ); + foreach ( $deltas as $type => $seconds ) { + $cBackoffs[$type] = isset( $cBackoffs[$type] ) && $cBackoffs[$type] >= $ctime + ? $cBackoffs[$type] + $seconds + : $ctime + $seconds; + } + foreach ( $cBackoffs as $type => $timestamp ) { + if ( $timestamp < $ctime ) { + unset( $cBackoffs[$type] ); + } } ftruncate( $handle, 0 ); - fwrite( $handle, json_encode( $backoffs ) ); + fwrite( $handle, json_encode( $cBackoffs ) ); flock( $handle, LOCK_UN ); fclose( $handle ); + + $deltas = array(); + + return $cBackoffs; } /** diff --git a/includes/libs/CSSJanus.php b/includes/libs/CSSJanus.php index 30b92c72ff..ae28163b25 100644 --- a/includes/libs/CSSJanus.php +++ b/includes/libs/CSSJanus.php @@ -179,6 +179,22 @@ class CSSJanus { $css = $noFlipClass->detokenize( $css ); $css = $noFlipSingle->detokenize( $css ); + // Remove remaining /* @noflip */ annotations, they won't be needed anymore + // and can interfere with other code (bug 69698). + $css = self::nullTransform( $css ); + + return $css; + } + + /** + * Remove @noflip annotations, but don't do any other transforms. + * @param string $css stylesheet to transform + * @return string Transformed stylesheet + */ + public static function nullTransform( $css ) { + $patt = self::$patterns['noflip_annotation']; + $css = preg_replace( "/($patt)\\s*/i", '', $css ); + return $css; } diff --git a/includes/libs/CSSMin.php b/includes/libs/CSSMin.php index 4e2ca836d8..dcaa6857a2 100644 --- a/includes/libs/CSSMin.php +++ b/includes/libs/CSSMin.php @@ -135,27 +135,21 @@ class CSSMin { */ public static function getMimeType( $file ) { $realpath = realpath( $file ); - // Try a couple of different ways to get the MIME-type of a file, in order of - // preference if ( $realpath && function_exists( 'finfo_file' ) && function_exists( 'finfo_open' ) && defined( 'FILEINFO_MIME_TYPE' ) ) { - // As of PHP 5.3, this is how you get the MIME-type of a file; it uses the Fileinfo - // PECL extension return finfo_file( finfo_open( FILEINFO_MIME_TYPE ), $realpath ); - } elseif ( function_exists( 'mime_content_type' ) ) { - // Before this was deprecated in PHP 5.3, this was how you got the MIME-type of a file - return mime_content_type( $file ); - } else { - // Worst-case scenario has happened, use the file extension to infer the MIME-type - $ext = strtolower( pathinfo( $file, PATHINFO_EXTENSION ) ); - if ( isset( self::$mimeTypes[$ext] ) ) { - return self::$mimeTypes[$ext]; - } } + + // Infer the MIME-type from the file extension + $ext = strtolower( pathinfo( $file, PATHINFO_EXTENSION ) ); + if ( isset( self::$mimeTypes[$ext] ) ) { + return self::$mimeTypes[$ext]; + } + return false; } diff --git a/includes/logging/LogEntry.php b/includes/logging/LogEntry.php index bebe3a9fee..46c55157c4 100644 --- a/includes/logging/LogEntry.php +++ b/includes/logging/LogEntry.php @@ -533,6 +533,10 @@ class ManualLogEntry extends LogEntryBase { $dbw->insert( 'log_search', $rows, __METHOD__, 'IGNORE' ); } + // Update any bloom filter cache + $member = $this->getTarget()->getNamespace() . ':' . $this->getTarget()->getDBkey(); + BloomCache::get( 'main' )->insert( wfWikiId(), 'TitleHasLogs', $member ); + return $this->id; } diff --git a/includes/objectcache/MemcachedPeclBagOStuff.php b/includes/objectcache/MemcachedPeclBagOStuff.php index 8700c8cdf5..c853bcf467 100644 --- a/includes/objectcache/MemcachedPeclBagOStuff.php +++ b/includes/objectcache/MemcachedPeclBagOStuff.php @@ -247,6 +247,7 @@ class MemcachedPeclBagOStuff extends MemcachedBagOStuff { $callback = array( $this, 'encodeKey' ); $result = $this->client->getMulti( array_map( $callback, $keys ) ); wfProfileOut( __METHOD__ ); + $result = $result ?: array(); // must be an array return $this->checkResult( false, $result ); } diff --git a/includes/page/Article.php b/includes/page/Article.php index 8970539934..dab075e8cc 100644 --- a/includes/page/Article.php +++ b/includes/page/Article.php @@ -1190,15 +1190,18 @@ class Article implements Page { */ public function showMissingArticle() { global $wgSend404Code; + $outputPage = $this->getContext()->getOutput(); // Whether the page is a root user page of an existing user (but not a subpage) $validUserPage = false; + $title = $this->getTitle(); + # Show info in user (talk) namespace. Does the user exist? Is he blocked? - if ( $this->getTitle()->getNamespace() == NS_USER - || $this->getTitle()->getNamespace() == NS_USER_TALK + if ( $title->getNamespace() == NS_USER + || $title->getNamespace() == NS_USER_TALK ) { - $parts = explode( '/', $this->getTitle()->getText() ); + $parts = explode( '/', $title->getText() ); $rootPart = $parts[0]; $user = User::newFromName( $rootPart, false /* allow IP users*/ ); $ip = User::isIP( $rootPart ); @@ -1222,9 +1225,9 @@ class Article implements Page { ) ) ); - $validUserPage = !$this->getTitle()->isSubpage(); + $validUserPage = !$title->isSubpage(); } else { - $validUserPage = !$this->getTitle()->isSubpage(); + $validUserPage = !$title->isSubpage(); } } @@ -1236,12 +1239,16 @@ class Article implements Page { wfRunHooks( 'Article::MissingArticleConditions', array( &$conds, $logTypes ) ); # Show delete and move logs - LogEventsList::showLogExtract( $outputPage, $logTypes, $this->getTitle(), '', - array( 'lim' => 10, - 'conds' => $conds, - 'showIfEmpty' => false, - 'msgKey' => array( 'moveddeleted-notice' ) ) - ); + $member = $title->getNamespace() . ':' . $title->getDBkey(); + // @todo: move optimization to showLogExtract()? + if ( BloomCache::get( 'main' )->check( wfWikiId(), 'TitleHasLogs', $member ) ) { + LogEventsList::showLogExtract( $outputPage, $logTypes, $title, '', + array( 'lim' => 10, + 'conds' => $conds, + 'showIfEmpty' => false, + 'msgKey' => array( 'moveddeleted-notice' ) ) + ); + } if ( !$this->mPage->hasViewableContent() && $wgSend404Code && !$validUserPage ) { // If there's no backing content, send a 404 Not Found @@ -1264,11 +1271,11 @@ class Article implements Page { $oldid = $this->getOldID(); if ( $oldid ) { $text = wfMessage( 'missing-revision', $oldid )->plain(); - } elseif ( $this->getTitle()->getNamespace() === NS_MEDIAWIKI ) { + } elseif ( $title->getNamespace() === NS_MEDIAWIKI ) { // Use the default message text - $text = $this->getTitle()->getDefaultMessageText(); - } elseif ( $this->getTitle()->quickUserCan( 'create', $this->getContext()->getUser() ) - && $this->getTitle()->quickUserCan( 'edit', $this->getContext()->getUser() ) + $text = $title->getDefaultMessageText(); + } elseif ( $title->quickUserCan( 'create', $this->getContext()->getUser() ) + && $title->quickUserCan( 'edit', $this->getContext()->getUser() ) ) { $message = $this->getContext()->getUser()->isLoggedIn() ? 'noarticletext' : 'noarticletextanon'; $text = wfMessage( $message )->plain(); @@ -1455,7 +1462,7 @@ class Article implements Page { * @param Title|array $target Destination(s) to redirect * @param bool $appendSubtitle [optional] * @param bool $forceKnown Should the image be shown as a bluelink regardless of existence? - * @return string Containing HMTL with redirect link + * @return string Containing HTML with redirect link */ public function viewRedirect( $target, $appendSubtitle = true, $forceKnown = false ) { $lang = $this->getTitle()->getPageLanguage(); @@ -1476,7 +1483,7 @@ class Article implements Page { * @param Language $lang * @param Title|array $target Destination(s) to redirect * @param bool $forceKnown Should the image be shown as a bluelink regardless of existence? - * @return string Containing HMTL with redirect link + * @return string Containing HTML with redirect link */ public static function getRedirectHeaderHtml( Language $lang, $target, $forceKnown = false ) { global $wgStylePath; diff --git a/includes/page/ImagePage.php b/includes/page/ImagePage.php index 380252f58a..d06c8191ec 100644 --- a/includes/page/ImagePage.php +++ b/includes/page/ImagePage.php @@ -267,8 +267,7 @@ class ImagePage extends Article { # @todo FIXME: Why is this using escapeId for a class?! $class = Sanitizer::escapeId( $v['id'] ); if ( $type == 'collapsed' ) { - // Handled by mediawiki.action.view.metadata module - // and skins/common/shared.css. + // Handled by mediawiki.action.view.metadata module. $class .= ' collapsable'; } $r .= "\n"; @@ -1329,6 +1328,9 @@ class ImageHistoryList extends ContextSource { $url = $lang->userTimeAndDate( $timestamp, $user ); } $row .= '' . $url . ''; + } elseif ( !$file->exists() ) { + $row .= '' + . $lang->userTimeAndDate( $timestamp, $user ) . ''; } else { $url = $iscur ? $this->current->getUrl() : $this->current->getArchiveUrl( $img ); $row .= Xml::element( diff --git a/includes/pager/IndexPager.php b/includes/pager/IndexPager.php index 1d93c27f68..ce6dc50cbf 100644 --- a/includes/pager/IndexPager.php +++ b/includes/pager/IndexPager.php @@ -64,6 +64,14 @@ * @ingroup Pager */ abstract class IndexPager extends ContextSource implements Pager { + /** + * Constants for the $mDefaultDirection field. + * + * These are boolean for historical reasons and should stay boolean for backwards-compatibility. + */ + const DIR_ASCENDING = false; + const DIR_DESCENDING = true; + public $mRequest; public $mLimitsShown = array( 20, 50, 100, 250, 500 ); public $mDefaultLimit = 50; @@ -87,7 +95,7 @@ abstract class IndexPager extends ContextSource implements Pager { protected $mOrderType; /** * $mDefaultDirection gives the direction to use when sorting results: - * false for ascending, true for descending. If $mIsBackwards is set, we + * DIR_ASCENDING or DIR_DESCENDING. If $mIsBackwards is set, we * start from the opposite end, but we still sort the page itself according * to $mDefaultDirection. E.g., if $mDefaultDirection is false but we're * going backwards, we'll display the last page of results, but the last @@ -190,6 +198,7 @@ abstract class IndexPager extends ContextSource implements Pager { $fname = __METHOD__ . ' (' . get_class( $this ) . ')'; wfProfileIn( $fname ); + // @todo This should probably compare to DIR_DESCENDING and DIR_ASCENDING constants $descending = ( $this->mIsBackwards == $this->mDefaultDirection ); # Plus an extra row so that we can tell the "next" link should be shown $queryLimit = $this->mLimit + 1; @@ -447,8 +456,8 @@ abstract class IndexPager extends ContextSource implements Pager { * * @param string $text Text displayed on the link * @param array $query Associative array of parameter to be in the query string - * @param string $type Value of the "rel" attribute - * + * @param string $type Link type used to create additional attributes, like "rel", "class" or + * "title". Valid values (non-exhaustive list): 'first', 'last', 'prev', 'next', 'asc', 'desc'. * @return string HTML fragment */ function makeLink( $text, array $query = null, $type = null ) { @@ -457,15 +466,19 @@ abstract class IndexPager extends ContextSource implements Pager { } $attrs = array(); - if ( in_array( $type, array( 'first', 'prev', 'next', 'last' ) ) ) { - # HTML5 rel attributes + if ( in_array( $type, array( 'prev', 'next' ) ) ) { $attrs['rel'] = $type; } + if ( in_array( $type, array( 'asc', 'desc' ) ) ) { + $attrs['title'] = wfMessage( $type == 'asc' ? 'sort-ascending' : 'sort-descending' )->text(); + } + if ( $type ) { $attrs['class'] = "mw-{$type}link"; } + return Linker::linkKnown( $this->getTitle(), $text, @@ -705,8 +718,8 @@ abstract class IndexPager extends ContextSource implements Pager { } /** - * Return the default sorting direction: false for ascending, true for - * descending. You can also have an associative array of ordertype => dir, + * Return the default sorting direction: DIR_ASCENDING or DIR_DESCENDING. + * You can also have an associative array of ordertype => dir, * if multiple order types are supported. In this case getIndexField() * must return an array, and the keys of that must exactly match the keys * of this. @@ -724,6 +737,6 @@ abstract class IndexPager extends ContextSource implements Pager { * @return bool */ protected function getDefaultDirections() { - return false; + return IndexPager::DIR_ASCENDING; } } diff --git a/includes/pager/ReverseChronologicalPager.php b/includes/pager/ReverseChronologicalPager.php index 3f96382db0..4f8c438db0 100644 --- a/includes/pager/ReverseChronologicalPager.php +++ b/includes/pager/ReverseChronologicalPager.php @@ -26,7 +26,7 @@ * @ingroup Pager */ abstract class ReverseChronologicalPager extends IndexPager { - public $mDefaultDirection = true; + public $mDefaultDirection = IndexPager::DIR_DESCENDING; public $mYear; public $mMonth; diff --git a/includes/pager/TablePager.php b/includes/pager/TablePager.php index 19538c6ac8..c5141a9347 100644 --- a/includes/pager/TablePager.php +++ b/includes/pager/TablePager.php @@ -42,56 +42,107 @@ abstract class TablePager extends IndexPager { $this->mSort = $this->getDefaultSort(); } if ( $this->getRequest()->getBool( 'asc' ) ) { - $this->mDefaultDirection = false; + $this->mDefaultDirection = IndexPager::DIR_ASCENDING; } elseif ( $this->getRequest()->getBool( 'desc' ) ) { - $this->mDefaultDirection = true; + $this->mDefaultDirection = IndexPager::DIR_DESCENDING; } /* Else leave it at whatever the class default is */ parent::__construct(); } + /** + * Get the formatted result list. Calls getStartBody(), formatRow() and getEndBody(), concatenates + * the results and returns them. + * + * Also adds the required styles to our OutputPage object (this means that if context wasn't + * passed to constructor or otherwise set up, you will get a pager with missing styles). + * + * This method has been made 'final' in 1.24. There's no reason to override it, and if there exist + * any subclasses that do, the style loading hack is probably broken in them. Let's fail fast + * rather than mysteriously render things wrong. + * + * @deprecated since 1.24, use getBodyOutput() or getFullOutput() instead + * @return string + */ + final public function getBody() { + $this->getOutput()->addModuleStyles( $this->getModuleStyles() ); + return parent::getBody(); + } + + /** + * Get the formatted result list. + * + * Calls getBody() and getModuleStyles() and builds a ParserOutput object. (This is a bit hacky + * but works well.) + * + * @since 1.24 + * @return ParserOutput + */ + public function getBodyOutput() { + $body = parent::getBody(); + + $pout = new ParserOutput; + $pout->setText( $body ); + $pout->addModuleStyles( $this->getModuleStyles() ); + return $pout; + } + + /** + * Get the formatted result list, with navigation bars. + * + * Calls getBody(), getNavigationBar() and getModuleStyles() and + * builds a ParserOutput object. (This is a bit hacky but works well.) + * + * @since 1.24 + * @return ParserOutput + */ + public function getFullOutput() { + $navigation = $this->getNavigationBar(); + $body = parent::getBody(); + + $pout = new ParserOutput; + $pout->setText( $navigation . $body . $navigation ); + $pout->addModuleStyles( $this->getModuleStyles() ); + return $pout; + } + /** * @protected * @return string */ function getStartBody() { - global $wgStylePath; $sortClass = $this->getSortHeaderClass(); $s = ''; $fields = $this->getFieldNames(); - # Make table header + // Make table header foreach ( $fields as $field => $name ) { if ( strval( $name ) == '' ) { $s .= Html::rawElement( 'th', array(), ' ' ) . "\n"; } elseif ( $this->isFieldSortable( $field ) ) { $query = array( 'sort' => $field, 'limit' => $this->mLimit ); - if ( $field == $this->mSort ) { - # This is the sorted column - # Prepare a link that goes in the other sort order - if ( $this->mDefaultDirection ) { - # Descending - $image = 'Arr_d.png'; + $linkType = null; + $class = null; + + if ( $this->mSort == $field ) { + // The table is sorted by this field already, make a link to sort in the other direction + // We don't actually know in which direction other fields will be sorted by default… + if ( $this->mDefaultDirection == IndexPager::DIR_DESCENDING ) { + $linkType = 'asc'; + $class = "$sortClass TablePager_sort-descending"; $query['asc'] = '1'; $query['desc'] = ''; - $alt = $this->msg( 'descending_abbrev' )->escaped(); } else { - # Ascending - $image = 'Arr_u.png'; + $linkType = 'desc'; + $class = "$sortClass TablePager_sort-ascending"; $query['asc'] = ''; $query['desc'] = '1'; - $alt = $this->msg( 'ascending_abbrev' )->escaped(); } - $image = "$wgStylePath/common/images/$image"; - $link = $this->makeLink( - Html::element( 'img', array( 'width' => 12, 'height' => 12, - 'alt' => $alt, 'src' => $image ) ) . htmlspecialchars( $name ), $query ); - $s .= Html::rawElement( 'th', array( 'class' => $sortClass ), $link ) . "\n"; - } else { - $s .= Html::rawElement( 'th', array(), - $this->makeLink( htmlspecialchars( $name ), $query ) ) . "\n"; } + + $link = $this->makeLink( htmlspecialchars( $name ), $query, $linkType ); + $s .= Html::rawElement( 'th', array( 'class' => $class ), $link ) . "\n"; } else { $s .= Html::element( 'th', array(), $name ) . "\n"; } @@ -99,7 +150,6 @@ abstract class TablePager extends IndexPager { $tableClass = $this->getTableClass(); $ret = Html::openElement( 'table', array( - 'style' => 'border:1px;', 'class' => "mw-datatable $tableClass" ) ); $ret .= Html::rawElement( 'thead', array(), Html::rawElement( 'tr', array(), "\n" . $s . "\n" ) ); @@ -235,45 +285,23 @@ abstract class TablePager extends IndexPager { * @return string HTML */ public function getNavigationBar() { - global $wgStylePath; - if ( !$this->isNavigationBarShown() ) { return ''; } - $path = "$wgStylePath/common/images"; $labels = array( 'first' => 'table_pager_first', 'prev' => 'table_pager_prev', 'next' => 'table_pager_next', 'last' => 'table_pager_last', ); - $images = array( - 'first' => 'arrow_first_25.png', - 'prev' => 'arrow_left_25.png', - 'next' => 'arrow_right_25.png', - 'last' => 'arrow_last_25.png', - ); - $disabledImages = array( - 'first' => 'arrow_disabled_first_25.png', - 'prev' => 'arrow_disabled_left_25.png', - 'next' => 'arrow_disabled_right_25.png', - 'last' => 'arrow_disabled_last_25.png', - ); - if ( $this->getLanguage()->isRTL() ) { - $keys = array_keys( $labels ); - $images = array_combine( $keys, array_reverse( $images ) ); - $disabledImages = array_combine( $keys, array_reverse( $disabledImages ) ); - } $linkTexts = array(); $disabledTexts = array(); foreach ( $labels as $type => $label ) { $msgLabel = $this->msg( $label )->escaped(); - $linkTexts[$type] = Html::element( 'img', array( 'src' => "$path/{$images[$type]}", - 'alt' => $msgLabel ) ) . "
    $msgLabel"; - $disabledTexts[$type] = Html::element( 'img', array( 'src' => "$path/{$disabledImages[$type]}", - 'alt' => $msgLabel ) ) . "
    $msgLabel"; + $linkTexts[$type] = "
    $msgLabel
    "; + $disabledTexts[$type] = "
    $msgLabel
    "; } $links = $this->getPagingLinks( $linkTexts, $disabledTexts ); @@ -281,12 +309,26 @@ abstract class TablePager extends IndexPager { $s .= Html::openElement( 'tr' ) . "\n"; $width = 100 / count( $links ) . '%'; foreach ( $labels as $type => $label ) { - $s .= Html::rawElement( 'td', array( 'style' => "width:$width;" ), $links[$type] ) . "\n"; + // We want every cell to have the same width. We could use table-layout: fixed; in CSS, + // but it only works if we specify the width of a cell or the table and we don't want to. + // There is no better way. + $s .= Html::rawElement( 'td', + array( 'style' => "width: $width;", 'class' => "TablePager_nav-$type" ), + $links[$type] ) . "\n"; } $s .= Html::closeElement( 'tr' ) . Html::closeElement( 'table' ) . "\n"; return $s; } + /** + * ResourceLoader modules that must be loaded to provide correct styling for this pager + * @since 1.24 + * @return string[] + */ + public function getModuleStyles() { + return array( 'mediawiki.pager.tablePager' ); + } + /** * Get a "