From: jenkins-bot Date: Wed, 13 Jun 2018 22:58:28 +0000 (+0000) Subject: Merge "Do not require titles on Special:ComparePages" X-Git-Tag: 1.34.0-rc.0~5077 X-Git-Url: http://git.cyclocoop.org//%27http:/jquery.khurshid.com/ifixpng.php/%27?a=commitdiff_plain;h=58c869edd257ac3b98b1167956ca98aac73ad2b8;hp=9f2b1c20fd8bf6d4a508436ba460e8d3f504846a;p=lhc%2Fweb%2Fwiklou.git Merge "Do not require titles on Special:ComparePages" --- diff --git a/HISTORY b/HISTORY index 0693b21c5d..7540af3bca 100644 --- a/HISTORY +++ b/HISTORY @@ -1,4 +1,490 @@ -Change notes from older releases. For current info see RELEASE-NOTES-1.31. +Change notes from older releases. For current info see RELEASE-NOTES-1.32. + += MediaWiki 1.31 = + +== MediaWiki 1.31.0 == + +=== Changes since MediaWiki 1.31.0-rc.2 === +* (T195783) Initialize PSR-4 namespaces at same stage as normal autoloader. +* (T196092) Hide MySQL binary/utf-8 charset option in the installer. +* (T196185) Don't allow setting $wgDBmysql5 in the installer. +* (T196125) php-memcached 3.0 (provided with PHP 7.0) is now supported. +* (T182366) UploadBase::checkXMLEncodingMissmatch() now works on PHP 7.1+ +* (T118683) Fix exception from &$user deref on HHVM in the TitleMoveComplete hook. +* (T196672) The mtime of extension.json files is now able to be zero +* (T180403) Validate $length in padleft/padright parser functions. +* (T143790) Make $wgEmailConfirmToEdit only affect edit actions. + +=== Changes since MediaWiki 1.31.0-rc.0 === +* (T33223) Drop archive.ar_text and ar_flags. +* Add default edit rate limit of 90 edits/minute for all users. +* (T187645) Use codepoint as tiebreaker when getting first-letters in + IcuCollation. +* (T191947) Don't shell during the installer if shelling out is disabled. +* (T194319) Improve duplicate config setting exception as part of extension + registration. +* (T195211) Don't require trailing slash in PSR-4 autoloader directory. +* (T186565) Fix PHP Notice from `ob_end_flush()` in `FileRepo::streamFile()`. +* Do not incorrectly hide namespace input field in the installer. +* (T186456) Refactor checks looking for PEAR maik libraries to be clearer. + +=== Important pre-upgrade notes for 1.31 === +* If you're using MySQL, SQLite, or MSSQL, are not using update.php to apply + schema changes, and cannot have downtime to run migrateArchiveText.php and + apply patch-drop-ar_text.sql manually, you'll have to apply a default value + to the ar_text and ar_flags columns of the archive table or make those + columns nullable before upgrading to MediaWiki 1.31. + maintenance/archives/patch-nullable-ar_text.sql shows how to do this for MySQL. + +=== Configuration changes in 1.31 === +* $wgEnableAPI and $wgEnableWriteAPI are now deprecated and will be removed in + a future version. The API is now considered to be stable, secure and + essential. +* $wgUsejQueryThree was removed, as it is now the default. This was documented + as a temporary variable during the migration period, deprecated since 1.29. +* $wgLogoHD has been updated to support svg images and uses $wgLogo where + possible for fallback images such as png. +* (T44246) $wgFilterLogTypes will no longer ignore 'patrol' when user does not + have the right to mark things patrolled. +* Wikis that contain imported revisions or CentralAuth global blocks should run + maintenance/cleanupUsersWithNoId.php. +* The configuration settings $wgResourceLoaderMinifierStatementsOnOwnLine and + $wgResourceLoaderMinifierMaxLineLength, deprecated since 1.27, were removed. +* (T180921) $wgReferrerPolicy now supports having fallbacks for browsers that + are not using the latest version of the Referrer Policy specification. +* $wgFragmentMode is now set to [ 'legacy', 'html5' ] by default. This is a + first step of migration to human-readable section IDs that will later result + in 'html5' being the default mode. +* CACHE_ACCEL now only supports APC(u) or WinCache. XCache support was removed + as upstream is inactive and has no plans to move to PHP 7. +* The old CategorizedRecentChanges feature, including its related configuration + option $wgAllowCategorizedRecentChanges, has been removed. +* (T188472) The 'comma' value for $wgArticleCountMethod is no longer supported + for performance reasons, and installations with this setting will now work as + if it was configured with 'any'. +* (T185753) MediaWiki now defaults to using RemexHtml to tidy up user input, + rather than being off by default. If you wish to disable HTML tidying + entirely, set $wgTidyConfig to null; if you wish to use the old, deprecated + Tidy external binary, both set $wgTidyConfig to null and $wgUseTidy to true. +* $wgLogAutopatrol now defaults to false instead of true. +* $wgValidateAllHtml was removed and will be ignored. +* $wgScriptExtension, deprecated and ignored since 1.25, was removed. See the + 1.25 release notes for more information. +* $wgUseAjax is now marked as deprecated, just like the deprecated AJAX + framework that it enables. Some extensions mistakenly used this to check + whether any AJAX functionality at all should be enabled, further making this + problematic to retain. +* $wgDBmysql5 is now deprecated, and will be removed in a future version. It + has been marked as experimental ever since it was introduced. + +=== New features in 1.31 === +* (T76554) User sub-pages named ….json are now protected in the same way that + ….js and ….css pages are, so that configuration options can safely be placed + there. +* Wikimedia\Rdbms\IDatabase->select() and similar methods now support joins + with parentheses for grouping. +* As a first pass in standardizing dialog boxes across the MediaWiki product, + Html class now provides helper methods for messageBox, successBox, errorBox + and warningBox generation. +* (T9240) Imports will now record unknown (and, optionally, known) usernames in + a format like "iw>Example". +* (T20209) Linker (used on history pages, log pages, and so on) will display + usernames formed like "iw>Example" as interwiki links, as if by wikitext like + [[iw:User:Example|iw>Example]]. +* (T111605) The 'ImportHandleUnknownUser' hook allows extensions to auto-create + users during an import. +* Added a hook, ParserOutputPostCacheTransform, to allow extensions to affect + the ParserOutput::getText() post-cache transformations. +* Added a hook, UploadForm:getInitialPageText, to allow extensions to alter the + initial page text for file uploads. +* (T181651) The info page for File pages now displays the file's base-16 SHA1 + hash value in the table of basic information. +* Style tags with a 'data-mw-deduplicate' attribute will be deduplicated as a + ParserOutput::getText() post-cache transformation. This may be disabled by + passing 'deduplicateStyles' => false to that method. +* The identity of the logged-in or IP "actor" for logged actions is being moved + into a new actor table, with the rows in tables such as revision and logging + referring to the actor ID instead of storing the user ID and name/IP in + every row. + * This is currently gated by $wgActorTableSchemaMigrationStage. Most wikis + can set this to MIGRATION_NEW and run maintenance/migrateActors.php as + soon as any necessary extensions are updated. + * Most code accessing rows for logged actions from the database should use + the relevant getQueryInfo() methods to get the information needed to build + the SQL query. The ActorMigration class may also be used to get feature + -flagged information needed to access actor-related fields during the + migration period. +* Added Wikimedia\Rdbms\IDatabase::cancelAtomic(), to roll back an atomic + section without having to roll back the whole transaction. +* Wikimedia\Rdbms\IDatabase::doAtomicSection(), non-native ::insertSelect(), + and non-MySQL ::replace() and ::upsert() no longer roll back the whole + transaction on failure. +* (T189785) Added a monthly heartbeat ping to the pingback feature. +* The CLI installer (maintenance/install.php) learned to detect and include + extensions. Pass --with-extensions to enable that feature. +* (T184791) rc_patrolled now has three states: "0" for unpatrolled, + "1" for manually patrolled and "2" for autopatrolled actions. +* Extensions can now set their type to "editor" if they provide an editor or + enhance the editing experience. +* Extensions can use a PSR-4 autoloader by setting an "AutoloadNamespaces" + property in extension.json. See the documentation at + + for more details and an example. +* (T19099) Tabs which link to pages that don't exist (like those to uncreated + discussion pages) now have a tooltip to indicate state, not just colour. + +=== External library changes in 1.31 === +* pear/mail, pear/mail_mime and pear/mail_mime-decode have been moved from + suggested to required. These packages now must be installed via composer + and not via PEAR itself. + +==== Upgraded external libraries ==== +* Updated jquery.chosen from v0.9.14 to v1.8.2. +* Updated composer/spdx-licenses from 1.1.4 to 1.3.0 (development dependency). +* Updated nikic/php-parser from 2.1.0 to 3.1.3 (development dependency). +* Updated wikimedia/ip-set from 1.1.0 to 1.2.0. +* Updated wikimedia/relpath from 2.0.0 to 2.1.1. +* Updated wikimedia/running-stat from 1.1.0 to 1.2.0. +* Updated wikimedia/wrappedstring from 2.2.0 to 2.3.0. +* Updated mediawiki/at-ease from 1.1.0 to 1.2.0. +* Updated wikimedia/php-session-serializer from 1.0.4 to 1.0.6. +* Updated wikimedia/remex-html from 1.0.2 to 1.0.3. +* Updated wikimedia/html-formatter from 1.0.1 to 1.0.2. + +==== New external libraries ==== +* Added wikimedia/object-factory 1.0.0 + +==== Removed and replaced external libraries ==== +* (T17845) The deprecated 'jquery.badge' module was removed. +* The deprecated 'jquery.autoEllipsis' module was removed. Use the CSS + text-overflow property instead. +* The deprecated 'jquery.placeholder' module was removed. +* The deprecated 'jquery.appear' module was removed. Use the + 'mediawiki.viewport' module instead. +* mediawiki/at-ease was replaced with wikimedia/at-ease. + +=== Bug fixes in 1.31 === +* (T90902) Non-breaking space in header ID breaks anchor. +* (T189375) CSSMin now allows quoted urls in `url()` syntax to start with a + space. +* (T2087, T10897, T87753, T174639) Whitespace created by category and language + links is now stripped rather than leaving blank lines in odd places. +* (T3780) Uploads with UTF-8 names now work on PHP7.1+ on Windows servers. +* (T182366) UploadBase::checkXMLEncodingMissmatch() now works on PHP 7.1+ + +=== Action API changes in 1.31 === +* (T185058) The 'name' value to tgprop for action=query&list=tags has been + removed. It has never made a difference in the output, the name was always + returned regardless. +* The 'watch' and 'unwatch' parameters for action=move have been removed. They + were deprecated and also accidentally nonfunctional since 1.17 in 2010. Use + 'watchlist' instead. + +=== Action API internal changes in 1.31 === +* ApiBase::getProfileDBTime, deprecated since 1.25, was removed. +* ApiBase::getModuleProfileName, deprecated since 1.25, was removed. +* ApiBase::getProfileTime, deprecated since 1.25, was removed. + +=== Languages updated in 1.31 === +MediaWiki supports over 350 languages. Many localisations are updated +regularly. Below only new and removed languages are listed, as well as +changes to languages because of Phabricator reports. + +* (T180052) Mirandese (mwl) now supports gendered NS_USER/NS_USER_TALK. +* (T182305) New language support: Nyungar (nys). +* (T186359) New language support: Siberian Tatar [cебертатар] (sty). +* (T186635) New language support: Guianan Creole (gcr). +* (T186647) New language support: Kumyk [къумукъ] (kum). +* (T187750) New language support: Spanish formal address (es-formal). +* (T187824) New language support: Hungarian formal address (hu-formal). +* (T189127) New language support: Gorontalo (gor). + +=== Breaking changes in 1.31 === +* MessageBlobStore::insertMessageBlob(), deprecated in 1.27, was removed. +* The OutputPage class constructor now requires a context parameter. + Instantiating without context was deprecated in 1.18. +* The mw.page JavaScript singleton, deprecated in 1.30, was removed. +* Article::getLastPurgeTimestamp(), WikiPage::getLastPurgeTimestamp(), and the + related WikiPage::PURGE_* constants, deprecated in 1.29, were removed. +* The Article::selectFields(), ::onArticleCreate(), ::onArticleDelete(), and + ::onArticleEdit() methods, deprecated in 1.24, were removed. +* Installer::locateExecutable() and ::locateExecutableInDefaultPaths() were + removed. Use ExecutableFinder::findInDefaultPaths() instead. +* The deprecated MW_DIFF_VERSION constant was removed. + DifferenceEngine::MW_DIFF_VERSION should be used instead. +* Due to significant refactoring, method ContribsPager::getUserCond() that had + no access restriction has been removed. +* The Block class will no longer accept usable-but-missing usernames for + 'byText' or ->setBlocker(). Callers should either ensure the blocker exists + locally or use a new interwiki-format username like "iw>Example". +* The following methods and constants from the WatchedItem class, which were + deprecated in 1.27, have been removed: + * WatchedItem::getTitle() + * WatchedItem::fromUserTitle() + * WatchedItem::addWatch() + * WatchedItem::removeWatch() + * WatchedItem::isWatched() + * WatchedItem::duplicateEntries() + * WatchedItem::IGNORE_USER_RIGHTS + * WatchedItem::CHECK_USER_RIGHTS + * WatchedItem::DEPRECATED_USAGE_TIMESTAMP +* The $statementsOnOwnLine parameter of JavaScriptMinifier::minify was removed. + $wgResourceLoaderMinifierStatementsOnOwnLine, the corresponding configuration + variable, has been deprecated since 1.27 and was removed as well. +* The $maxLineLength parameter of JavaScriptMinifier::minify was removed. + $wgResourceLoaderMinifierMaxLineLength, the corresponding configuration + variable, has been deprecated since 1.27 and was removed as well. +* The HtmlFormatter class, deprecated in 1.27, was removed. The namespaced + HtmlFormatter\HtmlFormatter class should be used instead. +* The driver 'mysql' for MySQL, deprecated in MediaWiki 1.30, has been removed. + The driver has been deprecated since PHP 5.5 and was removed in PHP 7.0. The + default driver for MySQL has been 'mysqli' since MediaWiki 1.22. +* The following properties of PreparedEdit were deprecated in 1.21 and have + been removed: + * PreparedEdit->newText + * PreparedEdit->oldText + * PreparedEdit->pst +* ParserOutput objects which are generated using a non-default value for + ParserOptions::setWrapOutputClass() can no longer be added to the parser + cache. +* The following deprecated methods from the OutputPage class have been removed: + * OutputPage::addExtensionStyle(); deprecated in 1.27 + * OutputPage::getExtStyle(); deprecated in 1.27 + * OutputPage::setETag(); deprecated in 1.28 (obsolete no-op) + * OutputPage::setSquidMaxage(); deprecated in 1.27 + * OutputPage::readOnlyPage(); deprecated in 1.25 + * OutputPage::rateLimited(); deprecated in 1.25 + * Additionally, the protected OutputPage::$mExtStyles array, only accessed + through the above and with no known uses, was removed. +* The no-op method Skin::showIPinHeader(), deprecated in 1.27, was removed. +* The following variables and methods in EditPage, deprecated in MediaWiki 1.30, + were removed: + * $isCssJsSubpage — use ::isUserConfigPage() + * $isCssSubpage — use ::isUserCssConfigPage() + * $isJsSubpage — use ::isUserJsConfigPage() + * $isWrongCaseCssJsPage – use ::isWrongCaseUserConfigPage() + * ::getSummaryInput() – use ::getSummaryInputWidget() + * ::getSummaryInputOOUI() – use ::getSummaryInputWidget() + * ::getCheckboxes() – use ::getCheckboxesWidget() or + ::getCheckboxesDefinition() + * ::getCheckboxesOOUI() – use ::getCheckboxesWidget() or + ::getCheckboxesDefinition() +* ResourceLoaderModule::getPosition(), deprecated in 1.29, has been removed. +* In User, the cookie-related methods which were wrappers for the functions on + the response object, and were deprecated in 1.27, have been removed: + * ::setCookie() + * ::clearCookie() + * ::setExtendedLoginCookie() + Note that User::setCookies() remains, and is not deprecated. +* Also in User, some auth-related methods which were deprecated in 1.27 have + been removed: + * ::getEditTokenTimestamp() – use MediaWiki\Session\Token::getTimestamp() + * ::getPasswordFactory() – create a PasswordFactory directly + * ::passwordChangeInputAttribs() +* The global functions wfProfileIn and wfProfileOut, deprecated in 1.25, have + been removed. +* SpecialPageFactory::getList(), deprecated in 1.24, has been removed. You can + use ::getNames() instead. +* OpenSearch::getOpenSearchTemplate(), deprecated in 1.25, has been removed. You + can use ApiOpenSearch::getOpenSearchTemplate() instead. +* The global function wfBaseConvert, deprecated in 1.27, has been removed. Use + Wikimedia\base_convert() directly. +* Calling Database::begin() explicitly during an implicit transaction or when + DBO_TRX is set results in an exception. Calling Database::commit() explicitly + for an implicit transaction also results in an exception. Previously these + were logged as errors. The startAtomic() and endAtomic() methods, or + AtomicSectionUpdate should be used instead. +* The global function wfOutputHandler() was removed, use the its replacement + MediaWiki\OutputHandler::handle() instead. The global function was only + sometimes defined. Its replacement is always available via the autoloader. +* ChangeTags::listExtensionActivatedTags and ::listExtensionDefinedTags, + deprecated in 1.28, have been removed. Use ::listSoftwareActivatedTags() and + ::listSoftwareDefinedTags() instead. +* Title::getTitleInvalidRegex(), deprecated in 1.25, has been removed. You can + use MediaWikiTitleCodec::getTitleInvalidRegex() instead. +* HTMLForm & VFormHTMLForm::isVForm(), deprecated in 1.25, have been removed. +* The ProfileSection class, deprecated in 1.25 and unused, has been removed. +* The ResourceLoaderGetLessVars hook, deprecated in 1.30, has been removed. Use + ResourceLoaderModule::getLessVars() to expose local variables instead of + global ones. +* As part of work to modernise user-generated content clean-up, a config option + and some methods related to HTML validity were removed without deprecation. + The public methods MWTidy::checkErrors() and the path through which it was + called, TidyDriverBase::validate(), are removed, as are the testing methods + MediaWikiTestCase::assertValidHtmlSnippet() and ::assertValidHtmlDocument(). + The $wgValidateAllHtml configuration option is removed and will be ignored. +* Execution of external programs using MediaWiki\Shell\Command now applies + the RESTRICT_DEFAULT Firejail restriction by default. +* The ResourceLoaderModule::getHashMtime() and ::getDefinitionMtime() methods, + deprecated in 1.26, were removed. +* The deprecated 'mediawiki.widgets.CategorySelector' module alias was removed. + Use the 'mediawiki.widgets.CategoryMultiselectWidget' module directly. + +=== Deprecations in 1.31 === +* The Revision class was deprecated in favor of RevisionStore, BlobStore, and + RevisionRecord and its subclasses. +* The global function wfBCP47 is deprecated in favour of LanguageCode::bcp47. +* The global function wfCountDown is now deprecated in favor of + Maintenance::countDown. +* Several methods for returning lists of fields to select from the database + have been deprecated in favor of similar methods that also return the tables + to select from and the join conditions for those tables. + * Block::selectFields() → Block::getQueryInfo() + * RecentChange::selectFields() → RecentChange::getQueryInfo() + * ArchivedFile::selectFields() → ArchivedFile::getQueryInfo() + * LocalFile::selectFields() → LocalFile::getQueryInfo() + * LocalFile::getCacheFields() with a prefix no longer works + * LocalFile::getLazyCacheFields() with a prefix no longer works + * OldLocalFile::selectFields() → OldLocalFile::getQueryInfo() + * RecentChange::selectFields() → RecentChange::getQueryInfo() + * Revision::userJoinCond() → Revision::getQueryInfo( [ 'user' ] ) + * Revision::selectUserFields() → Revision::getQueryInfo( [ 'user' ] ) + * Revision::pageJoinCond() → Revision::getQueryInfo( [ 'page' ] ) + * Revision::selectPageFields() → Revision::getQueryInfo( [ 'page' ] ) + * Revision::selectTextFields() → Revision::getQueryInfo( [ 'text' ] ) + * Revision::selectFields() → Revision::getQueryInfo() + * Revision::selectArchiveFields() → Revision::getArchiveQueryInfo() + * User::selectFields() → User::getQueryInfo() + * WikiPage::selectFields() → WikiPage::getQueryInfo() +* Revision::setUserIdAndName() was deprecated. +* Access to TitleValue class properties was deprecated, the relevant getters + should be used instead. +* DifferenceEngine::getDiffBodyCacheKey() is deprecated. Subclasses should + override DifferenceEngine::getDiffBodyCacheKeyParams() instead. +* Use of Maintenance::error( $err, $die ) to exit script was deprecated. Use + Maintenance::fatalError() instead. +* Passing a ParserOptions object to OutputPage::parserOptions() is deprecated. +* The RevisionInsertComplete hook is now deprecated; use instead the hook + RevisionRecordInserted. RevisionInsertComplete is still called, but the second + and third parameter will always be null. Hard deprecation is scheduled for 1.32. +* The following methods that get and set ParserOutput state are deprecated. + Callers should use the new stateless $options parameter to + ParserOutput::getText() instead. + * ParserOptions::getEditSection() + * ParserOptions::setEditSection() + * ParserOutput::getEditSectionTokens() + * ParserOutput::setEditSectionTokens() + * ParserOutput::getTOCEnabled() + * ParserOutput::setTOCEnabled() + * OutputPage::enableSectionEditLinks() + * OutputPage::sectionEditLinksEnabled() + * The public ParserOutput state fields $mTOCEnabled and $mEditSectionTokens + are also deprecated. +* License::getLicenses has been deprecated; use License::getLines instead. +* QuickTemplate::setRef() was deprecated in favour of QuickTemplate::set(). + Setting template variables by reference allowed violating the principle of + data being immutable once added to the skin template. In practice, this method + was not being used for that. Rather, setRef() existed as memory optimisation + for PHP 4. +* QuickTemplate::setTranslator() and MediaWikiI18N::set() were deprecated in + favour of Skin::msg() parameters. +* MediaWikiI18N::translate() was deprecated in favour of Skin::msg() or + wfMessage(). +* Passing false to ParserOptions::setWrapOutputClass() is deprecated. Use the + 'unwrap' transform to ParserOutput::getText() instead. +* \ObjectFactory (no namespace) is deprecated, the namespaced class + \Wikimedia\ObjectFactory from the wikimedia/object-factory library should be + used instead. +* CommentStore::newKey is deprecated. Instead, get an instance from + MediaWikiServices. +* The following CommentStore methods have had their signatures changed to + introduce a $key parameter, usage of the methods on instances retrieved from + CommentStore::newKey will remain unchanged but deprecated: + * CommentStore::getFields + * CommentStore::getJoin + * CommentStore::getComment + * CommentStore::getCommentLegacy + * CommentStore::insert + * CommentStore::insertWithTemplate +* The following methods in Title have been renamed, and the old ones are + deprecated: + * Title::getSkinFromCssJsSubpage – use ::getSkinFromConfigSubpage + * Title::isCssOrJsPage – use ::isSiteConfigPage + * Title::isCssJsSubpage – use ::isUserConfigPage + * Title::isCssSubpage – use ::isUserCssConfigPage + * Title::isJsSubpage – use ::isUserJsConfigPage +* The following methods related to caching of half-parsed HTML were deprecated: + * Parser::serializeHalfParsedText() + * Parser::unserializeHalfParsedText() + * Parser::isValidHalfParsedText() + * StripState::getSubState() + * StripState::merge() +* The DeferredStringifier class is deprecated, use Message::listParam() instead. +* The type string for the parameter $lang of DateFormatter::getInstance is + deprecated. +* Wikimedia\Rdbms\SavepointPostgres is deprecated. +* The DO_MAINTENANCE constant is deprecated. RUN_MAINTENANCE_IF_MAIN should be + used instead. +* The function wfShellWikiCmd() has been deprecated, use + MediaWiki\Shell::makeScriptCommand(). +* In the future, the hooks 'PreferencesFormPreSave' and 'PreferencesGetLegend' + will be allowed to provide any HTMLForm object rather than PreferencesForm. + +=== Other changes in 1.31 === +* Browser support for Internet Explorer 10 was lowered from Grade A to Grade C. +* Browser support for Opera 12 and older was dropped entirely. Opera 15+ + continues at Grade A. +* Multi-content-revision capability was introduced into the storage layer. See + . +* The "free" CSS class is now only applied to unbracketed URLs in wikitext. + Links written using square brackets will get the class "text" not "free". +* RFC 157418: Whitespace is trimmed from wikitext headings, wikitext list items, + wikitext table captions, wikitext table headings, wikitext table cells. HTML + headings, HTML list items, HTML table captions, HTML table headings, HTML + table cells will not have this trimming behavior. + +== Compatibility == +MediaWiki 1.31 requires PHP 7.0.0 or later. Although HHVM 3.18.5 or later is +supported, it is generally advised to use PHP 7.0.0 or later for long term +support. + +MySQL/MariaDB is the recommended DBMS. PostgreSQL or SQLite can also be used, +but support for them is somewhat less mature. There is experimental support for +Oracle and Microsoft SQL Server. + +The supported versions are: + +* MySQL 5.5.8 or later +* PostgreSQL 9.2 or later +* SQLite 3.3.7 or later +* Oracle 9.0.1 or later +* Microsoft SQL Server 2005 (9.00.1399) + +== Upgrading == +1.31 has several database changes since 1.30, and will not work without schema +updates. Note that due to changes to some very large tables like the revision +table, the schema update may take quite long (minutes on a medium sized site, +many hours on a large site). + +Don't forget to always back up your database before upgrading! + +See the file UPGRADE for more detailed upgrade instructions, including +important information when upgrading from versions prior to 1.11. + +For notes on 1.30.x and older releases, see HISTORY. + +== Online documentation == +Documentation for both end-users and site administrators is available on +MediaWiki.org, and is covered under the GNU Free Documentation License (except +for pages that explicitly state that their contents are in the public domain): + + https://www.mediawiki.org/wiki/Special:MyLanguage/Documentation + +== Mailing list == +A mailing list is available for MediaWiki user support and discussion: + + https://lists.wikimedia.org/mailman/listinfo/mediawiki-l + +A low-traffic announcements-only list is also available: + + https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce + +It's highly recommended that you sign up for one of these lists if you're +going to run a public MediaWiki, so you can be notified of security fixes. + +== IRC help == +There's usually someone online in #mediawiki on irc.freenode.net. + = MediaWiki 1.30 = diff --git a/RELEASE-NOTES-1.31 b/RELEASE-NOTES-1.31 deleted file mode 100644 index ade45b03b4..0000000000 --- a/RELEASE-NOTES-1.31 +++ /dev/null @@ -1,485 +0,0 @@ -== MediaWiki 1.31 == - -THIS IS NOT A RELEASE YET - -MediaWiki 1.31 is an alpha-quality branch and is not recommended for use in -production. - -=== Changes since MediaWiki 1.31.0-rc.2 === -* (T195783) Initialize PSR-4 namespaces at same stage as normal autoloader. -* (T196092) Hide MySQL binary/utf-8 charset option in the installer. -* (T196185) Don't allow setting $wgDBmysql5 in the installer. -* (T196125) php-memcached 3.0 (provided with PHP 7.0) is now supported. -* (T182366) UploadBase::checkXMLEncodingMissmatch() now works on PHP 7.1+ -* (T118683) Fix exception from &$user deref on HHVM in the TitleMoveComplete hook. -* (T196672) The mtime of extension.json files is now able to be zero - -=== Changes since MediaWiki 1.31.0-rc.0 === -* (T33223) Drop archive.ar_text and ar_flags. -* Add default edit rate limit of 90 edits/minute for all users. -* (T187645) Use codepoint as tiebreaker when getting first-letters in - IcuCollation. -* (T191947) Don't shell during the installer if shelling out is disabled. -* (T194319) Improve duplicate config setting exception as part of extension - registration. -* (T195211) Don't require trailing slash in PSR-4 autoloader directory. -* (T186565) Fix PHP Notice from `ob_end_flush()` in `FileRepo::streamFile()`. -* Do not incorrectly hide namespace input field in the installer. -* (T186456) Refactor checks looking for PEAR maik libraries to be clearer. - -=== Important pre-upgrade notes for 1.31 === -* If you're using MySQL, SQLite, or MSSQL, are not using update.php to apply - schema changes, and cannot have downtime to run migrateArchiveText.php and - apply patch-drop-ar_text.sql manually, you'll have to apply a default value - to the ar_text and ar_flags columns of the archive table or make those - columns nullable before upgrading to MediaWiki 1.31. - maintenance/archives/patch-nullable-ar_text.sql shows how to do this for MySQL. - -=== Configuration changes in 1.31 === -* $wgEnableAPI and $wgEnableWriteAPI are now deprecated and will be removed in - a future version. The API is now considered to be stable, secure and - essential. -* $wgUsejQueryThree was removed, as it is now the default. This was documented - as a temporary variable during the migration period, deprecated since 1.29. -* $wgLogoHD has been updated to support svg images and uses $wgLogo where - possible for fallback images such as png. -* (T44246) $wgFilterLogTypes will no longer ignore 'patrol' when user does not - have the right to mark things patrolled. -* Wikis that contain imported revisions or CentralAuth global blocks should run - maintenance/cleanupUsersWithNoId.php. -* The configuration settings $wgResourceLoaderMinifierStatementsOnOwnLine and - $wgResourceLoaderMinifierMaxLineLength, deprecated since 1.27, were removed. -* (T180921) $wgReferrerPolicy now supports having fallbacks for browsers that - are not using the latest version of the Referrer Policy specification. -* $wgFragmentMode is now set to [ 'legacy', 'html5' ] by default. This is a - first step of migration to human-readable section IDs that will later result - in 'html5' being the default mode. -* CACHE_ACCEL now only supports APC(u) or WinCache. XCache support was removed - as upstream is inactive and has no plans to move to PHP 7. -* The old CategorizedRecentChanges feature, including its related configuration - option $wgAllowCategorizedRecentChanges, has been removed. -* (T188472) The 'comma' value for $wgArticleCountMethod is no longer supported - for performance reasons, and installations with this setting will now work as - if it was configured with 'any'. -* (T185753) MediaWiki now defaults to using RemexHtml to tidy up user input, - rather than being off by default. If you wish to disable HTML tidying - entirely, set $wgTidyConfig to null; if you wish to use the old, deprecated - Tidy external binary, both set $wgTidyConfig to null and $wgUseTidy to true. -* $wgLogAutopatrol now defaults to false instead of true. -* $wgValidateAllHtml was removed and will be ignored. -* $wgScriptExtension, deprecated and ignored since 1.25, was removed. See the - 1.25 release notes for more information. -* $wgUseAjax is now marked as deprecated, just like the deprecated AJAX - framework that it enables. Some extensions mistakenly used this to check - whether any AJAX functionality at all should be enabled, further making this - problematic to retain. -* $wgDBmysql5 is now deprecated, and will be removed in a future version. It - has been marked as experimental ever since it was introduced. - -=== New features in 1.31 === -* (T76554) User sub-pages named ….json are now protected in the same way that - ….js and ….css pages are, so that configuration options can safely be placed - there. -* Wikimedia\Rdbms\IDatabase->select() and similar methods now support joins - with parentheses for grouping. -* As a first pass in standardizing dialog boxes across the MediaWiki product, - Html class now provides helper methods for messageBox, successBox, errorBox - and warningBox generation. -* (T9240) Imports will now record unknown (and, optionally, known) usernames in - a format like "iw>Example". -* (T20209) Linker (used on history pages, log pages, and so on) will display - usernames formed like "iw>Example" as interwiki links, as if by wikitext like - [[iw:User:Example|iw>Example]]. -* (T111605) The 'ImportHandleUnknownUser' hook allows extensions to auto-create - users during an import. -* Added a hook, ParserOutputPostCacheTransform, to allow extensions to affect - the ParserOutput::getText() post-cache transformations. -* Added a hook, UploadForm:getInitialPageText, to allow extensions to alter the - initial page text for file uploads. -* (T181651) The info page for File pages now displays the file's base-16 SHA1 - hash value in the table of basic information. -* Style tags with a 'data-mw-deduplicate' attribute will be deduplicated as a - ParserOutput::getText() post-cache transformation. This may be disabled by - passing 'deduplicateStyles' => false to that method. -* The identity of the logged-in or IP "actor" for logged actions is being moved - into a new actor table, with the rows in tables such as revision and logging - referring to the actor ID instead of storing the user ID and name/IP in - every row. - * This is currently gated by $wgActorTableSchemaMigrationStage. Most wikis - can set this to MIGRATION_NEW and run maintenance/migrateActors.php as - soon as any necessary extensions are updated. - * Most code accessing rows for logged actions from the database should use - the relevant getQueryInfo() methods to get the information needed to build - the SQL query. The ActorMigration class may also be used to get feature - -flagged information needed to access actor-related fields during the - migration period. -* Added Wikimedia\Rdbms\IDatabase::cancelAtomic(), to roll back an atomic - section without having to roll back the whole transaction. -* Wikimedia\Rdbms\IDatabase::doAtomicSection(), non-native ::insertSelect(), - and non-MySQL ::replace() and ::upsert() no longer roll back the whole - transaction on failure. -* (T189785) Added a monthly heartbeat ping to the pingback feature. -* The CLI installer (maintenance/install.php) learned to detect and include - extensions. Pass --with-extensions to enable that feature. -* (T184791) rc_patrolled now has three states: "0" for unpatrolled, - "1" for manually patrolled and "2" for autopatrolled actions. -* Extensions can now set their type to "editor" if they provide an editor or - enhance the editing experience. -* Extensions can use a PSR-4 autoloader by setting an "AutoloadNamespaces" - property in extension.json. See the documentation at - - for more details and an example. -* (T19099) Tabs which link to pages that don't exist (like those to uncreated - discussion pages) now have a tooltip to indicate state, not just colour. - -=== External library changes in 1.31 === -* pear/mail, pear/mail_mime and pear/mail_mime-decode have been moved from - suggested to required. These packages now must be installed via composer - and not via PEAR itself. - -==== Upgraded external libraries ==== -* Updated jquery.chosen from v0.9.14 to v1.8.2. -* Updated composer/spdx-licenses from 1.1.4 to 1.3.0 (development dependency). -* Updated nikic/php-parser from 2.1.0 to 3.1.3 (development dependency). -* Updated wikimedia/ip-set from 1.1.0 to 1.2.0. -* Updated wikimedia/relpath from 2.0.0 to 2.1.1. -* Updated wikimedia/running-stat from 1.1.0 to 1.2.0. -* Updated wikimedia/wrappedstring from 2.2.0 to 2.3.0. -* Updated mediawiki/at-ease from 1.1.0 to 1.2.0. -* Updated wikimedia/php-session-serializer from 1.0.4 to 1.0.6. -* Updated wikimedia/remex-html from 1.0.2 to 1.0.3. -* Updated wikimedia/html-formatter from 1.0.1 to 1.0.2. - -==== New external libraries ==== -* Added wikimedia/object-factory 1.0.0 - -==== Removed and replaced external libraries ==== -* (T17845) The deprecated 'jquery.badge' module was removed. -* The deprecated 'jquery.autoEllipsis' module was removed. Use the CSS - text-overflow property instead. -* The deprecated 'jquery.placeholder' module was removed. -* The deprecated 'jquery.appear' module was removed. Use the - 'mediawiki.viewport' module instead. -* mediawiki/at-ease was replaced with wikimedia/at-ease. - -=== Bug fixes in 1.31 === -* (T90902) Non-breaking space in header ID breaks anchor. -* (T189375) CSSMin now allows quoted urls in `url()` syntax to start with a - space. -* (T2087, T10897, T87753, T174639) Whitespace created by category and language - links is now stripped rather than leaving blank lines in odd places. -* (T3780) Uploads with UTF-8 names now work on PHP7.1+ on Windows servers. -* (T182366) UploadBase::checkXMLEncodingMissmatch() now works on PHP 7.1+ - -=== Action API changes in 1.31 === -* (T185058) The 'name' value to tgprop for action=query&list=tags has been - removed. It has never made a difference in the output, the name was always - returned regardless. -* The 'watch' and 'unwatch' parameters for action=move have been removed. They - were deprecated and also accidentally nonfunctional since 1.17 in 2010. Use - 'watchlist' instead. - -=== Action API internal changes in 1.31 === -* ApiBase::getProfileDBTime, deprecated since 1.25, was removed. -* ApiBase::getModuleProfileName, deprecated since 1.25, was removed. -* ApiBase::getProfileTime, deprecated since 1.25, was removed. - -=== Languages updated in 1.31 === -MediaWiki supports over 350 languages. Many localisations are updated -regularly. Below only new and removed languages are listed, as well as -changes to languages because of Phabricator reports. - -* (T180052) Mirandese (mwl) now supports gendered NS_USER/NS_USER_TALK. -* (T182305) New language support: Nyungar (nys). -* (T186359) New language support: Siberian Tatar [cебертатар] (sty). -* (T186635) New language support: Guianan Creole (gcr). -* (T186647) New language support: Kumyk [къумукъ] (kum). -* (T187750) New language support: Spanish formal address (es-formal). -* (T187824) New language support: Hungarian formal address (hu-formal). -* (T189127) New language support: Gorontalo (gor). - -=== Breaking changes in 1.31 === -* MessageBlobStore::insertMessageBlob(), deprecated in 1.27, was removed. -* The OutputPage class constructor now requires a context parameter. - Instantiating without context was deprecated in 1.18. -* The mw.page JavaScript singleton, deprecated in 1.30, was removed. -* Article::getLastPurgeTimestamp(), WikiPage::getLastPurgeTimestamp(), and the - related WikiPage::PURGE_* constants, deprecated in 1.29, were removed. -* The Article::selectFields(), ::onArticleCreate(), ::onArticleDelete(), and - ::onArticleEdit() methods, deprecated in 1.24, were removed. -* Installer::locateExecutable() and ::locateExecutableInDefaultPaths() were - removed. Use ExecutableFinder::findInDefaultPaths() instead. -* The deprecated MW_DIFF_VERSION constant was removed. - DifferenceEngine::MW_DIFF_VERSION should be used instead. -* Due to significant refactoring, method ContribsPager::getUserCond() that had - no access restriction has been removed. -* The Block class will no longer accept usable-but-missing usernames for - 'byText' or ->setBlocker(). Callers should either ensure the blocker exists - locally or use a new interwiki-format username like "iw>Example". -* The following methods and constants from the WatchedItem class, which were - deprecated in 1.27, have been removed: - * WatchedItem::getTitle() - * WatchedItem::fromUserTitle() - * WatchedItem::addWatch() - * WatchedItem::removeWatch() - * WatchedItem::isWatched() - * WatchedItem::duplicateEntries() - * WatchedItem::IGNORE_USER_RIGHTS - * WatchedItem::CHECK_USER_RIGHTS - * WatchedItem::DEPRECATED_USAGE_TIMESTAMP -* The $statementsOnOwnLine parameter of JavaScriptMinifier::minify was removed. - $wgResourceLoaderMinifierStatementsOnOwnLine, the corresponding configuration - variable, has been deprecated since 1.27 and was removed as well. -* The $maxLineLength parameter of JavaScriptMinifier::minify was removed. - $wgResourceLoaderMinifierMaxLineLength, the corresponding configuration - variable, has been deprecated since 1.27 and was removed as well. -* The HtmlFormatter class, deprecated in 1.27, was removed. The namespaced - HtmlFormatter\HtmlFormatter class should be used instead. -* The driver 'mysql' for MySQL, deprecated in MediaWiki 1.30, has been removed. - The driver has been deprecated since PHP 5.5 and was removed in PHP 7.0. The - default driver for MySQL has been 'mysqli' since MediaWiki 1.22. -* The following properties of PreparedEdit were deprecated in 1.21 and have - been removed: - * PreparedEdit->newText - * PreparedEdit->oldText - * PreparedEdit->pst -* ParserOutput objects which are generated using a non-default value for - ParserOptions::setWrapOutputClass() can no longer be added to the parser - cache. -* The following deprecated methods from the OutputPage class have been removed: - * OutputPage::addExtensionStyle(); deprecated in 1.27 - * OutputPage::getExtStyle(); deprecated in 1.27 - * OutputPage::setETag(); deprecated in 1.28 (obsolete no-op) - * OutputPage::setSquidMaxage(); deprecated in 1.27 - * OutputPage::readOnlyPage(); deprecated in 1.25 - * OutputPage::rateLimited(); deprecated in 1.25 - * Additionally, the protected OutputPage::$mExtStyles array, only accessed - through the above and with no known uses, was removed. -* The no-op method Skin::showIPinHeader(), deprecated in 1.27, was removed. -* The following variables and methods in EditPage, deprecated in MediaWiki 1.30, - were removed: - * $isCssJsSubpage — use ::isUserConfigPage() - * $isCssSubpage — use ::isUserCssConfigPage() - * $isJsSubpage — use ::isUserJsConfigPage() - * $isWrongCaseCssJsPage – use ::isWrongCaseUserConfigPage() - * ::getSummaryInput() – use ::getSummaryInputWidget() - * ::getSummaryInputOOUI() – use ::getSummaryInputWidget() - * ::getCheckboxes() – use ::getCheckboxesWidget() or - ::getCheckboxesDefinition() - * ::getCheckboxesOOUI() – use ::getCheckboxesWidget() or - ::getCheckboxesDefinition() -* ResourceLoaderModule::getPosition(), deprecated in 1.29, has been removed. -* In User, the cookie-related methods which were wrappers for the functions on - the response object, and were deprecated in 1.27, have been removed: - * ::setCookie() - * ::clearCookie() - * ::setExtendedLoginCookie() - Note that User::setCookies() remains, and is not deprecated. -* Also in User, some auth-related methods which were deprecated in 1.27 have - been removed: - * ::getEditTokenTimestamp() – use MediaWiki\Session\Token::getTimestamp() - * ::getPasswordFactory() – create a PasswordFactory directly - * ::passwordChangeInputAttribs() -* The global functions wfProfileIn and wfProfileOut, deprecated in 1.25, have - been removed. -* SpecialPageFactory::getList(), deprecated in 1.24, has been removed. You can - use ::getNames() instead. -* OpenSearch::getOpenSearchTemplate(), deprecated in 1.25, has been removed. You - can use ApiOpenSearch::getOpenSearchTemplate() instead. -* The global function wfBaseConvert, deprecated in 1.27, has been removed. Use - Wikimedia\base_convert() directly. -* Calling Database::begin() explicitly during an implicit transaction or when - DBO_TRX is set results in an exception. Calling Database::commit() explicitly - for an implicit transaction also results in an exception. Previously these - were logged as errors. The startAtomic() and endAtomic() methods, or - AtomicSectionUpdate should be used instead. -* The global function wfOutputHandler() was removed, use the its replacement - MediaWiki\OutputHandler::handle() instead. The global function was only - sometimes defined. Its replacement is always available via the autoloader. -* ChangeTags::listExtensionActivatedTags and ::listExtensionDefinedTags, - deprecated in 1.28, have been removed. Use ::listSoftwareActivatedTags() and - ::listSoftwareDefinedTags() instead. -* Title::getTitleInvalidRegex(), deprecated in 1.25, has been removed. You can - use MediaWikiTitleCodec::getTitleInvalidRegex() instead. -* HTMLForm & VFormHTMLForm::isVForm(), deprecated in 1.25, have been removed. -* The ProfileSection class, deprecated in 1.25 and unused, has been removed. -* The ResourceLoaderGetLessVars hook, deprecated in 1.30, has been removed. Use - ResourceLoaderModule::getLessVars() to expose local variables instead of - global ones. -* As part of work to modernise user-generated content clean-up, a config option - and some methods related to HTML validity were removed without deprecation. - The public methods MWTidy::checkErrors() and the path through which it was - called, TidyDriverBase::validate(), are removed, as are the testing methods - MediaWikiTestCase::assertValidHtmlSnippet() and ::assertValidHtmlDocument(). - The $wgValidateAllHtml configuration option is removed and will be ignored. -* Execution of external programs using MediaWiki\Shell\Command now applies - the RESTRICT_DEFAULT Firejail restriction by default. -* The ResourceLoaderModule::getHashMtime() and ::getDefinitionMtime() methods, - deprecated in 1.26, were removed. -* The deprecated 'mediawiki.widgets.CategorySelector' module alias was removed. - Use the 'mediawiki.widgets.CategoryMultiselectWidget' module directly. - -=== Deprecations in 1.31 === -* The Revision class was deprecated in favor of RevisionStore, BlobStore, and - RevisionRecord and its subclasses. -* The global function wfBCP47 is deprecated in favour of LanguageCode::bcp47. -* The global function wfCountDown is now deprecated in favor of - Maintenance::countDown. -* Several methods for returning lists of fields to select from the database - have been deprecated in favor of similar methods that also return the tables - to select from and the join conditions for those tables. - * Block::selectFields() → Block::getQueryInfo() - * RecentChange::selectFields() → RecentChange::getQueryInfo() - * ArchivedFile::selectFields() → ArchivedFile::getQueryInfo() - * LocalFile::selectFields() → LocalFile::getQueryInfo() - * LocalFile::getCacheFields() with a prefix no longer works - * LocalFile::getLazyCacheFields() with a prefix no longer works - * OldLocalFile::selectFields() → OldLocalFile::getQueryInfo() - * RecentChange::selectFields() → RecentChange::getQueryInfo() - * Revision::userJoinCond() → Revision::getQueryInfo( [ 'user' ] ) - * Revision::selectUserFields() → Revision::getQueryInfo( [ 'user' ] ) - * Revision::pageJoinCond() → Revision::getQueryInfo( [ 'page' ] ) - * Revision::selectPageFields() → Revision::getQueryInfo( [ 'page' ] ) - * Revision::selectTextFields() → Revision::getQueryInfo( [ 'text' ] ) - * Revision::selectFields() → Revision::getQueryInfo() - * Revision::selectArchiveFields() → Revision::getArchiveQueryInfo() - * User::selectFields() → User::getQueryInfo() - * WikiPage::selectFields() → WikiPage::getQueryInfo() -* Revision::setUserIdAndName() was deprecated. -* Access to TitleValue class properties was deprecated, the relevant getters - should be used instead. -* DifferenceEngine::getDiffBodyCacheKey() is deprecated. Subclasses should - override DifferenceEngine::getDiffBodyCacheKeyParams() instead. -* Use of Maintenance::error( $err, $die ) to exit script was deprecated. Use - Maintenance::fatalError() instead. -* Passing a ParserOptions object to OutputPage::parserOptions() is deprecated. -* The RevisionInsertComplete hook is now deprecated; use instead the hook - RevisionRecordInserted. RevisionInsertComplete is still called, but the second - and third parameter will always be null. Hard deprecation is scheduled for 1.32. -* The following methods that get and set ParserOutput state are deprecated. - Callers should use the new stateless $options parameter to - ParserOutput::getText() instead. - * ParserOptions::getEditSection() - * ParserOptions::setEditSection() - * ParserOutput::getEditSectionTokens() - * ParserOutput::setEditSectionTokens() - * ParserOutput::getTOCEnabled() - * ParserOutput::setTOCEnabled() - * OutputPage::enableSectionEditLinks() - * OutputPage::sectionEditLinksEnabled() - * The public ParserOutput state fields $mTOCEnabled and $mEditSectionTokens - are also deprecated. -* License::getLicenses has been deprecated; use License::getLines instead. -* QuickTemplate::setRef() was deprecated in favour of QuickTemplate::set(). - Setting template variables by reference allowed violating the principle of - data being immutable once added to the skin template. In practice, this method - was not being used for that. Rather, setRef() existed as memory optimisation - for PHP 4. -* QuickTemplate::setTranslator() and MediaWikiI18N::set() were deprecated in - favour of Skin::msg() parameters. -* MediaWikiI18N::translate() was deprecated in favour of Skin::msg() or - wfMessage(). -* Passing false to ParserOptions::setWrapOutputClass() is deprecated. Use the - 'unwrap' transform to ParserOutput::getText() instead. -* \ObjectFactory (no namespace) is deprecated, the namespaced class - \Wikimedia\ObjectFactory from the wikimedia/object-factory library should be - used instead. -* CommentStore::newKey is deprecated. Instead, get an instance from - MediaWikiServices. -* The following CommentStore methods have had their signatures changed to - introduce a $key parameter, usage of the methods on instances retrieved from - CommentStore::newKey will remain unchanged but deprecated: - * CommentStore::getFields - * CommentStore::getJoin - * CommentStore::getComment - * CommentStore::getCommentLegacy - * CommentStore::insert - * CommentStore::insertWithTemplate -* The following methods in Title have been renamed, and the old ones are - deprecated: - * Title::getSkinFromCssJsSubpage – use ::getSkinFromConfigSubpage - * Title::isCssOrJsPage – use ::isSiteConfigPage - * Title::isCssJsSubpage – use ::isUserConfigPage - * Title::isCssSubpage – use ::isUserCssConfigPage - * Title::isJsSubpage – use ::isUserJsConfigPage -* The following methods related to caching of half-parsed HTML were deprecated: - * Parser::serializeHalfParsedText() - * Parser::unserializeHalfParsedText() - * Parser::isValidHalfParsedText() - * StripState::getSubState() - * StripState::merge() -* The DeferredStringifier class is deprecated, use Message::listParam() instead. -* The type string for the parameter $lang of DateFormatter::getInstance is - deprecated. -* Wikimedia\Rdbms\SavepointPostgres is deprecated. -* The DO_MAINTENANCE constant is deprecated. RUN_MAINTENANCE_IF_MAIN should be - used instead. -* The function wfShellWikiCmd() has been deprecated, use - MediaWiki\Shell::makeScriptCommand(). -* In the future, the hooks 'PreferencesFormPreSave' and 'PreferencesGetLegend' - will be allowed to provide any HTMLForm object rather than PreferencesForm. - -=== Other changes in 1.31 === -* Browser support for Internet Explorer 10 was lowered from Grade A to Grade C. -* Browser support for Opera 12 and older was dropped entirely. Opera 15+ - continues at Grade A. -* Multi-content-revision capability was introduced into the storage layer. See - . -* The "free" CSS class is now only applied to unbracketed URLs in wikitext. - Links written using square brackets will get the class "text" not "free". -* RFC 157418: Whitespace is trimmed from wikitext headings, wikitext list items, - wikitext table captions, wikitext table headings, wikitext table cells. HTML - headings, HTML list items, HTML table captions, HTML table headings, HTML - table cells will not have this trimming behavior. - -== Compatibility == -MediaWiki 1.31 requires PHP 7.0.0 or later. Although HHVM 3.18.5 or later is -supported, it is generally advised to use PHP 7.0.0 or later for long term -support. - -MySQL/MariaDB is the recommended DBMS. PostgreSQL or SQLite can also be used, -but support for them is somewhat less mature. There is experimental support for -Oracle and Microsoft SQL Server. - -The supported versions are: - -* MySQL 5.5.8 or later -* PostgreSQL 9.2 or later -* SQLite 3.3.7 or later -* Oracle 9.0.1 or later -* Microsoft SQL Server 2005 (9.00.1399) - -== Upgrading == -1.31 has several database changes since 1.30, and will not work without schema -updates. Note that due to changes to some very large tables like the revision -table, the schema update may take quite long (minutes on a medium sized site, -many hours on a large site). - -Don't forget to always back up your database before upgrading! - -See the file UPGRADE for more detailed upgrade instructions, including -important information when upgrading from versions prior to 1.11. - -For notes on 1.30.x and older releases, see HISTORY. - -== Online documentation == -Documentation for both end-users and site administrators is available on -MediaWiki.org, and is covered under the GNU Free Documentation License (except -for pages that explicitly state that their contents are in the public domain): - - https://www.mediawiki.org/wiki/Special:MyLanguage/Documentation - -== Mailing list == -A mailing list is available for MediaWiki user support and discussion: - - https://lists.wikimedia.org/mailman/listinfo/mediawiki-l - -A low-traffic announcements-only list is also available: - - https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce - -It's highly recommended that you sign up for one of these lists if you're -going to run a public MediaWiki, so you can be notified of security fixes. - -== IRC help == -There's usually someone online in #mediawiki on irc.freenode.net. diff --git a/RELEASE-NOTES-1.32 b/RELEASE-NOTES-1.32 index 4e2bdfae24..5dbf873c86 100644 --- a/RELEASE-NOTES-1.32 +++ b/RELEASE-NOTES-1.32 @@ -25,6 +25,7 @@ production. This determines whether to set a cookie when an IP user is blocked. Doing so means that a blocked user, even after moving to a new IP address, will still be blocked. * The archive table's ar_rev_id field is now unique. +* Special:BotPasswords now requires reauthentication. === New features in 1.32 === * (T112474) Generalized the ResourceLoader mechanism for overriding modules @@ -41,6 +42,9 @@ production. reauthenticating. * FormSpecialPage::execute() will now call checkLoginSecurityLevel() if getLoginSecurityLevel() returns non-false. +* The 'ImageBeforeProduceHTML' hook is now passed three new parameters, $parser, + &$query and &$widthOption, allowing extensions even finer control over the resulting + HTML code. === External library changes in 1.32 === * … @@ -89,6 +93,7 @@ because of Phabricator reports. * (T193566) Added language support for Ambonese Malay (abs). * (T194047) Added language support for Shawiya, Latin script (shy-latn). * (T195940) Added language support for Batak Mandailing (btm). +* (T137491) Added language support for Standard Moroccan Amazigh (zgh). === Breaking changes in 1.32 === * $wgRequestTime, deprecated in 1.25, was removed. Use @@ -156,6 +161,10 @@ because of Phabricator reports. minor change to implement the toggle feature with CSS instead. To restore prior functionality, either explicitly load "jquery.mw-jump" in your skin or refer to T195256 for details on how to make the same change. +* Hook 'EditPageBeforeEditChecks' was removed; + use 'EditPageGetCheckboxesDefinition' instead. +* Linker::getLinkColour() and DummyLinker::getLinkColour(), deprecated since + 1.28, were removed. LinkRenderer::getLinkClasses() should be used instead. === Deprecations in 1.32 === * Use of a StartProfiler.php file is deprecated in favour of placing @@ -186,6 +195,22 @@ because of Phabricator reports. * The ApiQueryContributions class has been renamed to ApiQueryUserContribs. * The XMPInfo, XMPReader, and XMPValidate classes have been deprecated in favor of the namespaced classes provided by the wikimedia/xmp-reader library. +* SearchResultSet::{next,rewind} are deprecated. Calling code should + use foreach on the SearchResultSet, or the extractResults method. Extending + code should override extractResults. +* Instantiating SearchResultSet directly is deprecated. SearchEngine + implementations must subclass SearchResultSet for their purposes. +* SearchResult::setExtensionData argument has been changed from accepting an + array to accepting a Closure that returns the array when called. +* Class CryptRand, everything in MWCryptRand except generateHex() and function + MediaWikiServices::getCryptRand() are deprecated, use random_bytes() to + generate cryptographically secure random byte sequences. +* Parser::getConverterLanguage() is deprecated. Use ::getTargetLanguage() + instead. +* Language::markNoConversion() is deprecated. It confused readers because + it had unexpected behavior (only marking text if it looked like a URL) + and was only used in a single place in the code. Use + LanguageConverter::markNoConversion() instead. === Other changes in 1.32 === * … diff --git a/autoload.php b/autoload.php index 1adc5e4ea6..ac1ac18189 100644 --- a/autoload.php +++ b/autoload.php @@ -1070,6 +1070,7 @@ $wgAutoloadLocalClasses = [ 'PageProps' => __DIR__ . '/includes/PageProps.php', 'PageQueryPage' => __DIR__ . '/includes/specialpage/PageQueryPage.php', 'Pager' => __DIR__ . '/includes/pager/Pager.php', + 'PaginatingSearchEngine' => __DIR__ . '/includes/search/PaginatingSearchEngine.php', 'ParameterizedPassword' => __DIR__ . '/includes/password/ParameterizedPassword.php', 'Parser' => __DIR__ . '/includes/parser/Parser.php', 'ParserCache' => __DIR__ . '/includes/parser/ParserCache.php', diff --git a/composer.json b/composer.json index 99a3f64112..7eb4265464 100644 --- a/composer.json +++ b/composer.json @@ -65,7 +65,7 @@ "nikic/php-parser": "3.1.3", "nmred/kafka-php": "0.1.5", "phpunit/phpunit": "4.8.36 || ^6.5", - "psy/psysh": "0.8.11", + "psy/psysh": "0.9.6", "wikimedia/avro": "1.8.0", "wikimedia/testing-access-wrapper": "~1.0", "wmde/hamcrest-html-matchers": "^0.1.0" diff --git a/docs/hooks.txt b/docs/hooks.txt index 8c84509b56..48b76bb319 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -74,10 +74,10 @@ Using a hook-running strategy, we can avoid having all this option-specific stuff in our mainline code. Using hooks, the function becomes: function showAnArticle( $article ) { - if ( Hooks::run( 'ArticleShow', array( &$article ) ) ) { + if ( Hooks::run( 'ArticleShow', [ &$article ] ) ) { # code to actually show the article goes here - Hooks::run( 'ArticleShowComplete', array( &$article ) ); + Hooks::run( 'ArticleShowComplete', [ &$article ] ); } } @@ -137,13 +137,13 @@ Hooks are registered by adding them to the global $wgHooks array for a given event. All the following are valid ways to define hooks: $wgHooks['EventName'][] = 'someFunction'; # function, no data - $wgHooks['EventName'][] = array( 'someFunction', $someData ); - $wgHooks['EventName'][] = array( 'someFunction' ); # weird, but OK + $wgHooks['EventName'][] = [ 'someFunction', $someData ]; + $wgHooks['EventName'][] = [ 'someFunction' ]; # weird, but OK $wgHooks['EventName'][] = $object; # object only - $wgHooks['EventName'][] = array( $object, 'someMethod' ); - $wgHooks['EventName'][] = array( $object, 'someMethod', $someData ); - $wgHooks['EventName'][] = array( $object ); # weird but OK + $wgHooks['EventName'][] = [ $object, 'someMethod' ]; + $wgHooks['EventName'][] = [ $object, 'someMethod', $someData ]; + $wgHooks['EventName'][] = [ $object ]; # weird but OK When an event occurs, the function (or object method) will be called with the optional data provided as well as event-specific parameters. The above examples @@ -168,8 +168,8 @@ different: 'onArticleSave', 'onUserLogin', etc. The extra data is useful if we want to use the same function or object for different purposes. For example: - $wgHooks['PageContentSaveComplete'][] = array( 'ircNotify', 'TimStarling' ); - $wgHooks['PageContentSaveComplete'][] = array( 'ircNotify', 'brion' ); + $wgHooks['PageContentSaveComplete'][] = [ 'ircNotify', 'TimStarling' ]; + $wgHooks['PageContentSaveComplete'][] = [ 'ircNotify', 'brion' ]; This code would result in ircNotify being run twice when an article is saved: once for 'TimStarling', and once for 'brion'. @@ -187,7 +187,7 @@ The last result would be for cases where the hook function replaces the main functionality. For example, if you wanted to authenticate users to a custom system (LDAP, another PHP program, whatever), you could do: - $wgHooks['UserLogin'][] = array( 'ldapLogin', $ldapServer ); + $wgHooks['UserLogin'][] = [ 'ldapLogin', $ldapServer ]; function ldapLogin( $username, $password ) { # log user into LDAP @@ -232,7 +232,7 @@ wfRunHooks must be used, which was deprecated in MediaWiki 1.25. Note that hook parameters are passed in an array; this is a necessary inconvenience to make it possible to pass reference values (that can be changed) into the hook code. Also note that earlier versions of wfRunHooks took a -variable number of arguments; the array() calling protocol came about after +variable number of arguments; the [] calling protocol came about after MediaWiki 1.4rc1. ==Events and parameters== @@ -240,8 +240,8 @@ MediaWiki 1.4rc1. This is a list of known events and parameters; please add to it if you're going to add events to the MediaWiki code. -'AbortAutoAccount': DEPRECATED! Create a PreAuthenticationProvider instead. -Return false to cancel automated local account creation, where normally +'AbortAutoAccount': DEPRECATED since 1.27! Create a PreAuthenticationProvider +instead. Return false to cancel automated local account creation, where normally authentication against an external auth plugin would be creating a local account. $user: the User object about to be created (read-only, incomplete) @@ -259,7 +259,7 @@ $editor: The User who made the change. $title: The Title of the page that was edited. $rc: The current RecentChange object. -'AbortLogin': DEPRECATED! Create a PreAuthenticationProvider instead. +'AbortLogin': DEPRECATED since 1.27! Create a PreAuthenticationProvider instead. Return false to cancel account login. $user: the User object being authenticated against $password: the password being submitted, not yet checked for validity @@ -269,8 +269,8 @@ $password: the password being submitted, not yet checked for validity &$msg: the message identifier for abort reason (new in 1.18, not available before 1.18) -'AbortNewAccount': DEPRECATED! Create a PreAuthenticationProvider instead. -Return false to cancel explicit account creation. +'AbortNewAccount': DEPRECATED since 1.27! Create a PreAuthenticationProvider +instead. Return false to cancel explicit account creation. $user: the User object about to be created (read-only, incomplete) &$msg: out parameter: HTML to display on abort &$status: out parameter: Status object to return, replaces the older $msg param @@ -294,14 +294,14 @@ $name: name of the action &$fields: HTMLForm descriptor array $article: Article object -'AddNewAccount': DEPRECATED! Use LocalUserCreated. +'AddNewAccount': DEPRECATED since 1.27! Use LocalUserCreated. After a user account is created. $user: the User object that was created. (Parameter added in 1.7) $byEmail: true when account was created "by email" (added in 1.12) -'AfterBuildFeedLinks': Executed in OutputPage.php after all feed links (atom, rss,...) -are created. Can be used to omit specific feeds from being outputted. You must not use -this hook to add feeds, use OutputPage::addFeedLink() instead. +'AfterBuildFeedLinks': Executed in OutputPage.php after all feed links (atom, +rss,...) are created. Can be used to omit specific feeds from being outputted. +You must not use this hook to add feeds, use OutputPage::addFeedLink() instead. &$feedLinks: Array of created feed links 'AfterFinalPageOutput': Nearly at the end of OutputPage::output() but @@ -372,7 +372,7 @@ from ApiBase::addDeprecation(). &$msgs: Message[] Messages to include in the help. Multiple messages will be joined with spaces. -'APIEditBeforeSave': DEPRECATED! Use EditFilterMergedContent instead. +'APIEditBeforeSave': DEPRECATED since 1.28! Use EditFilterMergedContent instead. Before saving a page with api.php?action=edit, after processing request parameters. Return false to let the request fail, returning an error message or an tag if $resultArr was filled. @@ -409,8 +409,8 @@ $format: API format code for $text. &$params: Array of parameters $flags: int zero or OR-ed flags like ApiBase::GET_VALUES_FOR_HELP -'APIGetDescription': DEPRECATED! Use APIGetDescriptionMessages instead. -Use this hook to modify a module's description. +'APIGetDescription': DEPRECATED since 1.25! Use APIGetDescriptionMessages +instead. Use this hook to modify a module's description. &$module: ApiBase Module object &$desc: String description, or array of description strings @@ -418,8 +418,8 @@ Use this hook to modify a module's description. $module: ApiBase Module object &$msg: Array of Message objects -'APIGetParamDescription': DEPRECATED! Use APIGetParamDescriptionMessages -instead. +'APIGetParamDescription': DEPRECATED since 1.25! Use +APIGetParamDescriptionMessages instead. Use this hook to modify a module's parameter descriptions. &$module: ApiBase Module object &$desc: Array of parameter descriptions @@ -488,8 +488,8 @@ documentation. $module: ApiQueryBase module in question $result: ResultWrapper|bool returned from the IDatabase::select() &$hookData: array that was passed to the 'ApiQueryBaseBeforeQuery' hook and - will be passed to the 'ApiQueryBaseProcessRow' hook, intended for inter-hook - communication. + will be passed to the 'ApiQueryBaseProcessRow' hook, intended for inter-hook + communication. 'ApiQueryBaseBeforeQuery': Called for (some) API query modules before a database query is made. WARNING: It would be very easy to misuse this hook and @@ -504,7 +504,7 @@ $module: ApiQueryBase module in question &$query_options: array of options for the database request &$join_conds: join conditions for the tables &$hookData: array that will be passed to the 'ApiQueryBaseAfterQuery' and - 'ApiQueryBaseProcessRow' hooks, intended for inter-hook communication. + 'ApiQueryBaseProcessRow' hooks, intended for inter-hook communication. 'ApiQueryBaseProcessRow': Called for (some) API query modules as each row of the database result is processed. Return false to stop processing the result @@ -514,26 +514,26 @@ $module: ApiQueryBase module in question $row: stdClass Database result row &$data: array to be included in the ApiResult. &$hookData: array that was be passed to the 'ApiQueryBaseBeforeQuery' and - 'ApiQueryBaseAfterQuery' hooks, intended for inter-hook communication. + 'ApiQueryBaseAfterQuery' hooks, intended for inter-hook communication. 'APIQueryGeneratorAfterExecute': After calling the executeGenerator() method of an action=query submodule. Use this to extend core API modules. &$module: Module object &$resultPageSet: ApiPageSet object -'APIQueryInfoTokens': DEPRECATED! Use ApiQueryTokensRegisterTypes instead. -Use this hook to add custom tokens to prop=info. Every token has an action, -which will be used in the intoken parameter and in the output +'APIQueryInfoTokens': DEPRECATED since 1.24! Use ApiQueryTokensRegisterTypes +instead. Use this hook to add custom tokens to prop=info. Every token has an +action, which will be used in the intoken parameter and in the output (actiontoken="..."), and a callback function which should return the token, or false if the user isn't allowed to obtain it. The prototype of the callback function is func($pageid, $title), where $pageid is the page ID of the page the token is requested for and $title is the associated Title object. In the hook, just add your callback to the $tokenFunctions array and return true (returning false makes no sense). -&$tokenFunctions: array(action => callback) +&$tokenFunctions: [ action => callback ] -'APIQueryRecentChangesTokens': DEPRECATED! Use ApiQueryTokensRegisterTypes -instead. +'APIQueryRecentChangesTokens': DEPRECATED since 1.24! Use +ApiQueryTokensRegisterTypes instead. Use this hook to add custom tokens to list=recentchanges. Every token has an action, which will be used in the rctoken parameter and in the output (actiontoken="..."), and a callback function which should return the token, or @@ -543,9 +543,10 @@ page associated to the revision the token is requested for, $title the associated Title object and $rc the associated RecentChange object. In the hook, just add your callback to the $tokenFunctions array and return true (returning false makes no sense). -&$tokenFunctions: array(action => callback) +&$tokenFunctions: [ action => callback ] -'APIQueryRevisionsTokens': DEPRECATED! Use ApiQueryTokensRegisterTypes instead. +'APIQueryRevisionsTokens': DEPRECATED since 1.24! Use +ApiQueryTokensRegisterTypes instead. Use this hook to add custom tokens to prop=revisions. Every token has an action, which will be used in the rvtoken parameter and in the output (actiontoken="..."), and a callback function which should return the token, or @@ -555,7 +556,7 @@ page associated to the revision the token is requested for, $title the associated Title object and $rev the associated Revision object. In the hook, just add your callback to the $tokenFunctions array and return true (returning false makes no sense). -&$tokenFunctions: array(action => callback) +&$tokenFunctions: [ action => callback ] 'APIQuerySiteInfoGeneralInfo': Use this hook to add extra information to the sites general information. @@ -569,10 +570,11 @@ sites statistics information. 'ApiQueryTokensRegisterTypes': Use this hook to add additional token types to action=query&meta=tokens. Note that most modules will probably be able to use the 'csrf' token instead of creating their own token types. -&$salts: array( type => salt to pass to User::getEditToken() or array of salt - and key to pass to Session::getToken() ) +&$salts: [ type => salt to pass to User::getEditToken(), or array of salt + and key to pass to Session::getToken() ] -'APIQueryUsersTokens': DEPRECATED! Use ApiQueryTokensRegisterTypes instead. +'APIQueryUsersTokens': DEPRECATED since 1.24! Use ApiQueryTokensRegisterTypes +instead. Use this hook to add custom token to list=users. Every token has an action, which will be used in the ustoken parameter and in the output (actiontoken="..."), and a callback function which should return the token, or @@ -580,7 +582,7 @@ false if the user isn't allowed to obtain it. The prototype of the callback function is func($user) where $user is the User object. In the hook, just add your callback to the $tokenFunctions array and return true (returning false makes no sense). -&$tokenFunctions: array(action => callback) +&$tokenFunctions: [ action => callback ] 'ApiQueryWatchlistExtractOutputData': Extract row data for ApiQueryWatchlist. $module: ApiQueryWatchlist instance @@ -600,7 +602,7 @@ key for the array that represents the service data. In this data array, the key-value-pair identified by the apiLink key is required. &$apis: array of services -'ApiTokensGetTokenTypes': DEPRECATED! Use ApiQueryTokensRegisterTypes instead. +'ApiTokensGetTokenTypes': DEPRECATED since 1.24! Use ApiQueryTokensRegisterTypes instead. Use this hook to extend action=tokens with new token types. &$tokenTypes: supported token types in format 'type' => callback function used to retrieve this type of tokens. @@ -778,7 +780,8 @@ redirect was followed. from a set of AuthenticationRequest classes into a form descriptor; hooks can tweak the array to change how login etc. forms should look. $requests: array of AuthenticationRequests the fields are created from -$fieldInfo: field information array (union of all AuthenticationRequest::getFieldInfo() responses). +$fieldInfo: field information array (union of all + AuthenticationRequest::getFieldInfo() responses). &$formDescriptor: HTMLForm descriptor. The special key 'weight' can be set to change the order of the fields. $action: one of the AuthManager::ACTION_* constants. @@ -786,20 +789,21 @@ $action: one of the AuthManager::ACTION_* constants. 'AuthManagerLoginAuthenticateAudit': A login attempt either succeeded or failed for a reason other than misconfiguration or session loss. No return data is accepted; this hook is for auditing only. -$response: The MediaWiki\Auth\AuthenticationResponse in either a PASS or FAIL state. +$response: The MediaWiki\Auth\AuthenticationResponse in either a PASS or FAIL + state. $user: The User object being authenticated against, or null if authentication failed before getting that far. $username: A guess at the user name being authenticated, or null if we can't even determine that. -'AuthPluginAutoCreate': DEPRECATED! Use the 'LocalUserCreated' hook instead. -Called when creating a local account for an user logged in from an external -authentication method. +'AuthPluginAutoCreate': DEPRECATED since 1.27! Use the 'LocalUserCreated' hook +instead. Called when creating a local account for an user logged in from an +external authentication method. $user: User object created locally -'AuthPluginSetup': DEPRECATED! Extensions should be updated to use AuthManager. -Update or replace authentication plugin object ($wgAuth). Gives a chance for an -extension to set it programmatically to a variable class. +'AuthPluginSetup': DEPRECATED since 1.27! Extensions should be updated to use +AuthManager. Update or replace authentication plugin object ($wgAuth). Gives a +chance for an extension to set it programmatically to a variable class. &$auth: the $wgAuth object, probably a stub 'AutopromoteCondition': Check autopromote condition for user. @@ -972,9 +976,9 @@ No return data is accepted; this hook is for auditing only. $req: AuthenticationRequest object describing the change (and target user) $status: StatusValue with the result of the action -'ChangePasswordForm': DEPRECATED! Use AuthChangeFormFields or security levels. -For extensions that need to add a field to the ChangePassword form via the -Preferences form. +'ChangePasswordForm': DEPRECATED since 1.27! Use AuthChangeFormFields or +security levels. For extensions that need to add a field to the ChangePassword +form via the Preferences form. &$extraFields: An array of arrays that hold fields like would be passed to the pretty function. @@ -991,8 +995,8 @@ $rows: The data that will be rendered. May be a ResultWrapper instance or $unpatrolled: Whether or not we are showing unpatrolled changes. $watched: Whether or not the change is watched by the user. -'ChangesListSpecialPageFilters': DEPRECATED! Use 'ChangesListSpecialPageStructuredFilters' -instead. +'ChangesListSpecialPageFilters': DEPRECATED since 1.29! Use +'ChangesListSpecialPageStructuredFilters' instead. Called after building form options on pages inheriting from ChangesListSpecialPage (in core: RecentChanges, RecentChangesLinked and Watchlist). @@ -1075,8 +1079,9 @@ $rc_id: recentchanges table id $rev_id: revision table id $log_id: logging table id $params: tag params -$rc: RecentChange being tagged when the tagging accompanies the action or null -$user: User who performed the tagging when the tagging is subsequent to the action or null +$rc: RecentChange being tagged when the tagging accompanies the action, or null +$user: User who performed the tagging when the tagging is subsequent to the + action, or null 'ChangeTagsAllowedAdd': Called when checking if a user can add tags to a change. &$allowedTags: List of all the tags the user is allowed to add. Any tags the @@ -1186,16 +1191,16 @@ $lossy: boolean indicating whether lossy conversion is allowed. converted Content object. Note that $result->getContentModel() must return $toModel. -'ContentSecurityPolicyDefaultSource': Modify the allowed CSP load sources. This affects all -directives except for the script directive. If you want to add a script -source, see ContentSecurityPolicyScriptSource hook. +'ContentSecurityPolicyDefaultSource': Modify the allowed CSP load sources. This +affects all directives except for the script directive. If you want to add a +script source, see ContentSecurityPolicyScriptSource hook. &$defaultSrc: Array of Content-Security-Policy allowed sources $policyConfig: Current configuration for the Content-Security-Policy header -$mode: ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE - depending on type of header +$mode: ContentSecurityPolicy::REPORT_ONLY_MODE or + ContentSecurityPolicy::FULL_MODE depending on type of header -'ContentSecurityPolicyDirectives': Modify the content security policy directives. -Use this only if ContentSecurityPolicyDefaultSource and +'ContentSecurityPolicyDirectives': Modify the content security policy +directives. Use this only if ContentSecurityPolicyDefaultSource and ContentSecurityPolicyScriptSource do not meet your needs. &$directives: Array of CSP directives $policyConfig: Current configuration for the CSP header @@ -1208,8 +1213,8 @@ want non-script sources to be loaded from whatever you add. &$scriptSrc: Array of CSP directives $policyConfig: Current configuration for the CSP header -$mode: ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE - depending on type of header +$mode: ContentSecurityPolicy::REPORT_ONLY_MODE or + ContentSecurityPolicy::FULL_MODE depending on type of header 'CustomEditor': When invoking the page editor Return true to allow the normal editor to be used, or false if implementing @@ -1240,12 +1245,15 @@ $row: the DB row for this line Currently only data attributes reserved to MediaWiki are allowed (see Sanitizer::isReservedDataAttribute). -'DeleteUnknownPreferences': Called by the cleanupPreferences.php maintenance script to build a WHERE clause with which -to delete preferences that are not known about. This hook is used by extensions that have dynamically-named preferences -that should not be deleted in the usual cleanup process. For example, the Gadgets extension creates preferences prefixed -with 'gadget-', and so anything with that prefix is excluded from the deletion. -&where: An array that will be passed as the $cond parameter to IDatabase::select() to determine what will be deleted - from the user_properties table. +'DeleteUnknownPreferences': Called by the cleanupPreferences.php maintenance +script to build a WHERE clause with which to delete preferences that are not +known about. This hook is used by extensions that have dynamically-named +preferences that should not be deleted in the usual cleanup process. For +example, the Gadgets extension creates preferences prefixed with 'gadget-', and +so anything with that prefix is excluded from the deletion. +&where: An array that will be passed as the $cond parameter to + IDatabase::select() to determine what will be deleted from the user_properties + table. $db: The IDatabase object, useful for accessing $db->buildLike() etc. 'DifferenceEngineAfterLoadNewText': called in DifferenceEngine::loadNewText() @@ -1260,82 +1268,88 @@ checking if the variable's value is null. This hook can be used to inject content into said class member variable. $differenceEngine: DifferenceEngine object -'DifferenceEngineMarkPatrolledLink': Allows extensions to change the "mark as patrolled" link -which is shown both on the diff header as well as on the bottom of a page, usually -wrapped in a span element which has class="patrollink". +'DifferenceEngineMarkPatrolledLink': Allows extensions to change the "mark as +patrolled" link which is shown both on the diff header as well as on the bottom +of a page, usually wrapped in a span element which has class="patrollink". $differenceEngine: DifferenceEngine object &$markAsPatrolledLink: The "mark as patrolled" link HTML (string) $rcid: Recent change ID (rc_id) for this change (int) -'DifferenceEngineMarkPatrolledRCID': Allows extensions to possibly change the rcid parameter. -For example the rcid might be set to zero due to the user being the same as the -performer of the change but an extension might still want to show it under certain -conditions. +'DifferenceEngineMarkPatrolledRCID': Allows extensions to possibly change the +rcid parameter. For example the rcid might be set to zero due to the user being +the same as the performer of the change but an extension might still want to +show it under certain conditions. &$rcid: rc_id (int) of the change or 0 $differenceEngine: DifferenceEngine object $change: RecentChange object $user: User object representing the current user -'DifferenceEngineNewHeader': Allows extensions to change the $newHeader variable, which -contains information about the new revision, such as the revision's author, whether -the revision was marked as a minor edit or not, etc. +'DifferenceEngineNewHeader': Allows extensions to change the $newHeader +variable, which contains information about the new revision, such as the +revision's author, whether the revision was marked as a minor edit or not, etc. $differenceEngine: DifferenceEngine object &$newHeader: The string containing the various #mw-diff-otitle[1-5] divs, which -include things like revision author info, revision comment, RevisionDelete link and more + include things like revision author info, revision comment, RevisionDelete + link and more $formattedRevisionTools: Array containing revision tools, some of which may have -been injected with the DiffRevisionTools hook -$nextlink: String containing the link to the next revision (if any); also included in $newHeader -$rollback: Rollback link (string) to roll this revision back to the previous one, if any + been injected with the DiffRevisionTools hook +$nextlink: String containing the link to the next revision (if any); also + included in $newHeader +$rollback: Rollback link (string) to roll this revision back to the previous + one, if any $newminor: String indicating if the new revision was marked as a minor edit $diffOnly: Boolean parameter passed to DifferenceEngine#showDiffPage, indicating -whether we should show just the diff; passed in as a query string parameter to the -various URLs constructed here (i.e. $nextlink) + whether we should show just the diff; passed in as a query string parameter to + the various URLs constructed here (i.e. $nextlink) $rdel: RevisionDelete link for the new revision, if the current user is allowed -to use the RevisionDelete feature + to use the RevisionDelete feature $unhide: Boolean parameter indicating whether to show RevisionDeleted revisions -'DifferenceEngineOldHeader': Allows extensions to change the $oldHeader variable, which -contains information about the old revision, such as the revision's author, whether -the revision was marked as a minor edit or not, etc. +'DifferenceEngineOldHeader': Allows extensions to change the $oldHeader +variable, which contains information about the old revision, such as the +revision's author, whether the revision was marked as a minor edit or not, etc. $differenceEngine: DifferenceEngine object &$oldHeader: The string containing the various #mw-diff-otitle[1-5] divs, which -include things like revision author info, revision comment, RevisionDelete link and more -$prevlink: String containing the link to the previous revision (if any); also included in $oldHeader + include things like revision author info, revision comment, RevisionDelete + link and more +$prevlink: String containing the link to the previous revision (if any); also + included in $oldHeader $oldminor: String indicating if the old revision was marked as a minor edit $diffOnly: Boolean parameter passed to DifferenceEngine#showDiffPage, indicating -whether we should show just the diff; passed in as a query string parameter to the -various URLs constructed here (i.e. $prevlink) + whether we should show just the diff; passed in as a query string parameter to + the various URLs constructed here (i.e. $prevlink) $ldel: RevisionDelete link for the old revision, if the current user is allowed -to use the RevisionDelete feature + to use the RevisionDelete feature $unhide: Boolean parameter indicating whether to show RevisionDeleted revisions -'DifferenceEngineOldHeaderNoOldRev': Change the $oldHeader variable in cases when -there is no old revision +'DifferenceEngineOldHeaderNoOldRev': Change the $oldHeader variable in cases +when there is no old revision &$oldHeader: empty string by default -'DifferenceEngineRenderRevisionAddParserOutput': Allows extensions to change the parser output. -Return false to not add parser output via OutputPage's addParserOutput method. +'DifferenceEngineRenderRevisionAddParserOutput': Allows extensions to change the +parser output. Return false to not add parser output via OutputPage's +addParserOutput method. $differenceEngine: DifferenceEngine object $out: OutputPage object $parserOutput: ParserOutput object $wikiPage: WikiPage object -'DifferenceEngineRenderRevisionShowFinalPatrolLink': An extension can hook into this hook -point and return false to not show the final "mark as patrolled" link on the bottom -of a page. +'DifferenceEngineRenderRevisionShowFinalPatrolLink': An extension can hook into +this hook point and return false to not show the final "mark as patrolled" link +on the bottom of a page. This hook has no arguments. 'DifferenceEngineShowDiff': Allows extensions to affect the diff text which eventually gets sent to the OutputPage object. $differenceEngine: DifferenceEngine object -'DifferenceEngineShowEmptyOldContent': Allows extensions to change the diff table -body (without header) in cases when there is no old revision or the old and new -revisions are identical. +'DifferenceEngineShowEmptyOldContent': Allows extensions to change the diff +table body (without header) in cases when there is no old revision or the old +and new revisions are identical. $differenceEngine: DifferenceEngine object -'DifferenceEngineShowDiffPage': Add additional output via the available OutputPage -object into the diff view +'DifferenceEngineShowDiffPage': Add additional output via the available +OutputPage object into the diff view $out: OutputPage object 'DifferenceEngineShowDiffPageMaybeShowMissingRevision': called in @@ -1361,7 +1375,7 @@ an article &$article: article (object) being viewed &$oldid: oldid (int) being viewed -'DoEditSectionLink': DEPRECATED! Use SkinEditSectionLinks instead. +'DoEditSectionLink': DEPRECATED since 1.25! Use SkinEditSectionLinks instead. Override the HTML generated for section edit links $skin: Skin object rendering the UI $title: Title object for the title being linked to (may not be the same as @@ -1381,7 +1395,6 @@ $section: Section being edited &$error: Error message to return $summary: Edit summary for page - 'EditFilterMergedContent': Post-section-merge edit filter. This may be triggered by the EditPage or any other facility that modifies page content. Use the $status object to indicate whether the edit should be allowed, @@ -1389,7 +1402,7 @@ and to provide a reason for disallowing it. Return false to abort the edit, and true to continue. Returning true if $status->isOK() returns false means "don't save but continue user interaction", e.g. show the edit form. $status->apiHookResult can be set to an array to be returned by api.php -action=edit. This is used to deliver captchas. + action=edit. This is used to deliver captchas. $context: object implementing the IContextSource interface. $content: content of the edit box, as a Content object. $status: Status object to represent errors, etc. @@ -1417,9 +1430,9 @@ $resultDetails: Result details array 'EditPage::importFormData': allow extensions to read additional data posted in the form +Return value is ignored (should always return true) $editpage: EditPage instance $request: Webrequest -return value is ignored (should always return true) 'EditPage::showEditForm:fields': allows injection of form field into edit form Return value is ignored (should always return true) @@ -1461,18 +1474,11 @@ textarea in the edit form. &$buttons: Array of edit buttons "Save", "Preview", "Live", and "Diff" &$tabindex: HTML tabindex of the last edit check/button -'EditPageBeforeEditChecks': DEPRECATED! Use 'EditPageGetCheckboxesDefinition' instead, -or 'EditPage::showStandardInputs:options' if you don't actually care about checkboxes -and just want to add some HTML to the page. -Allows modifying the edit checks below the textarea in the edit form. -&$editpage: The current EditPage object -&$checks: Array of the HTML for edit checks like "watch this page"/"minor edit" -&$tabindex: HTML tabindex of the last edit check/button - 'EditPageBeforeEditToolbar': Allows modifying the edit toolbar above the textarea in the edit form. +Hook subscribers can return false to avoid the default toolbar code being +loaded. &$toolbar: The toolbar HTML -Hook subscribers can return false to avoid the default toolbar code being loaded. 'EditPageCopyrightWarning': Allow for site and per-namespace customization of contribution/copyright notice. @@ -1483,8 +1489,8 @@ $title: title of page being edited 'EditPageGetCheckboxesDefinition': Allows modifying the edit checkboxes below the textarea in the edit form. $editpage: The current EditPage object -&$checkboxes: Array of checkbox definitions. See EditPage::getCheckboxesDefinition() -for the format. +&$checkboxes: Array of checkbox definitions. See + EditPage::getCheckboxesDefinition() for the format. 'EditPageGetDiffContent': Allow modifying the wikitext that will be used in "Show changes". Note that it is preferable to implement diff handling for @@ -1520,7 +1526,8 @@ true to allow those checks to occur, and false if checking is done. &$from: MailAddress object of sending user &$subject: subject of the mail &$text: text of the mail -&$error: Out-param for an error. Should be set to a Status object or boolean false. +&$error: Out-param for an error. Should be set to a Status object or boolean + false. 'EmailUserCC': Before sending the copy of the email to the author. &$to: MailAddress object of receiving user @@ -1555,7 +1562,8 @@ $block: The RecentChanges objects in that block a grouped recent change inner line in EnhancedChangesList. Hook subscribers can return false to omit this line from recentchanges. $changesList: EnhancedChangesList object -&$data: An array with all the components that will be joined in order to create the line +&$data: An array with all the components that will be joined in order to create + the line $block: An array of RecentChange objects in that block $rc: The RecentChange object for this line &$classes: An array of classes to change @@ -1566,7 +1574,8 @@ $rc: The RecentChange object for this line 'EnhancedChangesListModifyBlockLineData': to alter data used to build a non-grouped recent change line in EnhancedChangesList. $changesList: EnhancedChangesList object -&$data: An array with all the components that will be joined in order to create the line +&$data: An array with all the components that will be joined in order to create + the line $rc: The RecentChange object for this line 'ExemptFromAccountCreationThrottle': Exemption from the account creation @@ -1672,10 +1681,10 @@ underscore) magic words. Called by MagicWord. 'GetExtendedMetadata': Get extended file metadata for the API &$combinedMeta: Array of the form: - 'MetadataPropName' => array( + 'MetadataPropName' => [ value' => prop value, 'source' => 'name of hook' - ). + ]. $file: File object of file in question $context: RequestContext (including language to use) $single: Only extract the current language; if false, the prop value should @@ -1773,7 +1782,7 @@ $lang: Language that will be used to render the timestamp 'getUserPermissionsErrors': Add a permissions error when permissions errors are checked for. Use instead of userCan for most cases. Return false if the user can't do it, and populate $result with the reason in the form of -array( messagename, param1, param2, ... ) or a MessageSpecifier instance (you +[ messagename, param1, param2, ... ] or a MessageSpecifier instance (you might want to use ApiMessage to provide machine-readable details for the API). For consistency, error messages should be plain text with no special coloring, bolding, etc. to show that @@ -1787,12 +1796,12 @@ $action: Action being checked 'getUserPermissionsErrorsExpensive': Equal to getUserPermissionsErrors, but is called only if expensive checks are enabled. Add a permissions error when permissions errors are checked for. Return false if the user can't do it, and -populate $result with the reason in the form of array( messagename, param1, -param2, ... ) or a MessageSpecifier instance (you might want to use ApiMessage -to provide machine-readable details for the API). For consistency, error -messages should be plain text with no -special coloring, bolding, etc. to show that they're errors; presenting them -properly to the user as errors is done by the caller. +populate $result with the reason in the form of [ messagename, param1, param2, +... ] or a MessageSpecifier instance (you might want to use ApiMessage to +provide machine-readable details for the API). For consistency, error messages +should be plain text with no special coloring, bolding, etc. to show that +they're errors; presenting them properly to the user as errors is done by the +caller. &$title: Title object being checked against &$user: Current user object $action: Action being checked @@ -1826,6 +1835,9 @@ just modify a few things using call-by-reference. includes/Linker.php for Linker::makeImageLink &$time: Timestamp of file in 'YYYYMMDDHHIISS' string form, or false for current &$res: Final HTML output, used if you return false +$parser: Parser instance +&$query: Query params for desc URL +&$widthOption: Used by the parser to remember the user preference thumbnailsize 'ImageOpenShowImageInlineBefore': Call potential extension just before showing the image on an image page. @@ -1886,9 +1898,9 @@ $revisionInfo: Array of revision information Return false to stop further processing of the tag $reader: XMLReader object -'ImportHandleUnknownUser': When a user doesn't exist locally, this hook is called -to give extensions an opportunity to auto-create it. If the auto-creation is -successful, return false. +'ImportHandleUnknownUser': When a user doesn't exist locally, this hook is +called to give extensions an opportunity to auto-create it. If the auto-creation +is successful, return false. $name: User name 'ImportHandleUploadXMLTag': When parsing a XML tag in a file upload. @@ -1972,7 +1984,7 @@ $user: User the password is being validated for $code: The language code or the language we're looking for a messages file for &$file: The messages file path, you can override this to change the location. -'LanguageGetMagic': DEPRECATED! Use $magicWords in a file listed in +'LanguageGetMagic': DEPRECATED since 1.16! Use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language &$magicExtensions: associative array of magic words synonyms @@ -2007,11 +2019,11 @@ $title: The page's Title. $out: The output page. $cssClassName: CSS class name of the language selector. -'LinkBegin': DEPRECATED! Use HtmlPageLinkRendererBegin instead. -Used when generating internal and interwiki links in -Linker::link(), before processing starts. Return false to skip default -processing and return $ret. See documentation for Linker::link() for details on -the expected meanings of parameters. +'LinkBegin': DEPRECATED since 1.28! Use HtmlPageLinkRendererBegin instead. +Used when generating internal and interwiki links in Linker::link(), before +processing starts. Return false to skip default processing and return $ret. See +documentation for Linker::link() for details on the expected meanings of +parameters. $skin: the Skin object $target: the Title that the link is pointing to &$html: the contents that the tag should have (raw HTML); null means @@ -2025,7 +2037,7 @@ $target: the Title that the link is pointing to &$options: array of options. Can include 'known', 'broken', 'noclasses'. &$ret: the value to return if your hook returns false. -'LinkEnd': DEPRECATED! Use HtmlPageLinkRendererEnd hook instead +'LinkEnd': DEPRECATED since 1.28! Use HtmlPageLinkRendererEnd hook instead Used when generating internal and interwiki links in Linker::link(), just before the function returns a value. If you return true, an element with HTML attributes $attribs and contents $html will be returned. If you @@ -2207,11 +2219,11 @@ in LoginForm::$validErrorMessages). &$messages: Already added messages (inclusive messages from LoginForm::$validErrorMessages) -'LoginUserMigrated': DEPRECATED! Create a PreAuthenticationProvider instead. -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. +'LoginUserMigrated': DEPRECATED since 1.27! Create a PreAuthenticationProvider +instead. 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. @@ -2371,8 +2383,8 @@ $new: the ?new= param value from the url 'NewPagesLineEnding': Called before a NewPages line is finished. $page: the SpecialNewPages object &$ret: the HTML line -$row: the database row for this page (the recentchanges record and a few extras - see - NewPagesPager::getQueryInfo) +$row: the database row for this page (the recentchanges record and a few extras + - see NewPagesPager::getQueryInfo) &$classes: the classes to add to the surrounding
  • &$attribs: associative array of other HTML attributes for the
  • element. Currently only data attributes reserved to MediaWiki are allowed @@ -2611,7 +2623,7 @@ cache or return false to not use it. &$parser: Parser object &$varCache: variable cache (array) -'ParserLimitReport': DEPRECATED! Use ParserLimitReportPrepare and +'ParserLimitReport': DEPRECATED since 1.22! Use ParserLimitReportPrepare and ParserLimitReportFormat instead. Called at the end of Parser:parse() when the parser will include comments about size of the text parsed. @@ -2648,7 +2660,8 @@ change the default value for an option, all existing parser cache entries will be invalid. To avoid bugs, you'll need to handle that somehow (e.g. with the RejectParserCacheValue hook) because MediaWiki won't do it for you. &$defaults: Set the default value for your option here. -&$inCacheKey: To fragment the parser cache on your option, set a truthy value here. +&$inCacheKey: To fragment the parser cache on your option, set a truthy value + here. &$lazyLoad: To lazy-initialize your option, set it null in $defaults and set a callable here. The callable is passed the ParserOptions object and the option name. @@ -2678,7 +2691,8 @@ run. Use when page save hooks require the presence of custom tables to ensure that tests continue to run properly. &$tables: array of table names -'ParserOutputStashForEdit': Called when an edit stash parse finishes, before the output is cached. +'ParserOutputStashForEdit': Called when an edit stash parse finishes, before the +output is cached. $page: the WikiPage of the candidate edit $content: the Content object of the candidate edit $output: the ParserOutput result of the candidate edit @@ -2740,7 +2754,8 @@ $key: the section name &$legend: the legend text. Defaults to wfMessage( "prefs-$key" )->text() but may be overridden -'PrefixSearchBackend': DEPRECATED! Override SearchEngine::completionSearchBackend instead. +'PrefixSearchBackend': DEPRECATED since 1.27! Override +SearchEngine::completionSearchBackend instead. Override the title prefix search used for OpenSearch and AJAX search suggestions. Put results into &$results outparam and return false. $ns: array of int namespace keys to search in @@ -2836,7 +2851,7 @@ $context: ResourceLoaderContext|null ResourceLoaderStartUpModule::getConfigSettings(). Use this to export static configuration variables to JavaScript. Things that depend on the current page or request state must be added through MakeGlobalVariablesScript instead. -&$vars: array( variable name => value ) +&$vars: [ variable name => value ] 'ResourceLoaderJqueryMsgModuleMagicWords': Called in ResourceLoaderJqueryMsgModule to allow adding magic words for jQueryMsg. @@ -2855,10 +2870,10 @@ called after the addition of 'qunit' and MediaWiki testing resources. &$testModules: array of JavaScript testing modules. The 'qunit' framework, included in core, is fed using tests/qunit/QUnitTestResources.php. To add a new qunit module named 'myext.tests': - $testModules['qunit']['myext.tests'] = array( + $testModules['qunit']['myext.tests'] = [ 'script' => 'extension/myext/tests.js', 'dependencies' => - ); + ]; For QUnit framework, the mediawiki.tests.qunit.testrunner dependency will be added to any module. &$ResourceLoader: object @@ -2866,8 +2881,8 @@ called after the addition of 'qunit' and MediaWiki testing resources. 'RevisionRecordInserted': Called after a revision is inserted into the database. $revisionRecord: the RevisionRecord that has just been inserted. -'RevisionInsertComplete': DEPRECATED! Use RevisionRecordInserted hook instead. -Called after a revision is inserted into the database. +'RevisionInsertComplete': DEPRECATED since 1.31! Use RevisionRecordInserted hook +instead. Called after a revision is inserted into the database. $revision: the Revision $data: DEPRECATED! Always null! $flags: DEPRECATED! Always null! @@ -2915,10 +2930,12 @@ $engine: SearchEngine for which the indexing is intended 'SearchResultsAugment': Allows extension to add its code to the list of search result augmentors. -&$setAugmentors: List of whole-set augmentor objects, must implement ResultSetAugmentor -&$rowAugmentors: List of per-row augmentor objects, must implement ResultAugmentor. -Note that lists should be in the format name => object and the names in both lists should -be distinct. +&$setAugmentors: List of whole-set augmentor objects, must implement + ResultSetAugmentor. +&$rowAugmentors: List of per-row augmentor objects, must implement + ResultAugmentor. +Note that lists should be in the format name => object and the names in both + lists should be distinct. 'SecondaryDataUpdates': Allows modification of the list of DataUpdates to perform when page content is modified. Currently called by @@ -3001,11 +3018,13 @@ $terms: Search terms, for highlighting 'ShowSearchHitTitle': Customise display of search hit title/link. &$title: Title to link to -&$titleSnippet: Label for the link representing the search result. Typically the article title. +&$titleSnippet: Label for the link representing the search result. Typically the + article title. $result: The SearchResult object $terms: String of the search terms entered $specialSearch: The SpecialSearch object -&$query: Array of query string parameters for the link representing the search result. +&$query: Array of query string parameters for the link representing the search + result. &$attributes: Array of title link attributes, can be modified by extension. 'SidebarBeforeOutput': Allows to edit sidebar just before it is output by skins. @@ -3183,7 +3202,7 @@ $pager: The UsersPager instance 'SpecialListusersFormatRow': Called right before the end of UsersPager::formatRow(). -&$item: HTML to be returned. Will be wrapped in
  • after the hook finishes +&$item: HTML to be returned. Will be wrapped in an
  • after the hook finishes $row: Database row object 'SpecialListusersHeader': Called after adding the submit button in @@ -3260,8 +3279,8 @@ use this to change some selection criteria or substitute a different title. &$title: If the hook returns false, a Title object to use instead of the result from the normal query -'SpecialRecentChangesFilters': DEPRECATED! Use ChangesListSpecialPageStructuredFilters -instead. +'SpecialRecentChangesFilters': DEPRECATED since 1.23! Use +ChangesListSpecialPageStructuredFilters instead. Called after building form options at RecentChanges. $special: the special page object &$filters: associative array of filter definitions. The keys are the HTML @@ -3273,8 +3292,8 @@ SpecialRecentChanges. &$extraOpts: array of added items, to which can be added $opts: FormOptions for this request -'SpecialRecentChangesQuery': DEPRECATED! Use ChangesListSpecialPageStructuredFilters -or ChangesListSpecialPageQuery instead. +'SpecialRecentChangesQuery': DEPRECATED since 1.23! Use +ChangesListSpecialPageStructuredFilters or ChangesListSpecialPageQuery instead. Called when building SQL query for SpecialRecentChanges and SpecialRecentChangesLinked. &$conds: array of WHERE conditionals for query @@ -3287,10 +3306,10 @@ $opts: FormOptions for this request 'SpecialResetTokensTokens': Called when building token list for SpecialResetTokens. &$tokens: array of token information arrays in the format of - array( + [ 'preference' => '', 'label-message' => '', - ) + ] 'SpecialSearchCreateLink': Called when making the message to create a page or go to the existing page. @@ -3303,7 +3322,8 @@ $url does a standard redirect to $title. Setting $url redirects to the specified URL. $term: The string the user searched for $title: The title the 'go' feature has decided to forward the user to -&$url: Initially null, hook subscribers can set this to specify the final url to redirect to +&$url: Initially null, hook subscribers can set this to specify the final url to + redirect to 'SpecialSearchNogomatch': Called when the 'Go' feature is triggered (generally from autocomplete search other than the main bar on Special:Search) and the @@ -3361,11 +3381,14 @@ $engine: the search engine message key to use in the name column, $context: IContextSource object -'SpecialTrackingCategories::preprocess': Called after LinkBatch on Special:TrackingCategories +'SpecialTrackingCategories::preprocess': Called after LinkBatch on +Special:TrackingCategories $specialPage: The SpecialTrackingCategories object -$trackingCategories: Array of data from Special:TrackingCategories with msg and cats +$trackingCategories: Array of data from Special:TrackingCategories with msg and + cats -'SpecialTrackingCategories::generateCatLink': Called for each cat link on Special:TrackingCategories +'SpecialTrackingCategories::generateCatLink': Called for each cat link on +Special:TrackingCategories $specialPage: The SpecialTrackingCategories object $catTitle: The Title object of the linked category &$html: The Result html @@ -3378,8 +3401,8 @@ Special:Upload. $wgVersion: Current $wgVersion for you to use &$versionUrl: Raw url to link to (eg: release notes) -'SpecialWatchlistFilters': DEPRECATED! Use ChangesListSpecialPageStructuredFilters -instead. +'SpecialWatchlistFilters': DEPRECATED since 1.23! Use +ChangesListSpecialPageStructuredFilters instead. Called after building form options at Watchlist. $special: the special page object &$filters: associative array of filter definitions. The keys are the HTML @@ -3391,8 +3414,8 @@ SpecialWatchlist. Allows extensions to register custom values they have inserted to rc_type so they can be returned as part of the watchlist. &$nonRevisionTypes: array of values in the rc_type field of recentchanges table -'SpecialWatchlistQuery': DEPRECATED! Use ChangesListSpecialPageStructuredFilters -or ChangesListSpecialPageQuery instead. +'SpecialWatchlistQuery': DEPRECATED since 1.23! Use +ChangesListSpecialPageStructuredFilters or ChangesListSpecialPageQuery instead. Called when building sql query for SpecialWatchlist. &$conds: array of WHERE conditionals for query &$tables: array of tables to be queried @@ -3455,7 +3478,8 @@ $old: old title $nt: new title $user: user who does the move -'TitleMoveStarting': Before moving an article (title), but just after the atomic DB section starts. +'TitleMoveStarting': Before moving an article (title), but just after the atomic +DB section starts. $old: old title $nt: new title $user: user who does the move @@ -3528,8 +3552,8 @@ $title: Title object of the page that we're about to undelete $title: title object related to the revision $rev: revision (object) that will be viewed -'UnitTestsAfterDatabaseSetup': Called right after MediaWiki's test infrastructure -has finished creating/duplicating core tables for unit tests. +'UnitTestsAfterDatabaseSetup': Called right after MediaWiki's test +infrastructure has finished creating/duplicating core tables for unit tests. $database: Database in question $prefix: Table prefix to be used in unit tests @@ -3541,7 +3565,7 @@ Since 1.24: Paths pointing to a directory will be recursively scanned for test case files matching the suffix "Test.php". &$paths: list of test cases and directories to search. -'UnknownAction': DEPRECATED! To add an action in an extension, +'UnknownAction': DEPRECATED since 1.19! To add an action in an extension, create a subclass of Action, and add a new key to $wgActions. An unknown "action" has occurred (useful for defining your own actions). $action: action name @@ -3602,12 +3626,12 @@ being uploaded, use UploadVerifyFile or UploadVerifyUpload. $upload: (object) An instance of UploadBase, with all info about the upload $user: (object) An instance of User, the user uploading this file $props: (array) File properties, as returned by FSFile::getPropsFromPath() -&$error: output: If the file stashing should be prevented, set this to the reason - in the form of array( messagename, param1, param2, ... ) or a MessageSpecifier - instance (you might want to use ApiMessage to provide machine-readable details - for the API). +&$error: output: If the file stashing should be prevented, set this to the + reason in the form of [ messagename, param1, param2, ... ] or a + MessageSpecifier instance (you might want to use ApiMessage to provide machine + -readable details for the API). -'UploadVerification': DEPRECATED! Use UploadVerifyFile instead. +'UploadVerification': DEPRECATED since 1.28! Use UploadVerifyFile instead. Additional chances to reject an uploaded file. $saveName: (string) destination file name $tempName: (string) filesystem path to the temporary file for checks @@ -3620,10 +3644,10 @@ in most cases over UploadVerification. $upload: (object) an instance of UploadBase, with all info about the upload $mime: (string) The uploaded file's MIME type, as detected by MediaWiki. Handlers will typically only apply for specific MIME types. -&$error: (object) output: true if the file is valid. Otherwise, set this to the reason - in the form of array( messagename, param1, param2, ... ) or a MessageSpecifier - instance (you might want to use ApiMessage to provide machine-readable details - for the API). +&$error: (object) output: true if the file is valid. Otherwise, set this to the + reason in the form of [ messagename, param1, param2, ... ] or a + MessageSpecifier instance (you might want to use ApiMessage to provide machine + -readable details for the API). 'UploadVerifyUpload': Upload verification, based on both file properties like MIME type (same as UploadVerifyFile) and the information entered by the user @@ -3634,7 +3658,7 @@ $props: (array) File properties, as returned by FSFile::getPropsFromPath() $comment: (string) Upload log comment (also used as edit summary) $pageText: (string) File description page text (only used for new uploads) &$error: output: If the file upload should be prevented, set this to the reason - in the form of array( messagename, param1, param2, ... ) or a MessageSpecifier + in the form of [ messagename, param1, param2, ... ] or a MessageSpecifier instance (you might want to use ApiMessage to provide machine-readable details for the API). @@ -3677,8 +3701,8 @@ messages!" message, return false to not delete it. &$user: User (object) that will clear the message $oldid: ID of the talk page revision being viewed (0 means the most recent one) -'UserCreateForm': DEPRECATED! Create an AuthenticationProvider instead. -Manipulate the login form. +'UserCreateForm': DEPRECATED since 1.27! Create an AuthenticationProvider +instead. Manipulate the login form. &$template: SimpleTemplate instance for the form 'UserEffectiveGroups': Called in User::getEffectiveGroups(). @@ -3705,7 +3729,7 @@ $user: User object &$timestamp: timestamp, change this to override local email authentication timestamp -'UserGetImplicitGroups': DEPRECATED! +'UserGetImplicitGroups': DEPRECATED since 1.25! Called in User::getImplicitGroups(). &$groups: List of implicit (automatically-assigned) groups @@ -3771,7 +3795,8 @@ $name: user name $user: user object &$s: database query object -'UserLoadFromSession': DEPRECATED! Create a MediaWiki\Session\SessionProvider instead. +'UserLoadFromSession': DEPRECATED since 1.27! Create a +MediaWiki\Session\SessionProvider instead. Called to authenticate users on external/environmental means; occurs before session is loaded. $user: user object being loaded @@ -3786,16 +3811,17 @@ $user: User object 'UserLoggedIn': Called after a user is logged in $user: User object for the logged-in user -'UserLoginComplete': Show custom content after a user has logged in via the web interface. -For functionality that needs to run after any login (API or web) use UserLoggedIn. +'UserLoginComplete': Show custom content after a user has logged in via the Web +interface. For functionality that needs to run after any login (API or web) use +UserLoggedIn. &$user: the user object that was created on login &$inject_html: Any HTML to inject after the "logged in" message. -$direct: (bool) The hook is called directly after a successful login. This will only happen once - per login. A UserLoginComplete call with direct=false can happen when the user visits the login - page while already logged in. +$direct: (bool) The hook is called directly after a successful login. This will + only happen once per login. A UserLoginComplete call with direct=false can + happen when the user visits the login page while already logged in. -'UserLoginForm': DEPRECATED! Create an AuthenticationProvider instead. -Manipulate the login form. +'UserLoginForm': DEPRECATED since 1.27! Create an AuthenticationProvider +instead. Manipulate the login form. &$template: QuickTemplate instance for the form 'UserLogout': Before a user logs out. @@ -3813,21 +3839,26 @@ $to: Array of MailAddress objects for the recipients 'UserMailerSplitTo': Called in UserMailer::send() to give extensions a chance to split up an email with multiple the To: field into separate emails. -&$to: array of MailAddress objects; unset the ones which should be mailed separately +&$to: array of MailAddress objects; unset the ones which should be mailed +separately -'UserMailerTransformContent': Called in UserMailer::send() to change email contents. -Extensions can block sending the email by returning false and setting $error. +'UserMailerTransformContent': Called in UserMailer::send() to change email +contents. Extensions can block sending the email by returning false and setting +$error. $to: array of MailAdresses of the targets $from: MailAddress of the sender -&$body: email body, either a string (for plaintext emails) or an array with 'text' and 'html' keys +&$body: email body, either a string (for plaintext emails) or an array with + 'text' and 'html' keys &$error: should be set to an error message string -'UserMailerTransformMessage': Called in UserMailer::send() to change email after it has gone through -the MIME transform. Extensions can block sending the email by returning false and setting $error. +'UserMailerTransformMessage': Called in UserMailer::send() to change email after +it has gone through the MIME transform. Extensions can block sending the email +by returning false and setting $error. $to: array of MailAdresses of the targets $from: MailAddress of the sender &$subject: email subject (not MIME encoded) -&$headers: email headers (except To: and Subject:) as an array of header name => value pairs +&$headers: email headers (except To: and Subject:) as an array of header +name => value pairs &$body: email body (in MIME format) as a string &$error: should be set to an error message string @@ -3856,27 +3887,29 @@ message(s). &$user: user retrieving new talks messages &$talks: array of new talks page(s) -'UserRights': DEPRECATED! Use UserGroupsChanged instead. +'UserRights': DEPRECATED since 1.26! Use UserGroupsChanged instead. After a user's group memberships are changed. &$user: User object that was changed $add: Array of strings corresponding to groups added $remove: Array of strings corresponding to groups removed -'UserSaveOptions': Called just before saving user preferences. Hook handlers can either add or -manipulate options, or reset one back to it's default to block changing it. Hook handlers are also -allowed to abort the process by returning false, e.g. to save to a global profile instead. Compare -to the UserSaveSettings hook, which is called after the preferences have been saved. +'UserSaveOptions': Called just before saving user preferences. Hook handlers can +either add or manipulate options, or reset one back to it's default to block +changing it. Hook handlers are also allowed to abort the process by returning +false, e.g. to save to a global profile instead. Compare to the UserSaveSettings +hook, which is called after the preferences have been saved. $user: The User for which the options are going to be saved &$options: The users options as an associative array, modifiable -'UserSaveSettings': Called directly after user preferences (user_properties in the database) have -been saved. Compare to the UserSaveOptions hook, which is called before. +'UserSaveSettings': Called directly after user preferences (user_properties in +the database) have been saved. Compare to the UserSaveOptions hook, which is +called before. $user: The User for which the options have been saved -'UserSetCookies': DEPRECATED! If you're trying to replace core session cookie -handling, you want to create a subclass of MediaWiki\Session\CookieSessionProvider -instead. Otherwise, you can no longer count on user data being saved to cookies -versus some other mechanism. +'UserSetCookies': DEPRECATED since 1.27! If you're trying to replace core +session cookie handling, you want to create a subclass of +MediaWiki\Session\CookieSessionProvider instead. Otherwise, you can no longer +count on user data being saved to cookies versus some other mechanism. Called when setting user cookies. $user: User object &$session: session array, will be added to the session @@ -3905,7 +3938,7 @@ displayed correctly in Special:ListUsers. $dbr: Read-only database handle $userIds: Array of user IDs whose groups we should look up &$cache: Array of user ID -> (array of internal group name (e.g. 'sysop') -> -UserGroupMembership object) + UserGroupMembership object) &$groups: Array of group name -> bool true mappings for members of a given user group @@ -3980,15 +4013,15 @@ dumps. One, and only one hook should set this, and return false. &$opts: Options to use for the query &$join: Join conditions -'WikiPageDeletionUpdates': manipulate the list of DeferrableUpdates to be applied when -a page is deleted. Called in WikiPage::getDeletionUpdates(). Note that updates -specific to a content model should be provided by the respective Content's -getDeletionUpdates() method. +'WikiPageDeletionUpdates': manipulate the list of DeferrableUpdates to be +applied when a page is deleted. Called in WikiPage::getDeletionUpdates(). Note +that updates specific to a content model should be provided by the respective +Content's getDeletionUpdates() method. $page: the WikiPage -$content: the Content to generate updates for, or null in case the page revision could not be - loaded. The delete will succeed despite this. -&$updates: the array of objects that implement DeferrableUpdate. Hook function may want to add to - it. +$content: the Content to generate updates for, or null in case the page revision + could not be loaded. The delete will succeed despite this. +&$updates: the array of objects that implement DeferrableUpdate. Hook function + may want to add to it. 'WikiPageFactory': Override WikiPage class used for a title $title: Title of the page diff --git a/includes/AjaxResponse.php b/includes/AjaxResponse.php index 3e42c08650..0c115053ba 100644 --- a/includes/AjaxResponse.php +++ b/includes/AjaxResponse.php @@ -242,7 +242,7 @@ class AjaxResponse { # this breaks strtotime(). $modsince = preg_replace( '/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"] ); $modsinceTime = strtotime( $modsince ); - $ismodsince = wfTimestamp( TS_MW, $modsinceTime ? $modsinceTime : 1 ); + $ismodsince = wfTimestamp( TS_MW, $modsinceTime ?: 1 ); wfDebug( "$fname: -- client send If-Modified-Since: $modsince", 'private' ); wfDebug( "$fname: -- we might send Last-Modified : $lastmod", 'private' ); diff --git a/includes/AuthPlugin.php b/includes/AuthPlugin.php index b73ecbd8ed..e12db24319 100644 --- a/includes/AuthPlugin.php +++ b/includes/AuthPlugin.php @@ -96,11 +96,7 @@ class AuthPlugin { * @return string */ public function getDomain() { - if ( isset( $this->domain ) ) { - return $this->domain; - } else { - return 'invaliddomain'; - } + return $this->domain ?? 'invaliddomain'; } /** diff --git a/includes/Category.php b/includes/Category.php index 46b86d8cd8..2cf44b86f8 100644 --- a/includes/Category.php +++ b/includes/Category.php @@ -335,6 +335,16 @@ class Category { $dbw->startAtomic( __METHOD__ ); + // Lock the `category` row before locking `categorylinks` rows to try + // to avoid deadlocks with LinksDeletionUpdate (T195397) + $dbw->selectField( + 'category', + 1, + [ 'cat_title' => $this->mName ], + __METHOD__, + [ 'FOR UPDATE' ] + ); + // Lock all the `categorylinks` records and gaps for this category; // this is a separate query due to postgres/oracle limitations $dbw->selectRowCount( diff --git a/includes/DummyLinker.php b/includes/DummyLinker.php index 7958420933..2f5455ef5a 100644 --- a/includes/DummyLinker.php +++ b/includes/DummyLinker.php @@ -5,14 +5,6 @@ */ class DummyLinker { - /** - * @deprecated since 1.28, use LinkRenderer::getLinkClasses() instead - */ - public function getLinkColour( $t, $threshold ) { - wfDeprecated( __METHOD__, '1.28' ); - return Linker::getLinkColour( $t, $threshold ); - } - public function link( $target, $html = null, diff --git a/includes/EditPage.php b/includes/EditPage.php index 22c29d6413..644b6255c1 100644 --- a/includes/EditPage.php +++ b/includes/EditPage.php @@ -2812,7 +2812,7 @@ ERROR; $this->autoSumm = md5( '' ); } - $autosumm = $this->autoSumm ? $this->autoSumm : md5( $this->summary ); + $autosumm = $this->autoSumm ?: md5( $this->summary ); $out->addHTML( Html::hidden( 'wpAutoSummary', $autosumm ) ); $out->addHTML( Html::hidden( 'oldid', $this->oldid ) ); @@ -4226,28 +4226,6 @@ ERROR; ); } - // Backwards-compatibility hack to run the EditPageBeforeEditChecks hook. It's important, - // people have used it for the weirdest things completely unrelated to checkboxes... - // And if we're gonna run it, might as well allow its legacy checkboxes to be shown. - $legacyCheckboxes = []; - if ( !$this->isNew ) { - $legacyCheckboxes['minor'] = ''; - } - $legacyCheckboxes['watch'] = ''; - // Copy new-style checkboxes into an old-style structure - foreach ( $checkboxes as $name => $oouiLayout ) { - $legacyCheckboxes[$name] = (string)$oouiLayout; - } - // Avoid PHP 7.1 warning of passing $this by reference - $ep = $this; - Hooks::run( 'EditPageBeforeEditChecks', [ &$ep, &$legacyCheckboxes, &$tabindex ], '1.29' ); - // Copy back any additional old-style checkboxes into the new-style structure - foreach ( $legacyCheckboxes as $name => $html ) { - if ( $html && !isset( $checkboxes[$name] ) ) { - $checkboxes[$name] = new OOUI\Widget( [ 'content' => new OOUI\HtmlSnippet( $html ) ] ); - } - } - return $checkboxes; } diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 335451e7b7..d9996f426f 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -2299,7 +2299,7 @@ function wfShellWikiCmd( $script, array $parameters = [], array $options = [] ) // Give site config file a chance to run the script in a wrapper. // The caller may likely want to call wfBasename() on $script. Hooks::run( 'wfShellWikiCmd', [ &$script, &$parameters, &$options ] ); - $cmd = isset( $options['php'] ) ? [ $options['php'] ] : [ $wgPhpCli ]; + $cmd = [ $options['php'] ?? $wgPhpCli ]; if ( isset( $options['wrapper'] ) ) { $cmd[] = $options['wrapper']; } diff --git a/includes/Linker.php b/includes/Linker.php index 663412798d..89a6a108ac 100644 --- a/includes/Linker.php +++ b/includes/Linker.php @@ -38,29 +38,6 @@ class Linker { const TOOL_LINKS_NOBLOCK = 1; const TOOL_LINKS_EMAIL = 2; - /** - * Return the CSS colour of a known link - * - * @deprecated since 1.28, use LinkRenderer::getLinkClasses() instead - * - * @since 1.16.3 - * @param LinkTarget $t - * @param int $threshold User defined threshold - * @return string CSS class - */ - public static function getLinkColour( LinkTarget $t, $threshold ) { - wfDeprecated( __METHOD__, '1.28' ); - $services = MediaWikiServices::getInstance(); - $linkRenderer = $services->getLinkRenderer(); - if ( $threshold !== $linkRenderer->getStubThreshold() ) { - // Need to create a new instance with the right stub threshold... - $linkRenderer = $services->getLinkRendererFactory()->create(); - $linkRenderer->setStubThreshold( $threshold ); - } - - return $linkRenderer->getLinkClasses( $t ); - } - /** * This function returns an HTML link to the given target. It serves a few * purposes: @@ -328,7 +305,9 @@ class Linker { $res = null; $dummy = new DummyLinker; if ( !Hooks::run( 'ImageBeforeProduceHTML', [ &$dummy, &$title, - &$file, &$frameParams, &$handlerParams, &$time, &$res ] ) ) { + &$file, &$frameParams, &$handlerParams, &$time, &$res, + $parser, &$query, &$widthOption + ] ) ) { return $res; } @@ -826,7 +805,7 @@ class Linker { $key = strtolower( $name ); } - return self::linkKnown( SpecialPage::getTitleFor( $name ), wfMessage( $key )->text() ); + return self::linkKnown( SpecialPage::getTitleFor( $name ), wfMessage( $key )->escaped() ); } /** diff --git a/includes/MWNamespace.php b/includes/MWNamespace.php index bfbd557923..73fdd826eb 100644 --- a/includes/MWNamespace.php +++ b/includes/MWNamespace.php @@ -254,11 +254,7 @@ class MWNamespace { */ public static function getCanonicalName( $index ) { $nslist = self::getCanonicalNamespaces(); - if ( isset( $nslist[$index] ) ) { - return $nslist[$index]; - } else { - return false; - } + return $nslist[$index] ?? false; } /** diff --git a/includes/MediaWiki.php b/includes/MediaWiki.php index 79787272eb..bcc3633321 100644 --- a/includes/MediaWiki.php +++ b/includes/MediaWiki.php @@ -104,7 +104,7 @@ class MediaWiki { if ( $ret === null || !$ret->isSpecialPage() ) { // We can have urls with just ?diff=,?oldid= or even just ?diff= $oldid = $request->getInt( 'oldid' ); - $oldid = $oldid ? $oldid : $request->getInt( 'diff' ); + $oldid = $oldid ?: $request->getInt( 'diff' ); // Allow oldid to override a changed or missing title if ( $oldid ) { $rev = Revision::newFromId( $oldid ); @@ -426,7 +426,7 @@ class MediaWiki { // If $target is set, then a hook wanted to redirect. if ( !$ignoreRedirect && ( $target || $page->isRedirect() ) ) { // Is the target already set by an extension? - $target = $target ? $target : $page->followRedirect(); + $target = $target ?: $page->followRedirect(); if ( is_string( $target ) ) { if ( !$this->config->get( 'DisableHardRedirects' ) ) { // we'll need to redirect @@ -723,6 +723,9 @@ class MediaWiki { MWExceptionHandler::rollbackMasterChangesAndLog( $e ); } + // Disable WebResponse setters for post-send processing (T191537). + WebResponse::disableForPostSend(); + $blocksHttpClient = true; // Defer everything else if possible... $callback = function () use ( $mode, &$blocksHttpClient ) { diff --git a/includes/MediaWikiServices.php b/includes/MediaWikiServices.php index ac98683535..dbb18a77fb 100644 --- a/includes/MediaWikiServices.php +++ b/includes/MediaWikiServices.php @@ -539,6 +539,7 @@ class MediaWikiServices extends ServiceContainer { /** * @since 1.28 + * @deprecated since 1.32, use random_bytes()/random_int() * @return CryptRand */ public function getCryptRand() { diff --git a/includes/MergeHistory.php b/includes/MergeHistory.php index 0e9bb4673d..4c655ebab5 100644 --- a/includes/MergeHistory.php +++ b/includes/MergeHistory.php @@ -167,7 +167,7 @@ class MergeHistory { // Convert into a Status object if ( $errors ) { foreach ( $errors as $error ) { - call_user_func_array( [ $status, 'fatal' ], $error ); + $status->fatal( ...$error ); } } diff --git a/includes/MovePage.php b/includes/MovePage.php index 1e9570d2f7..614ea7daa5 100644 --- a/includes/MovePage.php +++ b/includes/MovePage.php @@ -57,7 +57,7 @@ class MovePage { // Convert into a Status object if ( $errors ) { foreach ( $errors as $error ) { - call_user_func_array( [ $status, 'fatal' ], $error ); + $status->fatal( ...$error ); } } diff --git a/includes/OutputPage.php b/includes/OutputPage.php index c51f6f8ec2..405be1d2b2 100644 --- a/includes/OutputPage.php +++ b/includes/OutputPage.php @@ -755,11 +755,7 @@ class OutputPage extends ContextSource { * @return mixed Property value or null if not found */ public function getProperty( $name ) { - if ( isset( $this->mProperties[$name] ) ) { - return $this->mProperties[$name]; - } else { - return null; - } + return $this->mProperties[$name] ?? null; } /** @@ -2645,13 +2641,13 @@ class OutputPage extends ContextSource { foreach ( $errors as $error ) { $text .= '
  • '; - $text .= call_user_func_array( [ $this, 'msg' ], $error )->plain(); + $text .= $this->msg( ...$error )->plain(); $text .= "
  • \n"; } $text .= ''; } else { $text .= "
    \n" . - call_user_func_array( [ $this, 'msg' ], reset( $errors ) )->plain() . + $this->msg( ...reset( $errors ) )->plain() . "\n
    "; } @@ -3111,13 +3107,13 @@ class OutputPage extends ContextSource { // Pre-process information $separatorTransTable = $lang->separatorTransformTable(); - $separatorTransTable = $separatorTransTable ? $separatorTransTable : []; + $separatorTransTable = $separatorTransTable ?: []; $compactSeparatorTransTable = [ implode( "\t", array_keys( $separatorTransTable ) ), implode( "\t", $separatorTransTable ), ]; $digitTransTable = $lang->digitTransformTable(); - $digitTransTable = $digitTransTable ? $digitTransTable : []; + $digitTransTable = $digitTransTable ?: []; $compactDigitTransTable = [ implode( "\t", array_keys( $digitTransTable ) ), implode( "\t", $digitTransTable ), @@ -4018,8 +4014,8 @@ class OutputPage extends ContextSource { } if ( $this->CSPNonce === null ) { // XXX It might be expensive to generate randomness - // on every request, on windows. - $rand = MWCryptRand::generate( 15 ); + // on every request, on Windows. + $rand = random_bytes( 15 ); $this->CSPNonce = base64_encode( $rand ); } return $this->CSPNonce; diff --git a/includes/Revision.php b/includes/Revision.php index 213abbef90..b9a03f5fc3 100644 --- a/includes/Revision.php +++ b/includes/Revision.php @@ -1094,8 +1094,6 @@ class Revision implements IDBAccessObject { // Avoid PHP 7.1 warning of passing $this by reference $revision = $this; - // TODO: hard-deprecate in 1.32 (or even 1.31?) - Hooks::run( 'RevisionInsertComplete', [ &$revision, null, null ] ); return $rec->getId(); } diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index ace64ab928..3f8ba185d5 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -188,29 +188,8 @@ return [ ); }, - 'CryptRand' => function ( MediaWikiServices $services ) { - $secretKey = $services->getMainConfig()->get( 'SecretKey' ); - return new CryptRand( - [ - // To try vary the system information of the state a bit more - // by including the system's hostname into the state - 'wfHostname', - // It's mostly worthless but throw the wiki's id into the data - // for a little more variance - 'wfWikiID', - // If we have a secret key set then throw it into the state as well - function () use ( $secretKey ) { - return $secretKey ?: ''; - } - ], - // The config file is likely the most often edited file we know should - // be around so include its stat info into the state. - // The constant with its location will almost always be defined, as - // WebStart.php defines MW_CONFIG_FILE to $IP/LocalSettings.php unless - // being configured with MW_CONFIG_CALLBACK (e.g. the installer). - defined( 'MW_CONFIG_FILE' ) ? [ MW_CONFIG_FILE ] : [], - LoggerFactory::getInstance( 'CryptRand' ) - ); + 'CryptRand' => function () { + return new CryptRand(); }, 'CryptHKDF' => function ( MediaWikiServices $services ) { @@ -231,9 +210,7 @@ return [ $cache = ObjectCache::getLocalClusterInstance(); } - return new CryptHKDF( $secret, $config->get( 'HKDFAlgorithm' ), - $cache, $context, $services->getCryptRand() - ); + return new CryptHKDF( $secret, $config->get( 'HKDFAlgorithm' ), $cache, $context ); }, 'MediaHandlerFactory' => function ( MediaWikiServices $services ) { diff --git a/includes/Setup.php b/includes/Setup.php index e2fab4578e..41d59455cf 100644 --- a/includes/Setup.php +++ b/includes/Setup.php @@ -825,7 +825,7 @@ $wgInitialSessionId = null; if ( !defined( 'MW_NO_SESSION' ) && !$wgCommandLineMode ) { // If session.auto_start is there, we can't touch session name if ( $wgPHPSessionHandling !== 'disable' && !wfIniGetBool( 'session.auto_start' ) ) { - session_name( $wgSessionName ? $wgSessionName : $wgCookiePrefix . '_session' ); + session_name( $wgSessionName ?: $wgCookiePrefix . '_session' ); } // Create the SessionManager singleton and set up our session handler, diff --git a/includes/SiteConfiguration.php b/includes/SiteConfiguration.php index 6bd179a9da..8e77956e82 100644 --- a/includes/SiteConfiguration.php +++ b/includes/SiteConfiguration.php @@ -432,7 +432,7 @@ class SiteConfiguration { return $default; } - $ret = call_user_func_array( $this->siteParamsCallback, [ $this, $wiki ] ); + $ret = ( $this->siteParamsCallback )( $this, $wiki ); # Validate the returned value if ( !is_array( $ret ) ) { return $default; @@ -606,7 +606,7 @@ class SiteConfiguration { public function loadFullData() { if ( $this->fullLoadCallback && !$this->fullLoadDone ) { - call_user_func( $this->fullLoadCallback, $this ); + ( $this->fullLoadCallback )( $this ); $this->fullLoadDone = true; } } diff --git a/includes/Storage/RevisionRecord.php b/includes/Storage/RevisionRecord.php index ff0a70dd24..66ec2c07a2 100644 --- a/includes/Storage/RevisionRecord.php +++ b/includes/Storage/RevisionRecord.php @@ -474,7 +474,7 @@ abstract class RevisionRecord { $permissionlist = implode( ', ', $permissions ); if ( $title === null ) { wfDebug( "Checking for $permissionlist due to $field match on $bitfield\n" ); - return call_user_func_array( [ $user, 'isAllowedAny' ], $permissions ); + return $user->isAllowedAny( ...$permissions ); } else { $text = $title->getPrefixedText(); wfDebug( "Checking for $permissionlist on $text due to $field match on $bitfield\n" ); diff --git a/includes/Storage/RevisionStore.php b/includes/Storage/RevisionStore.php index 36af6cd8c2..ce09a6e768 100644 --- a/includes/Storage/RevisionStore.php +++ b/includes/Storage/RevisionStore.php @@ -47,6 +47,7 @@ use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; use RecentChange; +use Revision; use stdClass; use Title; use User; @@ -489,6 +490,10 @@ class RevisionStore Hooks::run( 'RevisionRecordInserted', [ $rev ] ); + // TODO: deprecate in 1.32! + $legacyRevision = new Revision( $rev ); + Hooks::run( 'RevisionInsertComplete', [ &$legacyRevision, null, null ] ); + return $rev; } diff --git a/includes/Title.php b/includes/Title.php index 9711749d33..91d8de4921 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -2553,7 +2553,10 @@ class Title implements LinkTarget { return $errors; } - if ( $wgEmailConfirmToEdit && !$user->isEmailConfirmed() ) { + if ( $wgEmailConfirmToEdit + && !$user->isEmailConfirmed() + && $action === 'edit' + ) { $errors[] = [ 'confirmedittext' ]; } diff --git a/includes/WebResponse.php b/includes/WebResponse.php index 0208a72ab9..0e5999ddfb 100644 --- a/includes/WebResponse.php +++ b/includes/WebResponse.php @@ -32,6 +32,22 @@ class WebResponse { */ protected static $setCookies = []; + /** @var bool Used to disable setters before running jobs post-request (T191537) */ + protected static $disableForPostSend = false; + + /** + * Disable setters for post-send processing + * + * After this call, self::setCookie(), self::header(), and + * self::statusHeader() will log a warning and return without + * setting cookies or headers. + * + * @since 1.32 + */ + public static function disableForPostSend() { + self::$disableForPostSend = true; + } + /** * Output an HTTP header, wrapper for PHP's header() * @param string $string Header to output @@ -39,6 +55,16 @@ class WebResponse { * @param null|int $http_response_code Forces the HTTP response code to the specified value. */ public function header( $string, $replace = true, $http_response_code = null ) { + if ( self::$disableForPostSend ) { + wfDebugLog( 'header', 'ignored post-send header {header}', 'all', [ + 'header' => $string, + 'replace' => $replace, + 'http_response_code' => $http_response_code, + 'exception' => new RuntimeException( 'Ignored post-send header' ), + ] ); + return; + } + \MediaWiki\HeaderCallback::warnIfHeadersSent(); if ( $http_response_code ) { header( $string, $replace, $http_response_code ); @@ -69,6 +95,14 @@ class WebResponse { * @param int $code Status code */ public function statusHeader( $code ) { + if ( self::$disableForPostSend ) { + wfDebugLog( 'header', 'ignored post-send status header {code}', 'all', [ + 'code' => $code, + 'exception' => new RuntimeException( 'Ignored post-send status header' ), + ] ); + return; + } + HttpStatus::header( $code ); } @@ -117,20 +151,29 @@ class WebResponse { $expire = time() + $wgCookieExpiration; } + $cookie = $options['prefix'] . $name; + $data = [ + 'name' => (string)$cookie, + 'value' => (string)$value, + 'expire' => (int)$expire, + 'path' => (string)$options['path'], + 'domain' => (string)$options['domain'], + 'secure' => (bool)$options['secure'], + 'httpOnly' => (bool)$options['httpOnly'], + ]; + + if ( self::$disableForPostSend ) { + wfDebugLog( 'cookie', 'ignored post-send cookie {cookie}', 'all', [ + 'cookie' => $cookie, + 'data' => $data, + 'exception' => new RuntimeException( 'Ignored post-send cookie' ), + ] ); + return; + } + $func = $options['raw'] ? 'setrawcookie' : 'setcookie'; if ( Hooks::run( 'WebResponseSetCookie', [ &$name, &$value, &$expire, &$options ] ) ) { - $cookie = $options['prefix'] . $name; - $data = [ - 'name' => (string)$cookie, - 'value' => (string)$value, - 'expire' => (int)$expire, - 'path' => (string)$options['path'], - 'domain' => (string)$options['domain'], - 'secure' => (bool)$options['secure'], - 'httpOnly' => (bool)$options['httpOnly'], - ]; - // Per RFC 6265, key is name + domain + path $key = "{$data['name']}\n{$data['domain']}\n{$data['path']}"; @@ -234,10 +277,7 @@ class FauxResponse extends WebResponse { public function getHeader( $key ) { $key = strtoupper( $key ); - if ( isset( $this->headers[$key] ) ) { - return $this->headers[$key]; - } - return null; + return $this->headers[$key] ?? null; } /** @@ -303,10 +343,7 @@ class FauxResponse extends WebResponse { * @return array|null */ public function getCookieData( $name ) { - if ( isset( $this->cookies[$name] ) ) { - return $this->cookies[$name]; - } - return null; + return $this->cookies[$name] ?? null; } /** diff --git a/includes/XmlSelect.php b/includes/XmlSelect.php index 89f2f41cb8..5d7406c64d 100644 --- a/includes/XmlSelect.php +++ b/includes/XmlSelect.php @@ -70,11 +70,7 @@ class XmlSelect { * @return string|null */ public function getAttribute( $name ) { - if ( isset( $this->attributes[$name] ) ) { - return $this->attributes[$name]; - } else { - return null; - } + return $this->attributes[$name] ?? null; } /** diff --git a/includes/api/ApiQueryLinks.php b/includes/api/ApiQueryLinks.php index 67bf619c89..144c7582b0 100644 --- a/includes/api/ApiQueryLinks.php +++ b/includes/api/ApiQueryLinks.php @@ -103,7 +103,7 @@ class ApiQueryLinks extends ApiQueryGeneratorBase { if ( $cond ) { $this->addWhere( $cond ); $multiNS = count( $lb->data ) !== 1; - $multiTitle = count( call_user_func_array( 'array_merge', $lb->data ) ) !== 1; + $multiTitle = count( array_merge( ...$lb->data ) ) !== 1; } else { // No titles so no results return; diff --git a/includes/api/ApiQueryPrefixSearch.php b/includes/api/ApiQueryPrefixSearch.php index 2fbc518b1e..04d3f2c9fc 100644 --- a/includes/api/ApiQueryPrefixSearch.php +++ b/includes/api/ApiQueryPrefixSearch.php @@ -51,7 +51,12 @@ class ApiQueryPrefixSearch extends ApiQueryGeneratorBase { $offset = $params['offset']; $searchEngine = $this->buildSearchEngine( $params ); - $titles = $searchEngine->extractTitles( $searchEngine->completionSearchWithVariants( $search ) ); + $suggestions = $searchEngine->completionSearchWithVariants( $search ); + $titles = $searchEngine->extractTitles( $suggestions ); + + if ( $suggestions->hasMoreResults() ) { + $this->setContinueEnumParameter( 'offset', $offset + $limit ); + } if ( $resultPageSet ) { $resultPageSet->setRedirectMergePolicy( function ( array $current, array $new ) { @@ -60,10 +65,6 @@ class ApiQueryPrefixSearch extends ApiQueryGeneratorBase { } return $current; } ); - if ( count( $titles ) > $limit ) { - $this->setContinueEnumParameter( 'offset', $offset + $limit ); - array_pop( $titles ); - } $resultPageSet->populateFromTitles( $titles ); foreach ( $titles as $index => $title ) { $resultPageSet->setGeneratorData( $title, [ 'index' => $index + $offset + 1 ] ); @@ -72,10 +73,6 @@ class ApiQueryPrefixSearch extends ApiQueryGeneratorBase { $result = $this->getResult(); $count = 0; foreach ( $titles as $title ) { - if ( ++$count > $limit ) { - $this->setContinueEnumParameter( 'offset', $offset + $limit ); - break; - } $vals = [ 'ns' => intval( $title->getNamespace() ), 'title' => $title->getPrefixedText(), @@ -86,8 +83,9 @@ class ApiQueryPrefixSearch extends ApiQueryGeneratorBase { $vals['pageid'] = intval( $title->getArticleID() ); } $fit = $result->addValue( [ 'query', $this->getModuleName() ], null, $vals ); + ++$count; if ( !$fit ) { - $this->setContinueEnumParameter( 'offset', $offset + $count - 1 ); + $this->setContinueEnumParameter( 'offset', $offset + $count ); break; } } diff --git a/includes/api/ApiQuerySearch.php b/includes/api/ApiQuerySearch.php index 7d46a5fb08..3d87a5f06a 100644 --- a/includes/api/ApiQuerySearch.php +++ b/includes/api/ApiQuerySearch.php @@ -60,6 +60,9 @@ class ApiQuerySearch extends ApiQueryGeneratorBase { // Create search engine instance and set options $search = $this->buildSearchEngine( $params ); + if ( isset( $params['sort'] ) ) { + $search->setSort( $params['sort'] ); + } $search->setFeatureData( 'rewrite', (bool)$params['enablerewrites'] ); $search->setFeatureData( 'interwiki', (bool)$interwiki ); @@ -142,20 +145,16 @@ class ApiQuerySearch extends ApiQueryGeneratorBase { $terms = $wgContLang->convertForSearchResult( $matches->termMatches() ); $titles = []; $count = 0; - $result = $matches->next(); $limit = $params['limit']; - while ( $result ) { - if ( ++$count > $limit ) { - // We've reached the one extra which shows that there are - // additional items to be had. Stop here... - $this->setContinueEnumParameter( 'offset', $params['offset'] + $params['limit'] ); - break; - } + if ( $matches->hasMoreResults() ) { + $this->setContinueEnumParameter( 'offset', $params['offset'] + $params['limit'] ); + } + foreach ( $matches as $result ) { + $count++; // Silently skip broken and missing titles if ( $result->isBrokenTitle() || $result->isMissingRevision() ) { - $result = $matches->next(); continue; } @@ -172,8 +171,6 @@ class ApiQuerySearch extends ApiQueryGeneratorBase { } else { $titles[] = $result->getTitle(); } - - $result = $matches->next(); } // Here we assume interwiki results do not count with @@ -301,8 +298,7 @@ class ApiQuerySearch extends ApiQueryGeneratorBase { // Include number of results if requested $totalhits += $interwikiMatches->getTotalHits(); - $result = $interwikiMatches->next(); - while ( $result ) { + foreach ( $interwikiMatches as $result ) { $title = $result->getTitle(); $vals = $this->getSearchResultData( $result, $prop, $terms ); @@ -322,8 +318,6 @@ class ApiQuerySearch extends ApiQueryGeneratorBase { // pagination info so just bail out break; } - - $result = $interwikiMatches->next(); } } if ( $totalhits !== null ) { @@ -391,6 +385,20 @@ class ApiQuerySearch extends ApiQueryGeneratorBase { 'enablerewrites' => false, ]; + // If we have more than one engine the list of available sorts is + // difficult to represent. For now don't expose it. + $alternatives = MediaWiki\MediaWikiServices::getInstance() + ->getSearchEngineConfig() + ->getSearchTypes(); + if ( count( $alternatives ) == 1 ) { + $this->allowedParams['sort'] = [ + ApiBase::PARAM_DFLT => 'relevance', + ApiBase::PARAM_TYPE => MediaWiki\MediaWikiServices::getInstance() + ->newSearchEngine() + ->getValidSorts(), + ]; + } + return $this->allowedParams; } diff --git a/includes/api/ApiQueryTokens.php b/includes/api/ApiQueryTokens.php index e86fdf3533..8854aac0de 100644 --- a/includes/api/ApiQueryTokens.php +++ b/includes/api/ApiQueryTokens.php @@ -94,7 +94,7 @@ class ApiQueryTokens extends ApiQueryBase { public static function getToken( User $user, MediaWiki\Session\Session $session, $salt ) { if ( is_array( $salt ) ) { $session->persist(); - return call_user_func_array( [ $session, 'getToken' ], $salt ); + return $session->getToken( ...$salt ); } else { return $user->getEditTokenObject( $salt, $session->getRequest() ); } diff --git a/includes/api/ApiQueryUserContribs.php b/includes/api/ApiQueryUserContribs.php index 420d138df7..fdcaa76932 100644 --- a/includes/api/ApiQueryUserContribs.php +++ b/includes/api/ApiQueryUserContribs.php @@ -306,9 +306,11 @@ class ApiQueryUserContribs extends ApiQueryBase { foreach ( $res as $row ) { $names[$row->user_name] = $row; } - call_user_func_array( - $this->params['dir'] == 'newer' ? 'ksort' : 'krsort', [ &$names, SORT_STRING ] - ); + if ( $this->params['dir'] == 'newer' ) { + ksort( $names, SORT_STRING ); + } else { + krsort( $names, SORT_STRING ); + } $neg = $op === '>' ? -1 : 1; $userIter = call_user_func( function () use ( $names, $fromName, $neg ) { foreach ( $names as $name => $row ) { diff --git a/includes/api/SearchApi.php b/includes/api/SearchApi.php index 40d477880f..fc6eddf800 100644 --- a/includes/api/SearchApi.php +++ b/includes/api/SearchApi.php @@ -76,7 +76,7 @@ trait SearchApi { if ( $alternatives[0] === null ) { $alternatives[0] = self::$BACKEND_NULL_PARAM; } - $this->allowedParams['backend'] = [ + $params['backend'] = [ ApiBase::PARAM_DFLT => $searchConfig->getSearchType(), ApiBase::PARAM_TYPE => $alternatives, ]; @@ -140,8 +140,7 @@ trait SearchApi { * will be set: * - backend: which search backend to use * - limit: mandatory - * - offset: optional, if set limit will be incremented by - * one ( to support the continue parameter ) + * - offset: optional * - namespace: mandatory * - search engine profiles defined by SearchApi::getSearchProfileParams() * @param string[]|null $params API request params (must be sanitized by @@ -157,15 +156,7 @@ trait SearchApi { $searchEngine = MediaWikiServices::getInstance()->getSearchEngineFactory()->create( $type ); $limit = $params['limit']; $searchEngine->setNamespaces( $params['namespace'] ); - $offset = null; - if ( isset( $params['offset'] ) ) { - // If the API supports offset then it probably - // wants to fetch limit+1 so it can check if - // more results are available to properly set - // the continue param - $offset = $params['offset']; - $limit += 1; - } + $offset = isset( $params['offset'] ) ? $params['offset'] : null; $searchEngine->setLimitOffset( $limit, $offset ); // Initialize requested search profiles. diff --git a/includes/api/i18n/en.json b/includes/api/i18n/en.json index e1ba665549..94e1ac6716 100644 --- a/includes/api/i18n/en.json +++ b/includes/api/i18n/en.json @@ -1165,6 +1165,7 @@ "apihelp-query+search-param-interwiki": "Include interwiki results in the search, if available.", "apihelp-query+search-param-backend": "Which search backend to use, if not the default.", "apihelp-query+search-param-enablerewrites": "Enable internal query rewriting. Some search backends can rewrite the query into another which is thought to provide better results, for instance by correcting spelling errors.", + "apihelp-query+search-param-sort": "Set the sort order of returned results.", "apihelp-query+search-example-simple": "Search for meaning.", "apihelp-query+search-example-text": "Search texts for meaning.", "apihelp-query+search-example-generator": "Get page info about the pages returned for a search for meaning.", diff --git a/includes/api/i18n/qqq.json b/includes/api/i18n/qqq.json index 3fcf499afc..1680bb87b1 100644 --- a/includes/api/i18n/qqq.json +++ b/includes/api/i18n/qqq.json @@ -1088,6 +1088,7 @@ "apihelp-query+search-param-interwiki": "{{doc-apihelp-param|query+search|interwiki}}", "apihelp-query+search-param-backend": "{{doc-apihelp-param|query+search|backend}}", "apihelp-query+search-param-enablerewrites": "{{doc-apihelp-param|query+search|enablerewrites}}", + "apihelp-query+search-param-sort": "{{doc-apihelp-param|query+search|sort}}", "apihelp-query+search-example-simple": "{{doc-apihelp-example|query+search}}", "apihelp-query+search-example-text": "{{doc-apihelp-example|query+search}}", "apihelp-query+search-example-generator": "{{doc-apihelp-example|query+search}}", diff --git a/includes/auth/ButtonAuthenticationRequest.php b/includes/auth/ButtonAuthenticationRequest.php index d274e18f7b..1268e68de5 100644 --- a/includes/auth/ButtonAuthenticationRequest.php +++ b/includes/auth/ButtonAuthenticationRequest.php @@ -90,14 +90,14 @@ class ButtonAuthenticationRequest extends AuthenticationRequest { } elseif ( is_string( $data['label'] ) ) { $data['label'] = new \Message( $data['label'] ); } elseif ( is_array( $data['label'] ) ) { - $data['label'] = call_user_func_array( 'Message::newFromKey', $data['label'] ); + $data['label'] = Message::newFromKey( ...$data['label'] ); } if ( !isset( $data['help'] ) ) { $data['help'] = new \RawMessage( '$1', $data['name'] ); } elseif ( is_string( $data['help'] ) ) { $data['help'] = new \Message( $data['help'] ); } elseif ( is_array( $data['help'] ) ) { - $data['help'] = call_user_func_array( 'Message::newFromKey', $data['help'] ); + $data['help'] = Message::newFromKey( ...$data['help'] ); } $ret = new static( $data['name'], $data['label'], $data['help'] ); foreach ( $data as $k => $v ) { diff --git a/includes/cache/GenderCache.php b/includes/cache/GenderCache.php index 1ec39a54d6..7228814d47 100644 --- a/includes/cache/GenderCache.php +++ b/includes/cache/GenderCache.php @@ -171,7 +171,7 @@ class GenderCache { $res = $dbr->select( $table, $fields, $conds, $comment, [], $joins ); foreach ( $res as $row ) { - $this->cache[$row->user_name] = $row->up_value ? $row->up_value : $default; + $this->cache[$row->user_name] = $row->up_value ?: $default; } } diff --git a/includes/cache/localisation/LocalisationCache.php b/includes/cache/localisation/LocalisationCache.php index dd9e8e194a..90108eb682 100644 --- a/includes/cache/localisation/LocalisationCache.php +++ b/includes/cache/localisation/LocalisationCache.php @@ -292,11 +292,7 @@ class LocalisationCache { $this->loadSubitem( $code, $key, $subkey ); } - if ( isset( $this->data[$code][$key][$subkey] ) ) { - return $this->data[$code][$key][$subkey]; - } else { - return null; - } + return $this->data[$code][$key][$subkey] ?? null; } /** @@ -603,11 +599,7 @@ class LocalisationCache { if ( $this->pluralRules === null ) { $this->loadPluralFiles(); } - if ( !isset( $this->pluralRules[$code] ) ) { - return null; - } else { - return $this->pluralRules[$code]; - } + return $this->pluralRules[$code] ?? null; } /** @@ -621,11 +613,7 @@ class LocalisationCache { if ( $this->pluralRuleTypes === null ) { $this->loadPluralFiles(); } - if ( !isset( $this->pluralRuleTypes[$code] ) ) { - return null; - } else { - return $this->pluralRuleTypes[$code]; - } + return $this->pluralRuleTypes[$code] ?? null; } /** @@ -1047,11 +1035,7 @@ class LocalisationCache { } foreach ( $data['preloadedMessages'] as $subkey ) { - if ( isset( $data['messages'][$subkey] ) ) { - $subitem = $data['messages'][$subkey]; - } else { - $subitem = null; - } + $subitem = $data['messages'][$subkey] ?? null; $preload['messages'][$subkey] = $subitem; } diff --git a/includes/changes/RecentChange.php b/includes/changes/RecentChange.php index 60fe85009c..94dcd077a5 100644 --- a/includes/changes/RecentChange.php +++ b/includes/changes/RecentChange.php @@ -520,11 +520,7 @@ class RecentChange { continue; } - if ( isset( $this->mExtra['actionCommentIRC'] ) ) { - $actionComment = $this->mExtra['actionCommentIRC']; - } else { - $actionComment = null; - } + $actionComment = $this->mExtra['actionCommentIRC'] ?? null; $feed = RCFeed::factory( $params ); $feed->notify( $this, $actionComment ); diff --git a/includes/changetags/ChangeTags.php b/includes/changetags/ChangeTags.php index 0c81144531..d019f41cea 100644 --- a/includes/changetags/ChangeTags.php +++ b/includes/changetags/ChangeTags.php @@ -386,7 +386,7 @@ class ChangeTags { 'ct_log_id' => $log_id, 'ct_rev_id' => $rev_id, 'ct_params' => $params, - 'ct_tag_id' => isset( $changeTagMapping[$tag] ) ? $changeTagMapping[$tag] : null, + 'ct_tag_id' => $changeTagMapping[$tag] ?? null, ] ); @@ -466,7 +466,7 @@ class ChangeTags { // $prevTags can be out of date on replica DBs, especially when addTags is called consecutively, // causing loss of tags added recently in tag_summary table. $prevTags = $dbw->selectField( 'tag_summary', 'ts_tags', $tsConds, __METHOD__ ); - $prevTags = $prevTags ? $prevTags : ''; + $prevTags = $prevTags ?: ''; $prevTags = array_filter( explode( ',', $prevTags ) ); // add tags diff --git a/includes/collation/IcuCollation.php b/includes/collation/IcuCollation.php index d92c215e11..5f401a588b 100644 --- a/includes/collation/IcuCollation.php +++ b/includes/collation/IcuCollation.php @@ -577,10 +577,6 @@ class IcuCollation extends Collation { '3.4' => '4.1', ]; - if ( isset( $map[$versionPrefix] ) ) { - return $map[$versionPrefix]; - } else { - return false; - } + return $map[$versionPrefix] ?? false; } } diff --git a/includes/db/DatabaseOracle.php b/includes/db/DatabaseOracle.php index 3362f0f907..f4f04f1ff9 100644 --- a/includes/db/DatabaseOracle.php +++ b/includes/db/DatabaseOracle.php @@ -675,7 +675,7 @@ class DatabaseOracle extends Database { } $table = strtolower( $this->removeIdentifierQuotes( $this->tableName( $table ) ) ); - return ( isset( $this->sequenceData[$table] ) ) ? $this->sequenceData[$table] : false; + return $this->sequenceData[$table] ?? false; } /** diff --git a/includes/exception/MWExceptionHandler.php b/includes/exception/MWExceptionHandler.php index 79f0a23374..9039cfca94 100644 --- a/includes/exception/MWExceptionHandler.php +++ b/includes/exception/MWExceptionHandler.php @@ -173,9 +173,7 @@ class MWExceptionHandler { global $wgPropagateErrors; if ( in_array( $level, self::$fatalErrorTypes ) ) { - return call_user_func_array( - 'MWExceptionHandler::handleFatalError', func_get_args() - ); + return self::handleFatalError( ...func_get_args() ); } // Map error constant to error name (reverse-engineer PHP error diff --git a/includes/filerepo/FileRepo.php b/includes/filerepo/FileRepo.php index 70068b998b..3d9a904bf5 100644 --- a/includes/filerepo/FileRepo.php +++ b/includes/filerepo/FileRepo.php @@ -1177,11 +1177,7 @@ class FileRepo { if ( $status->successCount == 0 ) { $status->setOK( false ); } - if ( isset( $status->value[0] ) ) { - $status->value = $status->value[0]; - } else { - $status->value = false; - } + $status->value = $status->value[0] ?? false; return $status; } diff --git a/includes/filerepo/RepoGroup.php b/includes/filerepo/RepoGroup.php index 005618126c..fa4567e0b2 100644 --- a/includes/filerepo/RepoGroup.php +++ b/includes/filerepo/RepoGroup.php @@ -163,7 +163,7 @@ class RepoGroup { } } - $image = $image ? $image : false; // type sanity + $image = $image ?: false; // type sanity # Cache file existence or non-existence if ( $useCache && ( !$image || $image->isCacheable() ) ) { $this->cache->set( $dbkey, $time, $image ); @@ -324,11 +324,8 @@ class RepoGroup { } if ( $index === 'local' ) { return $this->localRepo; - } elseif ( isset( $this->foreignRepos[$index] ) ) { - return $this->foreignRepos[$index]; - } else { - return false; } + return $this->foreignRepos[$index] ?? false; } /** @@ -372,8 +369,7 @@ class RepoGroup { $this->initialiseRepos(); } foreach ( $this->foreignRepos as $repo ) { - $args = array_merge( [ $repo ], $params ); - if ( call_user_func_array( $callback, $args ) ) { + if ( $callback( $repo, ...$params ) ) { return true; } } diff --git a/includes/htmlform/HTMLForm.php b/includes/htmlform/HTMLForm.php index 785d30f8a3..e72faa0e30 100644 --- a/includes/htmlform/HTMLForm.php +++ b/includes/htmlform/HTMLForm.php @@ -607,7 +607,7 @@ class HTMLForm extends ContextSource { $hoistedErrors = Status::newGood(); if ( $this->mValidationErrorMessage ) { foreach ( (array)$this->mValidationErrorMessage as $error ) { - call_user_func_array( [ $hoistedErrors, 'fatal' ], $error ); + $hoistedErrors->fatal( ...$error ); } } else { $hoistedErrors->fatal( 'htmlform-invalid-input' ); diff --git a/includes/htmlform/HTMLFormField.php b/includes/htmlform/HTMLFormField.php index cd4d4b749f..a70157572a 100644 --- a/includes/htmlform/HTMLFormField.php +++ b/includes/htmlform/HTMLFormField.php @@ -81,12 +81,9 @@ abstract class HTMLFormField { $args = func_get_args(); if ( $this->mParent ) { - $callback = [ $this->mParent, 'msg' ]; - } else { - $callback = 'wfMessage'; + return $this->mParent->msg( ...$args ); } - - return call_user_func_array( $callback, $args ); + return wfMessage( ...$args ); } /** @@ -315,7 +312,7 @@ abstract class HTMLFormField { } if ( isset( $this->mValidationCallback ) ) { - return call_user_func( $this->mValidationCallback, $value, $alldata, $this->mParent ); + return ( $this->mValidationCallback )( $value, $alldata, $this->mParent ); } return true; @@ -323,7 +320,7 @@ abstract class HTMLFormField { public function filter( $value, $alldata ) { if ( isset( $this->mFilterCallback ) ) { - $value = call_user_func( $this->mFilterCallback, $value, $alldata, $this->mParent ); + $value = ( $this->mFilterCallback )( $value, $alldata, $this->mParent ); } return $value; diff --git a/includes/htmlform/fields/HTMLCheckMatrix.php b/includes/htmlform/fields/HTMLCheckMatrix.php index df44626a3d..d885c9d2e5 100644 --- a/includes/htmlform/fields/HTMLCheckMatrix.php +++ b/includes/htmlform/fields/HTMLCheckMatrix.php @@ -239,11 +239,7 @@ class HTMLCheckMatrix extends HTMLFormField implements HTMLNestedFilterable { } public function getDefault() { - if ( isset( $this->mDefault ) ) { - return $this->mDefault; - } else { - return []; - } + return $this->mDefault ?? []; } public function filterDataForSubmit( $data ) { diff --git a/includes/installer/DatabaseUpdater.php b/includes/installer/DatabaseUpdater.php index 4fc04db12b..1cd76b9565 100644 --- a/includes/installer/DatabaseUpdater.php +++ b/includes/installer/DatabaseUpdater.php @@ -410,9 +410,9 @@ abstract class DatabaseUpdater { foreach ( $updates as $funcList ) { $func = $funcList[0]; - $arg = $funcList[1]; + $args = $funcList[1]; $origParams = $funcList[2]; - call_user_func_array( $func, $arg ); + $func( ...$args ); flush(); $this->updatesSkipped[] = $origParams; } @@ -479,7 +479,7 @@ abstract class DatabaseUpdater { } elseif ( $passSelf ) { array_unshift( $params, $this ); } - $ret = call_user_func_array( $func, $params ); + $ret = $func( ...$params ); flush(); if ( $ret !== false ) { $updatesDone[] = $origParams; diff --git a/includes/installer/Installer.php b/includes/installer/Installer.php index 05da0dbf49..0890bc4768 100644 --- a/includes/installer/Installer.php +++ b/includes/installer/Installer.php @@ -1597,23 +1597,11 @@ abstract class Installer { protected function doGenerateKeys( $keys ) { $status = Status::newGood(); - $strong = true; foreach ( $keys as $name => $length ) { - $secretKey = MWCryptRand::generateHex( $length, true ); - if ( !MWCryptRand::wasStrong() ) { - $strong = false; - } - + $secretKey = MWCryptRand::generateHex( $length ); $this->setVar( $name, $secretKey ); } - if ( !$strong ) { - $names = array_keys( $keys ); - $names = preg_replace( '/^(.*)$/', '\$$1', $names ); - global $wgLang; - $status->warning( 'config-insecure-keys', $wgLang->listToText( $names ), count( $names ) ); - } - return $status; } diff --git a/includes/installer/WebInstaller.php b/includes/installer/WebInstaller.php index 8fb980791e..018754bcfb 100644 --- a/includes/installer/WebInstaller.php +++ b/includes/installer/WebInstaller.php @@ -717,7 +717,7 @@ class WebInstaller extends Installer { */ public function showHelpBox( $msg /*, ... */ ) { $args = func_get_args(); - $html = call_user_func_array( [ $this, 'getHelpBox' ], $args ); + $html = $this->getHelpBox( ...$args ); $this->output->addHTML( $html ); } @@ -742,7 +742,7 @@ class WebInstaller extends Installer { public function showStatusMessage( Status $status ) { $errors = array_merge( $status->getErrorsArray(), $status->getWarningsArray() ); foreach ( $errors as $error ) { - call_user_func_array( [ $this, 'showMessage' ], $error ); + $this->showMessage( ...$error ); } } @@ -1121,13 +1121,13 @@ class WebInstaller extends Installer { * @return string */ protected function getDocUrl( $page ) { - $url = "{$_SERVER['PHP_SELF']}?page=" . urlencode( $page ); + $query = [ 'page' => $page ]; if ( in_array( $this->currentPageName, $this->pageSequence ) ) { - $url .= '&lastPage=' . urlencode( $this->currentPageName ); + $query['lastPage'] = $this->currentPageName; } - return $url; + return $this->getUrl( $query ); } /** @@ -1142,9 +1142,7 @@ class WebInstaller extends Installer { public function docLink( $linkText, $attribs, $parser ) { $url = $this->getDocUrl( $attribs['href'] ); - return '
    ' . - htmlspecialchars( $linkText ) . - ''; + return Html::element( 'a', [ 'href' => $url ], $linkText ); } /** diff --git a/includes/installer/i18n/ar.json b/includes/installer/i18n/ar.json index cb6051f8c4..d853009ccb 100644 --- a/includes/installer/i18n/ar.json +++ b/includes/installer/i18n/ar.json @@ -299,7 +299,6 @@ "config-install-interwiki-exists": "تحذير: يبدو أن جدول الإنترويكي به إدخالات بالفعل. تخطي القائمة الافتراضي.", "config-install-stats": "بدء الإحصاءات", "config-install-keys": "توليد المفاتيح السرية", - "config-insecure-keys": "تحذير: {{PLURAL:$2|مفتاح الأمان|مفاتيح الأمان}} ($1) التي تم إنشاؤها أثناء التثبيت ليست آمنة تماما; جرب تغيير{{PLURAL:$2|ه|هم}} يدويا.", "config-install-updates": "منع تشغيل التحديثات غير الضرورية", "config-install-updates-failed": "خطأ: إدخال مفاتيح التحديث إلى الجداول فشلت بسبب الخطأ التالي: $1", "config-install-sysop": "إنشاء حساب مستخدم إداري", diff --git a/includes/installer/i18n/ba.json b/includes/installer/i18n/ba.json index 6fcaca29b6..6d9a3c62d0 100644 --- a/includes/installer/i18n/ba.json +++ b/includes/installer/i18n/ba.json @@ -292,7 +292,6 @@ "config-install-interwiki-exists": "'''Киҫәтеү''': интервики-таблицала яҙма бар.\nСтандарт исемлек төҙөү төшөп ҡалды.", "config-install-stats": "Инициализация статистикаһы", "config-install-keys": "Серле асҡыстар төҙөү", - "config-insecure-keys": "'''Киҫәтеү''' {{PLURAL:$2|1=Ҡатнашыусы булдырған хәүефһеҙлек асҡысы $1 ышаныслы түгел}}. Асҡысты үҙгәртеү мөмкинлеген {{PLURAL:$2|1=}} ҡарағыҙ.", "config-install-updates": "Кәрәкмәген яңыртыуҙар туҡтатылды", "config-install-updates-failed": "Хата: Яңыртыуға асҡыс ҡуйыу түбәндәге хата менән тамамланды: $1", "config-install-sysop": "Администратор иҫәп яҙмаһын булдырыу", diff --git a/includes/installer/i18n/be-tarask.json b/includes/installer/i18n/be-tarask.json index 0402ef5d6e..da060da97d 100644 --- a/includes/installer/i18n/be-tarask.json +++ b/includes/installer/i18n/be-tarask.json @@ -295,7 +295,6 @@ "config-install-interwiki-exists": "'''Папярэджаньне''': выглядае, што табліца інтэрвікі ўжо запоўненая.\nСьпіс па змоўчваньні прапушчаны.", "config-install-stats": "Ініцыялізацыі статыстыкі", "config-install-keys": "Стварэньне сакрэтных ключоў", - "config-insecure-keys": "Папярэджаньне: {{PLURAL:$2|1=Ключ бясьпекі $1 створаны|Ключы бясьпекі $1 створаныя}} падчас усталяваньня, {{PLURAL:$2|1=не зьяўляецца паўнасьцю бясьпечным|не зьяўляюцца поўнасьцю бясьпечнымі}}. Рэкамэндуецца зьмяніць {{PLURAL:$2|1=яго ўручную|іх уручную}}.", "config-install-updates": "Прадухіленьне запуску непатрэбных абнаўленьняў", "config-install-updates-failed": "Памылка: устаўка ключоў абнаўленьня ў табліцы завершылася наступнай памылкай: $1", "config-install-sysop": "Стварэньне рахунку адміністратара", diff --git a/includes/installer/i18n/bg.json b/includes/installer/i18n/bg.json index 829a91003c..3988ada2ad 100644 --- a/includes/installer/i18n/bg.json +++ b/includes/installer/i18n/bg.json @@ -291,7 +291,6 @@ "config-install-interwiki-exists": "Внимание: Таблицата с междууикита изглежда вече съдържа данни.\nПропускане на списъка по подразбиране.", "config-install-stats": "Инициализиране на статистиките", "config-install-keys": "Генериране на тайни ключове", - "config-insecure-keys": "Внимание: {{PLURAL:$2|Сигурният ключ, създаден по време на инсталацията, не е напълно надежден|Сигурните ключове, създадени по време на инсталацията, не са напълно надеждни}} $1 . Обмислете да {{PLURAL:$2|го|ги}} смените ръчно.", "config-install-updates": "Предотвратяване стартирането на ненужни актуализации", "config-install-updates-failed": "Грешка: Вмъкването на обновяващи ключове в таблиците се провали по следната причина: $1", "config-install-sysop": "Създаване на администраторска сметка", diff --git a/includes/installer/i18n/cs.json b/includes/installer/i18n/cs.json index ba75bd3ce8..056531ed35 100644 --- a/includes/installer/i18n/cs.json +++ b/includes/installer/i18n/cs.json @@ -299,7 +299,6 @@ "config-install-interwiki-exists": "'''Upozornění''': Vypadá to, že tabulka interwiki již obsahuje nějaké záznamy.\nPřeskakuje se implicitní seznam.", "config-install-stats": "Inicializují se statistiky", "config-install-keys": "Vytvářejí se tajné klíče", - "config-insecure-keys": "'''Upozornění:''' {{PLURAL:$2|Tajný klíč|Tajné klíče}} ($1) vytvořené v průběhu instalace {{PLURAL:$2|není|nejsou}} zcela {{PLURAL:$2|bezpečný|bezpečné}}. Zvažte {{PLURAL:$2|jeho|jejich}} ruční změnu.", "config-install-updates": "Ruší se spuštění nepotřebných aktualizací", "config-install-updates-failed": "Chyba: Vložení aktualizačních klíčů do tabulek selhalo s následující chybou: $1", "config-install-sysop": "Zakládá se uživatelský účet správce", diff --git a/includes/installer/i18n/de.json b/includes/installer/i18n/de.json index 88d03440a1..7a448a7ad9 100644 --- a/includes/installer/i18n/de.json +++ b/includes/installer/i18n/de.json @@ -304,7 +304,6 @@ "config-install-interwiki-exists": "'''Warnung:''' Es wurden Interwikitabellen mit Daten gefunden.\nDie Standardliste wird übersprungen.", "config-install-stats": "Statistiken werden initialisiert", "config-install-keys": "Geheimschlüssel werden erstellt", - "config-insecure-keys": "'''Warnung:''' {{PLURAL:$2|Der Geheimschlüssel|Die Geheimschlüssel}} $1, {{PLURAL:$2|der|die}} während des Installationsvorgangs generiert {{PLURAL:$2|wurde, ist|wurden, sind}} nicht sehr sicher. {{PLURAL:$2|Er sollte|Sie sollten}} manuell geändert werden.", "config-install-updates": "Unnötige Aktualisierungen nicht ausführen", "config-install-updates-failed": "Fehler: Das Einfügen von Aktualisierungsschlüssel in die Tabellen ist mit dem folgenden Fehler fehlgeschlagen: $1", "config-install-sysop": "Administratorkonto wird erstellt", diff --git a/includes/installer/i18n/en.json b/includes/installer/i18n/en.json index 005fef6791..dbc18498e2 100644 --- a/includes/installer/i18n/en.json +++ b/includes/installer/i18n/en.json @@ -288,7 +288,6 @@ "config-install-interwiki-exists": "Warning: The interwiki table seems to already have entries.\nSkipping default list.", "config-install-stats": "Initializing statistics", "config-install-keys": "Generating secret keys", - "config-insecure-keys": "Warning: {{PLURAL:$2|A secure key|Secure keys}} ($1) generated during installation {{PLURAL:$2|is|are}} not completely safe. Consider changing {{PLURAL:$2|it|them}} manually.", "config-install-updates": "Prevent running unneeded updates", "config-install-updates-failed": "Error: Inserting update keys into tables failed with the following error: $1", "config-install-sysop": "Creating administrator user account", diff --git a/includes/installer/i18n/es.json b/includes/installer/i18n/es.json index 09fce8938c..921844dfcc 100644 --- a/includes/installer/i18n/es.json +++ b/includes/installer/i18n/es.json @@ -324,7 +324,6 @@ "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": "Generando claves secretas", - "config-insecure-keys": "Advertencia: {{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}}. Considera {{PLURAL:$2|cambiarla|cambiarlas}} manualmente.", "config-install-updates": "Evitar ejecutar actualizaciones innecesarias", "config-install-updates-failed": "Error: falló la inserción de claves de actualización en las tablas con el siguiente error: $1", "config-install-sysop": "Creando la cuenta de usuario del administrador", diff --git a/includes/installer/i18n/eu.json b/includes/installer/i18n/eu.json index 5c9a3afadc..f840b49fbf 100644 --- a/includes/installer/i18n/eu.json +++ b/includes/installer/i18n/eu.json @@ -293,7 +293,6 @@ "config-install-interwiki-exists": "Oharra: Interwikiko taula badirudi sarrerak dituela. \nTaula estandarra saltatzen.", "config-install-stats": "Estatistikak hasten", "config-install-keys": "Gako sekretuak sortzen", - "config-insecure-keys": "Oharra: ($1) instalazioan zehar sortu {{PLURAL:$2|den|diren}} {{PLURAL:$2|gako segurua|gako seguruak}}ez d(ir)a guztiz segurua(k). Kontuan hartu {{PLURAL:$2|hau|hauek}} eskuz aldatzeko aukera.", "config-install-updates": "Saihestu egikaratzen behar ez diren aktualizazioak", "config-install-updates-failed": "Errore Sartzea eguneratze-gakoak taulen barruan huts egin du hurrengo errorearekin: $1", "config-install-sysop": "Administratzaile kontua sortzen", diff --git a/includes/installer/i18n/fa.json b/includes/installer/i18n/fa.json index 3ef8df0733..31febc0c72 100644 --- a/includes/installer/i18n/fa.json +++ b/includes/installer/i18n/fa.json @@ -300,7 +300,6 @@ "config-install-interwiki-exists": "'''هشدار:''' به نظر می‌رسد جدول ویکی داخلی در حال حاضر دارای مقداری اطلاعات است.\nنادیده گرفتن فهرست پیش‌فرض.", "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": "ایجاد حساب کاربری مدیر", diff --git a/includes/installer/i18n/fi.json b/includes/installer/i18n/fi.json index 151dfa6f79..64dfa20e71 100644 --- a/includes/installer/i18n/fi.json +++ b/includes/installer/i18n/fi.json @@ -290,7 +290,6 @@ "config-install-interwiki-exists": "Varoitus: interwiki-taulussa on jo tietueita, ohitetaan oletuslista.", "config-install-stats": "Alustetaan tilastoja", "config-install-keys": "Muodostetaan salausavaimia", - "config-insecure-keys": "Varoitus: Asennuksen aikana {{PLURAL:$2|luotu turva-avain|luodut turva-avaimet}} ($1) {{PLURAL:$2|ei|eivät}} ole täysin {{PLURAL:$2|turvallinen|turvallisia}}. Harkitse {{PLURAL:$2|sen|niiden}} muuttamista manuaalisesti.", "config-install-updates": "Estä tarpeettomien päivitysten asennus", "config-install-updates-failed": "Virhe: Päivitysavainten lisääminen taulukoihin epäonnistui seuraavalla virheellä: $1", "config-install-sysop": "Luodaan ylläpitäjän tiliä", diff --git a/includes/installer/i18n/fr.json b/includes/installer/i18n/fr.json index 4bda25cf6e..6259731e34 100644 --- a/includes/installer/i18n/fr.json +++ b/includes/installer/i18n/fr.json @@ -317,7 +317,6 @@ "config-install-interwiki-exists": "'''Attention:''' La table des interwikis semble déjà contenir des entrées.\nLa liste par défaut ne sera pas inscrite.", "config-install-stats": "Initialisation des statistiques", "config-install-keys": "Génération de la clé secrète", - "config-insecure-keys": "'''Avertissement''' : {{PLURAL:$2|Une clé de sécurité générée ($1) pendant l'installation n'est pas complètement sécuritaire. Envisagez de la modifier manuellement.|Des clés de sécurité générées ($1) pendant l'installation ne sont pas complètement sécuritaires. Envisagez de les modifier manuellement.}}", "config-install-updates": "Empêcher l’exécution des mises à jour inutiles", "config-install-updates-failed": "Erreur : L’insertion de clés modifiées dans les tables a échoué avec l’erreur suivante : $1", "config-install-sysop": "Création du compte administrateur", diff --git a/includes/installer/i18n/gl.json b/includes/installer/i18n/gl.json index 7ad449d485..45bb959767 100644 --- a/includes/installer/i18n/gl.json +++ b/includes/installer/i18n/gl.json @@ -295,7 +295,6 @@ "config-install-interwiki-exists": "Atención: Semella que a táboa de interwiki xa contén entradas.\nSaltando a lista por defecto.", "config-install-stats": "Iniciando as estatísticas", "config-install-keys": "Xerando as claves secretas", - "config-insecure-keys": "Atención: {{PLURAL:$2|A clave de seguridade|As claves de seguridade}} ($1) {{PLURAL:$2|xerada|xeradas}} durante a instalación non {{PLURAL:$2|é|son}} completamente {{PLURAL:$2|segura|seguras}}. Considere a posibilidade de {{PLURAL:$2|cambiala|cambialas}} manualmente.", "config-install-updates": "Evitar executar actualizacións innecesarias", "config-install-updates-failed": "Error: a inserción de claves de actualización nas táboas fallou co seguinte erro: $1", "config-install-sysop": "Creando a conta de usuario de administrador", diff --git a/includes/installer/i18n/he.json b/includes/installer/i18n/he.json index 8c4d352d32..bc860d9d1a 100644 --- a/includes/installer/i18n/he.json +++ b/includes/installer/i18n/he.json @@ -295,7 +295,6 @@ "config-install-interwiki-exists": "'''אזהרה:''' נראה שבטבלת הבינוויקי כבר יש רשומות.\nמדלג על הרשומה ההתחלתית.", "config-install-stats": "אתחול סטטיסטיקות", "config-install-keys": "יצירת מפתחות סודיים", - "config-insecure-keys": "'''אזהרה''': {{PLURAL:$2|מפתח|מפתחות}} אבטחה ($1) {{PLURAL:$2|שנוצר|שנוצרו}} במהלך ההתקנה {{PLURAL:$2|אינו בטוח|אינם בטוחים}} מספיק. מומלץ לשקול לשנות {{PLURAL:$2|אותו|אותם}} ידנית.", "config-install-updates": "למנוע הרצת עדכונים מיותרים", "config-install-updates-failed": "שגיאה: הוספת מפתחות עדכון לטבלאות נכשל עם השגיאה הבאה: $1", "config-install-sysop": "יצירת חשבון מפעיל", diff --git a/includes/installer/i18n/hrx.json b/includes/installer/i18n/hrx.json index 2e077b2327..2c357c1ba9 100644 --- a/includes/installer/i18n/hrx.json +++ b/includes/installer/i18n/hrx.json @@ -275,7 +275,6 @@ "config-install-interwiki-exists": "'''Warnung:''' Es woare Interwikitabelle mit Date gefund.\nDie Standardliste weard üwersprung.", "config-install-stats": "Statistike werre initialisiert", "config-install-keys": "Geheimschlüssel werre erstellt", - "config-insecure-keys": "'''Warnung:''' {{PLURAL:$2|Der Geheimschlüssel|Die Geheimschlüssel}} $1, {{PLURAL:$2|der|die}} (während) im Verloof von der Installationsvoargang generiert {{PLURAL:$2|woard, ist|woare, sind}} net seahr sicher. {{PLURAL:$2|Er sollt|Sie sollte}} manuell geännert sin.", "config-install-sysop": "Administratorkonto weard erstellt", "config-install-subscribe-fail": "Abonniere von „mediawiki-announce“ ist gescheitert: $1", "config-install-subscribe-notpossible": "cURL ist net installiert und allow_url_fopen ist niet verfüchbar.", diff --git a/includes/installer/i18n/hu.json b/includes/installer/i18n/hu.json index 10011ba802..d9b6108a04 100644 --- a/includes/installer/i18n/hu.json +++ b/includes/installer/i18n/hu.json @@ -287,7 +287,6 @@ "config-install-interwiki-exists": "'''Figyelmeztetés''': Úgy tűnik, hogy az interwiki táblában már vannak bejegyzések.\nAlapértelmezett lista kihagyása.", "config-install-stats": "Statisztika inicializálása", "config-install-keys": "Titkos kulcsok generálása", - "config-insecure-keys": "'''Figyelmeztetés:''' A telepítés során generált $1 {{PLURAL:$2|biztonsági kulcs|biztonsági kulcsok}} nem teljesen $1 {{PLURAL:$2|biztonságos|biztonságosak}}. Érdemes {{PLURAL:$2||őket}} manuálisan megváltoztatni.", "config-install-updates": "Nem szükséges frissítések futtatásának megakadályozása", "config-install-sysop": "Az adminisztrátor felhasználói fiókjának létrehozása", "config-install-subscribe-fail": "Nem sikerült feliratkozni a mediawiki-announce levelezőlistára: $1", diff --git a/includes/installer/i18n/ia.json b/includes/installer/i18n/ia.json index 9ba487ca5e..e71a6bb37e 100644 --- a/includes/installer/i18n/ia.json +++ b/includes/installer/i18n/ia.json @@ -292,7 +292,6 @@ "config-install-interwiki-exists": "'''Aviso''': Le tabella interwiki pare jam haber entratas.\nLe lista predefinite es saltate.", "config-install-stats": "Initialisation del statisticas", "config-install-keys": "Generation de claves secrete", - "config-insecure-keys": "'''Attention:''' {{PLURAL:$2|Un clave|Alcun claves}} secur ($1) generate durante le installation non es completemente secur. Considera cambiar {{PLURAL:$2|lo|los}} manualmente.", "config-install-updates": "Impedir le execution de actualisationes innecessari", "config-install-updates-failed": "Error: Le insertion de claves de actualisation in le tabellas ha fallite con le error sequente: $1", "config-install-sysop": "Crea conto de usator pro administrator", diff --git a/includes/installer/i18n/id.json b/includes/installer/i18n/id.json index 5cae96561c..eb6f51c7e1 100644 --- a/includes/installer/i18n/id.json +++ b/includes/installer/i18n/id.json @@ -300,7 +300,6 @@ "config-install-interwiki-exists": "'''Peringatan''': Tabel antarwiki tampaknya sudah memiliki entri.\nMengabaikan daftar bawaan.", "config-install-stats": "Inisialisasi statistik", "config-install-keys": "Membuat kunci rahasia", - "config-insecure-keys": "'''Peringatan:''' {{PLURAL:$2|Suatu|Beberapa}} kunci aman ($1) yang dibuat selama instalasi {{PLURAL:$2|tidak|tidak}} benar-benar aman. Pertimbangkan untuk mengubah {{PLURAL:$2|kunci|kunci-kunci}} tersebut secara manual.", "config-install-updates": "Cegah jalannya pembaruan yang tidak dibutuhkan", "config-install-updates-failed": "Kesalahan: Memasukkan kunci pembaruan ke dalam tabel gagal dengan kode kesalahan: $1", "config-install-sysop": "Membuat akun pengguna pengurus", diff --git a/includes/installer/i18n/it.json b/includes/installer/i18n/it.json index 79845cf609..b9b52b62f2 100644 --- a/includes/installer/i18n/it.json +++ b/includes/installer/i18n/it.json @@ -305,7 +305,6 @@ "config-install-interwiki-exists": "'''Attenzione:''' la tabella interwiki sembra che contiene già elementi.\nSalto l'elenco predefinito.", "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", diff --git a/includes/installer/i18n/ja.json b/includes/installer/i18n/ja.json index 8b6a78a1d4..f5e65a5efc 100644 --- a/includes/installer/i18n/ja.json +++ b/includes/installer/i18n/ja.json @@ -311,7 +311,6 @@ "config-install-interwiki-exists": "警告: ウィキ間テーブルは既に登録されているようです。\n既定のテーブルを無視します。", "config-install-stats": "統計情報の初期化", "config-install-keys": "秘密鍵の生成", - "config-insecure-keys": "警告: インストール中に生成されたセキュアキー ($1) は完璧に安全ではありません。手動で変更することを検討してください。", "config-install-updates": "不要な更新を実行するのを防ぐ", "config-install-updates-failed": "エラー: 更新キーをテーブルに挿入する際に失敗しました。以下のエラーが起こっています: $1", "config-install-sysop": "管理者アカウントの作成", diff --git a/includes/installer/i18n/ko.json b/includes/installer/i18n/ko.json index 5e8d4dcda8..e0a9c8ba0e 100644 --- a/includes/installer/i18n/ko.json +++ b/includes/installer/i18n/ko.json @@ -124,8 +124,8 @@ "config-support-info": "미디어위키는 다음의 데이터베이스 시스템을 지원합니다:\n\n$1\n\n데이터베이스 시스템이 표시되지 않을 때 아래에 나열된 다음 지원을 활성화하려면 위의 링크된 지시에 따라 설치해볼 수 있습니다.", "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL]은 미디어위키의 기본 대상이며 가장 잘 지원됩니다. 미디어위키는 또한 MySQL와 호환되는 [{{int:version-db-mariadb-url}} MariaDB]와 [{{int:version-db-percona-url}} Percona 서버]에서도 작동합니다. ([https://secure.php.net/manual/en/mysql.installation.php MySQL 지원으로 PHP를 컴파일하는 방법])", "config-dbsupport-postgres": "* [{{int:version-db-postgres-url}} PostgreSQL]은 MySQL의 대안으로서 인기 있는 오픈 소스 데이터베이스 시스템입니다. ([https://secure.php.net/manual/en/pgsql.installation.php PostgreSQL 지원으로 PHP를 컴파일하는 방법])", - "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite]는 매우 잘 지원되고 가벼운 데이터베이스 시스템입니다. ([http://www.php.net/manual/en/pdo.installation.php SQLite 지원으로 PHP를 컴파일하는 방법], PDO 사용)", - "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle]은 상용 기업 데이터베이스입니다. ([http://www.php.net/manual/en/oci8.installation.php OCI8 지원으로 PHP를 컴파일하는 방법])", + "config-dbsupport-sqlite": "* [{{int:version-db-sqlite-url}} SQLite]는 매우 잘 지원되고 가벼운 데이터베이스 시스템입니다. ([https://secure.php.net/manual/en/pdo.installation.php SQLite 지원으로 PHP를 컴파일하는 방법], PDO 사용)", + "config-dbsupport-oracle": "* [{{int:version-db-oracle-url}} Oracle]은 상용 기업 데이터베이스입니다. ([https://secure.php.net/manual/en/oci8.installation.php OCI8 지원으로 PHP를 컴파일하는 방법])", "config-dbsupport-mssql": "* [{{int:version-db-mssql-url}} Microsoft SQL 서버]는 Windows용 상용 기업 데이터베이스입니다. ([https://secure.php.net/manual/en/sqlsrv.installation.php SQLSRV 지원으로 PHP를 컴파일하는 방법])", "config-header-mysql": "MySQL 설정", "config-header-postgres": "PostgreSQL 설정", @@ -298,7 +298,6 @@ "config-install-interwiki-exists": "경고: 인터위키 테이블이 이미 항목을 갖고 있는 것 같습니다.\n기본 목록을 건너뜁니다.", "config-install-stats": "통계를 초기화하는 중", "config-install-keys": "보안 키를 만드는 중", - "config-insecure-keys": "경고: 설치 중에 생성한 {{PLURAL:$2|보안 키}} ($1)는 완전히 안전하지 {{PLURAL:$2|않습니다}}. 직접 바꾸는 것을 고려하세요.", "config-install-updates": "불필요한 업데이트 실행 방지", "config-install-updates-failed": "오류: 다음 오류로 테이블 안에 업데이트 키를 넣기에 실패했습니다: $1", "config-install-sysop": "관리자 사용자 계정을 만드는 중", diff --git a/includes/installer/i18n/ksh.json b/includes/installer/i18n/ksh.json index 33ccabdfd3..5ac7ec607a 100644 --- a/includes/installer/i18n/ksh.json +++ b/includes/installer/i18n/ksh.json @@ -289,7 +289,6 @@ "config-install-interwiki-exists": "'''Opjepaß''': En der Engewiki-Tabäll schingk alt jät dren ze shtonn.\nDoh dom_mer nix dobei.", "config-install-stats": "De Shtatestek-Zahle wääde op Aanfang jeshtallt.", "config-install-keys": "Jeheime Schlößel wääde opjebout.", - "config-insecure-keys": "'''Opjepaß:''' {{PLURAL:$2|Ene jeheime Schlößel|Jeheim Schlößele|Keine jeheime Schlößel}} ($1) {{PLURAL:$2|es|sin|es}} automattesch aanjelaat woode. {{PLURAL:$2|Dä es|Di sin|Hä es}} ävver nit onbedengk janz sescher. Övverlääsch Der, {{PLURAL:$2|dä|di|en}} norr_ens vun Hand ze ändere.", "config-install-updates": "Donn kein onnühdeje Änderonge maache.", "config-install-updates-failed": "Dä: Schlößßelle för et Ändere en Tabälle bränge es donävve jajange. Jemäldt wood: $1", "config-install-sysop": "Dä Zohjang för der Wiki-Köbes weed aanjelaat.", diff --git a/includes/installer/i18n/lij.json b/includes/installer/i18n/lij.json index 8d05b79613..69821ec428 100644 --- a/includes/installer/i18n/lij.json +++ b/includes/installer/i18n/lij.json @@ -285,7 +285,6 @@ "config-install-interwiki-exists": "'''Atençion:''' pâ che inta tabella interwiki ghe segge za di elementi.\nA lista predefinia a se sata.", "config-install-stats": "Iniçializaçion de statisteghe", "config-install-keys": "Generaçion de ciave segrette", - "config-insecure-keys": "'''Atençion:''' {{PLURAL:$2|Una ciave segûa|De ciave segûe}} ($1) {{PLURAL:$2|generâ|generæ}} durante l'instalaçion {{PLURAL:$2|a|}} no {{PLURAL:$2|l'è|son}} completamente {{PLURAL:$2|segûa|segûe}}. Consciddera de cangiâ{{PLURAL:$2|la|le}} manoalmente.", "config-install-updates": "Impedî l'esecuçion di agiornamenti non necessai", "config-install-updates-failed": "Erô: l'inseimento de ciave de agiornamento inte tabelle o no l'è ariescio pe-o seguente erô: $1", "config-install-sysop": "Creaçion de l'utença pe l'aministratô", diff --git a/includes/installer/i18n/mk.json b/includes/installer/i18n/mk.json index 1e712b0f71..303e82ef15 100644 --- a/includes/installer/i18n/mk.json +++ b/includes/installer/i18n/mk.json @@ -292,7 +292,6 @@ "config-install-interwiki-exists": "'''Предупредување''': Табелата со интервикија веќе содржи ставки.\nГо прескокнувам основно-зададениот список.", "config-install-stats": "Ги подготвувам статистиките", "config-install-keys": "Создавање на тајни клучеви", - "config-insecure-keys": "'''Предупредување:''' {{PLURAL:$2|Безбедносниот клуч $1 создаден во текот на воспоставката не е сосем безбеден|Безбедносните клучеви $1 создадени во текот на воспоставката не се сосем безбедни}}. Ви препорачуваме да {{PLURAL:$2|го|ги}} смените рачно.", "config-install-updates": "Спречи вршење на непотребни поднови", "config-install-updates-failed": "Грешка: Вметнувањето на подновни клучеви во табелите не успеа, со следнава грешка: $1", "config-install-sysop": "Создавање на администраторска корисничка сметка", diff --git a/includes/installer/i18n/ms.json b/includes/installer/i18n/ms.json index 28b497f78c..334d3a00da 100644 --- a/includes/installer/i18n/ms.json +++ b/includes/installer/i18n/ms.json @@ -140,7 +140,6 @@ "config-install-interwiki-list": "Fail interwiki.list tidak dapat dibaca.", "config-install-interwiki-exists": "Amaran: Jadual antara wiki nampaknya sudah ada entri. Senarai asali dilangkau.", "config-install-keys": "Menjana kunci-kunci rahsia", - "config-insecure-keys": "Amaran: {{PLURAL:$2|Kunci keselamatan|Kunci-kunci keselamatan}} ($1) yang dihasilkan sewaktu pemasangan itu {{PLURAL:$2|adalah}} tidak selamat sepenuhnya. Oleh itu, {{PLURAL:$2|ia}} wajar ditukar secara manual.", "config-install-sysop": "Membuka akaun pengguna pentadbir", "config-install-mainpage": "Mewujudkan laman utama dengan kandungan lalai", "config-help": "bantuan", diff --git a/includes/installer/i18n/nap.json b/includes/installer/i18n/nap.json index 2f2ae1e8e3..797742736f 100644 --- a/includes/installer/i18n/nap.json +++ b/includes/installer/i18n/nap.json @@ -284,7 +284,6 @@ "config-install-interwiki-exists": "'''Attenziò:''' 'a tabbella interwiki pare ca cuntenesse già elemente.\nZumpann' 'a lista predefinita.", "config-install-stats": "Inizializzaziona d' 'e statistiche", "config-install-keys": "Generaziona d' 'e chiave segrete", - "config-insecure-keys": "'''Attenziò:''' {{PLURAL:$2|Na chiave sicura|'E chiave sicure}} ($1) {{PLURAL:$2|generata|generate}} pe' tramente ca se fà l'installazione nun {{PLURAL:$2|è|songo}} completamente {{PLURAL:$2|sicura|sicure}}. Cunziderate d' {{PLURAL:$2|'a|'e}} cagnà manualmente.", "config-install-updates": "Mpiccià ll'agghiurnamiente ca nun fossero necessarie", "config-install-updates-failed": "Errore: l'inserimento d' 'e chiave 'agghiurnamiento dint' 'e tabbelle nun è asciuto pecché se cunfermaje l'errore ccà annanze: $1", "config-install-sysop": "Crianno nu cunto utente ammenistratore", diff --git a/includes/installer/i18n/nb.json b/includes/installer/i18n/nb.json index c67d04e9ca..a3d69c9cd8 100644 --- a/includes/installer/i18n/nb.json +++ b/includes/installer/i18n/nb.json @@ -297,7 +297,6 @@ "config-install-interwiki-exists": "Advarsel: Interwiki-tabellen ser allerede ut til å ha innhold.\nLegger derfor ikke inn standardlisten.", "config-install-stats": "Initialiserer statisikk", "config-install-keys": "Genererer hemmelige nøkler", - "config-insecure-keys": "Advarsel: {{PLURAL:$2|En sikker nøkkel|Sikre nøkler}} ($1) generert under installeringen er ikke helt {{PLURAL:$2|trygg|trygge}}. Vurder å endre {{PLURAL:$2|den|dem}} manuelt.", "config-install-updates": "Forhindre unødvendige oppdateringer", "config-install-updates-failed": "Feil: Innsetting av oppdateringsnøkler i tabellene mislyktes med følgende feilmelding: $1", "config-install-sysop": "Oppretter brukerkonto for administrator", diff --git a/includes/installer/i18n/nl.json b/includes/installer/i18n/nl.json index 7bcd391b0b..6011a8b77b 100644 --- a/includes/installer/i18n/nl.json +++ b/includes/installer/i18n/nl.json @@ -309,7 +309,6 @@ "config-install-interwiki-exists": "'''Waarschuwing''': de interwikitabel heeft al inhoud.\nDe standaardlijst wordt overgeslagen.", "config-install-stats": "Statistieken initialiseren", "config-install-keys": "Bezig met aanmaken van geheime sleutels", - "config-insecure-keys": "'''Waarschuwing:''' De {{PLURAL:$2|sleutel die is aangemaakt|sleutels die zijn aangemaakt}} ($1) tijdens de installatie {{PLURAL:$2|is|zijn}} niet volledig veilig. Overweeg deze handmatig te wijzigen.", "config-install-updates": "Voorkomen dat updates onnodig worden uitgevoerd", "config-install-updates-failed": "Fout: het toevoegen van updatesleutels aan tabellen is mislukt met de volgende fout: $1", "config-install-sysop": "Account voor beheerder aanmaken", diff --git a/includes/installer/i18n/pl.json b/includes/installer/i18n/pl.json index d395f831b4..0f70dfbc86 100644 --- a/includes/installer/i18n/pl.json +++ b/includes/installer/i18n/pl.json @@ -309,7 +309,6 @@ "config-install-interwiki-exists": "'''Uwaga''' – wygląda na to, że tabela interwiki ma już jakieś wpisy.\nTworzenie domyślnej listy pominięto.", "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-updates-failed": "Błąd: Wstawianie kluczy aktualizacji d0 tabeli nie powiodło się z powodu następującego błędu: $1", "config-install-sysop": "Tworzenie konta administratora", diff --git a/includes/installer/i18n/pms.json b/includes/installer/i18n/pms.json index bcdf1a77d2..a06e0443e1 100644 --- a/includes/installer/i18n/pms.json +++ b/includes/installer/i18n/pms.json @@ -267,7 +267,6 @@ "config-install-interwiki-exists": "'''Avis''': La tàula interwiki a smija ch'a l'abia già dj'element.\nPër stàndard, la lista a sarà sautà.", "config-install-stats": "Inissialisassion dle statìstiche", "config-install-keys": "Generassion ëd le ciav segrete", - "config-insecure-keys": "'''Avis:''' {{PLURAL:$2|Na ciav sigura|Dle ciav sigure}} ($1) generà durant l'istalassion {{PLURAL:$2|a l'é|a son}} pa completament sigure. Ch'a consìdera ëd modifiche{{PLURAL:$2|la|je}} manualment.", "config-install-sysop": "Creassion dël cont ëd l'utent aministrator", "config-install-subscribe-fail": "As peul pa sot-scrivse mediawiki-announce: $1", "config-install-subscribe-notpossible": "cURL a l'é pa istalà e allow_url_fopen a l'é pa disponìbil.", diff --git a/includes/installer/i18n/pt-br.json b/includes/installer/i18n/pt-br.json index 60898d9bb0..e0216b36d0 100644 --- a/includes/installer/i18n/pt-br.json +++ b/includes/installer/i18n/pt-br.json @@ -310,7 +310,6 @@ "config-install-interwiki-exists": "Aviso: A tabela de interwiki parece já ter entradas.\\NPulando lista padrão.", "config-install-stats": "Inicializando estatísticas", "config-install-keys": "Gerando senhas secretas", - "config-insecure-keys": "Aviso: {{PLURAL:$2|Uma chave segura gerada|Algumas chaves seguras geradas}} ($1) durante a instalação {{PLURAL:$2|não é completamente segura|não são completamente seguras}}. Considere mudar {{PLURAL:$2|ela|elas}} manualmente.", "config-install-updates": "Impedir a execução de atualizações desnecessárias", "config-install-updates-failed": "Error: A inserção de chaves de atualização em tabelas falhou com o seguinte erro: $1", "config-install-sysop": "Criando conta de usuário administrador", diff --git a/includes/installer/i18n/pt.json b/includes/installer/i18n/pt.json index 9593ebe97f..c1fc5d8263 100644 --- a/includes/installer/i18n/pt.json +++ b/includes/installer/i18n/pt.json @@ -308,7 +308,6 @@ "config-install-interwiki-exists": "Aviso: A tabela de interwikis parece já conter entradas.\nO preenchimento padrão desta tabela será saltado.", "config-install-stats": "A inicializar as estatísticas", "config-install-keys": "A gerar as chaves secretas", - "config-insecure-keys": "Aviso: {{PLURAL:$2|Uma chave segura|Chaves seguras}} ($1) {{PLURAL:$2|gerada durante a instalação não é completamente segura|geradas durante a instalação não são completamente seguras}}. Considere a possibilidade de {{PLURAL:$2|alterá-la|alterá-las}} manualmente.", "config-install-updates": "Evitar executar atualizações desnecessárias", "config-install-updates-failed": "Erro: A inserção de chaves de atualização nas tabelas falhou com o seguinte erro: $1", "config-install-sysop": "A criar a conta de administrador", diff --git a/includes/installer/i18n/qqq.json b/includes/installer/i18n/qqq.json index 0779204613..d9edde5d13 100644 --- a/includes/installer/i18n/qqq.json +++ b/includes/installer/i18n/qqq.json @@ -308,7 +308,6 @@ "config-install-interwiki-exists": "Error notice during the installation saying that one of the database tables is already set up, so it's continuing without taking that step.", "config-install-stats": "*{{msg-mw|Config-install-database}}\n*{{msg-mw|Config-install-tables}}\n*{{msg-mw|Config-install-schema}}\n*{{msg-mw|Config-install-user}}\n*{{msg-mw|Config-install-interwiki}}\n*{{msg-mw|Config-install-stats}}\n*{{msg-mw|Config-install-keys}}\n*{{msg-mw|Config-install-sysop}}\n*{{msg-mw|Config-install-mainpage}}", "config-install-keys": "*{{msg-mw|Config-install-database}}\n*{{msg-mw|Config-install-tables}}\n*{{msg-mw|Config-install-schema}}\n*{{msg-mw|Config-install-user}}\n*{{msg-mw|Config-install-interwiki}}\n*{{msg-mw|Config-install-stats}}\n*{{msg-mw|Config-install-keys}}\n*{{msg-mw|Config-install-sysop}}\n*{{msg-mw|Config-install-mainpage}}", - "config-insecure-keys": "Parameters:\n* $1 - A list of names of the secret keys that were generated.\n* $2 - the number of items in the list $1, to be used with PLURAL.", "config-install-updates": "Message indicating that the updatelog table is filled with keys of updates that won't be run when running database updates.\n\nSee also:\n*{{msg-mw|Config-install-database}}\n*{{msg-mw|Config-install-tables}}\n*{{msg-mw|Config-install-interwiki}}\n*{{msg-mw|Config-install-stats}}\n*{{msg-mw|Config-install-keys}}\n*{{msg-mw|Config-install-updates}}\n*{{msg-mw|Config-install-schema}}\n*{{msg-mw|Config-install-user}}\n*{{msg-mw|Config-install-sysop}}\n*{{msg-mw|Config-install-mainpage}}", "config-install-updates-failed": "Used as error message. Parameters:\n* $1 - detailed error message", "config-install-sysop": "Message indicates that the administrator user account is being created\n\nSee also:\n*{{msg-mw|Config-install-database}}\n*{{msg-mw|Config-install-tables}}\n*{{msg-mw|Config-install-schema}}\n*{{msg-mw|Config-install-user}}\n*{{msg-mw|Config-install-interwiki}}\n*{{msg-mw|Config-install-stats}}\n*{{msg-mw|Config-install-keys}}\n*{{msg-mw|Config-install-sysop}}\n*{{msg-mw|Config-install-mainpage}}", diff --git a/includes/installer/i18n/ru.json b/includes/installer/i18n/ru.json index aeda43a719..ef38b51231 100644 --- a/includes/installer/i18n/ru.json +++ b/includes/installer/i18n/ru.json @@ -313,7 +313,6 @@ "config-install-interwiki-exists": "'''Предупреждение''': в интервики-таблице, кажется, уже есть записи.\nСоздание стандартного списка пропущено.", "config-install-stats": "Статистика инициализации", "config-install-keys": "Создание секретных ключей", - "config-insecure-keys": "'''Предупреждение.''' {{PLURAL:$2|1=Ключ безопасности $1, созданный во время установки, недостаточно надёжен|Ключи безопасности $1, созданные во время установки, недостаточно надёжны}}. Рассмотрите возможность {{PLURAL:$2|1=его|их}} изменения вручную.", "config-install-updates": "Предотвращение запуска ненужных обновлений", "config-install-updates-failed": "Ошибка: Вставка ключей обновления в таблицы завершилась со следующей ошибкой: $1", "config-install-sysop": "Создание учётной записи администратора", diff --git a/includes/installer/i18n/sco.json b/includes/installer/i18n/sco.json index 5b60540346..b489ca34d0 100644 --- a/includes/installer/i18n/sco.json +++ b/includes/installer/i18n/sco.json @@ -286,7 +286,6 @@ "config-install-interwiki-exists": "Warnishment: The interwiki buird awreadie seems tae hae entries.\nSkippin defaut let.", "config-install-stats": "Ineetializin stateestics", "config-install-keys": "Generatin hidlins keys", - "config-insecure-keys": "Warnishment: {{PLURAL:$2|Ae secure key|Secure keys}} ($1) generated durin instawation {{PLURAL:$2|is|ar}} naw compleatelie safe. Consider chyngin {{PLURAL:$2|it|theim}} manuallie.", "config-install-updates": "Hinder the runnin o onneedit updates.", "config-install-updates-failed": "Mistak: Insertin update keys intae the buirds failed wi the folleain mistak: $1", "config-install-sysop": "Makin admeenistrâter uiser accoont", diff --git a/includes/installer/i18n/sv.json b/includes/installer/i18n/sv.json index a691824e1b..c0ae4f0cf2 100644 --- a/includes/installer/i18n/sv.json +++ b/includes/installer/i18n/sv.json @@ -294,7 +294,6 @@ "config-install-interwiki-exists": "Varning: Interwiki-tabellen verkar redan innehålla poster.\nHoppar över standardlistan.", "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", diff --git a/includes/installer/i18n/tl.json b/includes/installer/i18n/tl.json index 6298cb7bf9..0249bae527 100644 --- a/includes/installer/i18n/tl.json +++ b/includes/installer/i18n/tl.json @@ -272,7 +272,6 @@ "config-install-interwiki-exists": "'''Babala''': Tila may mga laman na ang talahanayan ng interwiki.\nNilalaktawan ang likas na nakatakdang talaan.", "config-install-stats": "Sinisimulan ang estadistika", "config-install-keys": "Ginagawa ang lihim na mga susi", - "config-insecure-keys": "'''Babala:''' Nalikha ang {{PLURAL:$2|A secure key|ligtas na mga susi}} ($1) habang ang pagluluklok {{PLURAL:$2|ay|ay}} hindi pa lubos na ligtas. Isaalang-alang ang kinakamay na pagbago {{PLURAL:$2|nito|ng mga ito}}.", "config-install-sysop": "Nililikha ang account ng tagagamit na tagapangasiwa", "config-install-subscribe-fail": "Hindi nagawang magpasipi mula sa mediawiki-announce: $1", "config-install-subscribe-notpossible": "Hindi nakalagak ang cURL at hindi makukuha ang allow_url_fopen", diff --git a/includes/installer/i18n/uk.json b/includes/installer/i18n/uk.json index b1e69df8ae..a40bf1bbc3 100644 --- a/includes/installer/i18n/uk.json +++ b/includes/installer/i18n/uk.json @@ -298,7 +298,6 @@ "config-install-interwiki-exists": "'''Увага''': Таблиця інтервікі уже, здається, має записи.\nСтворення стандартного списку пропускається.", "config-install-stats": "Ініціалізація статистики", "config-install-keys": "Генерація секретних ключів", - "config-insecure-keys": "'''Увага:''' {{PLURAL:$2|1=Секретний ключ|Секретні ключі}} ($1), {{PLURAL:$2|1=згенерований в процесі встановлення, недостатньо надійний|згенеровані в процесі встановлення, недостатньо надійні}}. Розгляньте можливість {{PLURAL:$2|1=його|їх}} заміни вручну.", "config-install-updates": "Запобігти запуску непотрібних оновлень", "config-install-updates-failed": "Помилка: Вставка оновленних ключів в таблиці не вдалося через таку помилку:$1", "config-install-sysop": "Створення облікового запису адміністратора", diff --git a/includes/installer/i18n/vi.json b/includes/installer/i18n/vi.json index 0ecd6889e1..d69a260b12 100644 --- a/includes/installer/i18n/vi.json +++ b/includes/installer/i18n/vi.json @@ -292,7 +292,6 @@ "config-install-interwiki-exists": "'''Cảnh báo:''' Hình như đã có mục trong bảng liên wiki.\nĐã bỏ qua danh sách mặc định.", "config-install-stats": "Đang khởi tạo các thống kê", "config-install-keys": "Tạo ra các chìa khóa bí mật", - "config-insecure-keys": "Cảnh báo: {{PLURAL:$2|Một khóa an toàn|Khóa an toàn}} ($1) được tạo ra trong quá trình cài đặt {{PLURAL:$2}}không phải an toàn hẳn. Hãy cân nhắc việc thay đổi {{PLURAL:$2|nó|chúng}} thủ công.", "config-install-updates": "Tránh các cập nhật không cần thiết", "config-install-updates-failed": "Lỗi: Chèn phím cập nhật vào các bảng không thành công với các lỗi sau:1$", "config-install-sysop": "Đang mở tài khoản người dùng bảo quản viên", diff --git a/includes/installer/i18n/zh-hans.json b/includes/installer/i18n/zh-hans.json index d22c56658c..c46478da65 100644 --- a/includes/installer/i18n/zh-hans.json +++ b/includes/installer/i18n/zh-hans.json @@ -307,7 +307,6 @@ "config-install-interwiki-exists": "警告:跨wiki数据表似乎已有内容,跳过默认列表。", "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": "正在创建管理员用户帐号", diff --git a/includes/installer/i18n/zh-hant.json b/includes/installer/i18n/zh-hant.json index a54f66bd74..4854877b28 100644 --- a/includes/installer/i18n/zh-hant.json +++ b/includes/installer/i18n/zh-hant.json @@ -306,7 +306,6 @@ "config-install-interwiki-exists": "警告: interwiki 資料表內已有資料,略過建立預設資料。", "config-install-stats": "初始化統計資訊", "config-install-keys": "產生秘密金鑰中", - "config-insecure-keys": "警告:在安裝過程中所產生的 $2 組安全金鑰($1)並不完全安全。請考慮手動更改。", "config-install-updates": "略過執行不需要的更新", "config-install-updates-failed": "錯誤: 插入更新鍵值至資料表失敗,並出現以下錯誤:$1", "config-install-sysop": "正在建立管理員使用者帳號", diff --git a/includes/json/FormatJson.php b/includes/json/FormatJson.php index b99b0b826c..1ab17a06f5 100644 --- a/includes/json/FormatJson.php +++ b/includes/json/FormatJson.php @@ -38,7 +38,7 @@ class FormatJson { * HTML and XML. * * @warning Do not use this option for JSON that could end up in inline scripts. - * - HTML5, §4.3.1.2 Restrictions for contents of script elements + * - HTML 5.2, §4.12.1.3 Restrictions for contents of script elements * - XML 1.0 (5th Ed.), §2.4 Character Data and Markup * * @since 1.22 @@ -52,19 +52,18 @@ class FormatJson { * * @since 1.22 */ - const ALL_OK = 3; + const ALL_OK = self::UTF8_OK | self::XMLMETA_OK; /** - * If set, treat json objects '{...}' as associative arrays. Without this option, - * json objects will be converted to stdClass. - * The value is set to 1 to be backward compatible with 'true' that was used before. + * If set, treat JSON objects '{...}' as associative arrays. Without this option, + * JSON objects will be converted to stdClass. * * @since 1.24 */ const FORCE_ASSOC = 0x100; /** - * If set, attempts to fix invalid json. + * If set, attempt to fix invalid JSON. * * @since 1.24 */ @@ -130,18 +129,16 @@ class FormatJson { return false; } - if ( $pretty !== false ) { - if ( $pretty !== ' ' ) { - // Change the four-space indent to a tab indent - $json = str_replace( "\n ", "\n\t", $json ); - while ( strpos( $json, "\t " ) !== false ) { - $json = str_replace( "\t ", "\t\t", $json ); - } + if ( $pretty !== false && $pretty !== ' ' ) { + // Change the four-space indent to a tab indent + $json = str_replace( "\n ", "\n\t", $json ); + while ( strpos( $json, "\t " ) !== false ) { + $json = str_replace( "\t ", "\t\t", $json ); + } - if ( $pretty !== "\t" ) { - // Change the tab indent to the provided indent - $json = str_replace( "\t", $pretty, $json ); - } + if ( $pretty !== "\t" ) { + // Change the tab indent to the provided indent + $json = str_replace( "\t", $pretty, $json ); } } if ( $escaping & self::UTF8_OK ) { @@ -243,7 +240,7 @@ class FormatJson { /** * Remove multiline and single line comments from an otherwise valid JSON - * input string. This can be used as a preprocessor for to allow JSON + * input string. This can be used as a preprocessor, to allow JSON * formatted configuration files to contain comments. * * @param string $json diff --git a/includes/libs/ArrayUtils.php b/includes/libs/ArrayUtils.php index 0413ea0d5a..e23888779f 100644 --- a/includes/libs/ArrayUtils.php +++ b/includes/libs/ArrayUtils.php @@ -120,8 +120,8 @@ class ArrayUtils { $max = $valueCount; do { $mid = $min + ( ( $max - $min ) >> 1 ); - $item = call_user_func( $valueCallback, $mid ); - $comparison = call_user_func( $comparisonCallback, $target, $item ); + $item = $valueCallback( $mid ); + $comparison = $comparisonCallback( $target, $item ); if ( $comparison > 0 ) { $min = $mid; } elseif ( $comparison == 0 ) { @@ -133,8 +133,8 @@ class ArrayUtils { } while ( $min < $max - 1 ); if ( $min == 0 ) { - $item = call_user_func( $valueCallback, $min ); - $comparison = call_user_func( $comparisonCallback, $target, $item ); + $item = $valueCallback( $min ); + $comparison = $comparisonCallback( $target, $item ); if ( $comparison < 0 ) { // Before the first item return false; @@ -168,7 +168,7 @@ class ArrayUtils { $args[] = $array[$key]; } } - $valueret = call_user_func_array( __METHOD__, $args ); + $valueret = self::arrayDiffAssocRecursive( ...$args ); if ( count( $valueret ) ) { $ret[$key] = $valueret; } diff --git a/includes/libs/CryptHKDF.php b/includes/libs/CryptHKDF.php index c41aab339c..0478a33700 100644 --- a/includes/libs/CryptHKDF.php +++ b/includes/libs/CryptHKDF.php @@ -99,22 +99,14 @@ class CryptHKDF { 'whirlpool' => 64, ]; - /** - * @var CryptRand - */ - private $cryptRand; - /** * @param string $secretKeyMaterial * @param string $algorithm Name of hashing algorithm * @param BagOStuff $cache * @param string|array $context Context to mix into HKDF context - * @param CryptRand $cryptRand * @throws InvalidArgumentException if secret key material is too short */ - public function __construct( $secretKeyMaterial, $algorithm, BagOStuff $cache, $context, - CryptRand $cryptRand - ) { + public function __construct( $secretKeyMaterial, $algorithm, BagOStuff $cache, $context ) { if ( strlen( $secretKeyMaterial ) < 16 ) { throw new InvalidArgumentException( "secret was too short." ); } @@ -122,7 +114,6 @@ class CryptHKDF { $this->algorithm = $algorithm; $this->cache = $cache; $this->context = is_array( $context ) ? $context : [ $context ]; - $this->cryptRand = $cryptRand; // To prevent every call from hitting the same memcache server, pick // from a set of keys to use. mt_rand is only use to pick a random @@ -150,12 +141,12 @@ class CryptHKDF { $lastSalt = $this->cache->get( $this->cacheKey ); if ( $lastSalt === false ) { // If we don't have a previous value to use as our salt, we use - // 16 bytes from CryptRand, which will use a small amount of + // 16 bytes from random_bytes(), which will use a small amount of // entropy from our pool. Note, "XTR may be deterministic or keyed // via an optional “salt value” (i.e., a non-secret random // value)..." - http://eprint.iacr.org/2010/264.pdf. However, we // use a strongly random value since we can. - $lastSalt = $this->cryptRand->generate( 16 ); + $lastSalt = random_bytes( 16 ); } // Get a binary string that is hashLen long $this->salt = hash( $this->algorithm, $lastSalt, true ); diff --git a/includes/libs/CryptRand.php b/includes/libs/CryptRand.php index f7702dd3ac..a1bbd099c4 100644 --- a/includes/libs/CryptRand.php +++ b/includes/libs/CryptRand.php @@ -23,187 +23,54 @@ * @author Daniel Friesen * @file */ -use Psr\Log\LoggerInterface; +/** + * @deprecated since 1.32, use random_bytes()/random_int() + */ class CryptRand { /** - * Minimum number of iterations we want to make in our drift calculations. + * @deprecated since 1.32, unused */ const MIN_ITERATIONS = 1000; /** - * Number of milliseconds we want to spend generating each separate byte - * of the final generated bytes. - * This is used in combination with the hash length to determine the duration - * we should spend doing drift calculations. + * @deprecated since 1.32, unused */ const MSEC_PER_BYTE = 0.5; /** - * A boolean indicating whether the previous random generation was done using - * cryptographically strong random number generator or not. - */ - protected $strong = null; - - /** - * List of functions to call to generate some random state + * Initialize an initial random state based off of whatever we can find * - * @var callable[] - */ - protected $randomFuncs = []; - - /** - * List of files to generate some random state from + * @deprecated since 1.32, unused and does nothing * - * @var string[] - */ - protected $randomFiles = []; - - /** - * @var LoggerInterface - */ - protected $logger; - - public function __construct( array $randomFuncs, array $randomFiles, LoggerInterface $logger ) { - $this->randomFuncs = $randomFuncs; - $this->randomFiles = $randomFiles; - $this->logger = $logger; - } - - /** - * Initialize an initial random state based off of whatever we can find * @return string */ protected function initialRandomState() { - // $_SERVER contains a variety of unstable user and system specific information - // It'll vary a little with each page, and vary even more with separate users - // It'll also vary slightly across different machines - $state = serialize( $_SERVER ); - - // Try to gather a little entropy from the different php rand sources - $state .= rand() . uniqid( mt_rand(), true ); - - // Include some information about the filesystem's current state in the random state - $files = $this->randomFiles; - - // We know this file is here so grab some info about ourselves - $files[] = __FILE__; - - // We must also have a parent folder, and with the usual file structure, a grandparent - $files[] = __DIR__; - $files[] = dirname( __DIR__ ); - - foreach ( $files as $file ) { - Wikimedia\suppressWarnings(); - $stat = stat( $file ); - Wikimedia\restoreWarnings(); - if ( $stat ) { - // stat() duplicates data into numeric and string keys so kill off all the numeric ones - foreach ( $stat as $k => $v ) { - if ( is_numeric( $k ) ) { - unset( $k ); - } - } - // The absolute filename itself will differ from install to install so don't leave it out - $path = realpath( $file ); - if ( $path !== false ) { - $state .= $path; - } else { - $state .= $file; - } - $state .= implode( '', $stat ); - } else { - // The fact that the file isn't there is worth at least a - // minuscule amount of entropy. - $state .= '0'; - } - } - - // Try and make this a little more unstable by including the varying process - // id of the php process we are running inside of if we are able to access it - if ( function_exists( 'getmypid' ) ) { - $state .= getmypid(); - } - - // If available try to increase the instability of the data by throwing in - // the precise amount of memory that we happen to be using at the moment. - if ( function_exists( 'memory_get_usage' ) ) { - $state .= memory_get_usage( true ); - } - - foreach ( $this->randomFuncs as $randomFunc ) { - $state .= call_user_func( $randomFunc ); - } - - return $state; + return ''; } /** * Randomly hash data while mixing in clock drift data for randomness * + * @deprecated since 1.32, unused and does nothing + * * @param string $data The data to randomly hash. * @return string The hashed bytes * @author Tim Starling */ protected function driftHash( $data ) { - // Minimum number of iterations (to avoid slow operations causing the - // loop to gather little entropy) - $minIterations = self::MIN_ITERATIONS; - // Duration of time to spend doing calculations (in seconds) - $duration = ( self::MSEC_PER_BYTE / 1000 ) * MWCryptHash::hashLength(); - // Create a buffer to use to trigger memory operations - $bufLength = 10000000; - $buffer = str_repeat( ' ', $bufLength ); - $bufPos = 0; - - // Iterate for $duration seconds or at least $minIterations number of iterations - $iterations = 0; - $startTime = microtime( true ); - $currentTime = $startTime; - while ( $iterations < $minIterations || $currentTime - $startTime < $duration ) { - // Trigger some memory writing to trigger some bus activity - // This may create variance in the time between iterations - $bufPos = ( $bufPos + 13 ) % $bufLength; - $buffer[$bufPos] = ' '; - // Add the drift between this iteration and the last in as entropy - $nextTime = microtime( true ); - $delta = (int)( ( $nextTime - $currentTime ) * 1000000 ); - $data .= $delta; - // Every 100 iterations hash the data and entropy - if ( $iterations % 100 === 0 ) { - $data = sha1( $data ); - } - $currentTime = $nextTime; - $iterations++; - } - $timeTaken = $currentTime - $startTime; - $data = MWCryptHash::hash( $data ); - - $this->logger->debug( "Clock drift calculation " . - "(time-taken=" . ( $timeTaken * 1000 ) . "ms, " . - "iterations=$iterations, " . - "time-per-iteration=" . ( $timeTaken / $iterations * 1e6 ) . "us)" ); - - return $data; + return ''; } /** * Return a rolling random state initially build using data from unstable sources + * + * @deprecated since 1.32, unused and does nothing + * * @return string A new weak random state */ protected function randomState() { - static $state = null; - if ( is_null( $state ) ) { - // Initialize the state with whatever unstable data we can find - // It's important that this data is hashed right afterwards to prevent - // it from being leaked into the output stream - $state = MWCryptHash::hash( $this->initialRandomState() ); - } - // Generate a new random state based on the initial random state or previous - // random state by combining it with clock drift - $state = $this->driftHash( $state ); - - return $state; + return ''; } /** @@ -211,191 +78,36 @@ class CryptRand { * random bytes generation in the previously run generate* call * was cryptographically strong. * - * @return bool Returns true if the source was strong, false if not. + * @deprecated since 1.32, always returns true + * + * @return bool Always true */ public function wasStrong() { - if ( is_null( $this->strong ) ) { - throw new RuntimeException( __METHOD__ . ' called before generation of random data' ); - } - - return $this->strong; + return true; } /** - * Generate a run of (ideally) cryptographically random data and return + * Generate a run of cryptographically random data and return * it in raw binary form. * You can use CryptRand::wasStrong() if you wish to know if the source used * was cryptographically strong. * * @param int $bytes The number of bytes of random data to generate - * @param bool $forceStrong Pass true if you want generate to prefer cryptographically - * strong sources of entropy even if reading from them may steal - * more entropy from the system than optimal. * @return string Raw binary random data */ - public function generate( $bytes, $forceStrong = false ) { + public function generate( $bytes ) { $bytes = floor( $bytes ); - static $buffer = ''; - if ( is_null( $this->strong ) ) { - // Set strength to false initially until we know what source data is coming from - $this->strong = true; - } - - if ( strlen( $buffer ) < $bytes ) { - // If available make use of PHP 7's random_bytes - // On Linux, getrandom syscall will be used if available. - // On Windows CryptGenRandom will always be used - // On other platforms, /dev/urandom will be used. - // Avoids polyfills from before php 7.0 - // All error situations will throw Exceptions and or Errors - if ( PHP_VERSION_ID >= 70000 - || ( defined( 'HHVM_VERSION_ID' ) && HHVM_VERSION_ID >= 31101 ) - ) { - $rem = $bytes - strlen( $buffer ); - $buffer .= random_bytes( $rem ); - } - if ( strlen( $buffer ) >= $bytes ) { - $this->strong = true; - } - } - - if ( strlen( $buffer ) < $bytes && function_exists( 'mcrypt_create_iv' ) ) { - // If available make use of mcrypt_create_iv URANDOM source to generate randomness - // On unix-like systems this reads from /dev/urandom but does it without any buffering - // and bypasses openbasedir restrictions, so it's preferable to reading directly - // On Windows starting in PHP 5.3.0 Windows' native CryptGenRandom is used to generate - // entropy so this is also preferable to just trying to read urandom because it may work - // on Windows systems as well. - $rem = $bytes - strlen( $buffer ); - $iv = mcrypt_create_iv( $rem, MCRYPT_DEV_URANDOM ); - if ( $iv === false ) { - $this->logger->debug( "mcrypt_create_iv returned false." ); - } else { - $buffer .= $iv; - $this->logger->debug( "mcrypt_create_iv generated " . strlen( $iv ) . - " bytes of randomness." ); - } - } - - if ( strlen( $buffer ) < $bytes && function_exists( 'openssl_random_pseudo_bytes' ) ) { - $rem = $bytes - strlen( $buffer ); - $openssl_strong = false; - $openssl_bytes = openssl_random_pseudo_bytes( $rem, $openssl_strong ); - if ( $openssl_bytes === false ) { - $this->logger->debug( "openssl_random_pseudo_bytes returned false." ); - } else { - $buffer .= $openssl_bytes; - $this->logger->debug( "openssl_random_pseudo_bytes generated " . - strlen( $openssl_bytes ) . " bytes of " . - ( $openssl_strong ? "strong" : "weak" ) . " randomness." ); - } - if ( strlen( $buffer ) >= $bytes ) { - // openssl tells us if the random source was strong, if some of our data was generated - // using it use it's say on whether the randomness is strong - $this->strong = !!$openssl_strong; - } - } - - // Only read from urandom if we can control the buffer size or were passed forceStrong - if ( strlen( $buffer ) < $bytes && - ( function_exists( 'stream_set_read_buffer' ) || $forceStrong ) - ) { - $rem = $bytes - strlen( $buffer ); - if ( !function_exists( 'stream_set_read_buffer' ) && $forceStrong ) { - $this->logger->debug( "Was forced to read from /dev/urandom " . - "without control over the buffer size." ); - } - // /dev/urandom is generally considered the best possible commonly - // available random source, and is available on most *nix systems. - Wikimedia\suppressWarnings(); - $urandom = fopen( "/dev/urandom", "rb" ); - Wikimedia\restoreWarnings(); - - // Attempt to read all our random data from urandom - // php's fread always does buffered reads based on the stream's chunk_size - // so in reality it will usually read more than the amount of data we're - // asked for and not storing that risks depleting the system's random pool. - // If stream_set_read_buffer is available set the chunk_size to the amount - // of data we need. Otherwise read 8k, php's default chunk_size. - if ( $urandom ) { - // php's default chunk_size is 8k - $chunk_size = 1024 * 8; - if ( function_exists( 'stream_set_read_buffer' ) ) { - // If possible set the chunk_size to the amount of data we need - stream_set_read_buffer( $urandom, $rem ); - $chunk_size = $rem; - } - $random_bytes = fread( $urandom, max( $chunk_size, $rem ) ); - $buffer .= $random_bytes; - fclose( $urandom ); - $this->logger->debug( "/dev/urandom generated " . strlen( $random_bytes ) . - " bytes of randomness." ); - - if ( strlen( $buffer ) >= $bytes ) { - // urandom is always strong, set to true if all our data was generated using it - $this->strong = true; - } - } else { - $this->logger->debug( "/dev/urandom could not be opened." ); - } - } - - // If we cannot use or generate enough data from a secure source - // use this loop to generate a good set of pseudo random data. - // This works by initializing a random state using a pile of unstable data - // and continually shoving it through a hash along with a variable salt. - // We hash the random state with more salt to avoid the state from leaking - // out and being used to predict the /randomness/ that follows. - if ( strlen( $buffer ) < $bytes ) { - $this->logger->debug( __METHOD__ . - ": Falling back to using a pseudo random state to generate randomness." ); - } - while ( strlen( $buffer ) < $bytes ) { - $buffer .= MWCryptHash::hmac( $this->randomState(), strval( mt_rand() ) ); - // This code is never really cryptographically strong, if we use it - // at all, then set strong to false. - $this->strong = false; - } - - // Once the buffer has been filled up with enough random data to fulfill - // the request shift off enough data to handle the request and leave the - // unused portion left inside the buffer for the next request for random data - $generated = substr( $buffer, 0, $bytes ); - $buffer = substr( $buffer, $bytes ); - - $this->logger->debug( strlen( $buffer ) . - " bytes of randomness leftover in the buffer." ); - - return $generated; + return random_bytes( $bytes ); } /** - * Generate a run of (ideally) cryptographically random data and return + * Generate a run of cryptographically random data and return * it in hexadecimal string format. - * You can use CryptRand::wasStrong() if you wish to know if the source used - * was cryptographically strong. * * @param int $chars The number of hex chars of random data to generate - * @param bool $forceStrong Pass true if you want generate to prefer cryptographically - * strong sources of entropy even if reading from them may steal - * more entropy from the system than optimal. * @return string Hexadecimal random data */ - public function generateHex( $chars, $forceStrong = false ) { - // hex strings are 2x the length of raw binary so we divide the length in half - // odd numbers will result in a .5 that leads the generate() being 1 character - // short, so we use ceil() to ensure that we always have enough bytes - $bytes = ceil( $chars / 2 ); - // Generate the data and then convert it to a hex string - $hex = bin2hex( $this->generate( $bytes, $forceStrong ) ); - - // A bit of paranoia here, the caller asked for a specific length of string - // here, and it's possible (eg when given an odd number) that we may actually - // have at least 1 char more than they asked for. Just in case they made this - // call intending to insert it into a database that does truncation we don't - // want to give them too much and end up with their database and their live - // code having two different values because part of what we gave them is truncated - // hence, we strip out any run of characters longer than what we were asked for. - return substr( $hex, 0, $chars ); + public function generateHex( $chars ) { + return MWCryptRand::generateHex( $chars ); } } diff --git a/includes/libs/MemoizedCallable.php b/includes/libs/MemoizedCallable.php index 14462f1d9f..e9d1fc1ca3 100644 --- a/includes/libs/MemoizedCallable.php +++ b/includes/libs/MemoizedCallable.php @@ -123,7 +123,7 @@ class MemoizedCallable { $success = false; $result = $this->fetchResult( $key, $success ); if ( !$success ) { - $result = call_user_func_array( $this->callable, $args ); + $result = ( $this->callable )( ...$args ); $this->storeResult( $key, $result ); } diff --git a/includes/libs/StatusValue.php b/includes/libs/StatusValue.php index 6f348c2b96..3bdafe1282 100644 --- a/includes/libs/StatusValue.php +++ b/includes/libs/StatusValue.php @@ -68,7 +68,7 @@ class StatusValue { public static function newFatal( $message /*, parameters...*/ ) { $params = func_get_args(); $result = new static(); - call_user_func_array( [ &$result, 'fatal' ], $params ); + $result->fatal( ...$params ); return $result; } diff --git a/includes/libs/StringUtils.php b/includes/libs/StringUtils.php index 7915ccf191..d91ac85adb 100644 --- a/includes/libs/StringUtils.php +++ b/includes/libs/StringUtils.php @@ -206,7 +206,7 @@ class StringUtils { } elseif ( $tokenType == 'end' ) { if ( $foundStart ) { # Found match - $output .= call_user_func( $callback, [ + $output .= $callback( [ substr( $subject, $outputPos, $tokenOffset + $tokenLength - $outputPos ), substr( $subject, $contentPos, $tokenOffset - $contentPos ) ] ); diff --git a/includes/libs/filebackend/FileBackend.php b/includes/libs/filebackend/FileBackend.php index 2d4a772b7e..785cb72655 100644 --- a/includes/libs/filebackend/FileBackend.php +++ b/includes/libs/filebackend/FileBackend.php @@ -1590,7 +1590,7 @@ abstract class FileBackend implements LoggerAwareInterface { final protected function newStatus() { $args = func_get_args(); if ( count( $args ) ) { - $sv = call_user_func_array( [ StatusValue::class, 'newFatal' ], $args ); + $sv = StatusValue::newFatal( ...$args ); } else { $sv = StatusValue::newGood(); } diff --git a/includes/libs/filebackend/SwiftFileBackend.php b/includes/libs/filebackend/SwiftFileBackend.php index 3cd973ea48..2f7bc1ef8f 100644 --- a/includes/libs/filebackend/SwiftFileBackend.php +++ b/includes/libs/filebackend/SwiftFileBackend.php @@ -1103,7 +1103,7 @@ class SwiftFileBackend extends FileBackendStore { if ( empty( $params['allowOB'] ) ) { // Cancel output buffering and gzipping if set - call_user_func( $this->obResetFunc ); + ( $this->obResetFunc )(); } $handle = fopen( 'php://output', 'wb' ); @@ -1317,7 +1317,7 @@ class SwiftFileBackend extends FileBackendStore { foreach ( $httpReqs as $index => $httpReq ) { // Run the callback for each request of this operation $callback = $fileOpHandles[$index]->callback; - call_user_func_array( $callback, [ $httpReq, $statuses[$index] ] ); + $callback( $httpReq, $statuses[$index] ); // On failure, abort all remaining requests for this operation // (e.g. abort the DELETE request if the COPY request fails for a move) if ( !$statuses[$index]->isOK() ) { diff --git a/includes/libs/jsminplus.php b/includes/libs/jsminplus.php index e3c2d75863..08e9d690db 100644 --- a/includes/libs/jsminplus.php +++ b/includes/libs/jsminplus.php @@ -909,7 +909,7 @@ class JSParser } else { - $n->setup = $n2 ? $n2 : null; + $n->setup = $n2 ?: null; $this->t->mustMatch(OP_SEMICOLON); $n->condition = $this->t->peek() == OP_SEMICOLON ? null : $this->Expression($x); $this->t->mustMatch(OP_SEMICOLON); @@ -1656,7 +1656,7 @@ class JSNode { if ($token = $t->currentToken()) { - $this->type = $type ? $type : $token->type; + $this->type = $type ?: $token->type; $this->value = $token->value; $this->lineno = $token->lineno; $this->start = $token->start; @@ -1752,7 +1752,7 @@ class JSTokenizer public function init($source, $filename = '', $lineno = 1) { $this->source = $source; - $this->filename = $filename ? $filename : '[inline]'; + $this->filename = $filename ?: '[inline]'; $this->lineno = $lineno; $this->cursor = 0; diff --git a/includes/libs/lockmanager/DBLockManager.php b/includes/libs/lockmanager/DBLockManager.php index 564616dd97..aec9f25b9f 100644 --- a/includes/libs/lockmanager/DBLockManager.php +++ b/includes/libs/lockmanager/DBLockManager.php @@ -82,7 +82,7 @@ abstract class DBLockManager extends QuorumLockManager { $this->lockExpiry = $config['lockExpiry']; } else { $met = ini_get( 'max_execution_time' ); - $this->lockExpiry = $met ? $met : 60; // use some sane amount if 0 + $this->lockExpiry = $met ?: 60; // use some sane amount if 0 } $this->safeDelay = ( $this->lockExpiry <= 0 ) ? 60 // pick a safe-ish number to match DB timeout default diff --git a/includes/libs/lockmanager/MemcLockManager.php b/includes/libs/lockmanager/MemcLockManager.php index ebd72de894..f1f749faa0 100644 --- a/includes/libs/lockmanager/MemcLockManager.php +++ b/includes/libs/lockmanager/MemcLockManager.php @@ -89,7 +89,7 @@ class MemcLockManager extends QuorumLockManager { $memc = $this->getCache( $lockSrv ); // List of affected paths - $paths = call_user_func_array( 'array_merge', array_values( $pathsByType ) ); + $paths = array_merge( ...array_values( $pathsByType ) ); $paths = array_unique( $paths ); // List of affected lock record keys $keys = array_map( [ $this, 'recordKeyForPath' ], $paths ); @@ -164,7 +164,7 @@ class MemcLockManager extends QuorumLockManager { $memc = $this->getCache( $lockSrv ); // List of affected paths - $paths = call_user_func_array( 'array_merge', array_values( $pathsByType ) ); + $paths = array_merge( ...array_values( $pathsByType ) ); $paths = array_unique( $paths ); // List of affected lock record keys $keys = array_map( [ $this, 'recordKeyForPath' ], $paths ); diff --git a/includes/libs/lockmanager/RedisLockManager.php b/includes/libs/lockmanager/RedisLockManager.php index ea9dde7f2a..a624f0a971 100644 --- a/includes/libs/lockmanager/RedisLockManager.php +++ b/includes/libs/lockmanager/RedisLockManager.php @@ -76,7 +76,7 @@ class RedisLockManager extends QuorumLockManager { protected function getLocksOnServer( $lockSrv, array $pathsByType ) { $status = StatusValue::newGood(); - $pathList = call_user_func_array( 'array_merge', array_values( $pathsByType ) ); + $pathList = array_merge( ...array_values( $pathsByType ) ); $server = $this->lockServers[$lockSrv]; $conn = $this->redisPool->getConnection( $server, $this->logger ); @@ -171,7 +171,7 @@ LUA; protected function freeLocksOnServer( $lockSrv, array $pathsByType ) { $status = StatusValue::newGood(); - $pathList = call_user_func_array( 'array_merge', array_values( $pathsByType ) ); + $pathList = array_merge( ...array_values( $pathsByType ) ); $server = $this->lockServers[$lockSrv]; $conn = $this->redisPool->getConnection( $server, $this->logger ); diff --git a/includes/libs/mime/IEContentAnalyzer.php b/includes/libs/mime/IEContentAnalyzer.php index e9fb11f7a8..802ed2decb 100644 --- a/includes/libs/mime/IEContentAnalyzer.php +++ b/includes/libs/mime/IEContentAnalyzer.php @@ -500,13 +500,13 @@ class IEContentAnalyzer { < ( $counters['ctrl'] + $counters['high'] ) * 16 ) { $kindOfBinary = true; - $type = $binaryType ? $binaryType : $textType; + $type = $binaryType ?: $textType; if ( $type === false ) { $type = 'application/octet-stream'; } } else { $kindOfBinary = false; - $type = $textType ? $textType : $binaryType; + $type = $textType ?: $binaryType; if ( $type === false ) { $type = 'text/plain'; } diff --git a/includes/libs/objectcache/CachedBagOStuff.php b/includes/libs/objectcache/CachedBagOStuff.php index ae434c1738..dbab593915 100644 --- a/includes/libs/objectcache/CachedBagOStuff.php +++ b/includes/libs/objectcache/CachedBagOStuff.php @@ -87,11 +87,11 @@ class CachedBagOStuff extends HashBagOStuff { } public function makeKey( $class, $component = null ) { - return call_user_func_array( [ $this->backend, __FUNCTION__ ], func_get_args() ); + return $this->backend->makeKey( ...func_get_args() ); } public function makeGlobalKey( $class, $component = null ) { - return call_user_func_array( [ $this->backend, __FUNCTION__ ], func_get_args() ); + return $this->backend->makeGlobalKey( ...func_get_args() ); } // These just call the backend (tested elsewhere) diff --git a/includes/libs/objectcache/MultiWriteBagOStuff.php b/includes/libs/objectcache/MultiWriteBagOStuff.php index b03052267a..edd5fbca19 100644 --- a/includes/libs/objectcache/MultiWriteBagOStuff.php +++ b/includes/libs/objectcache/MultiWriteBagOStuff.php @@ -195,16 +195,15 @@ class MultiWriteBagOStuff extends BagOStuff { if ( $i == 0 || !$asyncWrites ) { // First store or in sync mode: write now and get result - if ( !call_user_func_array( [ $cache, $method ], $args ) ) { + if ( !$cache->$method( ...$args ) ) { $ret = false; } } else { // Secondary write in async mode: do not block this HTTP request $logger = $this->logger; - call_user_func( - $this->asyncHandler, + ( $this->asyncHandler )( function () use ( $cache, $method, $args, $logger ) { - if ( !call_user_func_array( [ $cache, $method ], $args ) ) { + if ( !$cache->$method( ...$args ) ) { $logger->warning( "Async $method op failed" ); } } @@ -235,10 +234,10 @@ class MultiWriteBagOStuff extends BagOStuff { } public function makeKey( $class, $component = null ) { - return call_user_func_array( [ $this->caches[0], __FUNCTION__ ], func_get_args() ); + return $this->caches[0]->makeKey( ...func_get_args() ); } public function makeGlobalKey( $class, $component = null ) { - return call_user_func_array( [ $this->caches[0], __FUNCTION__ ], func_get_args() ); + return $this->caches[0]->makeGlobalKey( ...func_get_args() ); } } diff --git a/includes/libs/objectcache/WANObjectCache.php b/includes/libs/objectcache/WANObjectCache.php index 97e0456e42..927a1e30b1 100644 --- a/includes/libs/objectcache/WANObjectCache.php +++ b/includes/libs/objectcache/WANObjectCache.php @@ -1603,7 +1603,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * @since 1.27 */ public function makeKey( $class, $component = null ) { - return call_user_func_array( [ $this->cache, __FUNCTION__ ], func_get_args() ); + return $this->cache->makeKey( ...func_get_args() ); } /** @@ -1614,7 +1614,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * @since 1.27 */ public function makeGlobalKey( $class, $component = null ) { - return call_user_func_array( [ $this->cache, __FUNCTION__ ], func_get_args() ); + return $this->cache->makeGlobalKey( ...func_get_args() ); } /** diff --git a/includes/libs/rdbms/database/DBConnRef.php b/includes/libs/rdbms/database/DBConnRef.php index dedf6eab98..b414a2a02a 100644 --- a/includes/libs/rdbms/database/DBConnRef.php +++ b/includes/libs/rdbms/database/DBConnRef.php @@ -46,7 +46,7 @@ class DBConnRef implements IDatabase { $this->conn = $this->lb->getConnection( $db, $groups, $wiki, $flags ); } - return call_user_func_array( [ $this->conn, $name ], $arguments ); + return $this->conn->$name( ...$arguments ); } public function getServerInfo() { diff --git a/includes/libs/rdbms/database/Database.php b/includes/libs/rdbms/database/Database.php index 16e654fe7c..57e5907a52 100644 --- a/includes/libs/rdbms/database/Database.php +++ b/includes/libs/rdbms/database/Database.php @@ -1214,13 +1214,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $startTime = microtime( true ); if ( $this->profiler ) { - call_user_func( [ $this->profiler, 'profileIn' ], $queryProf ); + $this->profiler->profileIn( $queryProf ); } $this->affectedRowCount = null; $ret = $this->doQuery( $commentedSql ); $this->affectedRowCount = $this->affectedRows(); if ( $this->profiler ) { - call_user_func( [ $this->profiler, 'profileOut' ], $queryProf ); + $this->profiler->profileOut( $queryProf ); } $queryRuntime = max( microtime( true ) - $startTime, 0.0 ); @@ -3230,7 +3230,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $e = null; do { try { - $retVal = call_user_func_array( $function, $args ); + $retVal = $function( ...$args ); break; } catch ( DBQueryError $e ) { if ( $this->wasDeadlock() ) { @@ -3310,7 +3310,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware // No transaction is active nor will start implicitly, so make one for this callback $this->startAtomic( __METHOD__, self::ATOMIC_CANCELABLE ); try { - call_user_func( $callback, $this ); + $callback( $this ); $this->endAtomic( __METHOD__ ); } catch ( Exception $e ) { $this->cancelAtomic( __METHOD__ ); @@ -3486,9 +3486,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware try { ++$count; list( $phpCallback ) = $callback; - call_user_func( $phpCallback, $this ); + $phpCallback( $this ); } catch ( Exception $ex ) { - call_user_func( $this->errorLogger, $ex ); + $this->errorLogger( $ex ); $e = $e ?: $ex; } } @@ -3522,7 +3522,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware try { $phpCallback( $trigger, $this ); } catch ( Exception $ex ) { - call_user_func( $this->errorLogger, $ex ); + ( $this->errorLogger )( $ex ); $e = $e ?: $ex; } } @@ -3723,7 +3723,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware ) { $sectionId = $this->startAtomic( $fname, $cancelable ); try { - $res = call_user_func_array( $callback, [ $this, $fname ] ); + $res = $callback( $this, $fname ); } catch ( Exception $e ) { $this->cancelAtomic( $fname, $sectionId ); @@ -4249,7 +4249,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $cmd = $this->replaceVars( $cmd ); if ( $inputCallback ) { - $callbackResult = call_user_func( $inputCallback, $cmd ); + $callbackResult = $inputCallback( $cmd ); if ( is_string( $callbackResult ) || !$callbackResult ) { $cmd = $callbackResult; @@ -4260,7 +4260,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware $res = $this->query( $cmd, $fname ); if ( $resultCallback ) { - call_user_func( $resultCallback, $res, $this ); + $resultCallback( $res, $this ); } if ( false === $res ) { diff --git a/includes/libs/rdbms/database/DatabaseSqlite.php b/includes/libs/rdbms/database/DatabaseSqlite.php index 2125c70fd5..4b925e6413 100644 --- a/includes/libs/rdbms/database/DatabaseSqlite.php +++ b/includes/libs/rdbms/database/DatabaseSqlite.php @@ -865,7 +865,7 @@ class DatabaseSqlite extends Database { $args = func_get_args(); $function = array_shift( $args ); - return call_user_func_array( $function, $args ); + return $function( ...$args ); } /** diff --git a/includes/libs/rdbms/lbfactory/LBFactory.php b/includes/libs/rdbms/lbfactory/LBFactory.php index 52c2df7a26..130a097c78 100644 --- a/includes/libs/rdbms/lbfactory/LBFactory.php +++ b/includes/libs/rdbms/lbfactory/LBFactory.php @@ -202,7 +202,7 @@ abstract class LBFactory implements ILBFactory { protected function forEachLBCallMethod( $methodName, array $args = [] ) { $this->forEachLB( function ( ILoadBalancer $loadBalancer, $methodName, array $args ) { - call_user_func_array( [ $loadBalancer, $methodName ], $args ); + $loadBalancer->$methodName( ...$args ); }, [ $methodName, $args ] ); @@ -650,14 +650,14 @@ abstract class LBFactory implements ILBFactory { /** * @param string $value Possible result of LBFactory::makeCookieValueFromCPIndex() - * @param int $minTimestamp Lowest UNIX timestamp of non-expired values (if present) + * @param int $minTimestamp Lowest UNIX timestamp that a non-expired value can have * @return array (index: int or null, clientId: string or null) * @since 1.32 */ public static function getCPInfoFromCookieValue( $value, $minTimestamp ) { static $placeholder = [ 'index' => null, 'clientId' => null ]; - if ( !preg_match( '/^(\d+)(?:@(\d+))?(?:#([0-9a-f]{32}))?$/', $value, $m ) ) { + if ( !preg_match( '/^(\d+)@(\d+)#([0-9a-f]{32})$/', $value, $m ) ) { return $placeholder; // invalid } diff --git a/includes/libs/rdbms/lbfactory/LBFactoryMulti.php b/includes/libs/rdbms/lbfactory/LBFactoryMulti.php index cfa26479bb..30074eca27 100644 --- a/includes/libs/rdbms/lbfactory/LBFactoryMulti.php +++ b/includes/libs/rdbms/lbfactory/LBFactoryMulti.php @@ -422,10 +422,10 @@ class LBFactoryMulti extends LBFactory { */ public function forEachLB( $callback, array $params = [] ) { foreach ( $this->mainLBs as $lb ) { - call_user_func_array( $callback, array_merge( [ $lb ], $params ) ); + $callback( $lb, ...$params ); } foreach ( $this->extLBs as $lb ) { - call_user_func_array( $callback, array_merge( [ $lb ], $params ) ); + $callback( $lb, ...$params ); } } } diff --git a/includes/libs/rdbms/lbfactory/LBFactorySimple.php b/includes/libs/rdbms/lbfactory/LBFactorySimple.php index 0d7b812da7..6a6bb8d17a 100644 --- a/includes/libs/rdbms/lbfactory/LBFactorySimple.php +++ b/includes/libs/rdbms/lbfactory/LBFactorySimple.php @@ -149,10 +149,10 @@ class LBFactorySimple extends LBFactory { */ public function forEachLB( $callback, array $params = [] ) { if ( isset( $this->mainLB ) ) { - call_user_func_array( $callback, array_merge( [ $this->mainLB ], $params ) ); + $callback( $this->mainLB, ...$params ); } foreach ( $this->extLBs as $lb ) { - call_user_func_array( $callback, array_merge( [ $lb ], $params ) ); + $callback( $lb, ...$params ); } } } diff --git a/includes/libs/rdbms/lbfactory/LBFactorySingle.php b/includes/libs/rdbms/lbfactory/LBFactorySingle.php index 587ab23c02..2c1a782a53 100644 --- a/includes/libs/rdbms/lbfactory/LBFactorySingle.php +++ b/includes/libs/rdbms/lbfactory/LBFactorySingle.php @@ -103,7 +103,7 @@ class LBFactorySingle extends LBFactory { */ public function forEachLB( $callback, array $params = [] ) { if ( isset( $this->lb ) ) { // may not be set during _destruct() - call_user_func_array( $callback, array_merge( [ $this->lb ], $params ) ); + $callback( $this->lb, ...$params ); } } } diff --git a/includes/libs/rdbms/loadbalancer/LoadBalancer.php b/includes/libs/rdbms/loadbalancer/LoadBalancer.php index 221bca4269..6b271a7708 100644 --- a/includes/libs/rdbms/loadbalancer/LoadBalancer.php +++ b/includes/libs/rdbms/loadbalancer/LoadBalancer.php @@ -864,7 +864,7 @@ class LoadBalancer implements ILoadBalancer { $this->connLogger->debug( __METHOD__ . ': calling initLB() before first connection.' ); // Load any "waitFor" positions before connecting so that doWait() is triggered $this->connectionAttempted = true; - call_user_func( $this->chronologyCallback, $this ); + ( $this->chronologyCallback )( $this ); } // Check if an auto-commit connection is being requested. If so, it will not reuse the @@ -1370,7 +1370,7 @@ class LoadBalancer implements ILoadBalancer { try { $conn->commit( $fname, $conn::FLUSHING_ALL_PEERS ); } catch ( DBError $e ) { - call_user_func( $this->errorLogger, $e ); + ( $this->errorLogger )( $e ); $failures[] = "{$conn->getServer()}: {$e->getMessage()}"; } } @@ -1723,8 +1723,7 @@ class LoadBalancer implements ILoadBalancer { foreach ( $this->conns as $connsByServer ) { foreach ( $connsByServer as $serverConns ) { foreach ( $serverConns as $conn ) { - $mergedParams = array_merge( [ $conn ], $params ); - call_user_func_array( $callback, $mergedParams ); + $callback( $conn, ...$params ); } } } @@ -1736,8 +1735,7 @@ class LoadBalancer implements ILoadBalancer { if ( isset( $connsByServer[$masterIndex] ) ) { /** @var IDatabase $conn */ foreach ( $connsByServer[$masterIndex] as $conn ) { - $mergedParams = array_merge( [ $conn ], $params ); - call_user_func_array( $callback, $mergedParams ); + $callback( $conn, ...$params ); } } } @@ -1750,8 +1748,7 @@ class LoadBalancer implements ILoadBalancer { continue; // skip master } foreach ( $serverConns as $conn ) { - $mergedParams = array_merge( [ $conn ], $params ); - call_user_func_array( $callback, $mergedParams ); + $callback( $conn, ...$params ); } } } diff --git a/includes/libs/redis/RedisConnRef.php b/includes/libs/redis/RedisConnRef.php index ede35fa2ee..bbcb267791 100644 --- a/includes/libs/redis/RedisConnRef.php +++ b/includes/libs/redis/RedisConnRef.php @@ -133,10 +133,10 @@ class RedisConnRef implements LoggerAwareInterface { private function tryCall( $method, $arguments ) { $this->conn->clearLastError(); try { - $res = call_user_func_array( [ $this->conn, $method ], $arguments ); + $res = $this->conn->$method( ...$arguments ); $authError = $this->checkAuthentication(); if ( $authError === self::AUTH_ERROR_TEMPORARY ) { - $res = call_user_func_array( [ $this->conn, $method ], $arguments ); + $res = $this->conn->$method( ...$arguments ); } if ( $authError === self::AUTH_ERROR_PERMANENT ) { throw new RedisException( "Failure reauthenticating to Redis." ); diff --git a/includes/linker/LinkRenderer.php b/includes/linker/LinkRenderer.php index 87d7e0a4a7..d096b001ea 100644 --- a/includes/linker/LinkRenderer.php +++ b/includes/linker/LinkRenderer.php @@ -204,7 +204,7 @@ class LinkRenderer { $realHtml = $html = null; } if ( !Hooks::run( 'LinkBegin', - [ $dummy, $title, &$html, &$extraAttribs, &$query, &$options, &$ret ] ) + [ $dummy, $title, &$html, &$extraAttribs, &$query, &$options, &$ret ], '1.28' ) ) { return $ret; } @@ -373,7 +373,7 @@ class LinkRenderer { $title = Title::newFromLinkTarget( $target ); $options = $this->getLegacyOptions( $isKnown ); if ( !Hooks::run( 'LinkEnd', - [ $dummy, $title, $options, &$html, &$attribs, &$ret ] ) + [ $dummy, $title, $options, &$html, &$attribs, &$ret ], '1.28' ) ) { return $ret; } diff --git a/includes/logging/LogEventsList.php b/includes/logging/LogEventsList.php index 9e4a630bd0..40498cd558 100644 --- a/includes/logging/LogEventsList.php +++ b/includes/logging/LogEventsList.php @@ -553,7 +553,7 @@ class LogEventsList extends ContextSource { } $permissionlist = implode( ', ', $permissions ); wfDebug( "Checking for $permissionlist due to $field match on $bitfield\n" ); - return call_user_func_array( [ $user, 'isAllowedAny' ], $permissions ); + return $user->isAllowedAny( ...$permissions ); } return true; } diff --git a/includes/logging/TagLogFormatter.php b/includes/logging/TagLogFormatter.php index 230d13b60b..8458e0b40a 100644 --- a/includes/logging/TagLogFormatter.php +++ b/includes/logging/TagLogFormatter.php @@ -30,6 +30,45 @@ * @since 1.25 */ class TagLogFormatter extends LogFormatter { + + protected function getMessageParameters() { + $params = parent::getMessageParameters(); + + $isRevLink = !empty( $params[3] ); + if ( $isRevLink ) { + $id = $params[3]; + $target = $this->entry->getTarget(); + $query = [ + 'oldid' => $id, + 'diff' => 'prev' + ]; + } else { + $id = $params[4]; + $target = SpecialPage::getTitleValueFor( 'Log' ); + $query = [ + 'logid' => $id, + ]; + } + + $formattedNumber = $this->context->getLanguage()->formatNum( $id, true ); + if ( $this->plaintext ) { + $link = $formattedNumber; + } elseif ( !$isRevLink || $target->exists() ) { + $link = $this->getLinkRenderer()->makeKnownLink( + $target, $formattedNumber, [], $query ); + } else { + $link = htmlspecialchars( $formattedNumber ); + } + + if ( $isRevLink ) { + $params[3] = Message::rawParam( $link ); + } else { + $params[4] = Message::rawParam( $link ); + } + + return $params; + } + protected function getMessageKey() { $key = parent::getMessageKey(); $params = $this->getMessageParameters(); @@ -50,4 +89,5 @@ class TagLogFormatter extends LogFormatter { return $key; } + } diff --git a/includes/media/BitmapHandler.php b/includes/media/BitmapHandler.php index cda037c16d..e2d32cfbe1 100644 --- a/includes/media/BitmapHandler.php +++ b/includes/media/BitmapHandler.php @@ -228,7 +228,7 @@ class BitmapHandler extends TransformationalImageHandler { $rotation = isset( $params['disableRotation'] ) ? 0 : $this->getRotation( $image ); list( $width, $height ) = $this->extractPreRotationDimensions( $params, $rotation ); - $cmd = call_user_func_array( 'wfEscapeShellArg', array_merge( + $cmd = wfEscapeShellArg( ...array_merge( [ $wgImageMagickConvertCommand ], $quality, // Specify white background color, will be used for transparent images @@ -449,7 +449,7 @@ class BitmapHandler extends TransformationalImageHandler { return $this->getMediaTransformError( $params, $errMsg ); } - $src_image = call_user_func( $loader, $params['srcPath'] ); + $src_image = $loader( $params['srcPath'] ); $rotation = function_exists( 'imagerotate' ) && !isset( $params['disableRotation'] ) ? $this->getRotation( $image ) : @@ -489,7 +489,7 @@ class BitmapHandler extends TransformationalImageHandler { if ( $useQuality && isset( $params['quality'] ) ) { $funcParams[] = $params['quality']; } - call_user_func_array( $saveType, $funcParams ); + $saveType( ...$funcParams ); imagedestroy( $dst_image ); imagedestroy( $src_image ); diff --git a/includes/media/SvgHandler.php b/includes/media/SvgHandler.php index a589dbf3fb..a9c7b4fe89 100644 --- a/includes/media/SvgHandler.php +++ b/includes/media/SvgHandler.php @@ -291,12 +291,16 @@ class SvgHandler extends ImageHandler { if ( is_array( $wgSVGConverters[$wgSVGConverter] ) ) { // This is a PHP callable $func = $wgSVGConverters[$wgSVGConverter][0]; - $args = array_merge( [ $srcPath, $dstPath, $width, $height, $lang ], - array_slice( $wgSVGConverters[$wgSVGConverter], 1 ) ); if ( !is_callable( $func ) ) { throw new MWException( "$func is not callable" ); } - $err = call_user_func_array( $func, $args ); + $err = $func( $srcPath, + $dstPath, + $width, + $height, + $lang, + ...array_slice( $wgSVGConverters[$wgSVGConverter], 1 ) + ); $retval = (bool)$err; } else { // External command diff --git a/includes/page/Article.php b/includes/page/Article.php index c865d4ed53..1abf97470f 100644 --- a/includes/page/Article.php +++ b/includes/page/Article.php @@ -279,8 +279,8 @@ class Article implements Page { if ( $this->mRevision !== null ) { // Revision title doesn't match the page title given? if ( $this->mPage->getId() != $this->mRevision->getPage() ) { - $function = [ get_class( $this->mPage ), 'newFromID' ]; - $this->mPage = call_user_func( $function, $this->mRevision->getPage() ); + $function = get_class( $this->mPage ). '::newFromID'; + $this->mPage = $function( $this->mRevision->getPage() ); } } } diff --git a/includes/parser/CoreParserFunctions.php b/includes/parser/CoreParserFunctions.php index 7f6dbe530e..42d5db70b8 100644 --- a/includes/parser/CoreParserFunctions.php +++ b/includes/parser/CoreParserFunctions.php @@ -449,7 +449,7 @@ class CoreParserFunctions { $parser->mOutput->setDisplayTitle( $text ); } if ( $old !== false && $old !== $text && !$arg ) { - $converter = $parser->getConverterLanguage()->getConverter(); + $converter = $parser->getTargetLanguage()->getConverter(); return '' . wfMessage( 'duplicate-displaytitle', // Message should be parsed, but these params should only be escaped. @@ -461,7 +461,7 @@ class CoreParserFunctions { return ''; } } else { - $converter = $parser->getConverterLanguage()->getConverter(); + $converter = $parser->getTargetLanguage()->getConverter(); $parser->getOutput()->addWarning( wfMessage( 'restricted-displaytitle', // Message should be parsed, but this param should only be escaped. @@ -882,7 +882,7 @@ class CoreParserFunctions { * Unicode-safe str_pad with the restriction that $length is forced to be <= 500 * @param Parser $parser * @param string $string - * @param int $length + * @param string $length * @param string $padding * @param int $direction * @return string @@ -897,7 +897,12 @@ class CoreParserFunctions { } # The remaining length to add counts down to 0 as padding is added - $length = min( $length, 500 ) - mb_strlen( $string ); + $length = min( (int)$length, 500 ) - mb_strlen( $string ); + if ( $length <= 0 ) { + // Nothing to add + return $string; + } + # $finalPadding is just $padding repeated enough times so that # mb_strlen( $string ) + mb_strlen( $finalPadding ) == $length $finalPadding = ''; @@ -977,7 +982,7 @@ class CoreParserFunctions { if ( $old === false || $old == $text || $arg ) { return ''; } else { - $converter = $parser->getConverterLanguage()->getConverter(); + $converter = $parser->getTargetLanguage()->getConverter(); return '' . wfMessage( 'duplicate-defaultsort', // Message should be parsed, but these params should only be escaped. diff --git a/includes/parser/Parser.php b/includes/parser/Parser.php index 8df5b5ba09..38bc95e802 100644 --- a/includes/parser/Parser.php +++ b/includes/parser/Parser.php @@ -460,11 +460,11 @@ class Parser { || isset( $this->mDoubleUnderscores['notitleconvert'] ) || $this->mOutput->getDisplayTitle() !== false ) ) { - $convruletitle = $this->getConverterLanguage()->getConvRuleTitle(); + $convruletitle = $this->getTargetLanguage()->getConvRuleTitle(); if ( $convruletitle ) { $this->mOutput->setTitleText( $convruletitle ); } else { - $titleText = $this->getConverterLanguage()->convertTitle( $title ); + $titleText = $this->getTargetLanguage()->convertTitle( $title ); $this->mOutput->setTitleText( $titleText ); } } @@ -897,6 +897,7 @@ class Parser { /** * Get the language object for language conversion + * @deprecated since 1.32, just use getTargetLanguage() * @return Language|null */ public function getConverterLanguage() { @@ -1380,7 +1381,7 @@ class Parser { # The position of the convert() call should not be changed. it # assumes that the links are all replaced and the only thing left # is the mark. - $text = $this->getConverterLanguage()->convert( $text ); + $text = $this->getTargetLanguage()->convert( $text ); } } @@ -1605,7 +1606,7 @@ class Parser { if ( $text === false ) { # Not an image, make a link $text = Linker::makeExternalLink( $url, - $this->getConverterLanguage()->markNoConversion( $url, true ), + $this->getTargetLanguage()->getConverter()->markNoConversion( $url ), true, 'free', $this->getExternalLinkAttribs( $url ), $this->mTitle ); # Register it in the output object... @@ -1894,7 +1895,10 @@ class Parser { list( $dtrail, $trail ) = Linker::splitTrail( $trail ); } - $text = $this->getConverterLanguage()->markNoConversion( $text ); + // Excluding protocol-relative URLs may avoid many false positives. + if ( preg_match( '/^(?:' . wfUrlProtocolsWithoutProtRel() . ')/', $text ) ) { + $text = $this->getTargetLanguage()->getConverter()->markNoConversion( $text ); + } $url = Sanitizer::cleanUrl( $url ); @@ -2360,7 +2364,7 @@ class Parser { } $sortkey = Sanitizer::decodeCharReferences( $sortkey ); $sortkey = str_replace( "\n", '', $sortkey ); - $sortkey = $this->getConverterLanguage()->convertCategoryKey( $sortkey ); + $sortkey = $this->getTargetLanguage()->convertCategoryKey( $sortkey ); $this->mOutput->addCategory( $nt->getDBkey(), $sortkey ); continue; @@ -2641,7 +2645,7 @@ class Parser { $this->mOutput->setFlag( 'vary-revision' ); wfDebug( __METHOD__ . ": {{PAGEID}} used in a new page, setting vary-revision...\n" ); } - $value = $pageid ? $pageid : null; + $value = $pageid ?: null; break; case 'revisionid': # Let the edit saving system know we should parse the page @@ -3185,8 +3189,8 @@ class Parser { if ( $title ) { $titleText = $title->getPrefixedText(); # Check for language variants if the template is not found - if ( $this->getConverterLanguage()->hasVariants() && $title->getArticleID() == 0 ) { - $this->getConverterLanguage()->findVariantLink( $part1, $title, true ); + if ( $this->getTargetLanguage()->hasVariants() && $title->getArticleID() == 0 ) { + $this->getTargetLanguage()->findVariantLink( $part1, $title, true ); } # Do recursion depth check $limit = $this->mOptions->getMaxTemplateDepth(); @@ -3435,7 +3439,7 @@ class Parser { } } - $result = call_user_func_array( $callback, $allArgs ); + $result = $callback( ...$allArgs ); # The interface for function hooks allows them to return a wikitext # string or an array containing the string and any flags. This mungs diff --git a/includes/parser/ParserDiffTest.php b/includes/parser/ParserDiffTest.php index 353825a8fb..93f4246e02 100644 --- a/includes/parser/ParserDiffTest.php +++ b/includes/parser/ParserDiffTest.php @@ -61,12 +61,9 @@ class ParserDiffTest { $results = []; $mismatch = false; $lastResult = null; - $first = true; - foreach ( $this->parsers as $i => $parser ) { - $currentResult = call_user_func_array( [ &$this->parsers[$i], $name ], $args ); - if ( $first ) { - $first = false; - } else { + foreach ( $this->parsers as $parser ) { + $currentResult = $parser->$name( ...$args ); + if ( count( $results ) > 0 ) { if ( is_object( $lastResult ) ) { if ( $lastResult != $currentResult ) { $mismatch = true; @@ -77,7 +74,7 @@ class ParserDiffTest { } } } - $results[$i] = $currentResult; + $results[] = $currentResult; $lastResult = $currentResult; } if ( $mismatch ) { diff --git a/includes/parser/ParserOutput.php b/includes/parser/ParserOutput.php index 9ec6cf82b2..265d1516a6 100644 --- a/includes/parser/ParserOutput.php +++ b/includes/parser/ParserOutput.php @@ -311,10 +311,10 @@ class ParserOutput extends CacheTime { } $skin = $wgOut->getSkin(); - return call_user_func_array( - [ $skin, 'doEditSectionLink' ], - [ $editsectionPage, $editsectionSection, - $editsectionContent, $wgLang->getCode() ] + return $skin->doEditSectionLink( $editsectionPage, + $editsectionSection, + $editsectionContent, + $wgLang->getCode() ); }, $text diff --git a/includes/password/BcryptPassword.php b/includes/password/BcryptPassword.php index f811e3f514..4ba34effe5 100644 --- a/includes/password/BcryptPassword.php +++ b/includes/password/BcryptPassword.php @@ -65,7 +65,7 @@ class BcryptPassword extends ParameterizedPassword { // Replace + with ., because bcrypt uses a non-MIME base64 format strtr( // Random base64 encoded string - base64_encode( MWCryptRand::generate( 16, true ) ), + base64_encode( random_bytes( 16 ) ), '+', '.' ), 0, 22 diff --git a/includes/password/EncryptedPassword.php b/includes/password/EncryptedPassword.php index 0ea3c63198..d1774ba8af 100644 --- a/includes/password/EncryptedPassword.php +++ b/includes/password/EncryptedPassword.php @@ -60,7 +60,7 @@ class EncryptedPassword extends ParameterizedPassword { if ( count( $this->args ) ) { $iv = base64_decode( $this->args[0] ); } else { - $iv = MWCryptRand::generate( openssl_cipher_iv_length( $this->params['cipher'] ), true ); + $iv = random_bytes( openssl_cipher_iv_length( $this->params['cipher'] ) ); } $this->hash = openssl_encrypt( @@ -102,7 +102,7 @@ class EncryptedPassword extends ParameterizedPassword { $this->params = $this->getDefaultParams(); // Check the key size with the new params - $iv = MWCryptRand::generate( openssl_cipher_iv_length( $this->params['cipher'] ), true ); + $iv = random_bytes( openssl_cipher_iv_length( $this->params['cipher'] ) ); $this->hash = openssl_encrypt( $underlyingHash, $this->params['cipher'], diff --git a/includes/password/Pbkdf2Password.php b/includes/password/Pbkdf2Password.php index 541fd0e1a2..60650452fc 100644 --- a/includes/password/Pbkdf2Password.php +++ b/includes/password/Pbkdf2Password.php @@ -47,7 +47,7 @@ class Pbkdf2Password extends ParameterizedPassword { public function crypt( $password ) { if ( count( $this->args ) == 0 ) { - $this->args[] = base64_encode( MWCryptRand::generate( 16, true ) ); + $this->args[] = base64_encode( random_bytes( 16 ) ); } if ( $this->shouldUseHashExtension() ) { diff --git a/includes/poolcounter/PoolCounterWorkViaCallback.php b/includes/poolcounter/PoolCounterWorkViaCallback.php index 834b8b1f83..aed52d1957 100644 --- a/includes/poolcounter/PoolCounterWorkViaCallback.php +++ b/includes/poolcounter/PoolCounterWorkViaCallback.php @@ -66,26 +66,26 @@ class PoolCounterWorkViaCallback extends PoolCounterWork { } public function doWork() { - return call_user_func_array( $this->doWork, [] ); + return ( $this->doWork )(); } public function getCachedWork() { if ( $this->doCachedWork ) { - return call_user_func_array( $this->doCachedWork, [] ); + return ( $this->doCachedWork )(); } return false; } public function fallback() { if ( $this->fallback ) { - return call_user_func_array( $this->fallback, [] ); + return ( $this->fallback )(); } return false; } public function error( $status ) { if ( $this->error ) { - return call_user_func_array( $this->error, [ $status ] ); + return ( $this->error )( $status ); } return false; } diff --git a/includes/registration/ExtensionRegistry.php b/includes/registration/ExtensionRegistry.php index a3684e8da5..c58b55ebfd 100644 --- a/includes/registration/ExtensionRegistry.php +++ b/includes/registration/ExtensionRegistry.php @@ -144,7 +144,7 @@ class ExtensionRegistry { // been loaded $cacheId = ObjectCache::detectLocalServerCache(); $cache = ObjectCache::newFromId( $cacheId ); - } catch ( MWException $e ) { + } catch ( InvalidArgumentException $e ) { $cache = new EmptyBagOStuff(); } // See if this queue is in APC diff --git a/includes/resourceloader/ResourceLoaderContext.php b/includes/resourceloader/ResourceLoaderContext.php index d41198ae55..3ceb915d27 100644 --- a/includes/resourceloader/ResourceLoaderContext.php +++ b/includes/resourceloader/ResourceLoaderContext.php @@ -226,7 +226,7 @@ class ResourceLoaderContext implements MessageLocalizer { * @return Message */ public function msg( $key ) { - return call_user_func_array( 'wfMessage', func_get_args() ) + return wfMessage( ...func_get_args() ) ->inLanguage( $this->getLanguage() ) // Use a dummy title because there is no real title // for this endpoint, and the cache won't vary on it diff --git a/includes/search/PaginatingSearchEngine.php b/includes/search/PaginatingSearchEngine.php new file mode 100644 index 0000000000..97ef2d57c5 --- /dev/null +++ b/includes/search/PaginatingSearchEngine.php @@ -0,0 +1,12 @@ +doSearchText( $term ); + return $this->maybePaginate( function () use ( $term ) { + return $this->doSearchText( $term ); + } ); } /** @@ -132,7 +134,9 @@ abstract class SearchEngine { * @return SearchResultSet|null */ public function searchTitle( $term ) { - return $this->doSearchTitle( $term ); + return $this->maybePaginate( function () use ( $term ) { + return $this->doSearchTitle( $term ); + } ); } /** @@ -146,6 +150,40 @@ abstract class SearchEngine { return null; } + /** + * Performs an overfetch and shrink operation to determine if + * the next page is available for search engines that do not + * explicitly implement their own pagination. + * + * @param Closure $fn Takes no arguments + * @return SearchResultSet|Status|null Result of calling $fn + */ + private function maybePaginate( Closure $fn ) { + if ( $this instanceof PaginatingSearchEngine ) { + return $fn(); + } + $this->limit++; + try { + $resultSetOrStatus = $fn(); + } finally { + $this->limit--; + } + + $resultSet = null; + if ( $resultSetOrStatus instanceof SearchResultSet ) { + $resultSet = $resultSetOrStatus; + } elseif ( $resultSetOrStatus instanceof Status && + $resultSetOrStatus->getValue() instanceof SearchResultSet + ) { + $resultSet = $resultSetOrStatus->getValue(); + } + if ( $resultSet ) { + $resultSet->shrink( $this->limit ); + } + + return $resultSetOrStatus; + } + /** * @since 1.18 * @param string $feature @@ -523,6 +561,22 @@ abstract class SearchEngine { return $search; } + /** + * Perform an overfetch of completion search results. This allows + * determining if another page of results is available. + * + * @param string $search + * @return SearchSuggestionSet + */ + protected function completionSearchBackendOverfetch( $search ) { + $this->limit++; + try { + return $this->completionSearchBackend( $search ); + } finally { + $this->limit--; + } + } + /** * Perform a completion search. * Does not resolve namespaces and does not check variants. @@ -560,7 +614,8 @@ abstract class SearchEngine { return SearchSuggestionSet::emptySuggestionSet(); // Return empty result } $search = $this->normalizeNamespaces( $search ); - return $this->processCompletionResults( $search, $this->completionSearchBackend( $search ) ); + $suggestions = $this->completionSearchBackendOverfetch( $search ); + return $this->processCompletionResults( $search, $suggestions ); } /** @@ -574,8 +629,8 @@ abstract class SearchEngine { } $search = $this->normalizeNamespaces( $search ); - $results = $this->completionSearchBackend( $search ); - $fallbackLimit = $this->limit - $results->getSize(); + $results = $this->completionSearchBackendOverfetch( $search ); + $fallbackLimit = 1 + $this->limit - $results->getSize(); if ( $fallbackLimit > 0 ) { global $wgContLang; @@ -614,15 +669,26 @@ abstract class SearchEngine { * @return SearchSuggestionSet */ protected function processCompletionResults( $search, SearchSuggestionSet $suggestions ) { + // We over-fetched to determine pagination. Shrink back down if we have extra results + // and mark if pagination is possible + $suggestions->shrink( $this->limit ); + $search = trim( $search ); // preload the titles with LinkBatch - $titles = $suggestions->map( function ( SearchSuggestion $sugg ) { + $lb = new LinkBatch( $suggestions->map( function ( SearchSuggestion $sugg ) { return $sugg->getSuggestedTitle(); - } ); - $lb = new LinkBatch( $titles ); + } ) ); $lb->setCaller( __METHOD__ ); $lb->execute(); + $diff = $suggestions->filter( function ( SearchSuggestion $sugg ) { + return $sugg->getSuggestedTitle()->isKnown(); + } ); + if ( $diff > 0 ) { + MediaWikiServices::getInstance()->getStatsdDataFactory() + ->updateCount( 'search.completion.missing', $diff ); + } + $results = $suggestions->map( function ( SearchSuggestion $sugg ) { return $sugg->getSuggestedTitle()->getPrefixedText(); } ); @@ -830,7 +896,6 @@ abstract class SearchEngine { $setAugmentors = []; $rowAugmentors = []; Hooks::run( "SearchResultsAugment", [ &$setAugmentors, &$rowAugmentors ] ); - if ( !$setAugmentors && !$rowAugmentors ) { // We're done here return; diff --git a/includes/search/SearchNearMatchResultSet.php b/includes/search/SearchNearMatchResultSet.php index 31417974d9..42bc62d670 100644 --- a/includes/search/SearchNearMatchResultSet.php +++ b/includes/search/SearchNearMatchResultSet.php @@ -3,28 +3,18 @@ * A SearchResultSet wrapper for SearchNearMatcher */ class SearchNearMatchResultSet extends SearchResultSet { - private $fetched = false; - /** * @param Title|null $match Title if matched, else null */ public function __construct( $match ) { - $this->result = $match; - } - - public function numRows() { - return $this->result ? 1 : 0; - } - - public function next() { - if ( $this->fetched || !$this->result ) { - return false; + if ( $match === null ) { + $this->results = []; + } else { + $this->results = [ SearchResult::newFromTitle( $match, $this ) ]; } - $this->fetched = true; - return SearchResult::newFromTitle( $this->result, $this ); } - public function rewind() { - $this->fetched = false; + public function numRows() { + return $this->results ? 1 : 0; } } diff --git a/includes/search/SearchResult.php b/includes/search/SearchResult.php index dc294c324e..2f20d9d52d 100644 --- a/includes/search/SearchResult.php +++ b/includes/search/SearchResult.php @@ -57,8 +57,8 @@ class SearchResult { protected $searchEngine; /** - * A set of extension data. - * @var array[] + * A function returning a set of extension data. + * @var Closure|null */ protected $extensionData; @@ -267,17 +267,34 @@ class SearchResult { * @return array[] */ public function getExtensionData() { - return $this->extensionData; + if ( $this->extensionData ) { + return call_user_func( $this->extensionData ); + } else { + return []; + } } /** * Set extension data for this result. * The data is: * augmentor name => data - * @param array[] $extensionData + * @param Closure|array $extensionData Takes no arguments, returns + * either array of extension data or null. */ - public function setExtensionData( array $extensionData ) { - $this->extensionData = $extensionData; + public function setExtensionData( $extensionData ) { + if ( $extensionData instanceof Closure ) { + $this->extensionData = $extensionData; + } elseif ( is_array( $extensionData ) ) { + wfDeprecated( __METHOD__ . ' with array argument', 1.32 ); + $this->extensionData = function () use ( $extensionData ) { + return $extensionData; + }; + } else { + $type = is_object( $extensionData ) + ? get_class( $extensionData ) + : gettype( $extensionData ); + throw new \InvalidArgumentException( + __METHOD__ . " must be called with Closure|array, but received $type" ); + } } - } diff --git a/includes/search/SearchResultSet.php b/includes/search/SearchResultSet.php index e3eb4c250e..5728a52304 100644 --- a/includes/search/SearchResultSet.php +++ b/includes/search/SearchResultSet.php @@ -24,8 +24,7 @@ /** * @ingroup Search */ -class SearchResultSet { - +class SearchResultSet implements Countable, IteratorAggregate { /** * Types of interwiki results */ @@ -54,7 +53,7 @@ class SearchResultSet { * as an array. * @var SearchResult[] */ - private $results; + protected $results; /** * Set of result's extra data, indexed per result id @@ -65,8 +64,31 @@ class SearchResultSet { */ protected $extraData = []; - public function __construct( $containedSyntax = false ) { + /** + * @var boolean True when there are more pages of search results available. + */ + private $hasMoreResults; + + /** + * @var ArrayIterator|null Iterator supporting BC iteration methods + */ + private $bcIterator; + + /** + * @param bool $containedSyntax True when query is not requesting a simple + * term match + * @param bool $hasMoreResults True when there are more pages of search + * results available. + */ + public function __construct( $containedSyntax = false, $hasMoreResults = false ) { + if ( static::class === __CLASS__ ) { + // This class will eventually be abstract. SearchEngine implementations + // already have to extend this class anyways to provide the actual + // search results. + wfDeprecated( __METHOD__, 1.32 ); + } $this->containedSyntax = $containedSyntax; + $this->hasMoreResults = $hasMoreResults; } /** @@ -81,7 +103,11 @@ class SearchResultSet { } function numRows() { - return 0; + return $this->count(); + } + + final public function count() { + return count( $this->extractResults() ); } /** @@ -171,20 +197,39 @@ class SearchResultSet { /** * Fetches next search result, or false. - * STUB - * FIXME: refactor as iterator, so we could use nicer interfaces. - * @deprecated since 1.32; Use self::extractResults() + * @deprecated since 1.32; Use self::extractResults() or foreach * @return SearchResult|false */ - function next() { - return false; + public function next() { + wfDeprecated( __METHOD__, '1.32' ); + $it = $this->bcIterator(); + $searchResult = $it->current(); + $it->next(); + return $searchResult === null ? false : $searchResult; } /** * Rewind result set back to beginning - * @deprecated since 1.32; Use self::extractResults() + * @deprecated since 1.32; Use self::extractResults() or foreach */ - function rewind() { + public function rewind() { + wfDeprecated( __METHOD__, '1.32' ); + $this->bcIterator()->rewind(); + } + + private function bcIterator() { + if ( $this->bcIterator === null ) { + $this->bcIterator = 'RECURSION'; + $this->bcIterator = $this->getIterator(); + } elseif ( $this->bcIterator === 'RECURSION' ) { + // Either next/rewind or extractResults must be implemented. This + // class was potentially instantiated directly. It should be + // abstract with abstract methods to enforce this but that's a + // breaking change... + wfDeprecated( static::class . ' without implementing extractResults', '1.32' ); + $this->bcIterator = new ArrayIterator( [] ); + } + return $this->bcIterator; } /** @@ -204,6 +249,34 @@ class SearchResultSet { return $this->containedSyntax; } + /** + * @return bool True when there are more pages of search results available. + */ + public function hasMoreResults() { + return $this->hasMoreResults; + } + + /** + * @param int $limit Shrink result set to $limit and flag + * if more results are available. + */ + public function shrink( $limit ) { + if ( $this->count() > $limit ) { + $this->hasMoreResults = true; + // shrinking result set for implementations that + // have not implemented extractResults and use + // the default cache location. Other implementations + // must override this as well. + if ( is_array( $this->results ) ) { + $this->results = array_slice( $this->results, 0, $limit ); + } else { + throw new \UnexpectedValueException( + "When overriding result store extending classes must " + . " also override " . __METHOD__ ); + } + } + } + /** * Extract all the results in the result set as array. * @return SearchResult[] @@ -258,15 +331,19 @@ class SearchResultSet { /** * Returns extra data for specific result and store it in SearchResult object. * @param SearchResult $result - * @return array|null List of data as name => value or null if none present. */ public function augmentResult( SearchResult $result ) { $id = $result->getTitle()->getArticleID(); - if ( !$id || !isset( $this->extraData[$id] ) ) { - return null; + if ( $id === -1 ) { + return; } - $result->setExtensionData( $this->extraData[$id] ); - return $this->extraData[$id]; + $result->setExtensionData( function () use ( $id ) { + if ( isset( $this->extraData[$id] ) ) { + return $this->extraData[$id]; + } else { + return []; + } + } ); } /** @@ -278,4 +355,8 @@ class SearchResultSet { public function getOffset() { return null; } + + final public function getIterator() { + return new ArrayIterator( $this->extractResults() ); + } } diff --git a/includes/search/SearchSuggestionSet.php b/includes/search/SearchSuggestionSet.php index aced5e18af..cb1f831711 100644 --- a/includes/search/SearchSuggestionSet.php +++ b/includes/search/SearchSuggestionSet.php @@ -35,6 +35,11 @@ class SearchSuggestionSet { */ private $pageMap = []; + /** + * @var bool Are more results available? + */ + private $hasMoreResults; + /** * Builds a new set of suggestions. * @@ -45,8 +50,10 @@ class SearchSuggestionSet { * unexpected behaviors. * * @param SearchSuggestion[] $suggestions (must be sorted by score) + * @param bool $hasMoreResults Are more results available? */ - public function __construct( array $suggestions ) { + public function __construct( array $suggestions, $hasMoreResults = false ) { + $this->hasMoreResults = $hasMoreResults; foreach ( $suggestions as $suggestion ) { $pageID = $suggestion->getSuggestedTitleID(); if ( $pageID && empty( $this->pageMap[$pageID] ) ) { @@ -56,6 +63,13 @@ class SearchSuggestionSet { } } + /** + * @return bool Are more results available? + */ + public function hasMoreResults() { + return $this->hasMoreResults; + } + /** * Get the list of suggestions. * @return SearchSuggestion[] @@ -73,6 +87,18 @@ class SearchSuggestionSet { return array_map( $callback, $this->suggestions ); } + /** + * Filter the suggestions array + * @param callback $callback Callable accepting single SearchSuggestion + * instance returning bool false to remove the item. + * @return int The number of suggestions removed + */ + public function filter( $callback ) { + $before = count( $this->suggestions ); + $this->suggestions = array_values( array_filter( $this->suggestions, $callback ) ); + return $before - count( $this->suggestions ); + } + /** * Add a new suggestion at the end. * If the score of the new suggestion is greater than the worst one, @@ -167,6 +193,7 @@ class SearchSuggestionSet { public function shrink( $limit ) { if ( count( $this->suggestions ) > $limit ) { $this->suggestions = array_slice( $this->suggestions, 0, $limit ); + $this->hasMoreResults = true; } } @@ -177,14 +204,15 @@ class SearchSuggestionSet { * NOTE: Suggestion scores will be generated. * * @param Title[] $titles + * @param bool $hasMoreResults Are more results available? * @return SearchSuggestionSet */ - public static function fromTitles( array $titles ) { + public static function fromTitles( array $titles, $hasMoreResults = false ) { $score = count( $titles ); $suggestions = array_map( function ( $title ) use ( &$score ) { return SearchSuggestion::fromTitle( $score--, $title ); }, $titles ); - return new SearchSuggestionSet( $suggestions ); + return new SearchSuggestionSet( $suggestions, $hasMoreResults ); } /** @@ -193,14 +221,15 @@ class SearchSuggestionSet { * NOTE: Suggestion scores will be generated. * * @param string[] $titles + * @param bool $hasMoreResults Are more results available? * @return SearchSuggestionSet */ - public static function fromStrings( array $titles ) { + public static function fromStrings( array $titles, $hasMoreResults = false ) { $score = count( $titles ); $suggestions = array_map( function ( $title ) use ( &$score ) { return SearchSuggestion::fromText( $score--, $title ); }, $titles ); - return new SearchSuggestionSet( $suggestions ); + return new SearchSuggestionSet( $suggestions, $hasMoreResults ); } /** diff --git a/includes/search/SqlSearchResultSet.php b/includes/search/SqlSearchResultSet.php index 53d09e82b1..022dc0a643 100644 --- a/includes/search/SqlSearchResultSet.php +++ b/includes/search/SqlSearchResultSet.php @@ -7,8 +7,11 @@ use Wikimedia\Rdbms\ResultWrapper; * @ingroup Search */ class SqlSearchResultSet extends SearchResultSet { + /** @var ResultWrapper Result object from database */ protected $resultSet; + /** @var string Requested search query */ protected $terms; + /** @var int|null Total number of hits for $terms */ protected $totalHits; function __construct( ResultWrapper $resultSet, $terms, $total = null ) { @@ -29,25 +32,21 @@ class SqlSearchResultSet extends SearchResultSet { return $this->resultSet->numRows(); } - function next() { + public function extractResults() { if ( $this->resultSet === false ) { - return false; - } - - $row = $this->resultSet->fetchObject(); - if ( $row === false ) { - return false; + return []; } - return SearchResult::newFromTitle( - Title::makeTitle( $row->page_namespace, $row->page_title ), $this - ); - } - - function rewind() { - if ( $this->resultSet ) { + if ( $this->results === null ) { + $this->results = []; $this->resultSet->rewind(); + while ( ( $row = $this->resultSet->fetchObject() ) !== false ) { + $this->results[] = SearchResult::newFromTitle( + Title::makeTitle( $row->page_namespace, $row->page_title ), $this + ); + } } + return $this->results; } function free() { diff --git a/includes/services/ServiceContainer.php b/includes/services/ServiceContainer.php index 4c52693a4a..c98b7da79c 100644 --- a/includes/services/ServiceContainer.php +++ b/includes/services/ServiceContainer.php @@ -355,9 +355,8 @@ class ServiceContainer implements DestructibleService { */ private function createService( $name ) { if ( isset( $this->serviceInstantiators[$name] ) ) { - $service = call_user_func_array( - $this->serviceInstantiators[$name], - array_merge( [ $this ], $this->extraInstantiationParams ) + $service = ( $this->serviceInstantiators[$name] )( + $this, ...$this->extraInstantiationParams ); // NOTE: when adding more wiring logic here, make sure copyWiring() is kept in sync! } else { diff --git a/includes/session/Session.php b/includes/session/Session.php index 024bf9a2b0..e9a03f20f4 100644 --- a/includes/session/Session.php +++ b/includes/session/Session.php @@ -481,7 +481,7 @@ final class Session implements \Countable, \Iterator, \ArrayAccess { // Encrypt // @todo: import a pure-PHP library for AES instead of doing $wgSessionInsecureSecrets - $iv = \MWCryptRand::generate( 16, true ); + $iv = random_bytes( 16 ); $algorithm = self::getEncryptionAlgorithm(); switch ( $algorithm[0] ) { case 'openssl': diff --git a/includes/skins/BaseTemplate.php b/includes/skins/BaseTemplate.php index d1bea8d1b2..c1c856d33d 100644 --- a/includes/skins/BaseTemplate.php +++ b/includes/skins/BaseTemplate.php @@ -36,7 +36,7 @@ abstract class BaseTemplate extends QuickTemplate { * @return Message */ public function getMsg( $name /* ... */ ) { - return call_user_func_array( [ $this->getSkin(), 'msg' ], func_get_args() ); + return $this->getSkin()->msg( ...func_get_args() ); } function msg( $str ) { @@ -597,10 +597,7 @@ abstract class BaseTemplate extends QuickTemplate { if ( $option == 'flat' ) { // fold footerlinks into a single array using a bit of trickery - $validFooterLinks = call_user_func_array( - 'array_merge', - array_values( $validFooterLinks ) - ); + $validFooterLinks = array_merge( ...array_values( $validFooterLinks ) ); } return $validFooterLinks; diff --git a/includes/skins/QuickTemplate.php b/includes/skins/QuickTemplate.php index aa20e202eb..296c133e0b 100644 --- a/includes/skins/QuickTemplate.php +++ b/includes/skins/QuickTemplate.php @@ -77,11 +77,7 @@ abstract class QuickTemplate { * @return mixed The value of the data requested or the deafult */ public function get( $name, $default = null ) { - if ( isset( $this->data[$name] ) ) { - return $this->data[$name]; - } else { - return $default; - } + return $this->data[$name] ?? $default; } /** diff --git a/includes/specialpage/AuthManagerSpecialPage.php b/includes/specialpage/AuthManagerSpecialPage.php index 81e13f00f0..557bd9cc5a 100644 --- a/includes/specialpage/AuthManagerSpecialPage.php +++ b/includes/specialpage/AuthManagerSpecialPage.php @@ -432,11 +432,11 @@ abstract class AuthManagerSpecialPage extends SpecialPage { $status = Status::newFatal( new RawMessage( '$1', $status ) ); } elseif ( is_array( $status ) ) { if ( is_string( reset( $status ) ) ) { - $status = call_user_func_array( 'Status::newFatal', $status ); + $status = Status::newFatal( ...$status ); } elseif ( is_array( reset( $status ) ) ) { $status = Status::newGood(); foreach ( $status as $message ) { - call_user_func_array( [ $status, 'fatal' ], $message ); + $status->fatal( ...$message ); } } else { throw new UnexpectedValueException( 'invalid HTMLForm::trySubmit() return value: ' diff --git a/includes/specialpage/ChangesListSpecialPage.php b/includes/specialpage/ChangesListSpecialPage.php index 0622584331..831644ef2f 100644 --- a/includes/specialpage/ChangesListSpecialPage.php +++ b/includes/specialpage/ChangesListSpecialPage.php @@ -704,9 +704,8 @@ abstract class ChangesListSpecialPage extends SpecialPage { return; } - $knownParams = call_user_func_array( - [ $this->getRequest(), 'getValues' ], - array_keys( $this->getOptions()->getAllValues() ) + $knownParams = $this->getRequest()->getValues( + ...array_keys( $this->getOptions()->getAllValues() ) ); // HACK: Temporarily until we can properly define "sticky" filters and parameters, diff --git a/includes/specialpage/LoginSignupSpecialPage.php b/includes/specialpage/LoginSignupSpecialPage.php index 45e9684c85..3082101dbb 100644 --- a/includes/specialpage/LoginSignupSpecialPage.php +++ b/includes/specialpage/LoginSignupSpecialPage.php @@ -1062,7 +1062,7 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage { // 'id' => 'mw-userlogin-help', // FIXME HTMLInfoField ignores this 'raw' => true, 'default' => Html::element( 'a', [ - 'href' => Skin::makeInternalOrExternalUrl( wfMessage( 'helplogin-url' ) + 'href' => Skin::makeInternalOrExternalUrl( $this->msg( 'helplogin-url' ) ->inContentLanguage() ->text() ), ], $this->msg( 'userlogin-helplink2' )->text() ), diff --git a/includes/specialpage/SpecialPage.php b/includes/specialpage/SpecialPage.php index 317aa0d7c8..5db8066228 100644 --- a/includes/specialpage/SpecialPage.php +++ b/includes/specialpage/SpecialPage.php @@ -791,10 +791,7 @@ class SpecialPage implements MessageLocalizer { * @see wfMessage */ public function msg( $key /* $args */ ) { - $message = call_user_func_array( - [ $this->getContext(), 'msg' ], - func_get_args() - ); + $message = $this->getContext()->msg( ...func_get_args() ); // RequestContext passes context to wfMessage, and the language is set from // the context, but setting the language for Message class removes the // interface message status, which breaks for example usernameless gender diff --git a/includes/specials/SpecialBlock.php b/includes/specials/SpecialBlock.php index efe354a346..bc632b1c0d 100644 --- a/includes/specials/SpecialBlock.php +++ b/includes/specials/SpecialBlock.php @@ -553,7 +553,7 @@ class SpecialBlock extends FormSpecialPage { if ( !$status->isOK() ) { $errors = $status->getErrorsArray(); - return call_user_func_array( [ $form, 'msg' ], $errors[0] ); + return $form->msg( ...$errors[0] ); } else { return true; } diff --git a/includes/specials/SpecialBotPasswords.php b/includes/specials/SpecialBotPasswords.php index f03565adef..2d3a0ccbb5 100644 --- a/includes/specials/SpecialBotPasswords.php +++ b/includes/specials/SpecialBotPasswords.php @@ -57,6 +57,10 @@ class SpecialBotPasswords extends FormSpecialPage { return $this->getConfig()->get( 'EnableBotPasswords' ); } + protected function getLoginSecurityLevel() { + return $this->getName(); + } + /** * Main execution point * @param string|null $par diff --git a/includes/specials/SpecialEmailuser.php b/includes/specials/SpecialEmailuser.php index f322ac40ef..0e931949cc 100644 --- a/includes/specials/SpecialEmailuser.php +++ b/includes/specials/SpecialEmailuser.php @@ -204,7 +204,7 @@ class SpecialEmailUser extends UnlistedSpecialPage { $nu = User::newFromName( $target ); $error = self::validateTarget( $nu, $sender ); - return $error ? $error : $nu; + return $error ?: $nu; } /** diff --git a/includes/specials/SpecialMIMEsearch.php b/includes/specials/SpecialMIMEsearch.php index a54d72de58..f43ed9bd6a 100644 --- a/includes/specials/SpecialMIMEsearch.php +++ b/includes/specials/SpecialMIMEsearch.php @@ -160,7 +160,7 @@ class MIMEsearchPage extends QueryPage { } public function execute( $par ) { - $this->mime = $par ? $par : $this->getRequest()->getText( 'mime' ); + $this->mime = $par ?: $this->getRequest()->getText( 'mime' ); $this->mime = trim( $this->mime ); list( $this->major, $this->minor ) = File::splitMime( $this->mime ); diff --git a/includes/specials/SpecialPageLanguage.php b/includes/specials/SpecialPageLanguage.php index e3485ff724..37412722bb 100644 --- a/includes/specials/SpecialPageLanguage.php +++ b/includes/specials/SpecialPageLanguage.php @@ -224,8 +224,8 @@ class SpecialPageLanguage extends FormSpecialPage { } // Hardcoded [def] if the language is set to null - $logOld = $oldLanguage ? $oldLanguage : $defLang . '[def]'; - $logNew = $newLanguage ? $newLanguage : $defLang . '[def]'; + $logOld = $oldLanguage ?: $defLang . '[def]'; + $logNew = $newLanguage ?: $defLang . '[def]'; // Writing new page language to database $dbw->update( diff --git a/includes/specials/SpecialVersion.php b/includes/specials/SpecialVersion.php index 911c9a63e3..35c5689e4f 100644 --- a/includes/specials/SpecialVersion.php +++ b/includes/specials/SpecialVersion.php @@ -1134,7 +1134,7 @@ class SpecialVersion extends SpecialPage { */ public function getEntryPointInfo() { global $wgArticlePath, $wgScriptPath; - $scriptPath = $wgScriptPath ? $wgScriptPath : "/"; + $scriptPath = $wgScriptPath ?: "/"; $entryPoints = [ 'version-entrypoints-articlepath' => $wgArticlePath, 'version-entrypoints-scriptpath' => $scriptPath, diff --git a/includes/specials/pagers/AllMessagesTablePager.php b/includes/specials/pagers/AllMessagesTablePager.php index e6a0f0be51..35c9931caa 100644 --- a/includes/specials/pagers/AllMessagesTablePager.php +++ b/includes/specials/pagers/AllMessagesTablePager.php @@ -58,7 +58,7 @@ class AllMessagesTablePager extends TablePager { $this->talk = $this->msg( 'talkpagelinktext' )->escaped(); - $this->lang = ( $langObj ? $langObj : $wgContLang ); + $this->lang = $langObj ?: $wgContLang; $this->langcode = $this->lang->getCode(); $this->foreign = !$this->lang->equals( $wgContLang ); diff --git a/includes/upload/UploadBase.php b/includes/upload/UploadBase.php index 6a471ba573..87b96acc79 100644 --- a/includes/upload/UploadBase.php +++ b/includes/upload/UploadBase.php @@ -160,7 +160,7 @@ abstract class UploadBase { * @return null|UploadBase */ public static function createFromRequest( &$request, $type = null ) { - $type = $type ? $type : $request->getVal( 'wpSourceType', 'File' ); + $type = $type ?: $request->getVal( 'wpSourceType', 'File' ); if ( !$type ) { return null; @@ -854,7 +854,7 @@ abstract class UploadBase { if ( !is_array( $error ) ) { $error = [ $error ]; } - return call_user_func_array( 'Status::newFatal', $error ); + return Status::newFatal( ...$error ); } $status = $this->getLocalFile()->upload( @@ -1063,7 +1063,7 @@ abstract class UploadBase { if ( !$isPartial ) { $error = $this->runUploadStashFileHook( $user ); if ( $error ) { - return call_user_func_array( 'Status::newFatal', $error ); + return Status::newFatal( ...$error ); } } try { diff --git a/includes/upload/UploadFromChunks.php b/includes/upload/UploadFromChunks.php index 68bcb9d9c7..ee6f250a76 100644 --- a/includes/upload/UploadFromChunks.php +++ b/includes/upload/UploadFromChunks.php @@ -210,7 +210,7 @@ class UploadFromChunks extends UploadFromFile { // override doStashFile() with completely different functionality in this class... $error = $this->runUploadStashFileHook( $this->user ); if ( $error ) { - call_user_func_array( [ $status, 'fatal' ], $error ); + $status->fatal( ...$error ); return $status; } try { @@ -422,9 +422,9 @@ class UploadChunkFileException extends MWException { class UploadChunkVerificationException extends MWException { public $msg; - public function __construct( $res ) { - $this->msg = call_user_func_array( 'wfMessage', $res ); - parent::__construct( call_user_func_array( 'wfMessage', $res ) + public function __construct( array $res ) { + $this->msg = wfMessage( ...$res ); + parent::__construct( wfMessage( ...$res ) ->inLanguage( 'en' )->useDatabase( false )->text() ); } } diff --git a/includes/utils/MWCryptRand.php b/includes/utils/MWCryptRand.php index 581895807c..0fc45f7e11 100644 --- a/includes/utils/MWCryptRand.php +++ b/includes/utils/MWCryptRand.php @@ -28,6 +28,7 @@ use MediaWiki\MediaWikiServices; class MWCryptRand { /** + * @deprecated since 1.32 * @return CryptRand */ protected static function singleton() { @@ -39,41 +40,49 @@ class MWCryptRand { * random bytes generation in the previously run generate* call * was cryptographically strong. * - * @return bool Returns true if the source was strong, false if not. + * @deprecated since 1.32, always returns true + * + * @return bool Always true */ public static function wasStrong() { - return self::singleton()->wasStrong(); + return true; } /** - * Generate a run of (ideally) cryptographically random data and return + * Generate a run of cryptographically random data and return * it in raw binary form. - * You can use MWCryptRand::wasStrong() if you wish to know if the source used - * was cryptographically strong. + * + * @deprecated since 1.32, use random_bytes() * * @param int $bytes The number of bytes of random data to generate - * @param bool $forceStrong Pass true if you want generate to prefer cryptographically - * strong sources of entropy even if reading from them may steal - * more entropy from the system than optimal. * @return string Raw binary random data */ - public static function generate( $bytes, $forceStrong = false ) { - return self::singleton()->generate( $bytes, $forceStrong ); + public static function generate( $bytes ) { + return random_bytes( floor( $bytes ) ); } /** - * Generate a run of (ideally) cryptographically random data and return + * Generate a run of cryptographically random data and return * it in hexadecimal string format. - * You can use MWCryptRand::wasStrong() if you wish to know if the source used - * was cryptographically strong. * * @param int $chars The number of hex chars of random data to generate - * @param bool $forceStrong Pass true if you want generate to prefer cryptographically - * strong sources of entropy even if reading from them may steal - * more entropy from the system than optimal. * @return string Hexadecimal random data */ - public static function generateHex( $chars, $forceStrong = false ) { - return self::singleton()->generateHex( $chars, $forceStrong ); + public static function generateHex( $chars ) { + // hex strings are 2x the length of raw binary so we divide the length in half + // odd numbers will result in a .5 that leads the generate() being 1 character + // short, so we use ceil() to ensure that we always have enough bytes + $bytes = ceil( $chars / 2 ); + // Generate the data and then convert it to a hex string + $hex = bin2hex( random_bytes( $bytes ) ); + + // A bit of paranoia here, the caller asked for a specific length of string + // here, and it's possible (eg when given an odd number) that we may actually + // have at least 1 char more than they asked for. Just in case they made this + // call intending to insert it into a database that does truncation we don't + // want to give them too much and end up with their database and their live + // code having two different values because part of what we gave them is truncated + // hence, we strip out any run of characters longer than what we were asked for. + return substr( $hex, 0, $chars ); } } diff --git a/includes/widget/search/BasicSearchResultSetWidget.php b/includes/widget/search/BasicSearchResultSetWidget.php index e23664050f..8521e68f00 100644 --- a/includes/widget/search/BasicSearchResultSetWidget.php +++ b/includes/widget/search/BasicSearchResultSetWidget.php @@ -123,10 +123,8 @@ class BasicSearchResultSetWidget { $terms = $wgContLang->convertForSearchResult( $resultSet->termMatches() ); $hits = []; - $result = $resultSet->next(); - while ( $result ) { - $hits[] .= $this->resultWidget->render( $result, $terms, $offset++ ); - $result = $resultSet->next(); + foreach ( $resultSet as $result ) { + $hits[] = $this->resultWidget->render( $result, $terms, $offset++ ); } return "
      " . implode( '', $hits ) . "
    "; diff --git a/includes/widget/search/SimpleSearchResultSetWidget.php b/includes/widget/search/SimpleSearchResultSetWidget.php index d0c259fea2..248099ada0 100644 --- a/includes/widget/search/SimpleSearchResultSetWidget.php +++ b/includes/widget/search/SimpleSearchResultSetWidget.php @@ -56,12 +56,10 @@ class SimpleSearchResultSetWidget implements SearchResultSetWidget { $iwResults = []; foreach ( $resultSets as $resultSet ) { - $result = $resultSet->next(); - while ( $result ) { + foreach ( $resultSet as $result ) { if ( !$result->isBrokenTitle() ) { $iwResults[$result->getTitle()->getInterwiki()][] = $result; } - $result = $resultSet->next(); } } diff --git a/languages/Language.php b/languages/Language.php index 321d5f895a..d762a5752c 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -3152,7 +3152,7 @@ class Language { return; } $this->mMagicHookDone = true; - Hooks::run( 'LanguageGetMagic', [ &$this->mMagicExtensions, $this->getCode() ] ); + Hooks::run( 'LanguageGetMagic', [ &$this->mMagicExtensions, $this->getCode() ], '1.16' ); } /** @@ -3208,7 +3208,7 @@ class Language { $this->mExtendedSpecialPageAliases = self::$dataCache->getItem( $this->mCode, 'specialPageAliases' ); Hooks::run( 'LanguageGetSpecialPageAliases', - [ &$this->mExtendedSpecialPageAliases, $this->getCode() ] ); + [ &$this->mExtendedSpecialPageAliases, $this->getCode() ], '1.16' ); } return $this->mExtendedSpecialPageAliases; @@ -4321,13 +4321,18 @@ class Language { * the "raw" tag (-{R| }-) to prevent conversion. * * This function is called "markNoConversion" for historical - * reasons. + * reasons *BUT DIFFERS SIGNIFICANTLY* from + * LanguageConverter::markNoConversion(), with which it is easily + * confused. * * @param string $text Text to be used for external link * @param bool $noParse Wrap it without confirming it's a real URL first * @return string The tagged text + * @deprecated since 1.32, use LanguageConverter::markNoConversion() + * instead. */ public function markNoConversion( $text, $noParse = false ) { + wfDeprecated( __METHOD__, '1.32' ); // Excluding protocal-relative URLs may avoid many false positives. if ( $noParse || preg_match( '/^(?:' . wfUrlProtocolsWithoutProtRel() . ')/', $text ) ) { return $this->mConverter->markNoConversion( $text ); diff --git a/languages/data/Names.php b/languages/data/Names.php index af844ee5e3..3a96283fc6 100644 --- a/languages/data/Names.php +++ b/languages/data/Names.php @@ -469,6 +469,7 @@ class Names { 'yue' => '粵語', # Cantonese 'za' => 'Vahcuengh', # Zhuang 'zea' => 'Zeêuws', # Zeeuws/Zeaws + 'zgh' => 'ⵜⴰⵎⴰⵣⵉⵖⵜ ⵜⴰⵏⴰⵡⴰⵢⵜ', # Moroccan Amazigh (multiple scripts - defaults to Neo-Tifinagh) 'zh' => '中文', # (Zhōng Wén) - Chinese 'zh-classical' => '文言', # Classical Chinese/Literary Chinese -- (see T10217) 'zh-cn' => "中文(中国大陆)\u{200E}", # Chinese (PRC) diff --git a/languages/i18n/ace.json b/languages/i18n/ace.json index e6a615e130..0ee0da0e2b 100644 --- a/languages/i18n/ace.json +++ b/languages/i18n/ace.json @@ -429,6 +429,11 @@ "retypenew": "Pasoë lom lageuëm barô:", "resetpass_submit": "Atô lageuëm rahsia lheuëh nyan tamöng", "changepassword-success": "Lageuëm rahsia droëneuh meuhasé geugantoë!", + "botpasswords-label-create": "Peugöt", + "botpasswords-label-update": "Peubarô", + "botpasswords-label-cancel": "Pubateue", + "botpasswords-label-delete": "Sampôh", + "botpasswords-label-resetpassword": "Atô keulayi lageuem rahsia", "resetpass_forbidden": "Lageuëm rahsia h'an jeuët geugantoë", "resetpass_forbidden-reason": "Lageuëm rahsia h`an jeuët geugantoë: $1", "resetpass-no-info": "Droëneuh suwah neutamöng mangat jeuët neu'eu laman nyoë", diff --git a/languages/i18n/be-tarask.json b/languages/i18n/be-tarask.json index 363502595f..cd958cf07e 100644 --- a/languages/i18n/be-tarask.json +++ b/languages/i18n/be-tarask.json @@ -1532,11 +1532,11 @@ "filetype-unwanted-type": "«.$1» — непажаданы тып файла.\n{{PLURAL:$3|1=Пажаданым тыпам файла зьяўляецца|Пажаданымі тыпамі файлаў зьяўляюцца:}} $2.", "filetype-banned-type": "«.$1» — {{PLURAL:$4|1=забаронены тып файлаў|забароненыя тыпы файлаў}}.\n{{PLURAL:$3|1=Дазволены тып файлаў|Дазволеныя тыпы файлаў}}: $2.", "filetype-missing": "Файл ня мае пашырэньня (напрыклад, «.jpg»).", - "empty-file": "Дасланы Вамі файл пусты.", - "file-too-large": "Дасланы Вамі файл занадта вялікі.", - "filename-tooshort": "Назва файла занадта кароткая.", - "filetype-banned": "Гэты тып файла забаронены.", - "verification-error": "Гэты файл не прайшоў вэрыфікацыю.", + "empty-file": "Дасланы вамі файл пусты.", + "file-too-large": "Дасланы вамі файл занадта вялікі.", + "filename-tooshort": "Назва файлу занадта кароткая.", + "filetype-banned": "Гэты тып файлу забаронены.", + "verification-error": "Гэты файл не прайшоў праверку.", "hookaborted": "Прапанаваная Вамі зьмена была адхіленая апрацоўшчыкам пашырэньня.", "illegal-filename": "Недазволеная назва файла.", "overwrite": "Замена існуючага файла забароненая.", diff --git a/languages/i18n/be.json b/languages/i18n/be.json index aaaf4ae162..f8c87a1739 100644 --- a/languages/i18n/be.json +++ b/languages/i18n/be.json @@ -621,7 +621,7 @@ "image_sample": "Напрыклад.jpg", "image_tip": "Файл у тэксце", "media_sample": "Напрыклад.ogg", - "media_tip": "Спасылка на медыя-файл", + "media_tip": "Спасылка на медыяфайл", "sig_tip": "Ваш подпіс і адзначаны час", "hr_tip": "Гарызантальная рыса (не злоўжывайце гэтым)", "summary": "Тлумачэнне:", diff --git a/languages/i18n/bg.json b/languages/i18n/bg.json index 21fefcb921..ade421bb49 100644 --- a/languages/i18n/bg.json +++ b/languages/i18n/bg.json @@ -3693,5 +3693,13 @@ "edit-error-short": "Грешка: $1", "edit-error-long": "Грешки:\n\n$1", "revid": "версия $1", - "pagedata-bad-title": "Невалидно заглавие: $1." + "pagedata-bad-title": "Невалидно заглавие: $1.", + "passwordpolicies": "Правила за паролите", + "passwordpolicies-summary": "Това е списъкът на действащите правила за паролите на потребителските групи дефинирани в това уики.", + "passwordpolicies-policy-minimalpasswordlength": "Паролата трябва да бъде от поне $1 {{PLURAL:$1|знак|знака}}", + "passwordpolicies-policy-minimumpasswordlengthtologin": "Паролата трябва да бъде поне $1 {{PLURAL:$1|знак|знака}} за да можете да влезете", + "passwordpolicies-policy-passwordcannotmatchusername": "Паролата не може да бъде същата като потребителското име", + "passwordpolicies-policy-passwordcannotmatchblacklist": "Паролата не може да съвпада с пароли от черния списък", + "passwordpolicies-policy-maximalpasswordlength": "Паролата трябва да бъде по-малко от $1 {{PLURAL:$1|знак|знака}}", + "passwordpolicies-policy-passwordcannotbepopular": "Паролата не може да бъде {{PLURAL:$1|най-популярната такава|от списъка на най-популярните $1 пароли}}" } diff --git a/languages/i18n/bn.json b/languages/i18n/bn.json index 7e76d0e5ea..db59cc7272 100644 --- a/languages/i18n/bn.json +++ b/languages/i18n/bn.json @@ -787,6 +787,8 @@ "expansion-depth-exceeded-warning": "পাতাটি এক্সেপশন সীমানা অতিক্রম করেছে", "parser-unstrip-loop-warning": "ত্রুটিপূর্ণ লুপ খুঁজে পাওয়া গিয়েছে", "unstrip-depth-warning": "লুপ রিকারশন সীমানা অতিক্রম করেছে ($1)", + "unstrip-depth-category": "পাতাগুলি যেখানে unstrip গভীরতার সীমা অতিক্রম করেছেন", + "unstrip-size-warning": "Unstrip আকারের সীমা অতিক্রম করেছে ($1)", "converter-manual-rule-error": "ম্যানুয়াল ভাষা রূপান্তর নিয়মে ত্রুটি পাওয়া গিয়েছে", "undo-success": "সম্পাদনাটি বাতিল করা যাবে। অনুগ্রহ করে নিচের তুলনাটি পরীক্ষা করে দেখুন ও নিশ্চিত করুন যে এটাই আপনি করতে চান, এবং তারপর নিচের সম্পাদনাগুলি সংরক্ষণ করে সম্পাদনাটির বাতিল প্রক্রিয়া সমাপ্ত করুন।", "undo-failure": "এ সম্পাদনা মধ্যবর্তী সম্পাদনাসমূহের কারণে পূর্বাবস্থায় ফিরিয়ে নেওয়া যাবে না।", @@ -1939,6 +1941,7 @@ "protectedtitles-submit": "শিরোনাম প্রদর্শন করুন", "listusers": "ব্যবহারকারীর তালিকা", "listusers-editsonly": "শুধুমাত্র এমন ব্যবহারকারীদের দেখাও যাদের অবদান আছে", + "listusers-temporarygroupsonly": "শুধুমাত্র অস্থায়ী ব্যবহারকারী দলের ব্যবহারকারীদের দেখান", "listusers-creationsort": "তৈরির তারিখ অনুসারে সাজাও", "listusers-desc": "বড় থেকে ছোট ক্রম অনুযায়ী সাজাও", "usereditcount": "$1 {{PLURAL:$1|সম্পাদনা|সম্পাদনা}}", diff --git a/languages/i18n/ca.json b/languages/i18n/ca.json index 2ba5bc6d6c..fdadfc5438 100644 --- a/languages/i18n/ca.json +++ b/languages/i18n/ca.json @@ -96,7 +96,7 @@ "tog-watchlisthideminor": "Amaga les edicions menors de la llista de seguiment", "tog-watchlisthideliu": "Amaga a la llista les edicions d'usuaris registrats", "tog-watchlistreloadautomatically": "Recarrega la llista de seguiment automàticament sempre que canviï un filtre (cal JavaScript)", - "tog-watchlistunwatchlinks": "Afegeix enllaços directes per a seguir o deixar de seguir les entrades de la llista de seguiment (cal Javascript per a la funcionalitat d'alternar)", + "tog-watchlistunwatchlinks": "Afegeix marcadors directes ({{int:Watchlist-unwatch}}/{{int:Watchlist-unwatch-undo}}) per a les pàgines en seguiment amb canvis (cal Javascript per a la funcionalitat d'alternar)", "tog-watchlisthideanons": "Amaga a la llista les edicions d'usuaris anònims", "tog-watchlisthidepatrolled": "Amaga edicions patrullades de la llista de seguiment", "tog-watchlisthidecategorization": "Amaga la categorització de les pàgines", @@ -410,6 +410,7 @@ "cascadeprotected": "Aquesta pàgina està protegida i no es pot modificar perquè està inclosa en {{PLURAL:$1|la següent pàgina, que té|les següents pàgines, que tenen}} activada l'opció de «protecció en cascada»:\n$2", "namespaceprotected": "No teniu permís per a modificar pàgines en l'espai de noms '''$1'''.", "customcssprotected": "No teniu permisos per editar la pàgina CSS perquè conté els paràmetres personals d'un altre usuari.", + "customjsonprotected": "No teniu permisos per editar aquesta pàgina JSON perquè conté configuracions personals d'un altre usuari.", "customjsprotected": "No teniu permisos per editar la pàgina JavaScript perquè conté els paràmetres personals d'un altre usuari.", "mycustomcssprotected": "No tens permís per editar aquesta pàgina CSS.", "mycustomjsonprotected": "No teniu permisos per editar aquesta pàgina JSON.", @@ -508,12 +509,12 @@ "wrongpasswordempty": "La contrasenya que s'ha introduït estava en blanc. Torneu-ho a provar.", "passwordtooshort": "La contrasenya ha de tenir un mínim {{PLURAL:$1|d'un caràcter|de $1 caràcters}}.", "passwordtoolong": "La contrasenya ha de tenir un màxim {{PLURAL:$1|d'un caràcter|de $1 caràcters}}.", - "passwordtoopopular": "No poden utilitzar-se contrasenyes d'ús habitual. Trieu-ne una més única.", + "passwordtoopopular": "No poden utilitzar-se contrasenyes d'ús habitual. Trieu una contrasenya que sigui més difícil d'endevinir.", "password-name-match": "La contrasenya ha de ser diferent del vostre nom d'usuari.", "password-login-forbidden": "No és permès d'utilitzar aquest nom d'usuari i contrasenya.", "mailmypassword": "Restableix la contrasenya", "passwordremindertitle": "Nova contrasenya temporal per al projecte {{SITENAME}}", - "passwordremindertext": "Algú (vós mateix segurament, des de l'adreça IP $1) ha sol·licitat que us enviéssim una nova contrasenya per a iniciar la sessió en el projecte {{SITENAME}} ($4).\nLa nova contrasenya temporal per a l'usuari «$2» és ara «$3». Si la vostra intenció era aquesta, ara hauríeu d'iniciar la sessió i canviar-la. Tingueu present que és temporal i caducarà d'aquí a {{PLURAL:$5|un dia|$5 dies}}.\n\nSi algú altre hagués fet aquesta sol·licitud o si ja haguéssiu recordat la vostra contrasenya i\nno volguéssiu canviar-la, ignoreu aquest missatge i continueu utilitzant\nla contrasenya antiga.", + "passwordremindertext": "Algú (des de l'adreça IP $1) ha sol·licitat una nova contrasenya per al projecte {{SITENAME}} ($4).\nLa nova contrasenya temporal per a l'usuari «$2» és ara «$3». Si la vostra intenció era aquesta, ara hauríeu d'iniciar la sessió i canviar-la. Tingueu present que és temporal i caducarà d'aquí a {{PLURAL:$5|un dia|$5 dies}}.\n\nSi algú altre hagués fet aquesta sol·licitud o si ja haguéssiu recordat la vostra contrasenya i\nno volguéssiu canviar-la, ignoreu aquest missatge i continueu utilitzant\nla contrasenya antiga.", "noemail": "No hi ha cap adreça electrònica registrada de l'usuari «$1».", "noemailcreate": "Heu d’indicar una adreça electrònica vàlida.", "passwordsent": "S'ha enviat una nova contrasenya a l'adreça electrònica registrada per «$1».\nInicieu una sessió després que la rebeu.", @@ -564,6 +565,7 @@ "botpasswords-existing": "Contrasenyes de bot existents", "botpasswords-createnew": "Crea una contrasenya de bot nova", "botpasswords-editexisting": "Edita una contrasenya de bot existent", + "botpasswords-label-needsreset": "(cal reiniciar la contrasenya)", "botpasswords-label-appid": "Nom del bot:", "botpasswords-label-create": "Crea", "botpasswords-label-update": "Actualitza", @@ -683,8 +685,8 @@ "subject-preview": "Previsualització de l’assumpte:", "previewerrortext": "S'ha produït un error quan es provava de previsualitzar els canvis.", "blockedtitle": "L'usuari està blocat", - "blockedtext": "'''S'ha procedit al blocatge del vostre compte d'usuari o la vostra adreça IP.'''\n\nEl blocatge l'ha dut a terme l'usuari $1.\nEl motiu donat és ''$2''.\n\n* Inici del blocatge: $8\n* Final del blocatge: $6\n* Compte blocat: $7\n\nPodeu contactar amb $1 o un dels [[{{MediaWiki:Grouppage-sysop}}|administradors]] per a discutir-ho.\n\nTingueu en compte que no podeu fer servir el formulari d'enviament de missatges de correu electrònic a cap usuari, a menys que tingueu una adreça de correu vàlida registrada a les vostres [[Special:Preferences|preferències d'usuari]] i no ho tingueu tampoc blocat.\n\nLa vostra adreça IP actual és $3, i el número d'identificació del blocatge és #$5.\nSi us plau, incloeu aquestes dades en totes les consultes que feu.", - "autoblockedtext": "La vostra adreça IP ha estat blocada automàticament perquè va ser usada per un usuari actualment blocat. Aquest usuari va ser blocat per l'{{GENDER:$1|administrador|administradora}} $1. El motiu donat per al blocatge és aquest:\n\n:$2\n\n* Inici del blocatge: $8\n* Final del blocatge: $6\n* Usuari blocat: $7\n\nPodeu contactar l'usuari $1 o algun altre dels [[{{MediaWiki:Grouppage-sysop}}|administradors]] per a discutir el blocatge.\n\nRecordeu que per a poder usar l'opció «Envia un missatge de correu electrònic a aquest usuari» haureu d'haver validat una adreça de correu electrònic a les vostres [[Special:Preferences|preferències]].\n\nEl número d'identificació de la vostra adreça IP és $3, i l'ID del blocatge és #$5. Si us plau, incloeu aquestes dades en totes les consultes que feu.", + "blockedtext": "S'ha procedit al blocatge del vostre compte d'usuari o la vostra adreça IP.\n\nEl blocatge l'ha dut a terme l'usuari $1.\nEl motiu donat és $2.\n\n* Inici del blocatge: $8\n* Final del blocatge: $6\n* Compte blocat: $7\n\nPodeu contactar amb $1 o un dels [[{{MediaWiki:Grouppage-sysop}}|administradors]] per a discutir-ho.\n\nTingueu en compte que no podeu fer servir la funció «{{int:emailuser}}» a menys que tingueu una adreça de correu vàlida registrada a les vostres [[Special:Preferences|preferències d'usuari]] i no ho tingueu tampoc blocat.\n\nLa vostra adreça IP actual és $3, i el número d'identificació del blocatge és #$5.\nSi us plau, incloeu aquestes dades en totes les consultes que feu.", + "autoblockedtext": "La vostra adreça IP ha estat blocada automàticament perquè va ser usada per un usuari actualment blocat. Aquest usuari va ser blocat per l'{{GENDER:$1|administrador|administradora}} $1. El motiu donat per al blocatge és aquest:\n\n:$2\n\n* Inici del blocatge: $8\n* Final del blocatge: $6\n* Usuari blocat: $7\n\nPodeu contactar l'usuari $1 o algun altre dels [[{{MediaWiki:Grouppage-sysop}}|administradors]] per a discutir el blocatge.\n\nRecordeu que per a poder usar l'opció «{{int:emailuser}}» haureu d'haver validat una adreça de correu electrònic a les vostres [[Special:Preferences|preferències]].\n\nEl número d'identificació de la vostra adreça IP és $3, i l'ID del blocatge és #$5. Si us plau, incloeu aquestes dades en totes les consultes que feu.", "systemblockedtext": "El vostre nom d'usuari o adreça IP ha estat blocada automàticament pel MediaWiki.\nEl motiu donat és:\n\n:$2\n\n* Inici del blocatge: $8\n* Caducitat del blocatge: $6\n* Destinatari del blocatge: $7\n\nLa vostra adreça IP actual és $3.\nAfegiu les dades de més amunt en qualsevol consulta que feu al respecte.", "blockednoreason": "no s'ha donat cap motiu", "whitelistedittext": "Heu de $1 per modificar pàgines.", @@ -707,6 +709,7 @@ "blocked-notice-logextract": "En aquests moments aquest compte d'usuari es troba blocat.\nPer més detalls, la darrera entrada del registre es mostra a continuació:", "clearyourcache": "Nota: Després de desar, possiblement necessitareu refrescar la memòria cau del vostre navegador per a veure'n els canvis.\n* Firefox / Safari: Premeu Shift i alhora cliqueu el botó Actualitza, o pressioneu Ctrl+F5 o Ctrl+R (⌘+R en un Mac)\n* Google Chrome: Premeu Ctrl+Shift+R (⌘+Shift+R en un Mac)\n* Internet Explorer: Premeu Ctrl i alhora cliqueu a Actualitza o pressioneu Ctrl+F5\n* Opera: Aneu a Menú → Preferències (Opera → Preferències en un Mac) i llavors a Privadesa i seguretat → Neteja dades de navegació → Imatges i fitxers en memòria cau.", "usercssyoucanpreview": "'''Consell:''' Utilitzeu el botó \"{{int:showpreview}}\" per provar el vostre nou CSS abans de desar-lo.", + "userjsonyoucanpreview": "Consell: Utilitzeu el botó «{{int:showpreview}}» per provar el nou JSON abans de desar-lo.", "userjsyoucanpreview": "'''Consell:''' Utilitzeu el botó \"{{int:showpreview}}\" per provar el vostre nou JavaScript abans de desar-lo.", "usercsspreview": "'''Recordeu que esteu previsualitzant el vostre CSS d'usuari.'''\n'''Encara no s'ha desat!'''", "userjspreview": "'''Recordeu que només estau provant/previsualitzant el vostre JavaScript, encara no ho heu desat!'''", @@ -739,7 +742,7 @@ "longpageerror": "'''Error: El text que heu introduït és {{PLURAL:$1|d'un kilobyte|de $1 kilobytes}} i sobrepassa el màxim permès de {{PLURAL:$2|one kilobyte|$2 kilobytes}}.'''\nNo es pot desar.", "readonlywarning": "Avís: La base de dades està blocada per manteniment, de manera que no podreu desar els canvis ara mateix.\nÉs possible que vulgueu copiar i enganxar el text en un arxiu de text i desar-ho més tard.\n\nL'administrador de sistema que l'ha blocada ha donat la següent explicació: $1", "protectedpagewarning": "'''ATENCIÓ: Aquesta pàgina està protegida i només els usuaris amb drets d'administrador la poden modificar.\nA continuació es mostra la darrera entrada del registre com a referència:", - "semiprotectedpagewarning": "'''Avís:''' Aquesta pàgina està blocada i només pot ser modificada per usuaris registrats.\nA continuació es mostra la darrera entrada del registre com a referència:", + "semiprotectedpagewarning": "Avís: Aquesta pàgina està blocada i només pot ser modificada per usuaris autoconfirmats.\nA continuació es mostra la darrera entrada del registre com a referència:", "cascadeprotectedwarning": "Atenció: Aquesta pàgina està protegida de forma que només la poden modificar usuaris amb [[Special:ListGroupRights|permisos específics]], ja que està inclosa a {{PLURAL:$1|la següent pàgina|les següents pàgines}} amb l'opció de «protecció en cascada» activada:", "titleprotectedwarning": "'''ATENCIÓ: Aquesta pàgina està protegida de tal manera que es necessiten uns [[Special:ListGroupRights|drets específics]] per a poder crear-la.'''\nA continuació es mostra la darrera entrada del registre com a referència:", "templatesused": "Aquesta pàgina fa servir {{PLURAL:$1|la següent plantilla|les següents plantilles}}:", @@ -801,6 +804,7 @@ "parser-template-loop-warning": "S'ha detectat un bucle de plantilla: [[$1]]", "template-loop-category": "Pàgines amb bucles de plantilla", "template-loop-category-desc": "La pàgina conté un bucle de plantilles, és a dir, una plantilla que s'inclou a si mateixa recursivament.", + "template-loop-warning": "Avís: Aquesta pàgina crida [[:$1]] provocant un bucle de plantilles (una crida recursiva infinita).", "parser-template-recursion-depth-warning": "S'ha excedit el límit de recursivitat de plantilles ($1)", "language-converter-depth-warning": "S'ha excedit el límit de profunditat del convertidor d'idiomes ($1)", "node-count-exceeded-category": "Pàgines on s'ha excedit el recompte de nodes", @@ -1051,8 +1055,8 @@ "stub-threshold-disabled": "Inhabilitat", "recentchangesdays": "Dies a mostrar en els canvis recents:", "recentchangesdays-max": "(màxim $1 {{PLURAL:$1|dia|dies}})", - "recentchangescount": "Nombre d'edicions a mostrar per defecte:", - "prefs-help-recentchangescount": "Inclou els canvis recents, els historials de pàgines i els registres.", + "recentchangescount": "Nombre d'edicions a mostrar per defecte en canvis recents, historials de pàgines i registres:", + "prefs-help-recentchangescount": "Nombre màxim: 1000", "prefs-help-watchlist-token2": "Aquesta és la clau secreta pel canal de continguts de la vostra llista de seguiment.\nQualsevol que la conegui podria llegir la vostra llista de seguiment, així que no la compartiu.\nSi és necessari, [[Special:ResetTokens|la podeu restaurar]].", "savedprefs": "S’han desat les vostres preferències.", "savedrights": "S'han desat els grups d'usuari de {{GENDER:$1|$1}}.", @@ -1073,6 +1077,7 @@ "timezoneregion-indian": "Oceà Índic", "timezoneregion-pacific": "Oceà Pacífic", "allowemail": "Permet que altres usuaris m'enviïn missatges per correu electrònic", + "email-allow-new-users-label": "Permet correus electrònics d'usuaris novells", "email-blacklist-label": "Prohibeix a aquests usuaris que m'enviïn correus electrònics:", "prefs-searchoptions": "Cerca", "prefs-namespaces": "Espais de noms", @@ -1081,7 +1086,7 @@ "prefs-custom-css": "CSS personalitzat", "prefs-custom-json": "JSON personalitzat", "prefs-custom-js": "JS personalitzat", - "prefs-common-config": "CSS/JS compartit per tots els skins:", + "prefs-common-config": "CSS/JSON/JavaScript compartit per a totes les aparences:", "prefs-reset-intro": "Podeu usar aquesta pàgina per a restablir les vostres preferències als valors per defecte.\nNo es podrà desfer el canvi.", "prefs-emailconfirm-label": "Confirmació de correu electrònic:", "youremail": "Correu electrònic:", @@ -1263,8 +1268,8 @@ "grant-createaccount": "Crea comptes", "grant-createeditmovepage": "Crea, modifica i reanomena pàgines", "grant-delete": "Suprimeix pàgines, revisions i entrades de registre", - "grant-editinterface": "Modifica l'espai de noms MediaWiki i els CSS/JavaScript d'usuari", - "grant-editmycssjs": "Modifiqueu el vostre CSS/JavaScript d'usuari", + "grant-editinterface": "Modifica l'espai de noms MediaWiki i els CSS/JSON/JavaScript d'usuari", + "grant-editmycssjs": "Modifiqueu el vostre CSS/JSON/JavaScript d'usuari", "grant-editmyoptions": "Editeu les vostres preferències d'usuari", "grant-editmywatchlist": "Modifica la llista de seguiment", "grant-editpage": "Modifica les pàgines existents", @@ -1517,7 +1522,7 @@ "recentchangeslinked-feed": "Canvis relacionats", "recentchangeslinked-toolbox": "Canvis relacionats", "recentchangeslinked-title": "Canvis relacionats amb «$1»", - "recentchangeslinked-summary": "Introduïu un nom de pàgina per veure els canvis en les pàgines enllaçades des de o cap a aquesta pàgina (per veure els membres d'una categoria, introduïu Categoria:Nom de la categoria).\nEls canvis en pàgines de la vostra [[Special:Watchlist|llista de seguiment]] apareixen en negreta.", + "recentchangeslinked-summary": "Introduïu un nom de pàgina per veure els canvis en les pàgines enllaçades des de o cap a aquesta pàgina (per veure els membres d'una categoria, introduïu {{ns:category}}:Nom de la categoria).\nEls canvis en pàgines de la vostra [[Special:Watchlist|llista de seguiment]] apareixen en negreta.", "recentchangeslinked-page": "Nom de la pàgina:", "recentchangeslinked-to": "Mostra els canvis de les pàgines enllaçades amb la pàgina donada", "recentchanges-page-added-to-category": "[[:$1]] afegida a la categoria", @@ -3732,7 +3737,7 @@ "expandtemplates": "Expansió de plantilles", "expand_templates_intro": "Aquesta pàgina especial expandeix de forma recursiva totes les plantilles d'un text donat.\nTambé expandeix les funcions sintàctiques, com ara {{#language:…}}, i les variables predefinides, com {{CURRENTDAY}} —de fet, gairebé tot que estigui entre claus dobles.", "expand_templates_title": "Títol per contextualitzar ({{FULLPAGENAME}}, etc):", - "expand_templates_input": "El vostre text:", + "expand_templates_input": "Wikitext d'entrada:", "expand_templates_output": "Resultat:", "expand_templates_xml_output": "Sortida XML", "expand_templates_html_output": "Sortida en HTML sense filtrar", @@ -3744,7 +3749,7 @@ "expand_templates_preview": "Previsualitza", "expand_templates_preview_fail_html": "Atès que {{SITENAME}} té HTML cru habilitat i s'ha produït una pèrdua de dades de la sessió, s'ha amagat la vista prèvia com a mesura de precaució contra atacs en JavaScript.\n\nSi això és un intent de previsualització legítim, torneu-ho a provar.\nSi encara no funciona, intenteu [[Special:UserLogout|finalitzar la sessió]] i comproveu si el vostre navegador permet galetes d'aquest lloc.", "expand_templates_preview_fail_html_anon": "Atès que {{SITENAME}} té l'HTML cru habilitat i no heu iniciat una sessió, s'ha amagat la previsualització com a prevenció d'atacs en JavaScript.\n\nSi això és un intent de previsualització legítim, [[Special:UserLogin|inicieu una sessió]] i torneu-ho a provar.", - "expand_templates_input_missing": "Cal que proporcioneu al menys algun text d'entrada.", + "expand_templates_input_missing": "Cal que proporcioneu al menys algun wikitext d'entrada.", "pagelanguage": "Canvia l'idioma de la pàgina", "pagelang-name": "Pàgina", "pagelang-language": "Idioma", @@ -3952,5 +3957,10 @@ "gotointerwiki-external": "Esteu a punt d’abandonar {{SITENAME}} per a visitar [[$2]], un lloc web diferent.\n\n'''[$1 Continua a $1]'''", "undelete-cantedit": "Com que no podeu editar aquesta pàgina, no en podeu desfer la supressió.", "pagedata-title": "Dades de la pàgina", - "pagedata-bad-title": "Títol no vàlid: $1" + "pagedata-bad-title": "Títol no vàlid: $1", + "passwordpolicies": "Polítiques de contrasenya", + "passwordpolicies-group": "Grup", + "passwordpolicies-policies": "Polítiques", + "passwordpolicies-policy-minimalpasswordlength": "La contrasenya ha de tenir un mínim {{PLURAL:$1|d'un caràcter|de $1 caràcters}}", + "passwordpolicies-policy-passwordcannotmatchusername": "La contrasenya no pot ser igual que el nom d'usuari" } diff --git a/languages/i18n/ce.json b/languages/i18n/ce.json index 14deacc541..b703394d0d 100644 --- a/languages/i18n/ce.json +++ b/languages/i18n/ce.json @@ -558,7 +558,7 @@ "nowiki_sample": "Кхуза хӀоттаде хийца оьшуш доцу йоза", "nowiki_tip": "Тергал ца бо вики-бáрамхlоттор", "image_sample": "Example.jpg", - "image_tip": "Чохь йолу файл", + "image_tip": "Файл чуйиллар", "media_sample": "Example.ogg", "media_tip": "Хьажорг медиа-файлан тӀе", "sig_tip": "Хьан куьгтаlор аъ хlоттина хан", @@ -688,6 +688,10 @@ "expansion-depth-exceeded-category": "Схьаелларан кӀоргалла тӀех даьккхина агӀонаш", "expansion-depth-exceeded-warning": "АгӀонгахь чуйихкар тӀехдаьккхина", "parser-unstrip-loop-warning": "ДӀачӀагӀанца pre карина", + "unstrip-depth-warning": "Рекурси ($1) доза тӀехдаьлла", + "unstrip-depth-category": "КӀоргалла цагуш йолу агӀонаш", + "unstrip-size-warning": "Unstrip рекурси ($1) доза тӀехдаьлла", + "unstrip-size-category": "Билгалдар цагуш долу агӀонаш", "undo-success": "Нисйинарг а тlе цалаца мега. Дехар до, хьажа цхьатерра йуй башхо, тешна хила, баккъалла иза хийцам буйте хьуна безарг, тlакха тlе таlайе «дlайазйе агlо», хийцам хlотта ба.", "undo-failure": "Юккъера хийцамаш бахьнехь нисдар юхадаккха йиш яц.", "undo-norev": "Нисдар юхадаккха цало, иза доцу делла я дӀаяьккхина дела.", @@ -1362,6 +1366,7 @@ "uploaddisabled": "Чуяккхар магийна дац", "copyuploaddisabled": "URL тӀера чуяккхар дӀадайина ду.", "uploaddisabledtext": "Файлаш чуяхар дӀадайина ду.", + "uploaded-href-attribute-svg": "Элементаш тӀетовжа (href) мега data: (файл чуйиллар) тӀе, хьажорг http:// я https:// я фрагмент (#, оцу документ тӀехь). Кхечу элементашна, масала санна, data: а, фрагмент а бен цамагийна. \nСурт чудийлла хьажа SVG форматехь. Карина <$1 $2=\"$3\">.", "uploadscriptednamespace": "ХӀокху SVG-файлан цӀерийн меттиг нийса яц '$1'", "upload-source": "ДIайолалун файл", "sourcefilename": "ДIайолалун файл:", @@ -3034,6 +3039,8 @@ "limitreport-templateargumentsize-value": "$1/$2 {{PLURAL:$2|байт}}", "limitreport-expansiondepth": "Шордаларан уггар йокха кӀоргалла", "limitreport-expensivefunctioncount": "Анализаторан «еза» функцийн дукхалла", + "limitreport-unstrip-depth": "КӀорге рекурси Unstrip", + "limitreport-unstrip-size": "Чуьраниг схьаделачул тӀехьа Unstrip болу барам", "expandtemplates": "Кепаш схьаястар", "expand_templates_intro": "ХӀокху белхан агӀорахь йиш ю йоза хийца.\nКхин кепаш схьаяста.\n{{#language:…}} кхочуш дан тайп\n{{CURRENTDAY}}.", "expand_templates_title": "АгӀона {{FULLPAGENAME}} корта кхин а:", diff --git a/languages/i18n/cv.json b/languages/i18n/cv.json index 35a0f30cea..3a3478c11f 100644 --- a/languages/i18n/cv.json +++ b/languages/i18n/cv.json @@ -1022,7 +1022,8 @@ "specialpages-group-media": "Медиа-материалсемпе тултарăшсем", "specialpages-group-users": "Хутшăнакансем тата правасем", "specialpages-group-highuse": "Нумай усă куракан страницăсем", - "tag-list-wrapper": "([[Special:Tags|$1 метка]]: $2)", + "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Тег|Тегсем}}]]: $2)", + "tags-title": "Тегсем", "compare-submit": "Танлаштар", "htmlform-selectorother-other": "Урăххи", "htmlform-no": "Çук", diff --git a/languages/i18n/en.json b/languages/i18n/en.json index fcf2e25721..ee098ddc6c 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -1400,7 +1400,7 @@ "rcfilters-savedqueries-rename": "Rename", "rcfilters-savedqueries-setdefault": "Set as default", "rcfilters-savedqueries-unsetdefault": "Remove as default", - "rcfilters-savedqueries-remove": "Remove", + "rcfilters-savedqueries-remove": "Delete", "rcfilters-savedqueries-new-name-label": "Name", "rcfilters-savedqueries-new-name-placeholder": "Describe the purpose of the filter", "rcfilters-savedqueries-apply-label": "Create filter", @@ -1416,7 +1416,7 @@ "rcfilters-empty-filter": "No active filters. All contributions are shown.", "rcfilters-filterlist-title": "Filters", "rcfilters-filterlist-whatsthis": "How do these work?", - "rcfilters-filterlist-feedbacklink": "Tell us what you think about these (new) filtering tools", + "rcfilters-filterlist-feedbacklink": "Tell us what you think about these filtering tools", "rcfilters-highlightbutton-title": "Highlight results", "rcfilters-highlightmenu-title": "Select a color", "rcfilters-highlightmenu-help": "Select a color to highlight this property", diff --git a/languages/i18n/eo.json b/languages/i18n/eo.json index c7019d8833..6d77b1085a 100644 --- a/languages/i18n/eo.json +++ b/languages/i18n/eo.json @@ -891,7 +891,7 @@ "revdelete-edit-reasonlist": "Redakti kialojn por forigo", "revdelete-offender": "AÅ­toro de revizio:", "suppressionlog": "Protokolo pri subigado", - "suppressionlogtext": "Malsupre estas listo de forigoj kaj forbaroj pri enhavo kaŝita de administrantoj.\nRigardu la [[Special:BlockList|forbarliston]] por la listo de nune operaciaj forbaroj kaj forigoj.", + "suppressionlogtext": "Jen listo de forigoj kaj forbaroj pri enhavo kaŝita per administrantoj.\nVidi la [[Special:BlockList|forbarliston]] por la listo de forigoj kaj forbaroj aktuale operaciaj.", "mergehistory": "Kunigi historiojn de paĝoj", "mergehistory-header": "Ĉi tiu paĝo permesas al vi kunigi versiojn de la historio de unu fonta paĝo en pli novan paĝon.\nCertigu ke ĉi tiu ŝanĝo tenos kontinuecon de la historia paĝo.", "mergehistory-box": "Kunigi versiojn de du paĝoj:", diff --git a/languages/i18n/eu.json b/languages/i18n/eu.json index 4816efafb8..db373b5b9a 100644 --- a/languages/i18n/eu.json +++ b/languages/i18n/eu.json @@ -694,7 +694,7 @@ "explainconflict": "Zu orrialdea aldatzen hasi ondoren beste norbaitek ere aldaketak egin ditu.\nGoiko testu koadroan ikus daiteke orrialdeak uneotan duen edukia.\nZure aldaketak beheko testu koadroan ikus daitezke.\nZure testua dagoenarekin elkartu beharko duzu.\nOrrialdea gordetzeko erabakitzen duzun unean goiko koadroko edukia '''bakarrik''' gordeko da.", "yourtext": "Zure testua", "storedversion": "Gordetako bertsioa", - "editingold": "'''KONTUZ: Artikulu honen bertsio zahar bat aldatzen ari zara. Gorde egiten baduzu, azkenengo aldaketa baino lehenagoko aldakuntzak, ezabatuak izango dira.'''", + "editingold": "KONTUZ: Artikulu honen bertsio zahar bat aldatzen ari zara. Gordetzen baduzu, bertsio hau baino geroago egindako aldaketa guztiak ezabatuko dira.", "unicode-support-fail": "Zure nabigatzaileak Unicode onartzen ez duela dirudi. Orrialdeak editatu behar dira, beraz, edizioa ez da gorde.", "yourdiff": "Ezberdintasunak", "copyrightwarning": "Kontuan izan ezazu {{SITENAME}} webgunean egindako ekarpen guztiak $2 lizentziaren pean argitaratzen direla (xehetasunetarako, ikus $1). Zuk idatzitakoa libreki aldatua eta banatua izatea nahi ez baduzu, ez ezazu hemen jarri.
    \nEra berean, hitzematen ari zara hau zuk zeuk idatzia dela, edo jabari publikotik nahiz askea den beste ituri batetik kopiatu duzula.\n'''Ez erabili copyright eskubideek babestutako lanik, baimenik gabe!'''", diff --git a/languages/i18n/fa.json b/languages/i18n/fa.json index 8f28907bd6..0d44d82952 100644 --- a/languages/i18n/fa.json +++ b/languages/i18n/fa.json @@ -433,7 +433,7 @@ "logouttext": "'''اکنون شما ثبت خروج کرده‌اید.'''\nتوجه داشته باشید که تا حافظهٔ نهان مرورگرتان را پاک نکنید، بعضی از صفحات ممکن است همچنان به گونه‌ای نمایش یابند که انگار وارد شده‌اید.", "cannotlogoutnow-title": "الان امکان خروج از سامانه نیست", "cannotlogoutnow-text": "در زمان استفاده از $1 امکان خروج از سامانه وجود ندارد.", - "welcomeuser": "$1 به {{SITENAME}} خوش‌آمدید!", + "welcomeuser": "خوشامدید $1!", "welcomecreation-msg": "حساب کاربری شما ایجاد شده است.\nفراموش نکنید که [[Special:Preferences|ترجیحات {{SITENAME}}]] خود را تغییر دهید.", "yourname": "نام کاربری:", "userlogin-yourname": "نام کاربری", @@ -1919,7 +1919,7 @@ "unusedcategories": "رده‌های استفاده‌نشده", "unusedimages": "پرونده‌های استفاده‌نشده", "wantedcategories": "رده‌های مورد نیاز", - "wantedpages": "برگه‌های مورد نیاز", + "wantedpages": "صفحه‌های مورد نیاز", "wantedpages-summary": "فهرست صفحه‌های ناموجود با بیشترین پیوند به آنها، به استثنای صفحه‌هایی که فقط تغییرمسیر به آنها دارند. برای یک فهرست از صفحه‌های ناموجود که تغییرمسیر به آنها دارند، [[{{#special:BrokenRedirects}}|فهرست تغییرمسیرهای شکسته]] را ببینید.", "wantedpages-badtitle": "عنوان نامجاز در مجموعهٔ نتایج: $1", "wantedfiles": "پرونده‌های مورد نیاز", diff --git a/languages/i18n/fi.json b/languages/i18n/fi.json index 2484110197..060a61b87a 100644 --- a/languages/i18n/fi.json +++ b/languages/i18n/fi.json @@ -1469,6 +1469,10 @@ "rcfilters-watchlist-showupdated": "Muutokset sivuihin, joilla et ole vieraillut sen jälkeen kun muutokset on tehty, on lihavoitu ja värimerkitty.", "rcfilters-preference-label": "Piilota tuoreiden muutosten parannettu versio", "rcfilters-preference-help": "Peruuttaa vuoden 2017 käyttöliittymän uudistuksen ja kaikki sen jälkeen lisätyt työkalut.", + "rcfilters-watchlist-preference-label": "Piilota tarkkailulistan parannettu versio", + "rcfilters-watchlist-preference-help": "Poistaa käytöstä vuoden 2017 ulkoasun uudistuksen ja kaikki sen jälkeen lisätyt työkalut.", + "rcfilters-filter-showlinkedfrom-option-label": "Sivut, joihin linkitetään valitulta sivulta", + "rcfilters-filter-showlinkedto-option-label": "Sivut, jotka linkittävät valitulle sivulle", "rcfilters-target-page-placeholder": "Anna sivun nimi (tai luokka)", "rcnotefrom": "Alla ovat muutokset $3, $4 lähtien. (Enintään $1 näytetään.)", "rclistfromreset": "Tyhjennä ajankohdan valinta", @@ -4034,9 +4038,13 @@ "pagedata-not-acceptable": "Vastaavaa muotoa ei löytynyt. Tuetut MIME-tyypit: $1", "pagedata-bad-title": "Virheellinen otsikko: $1.", "passwordpolicies": "Salasanakäytännöt", + "passwordpolicies-summary": "Tämä on luettelo käytössä olevista salasanakäytännöistä tämän wikin käyttäjäryhmille.", "passwordpolicies-group": "Ryhmä", "passwordpolicies-policies": "Käytännöt", "passwordpolicies-policy-minimalpasswordlength": "Salasanan on oltava ainakin $1 {{PLURAL:$1|merkki|merkkiä}} pitkä", + "passwordpolicies-policy-minimumpasswordlengthtologin": "Salasanassa on oltava vähintään $1 {{PLURAL:$1|merkki|merkkiä}} pystyäksesi kirjautumaan", "passwordpolicies-policy-passwordcannotmatchusername": "Salasana ei voi olla sama kuin käyttäjänimi", - "passwordpolicies-policy-maximalpasswordlength": "Salasanan on oltava vähemmän kuin $1 {{PLURAL:$1|merkki|merkkiä}} pitkä" + "passwordpolicies-policy-passwordcannotmatchblacklist": "Salasana ei voi vastata mustalla listalla olevia salasanoja", + "passwordpolicies-policy-maximalpasswordlength": "Salasanan on oltava vähemmän kuin $1 {{PLURAL:$1|merkki|merkkiä}} pitkä", + "passwordpolicies-policy-passwordcannotbepopular": "Salasana ei voi olla {{PLURAL:$1|suosittu salasana|$1 suositun salasanan listalla}}" } diff --git a/languages/i18n/fr.json b/languages/i18n/fr.json index 4614b74f9d..d5590ef9aa 100644 --- a/languages/i18n/fr.json +++ b/languages/i18n/fr.json @@ -1603,6 +1603,7 @@ "rcfilters-preference-label": "Masquer la version améliorée des modifications récentes", "rcfilters-preference-help": "Désactive la version 2017 de l'interface ainsi que de tous les outils ajoutés alors et depuis.", "rcfilters-watchlist-preference-label": "Masquer la version améliorée de la liste de suivi", + "rcfilters-watchlist-preference-help": "Annuler la nouvelle conception de l’interface 2017 et tous les outils ajoutés alors et depuis.", "rcfilters-filter-showlinkedfrom-label": "Montrer les modifications des pages liées depuis", "rcfilters-filter-showlinkedfrom-option-label": "Pages liées depuis la page sélectionnée", "rcfilters-filter-showlinkedto-label": "Montrer les modifications des pages pointant vers", diff --git a/languages/i18n/gcr.json b/languages/i18n/gcr.json index 126208a5ca..af466660c4 100644 --- a/languages/i18n/gcr.json +++ b/languages/i18n/gcr.json @@ -141,7 +141,7 @@ "newwindow": "(Ka ouvri so kò andan roun nouvèl finèt)", "cancel": "Anilé", "moredotdotdot": "Plis...", - "morenotlisted": "Sa lis pé sa enkonplèt", + "morenotlisted": "Sa lis pouvé fika enkonplèt", "mypage": "Paj", "mytalk": "Diskisyon", "anontalk": "Diskisyon", @@ -293,7 +293,7 @@ "databaseerror-function": "Fonksyon : $1", "databaseerror-error": "Érò : $1", "transaction-duration-limit-exceeded": "Pou évité roun tròp fò ogmantasyon di délè di réplikasyon, sa tranzaksyon té anilé piskétan douré di ékritir ($1) dépasé limit-a di $2 ségonn. Si zòt ka sasé modifyé oun gran nonm di éléman similtanéman, éséyé plito di éfèktchwé opérasyon-an an plizyò étap pli piti.", - "laggedslavemode": "Panga, sa paj pa pé kontni tout dannyé modifikasyon éfèktchwé", + "laggedslavemode": "Panga, sa paj pa pouvé kontni tout dannyé modifikasyon éfèktchwé", "readonly": "Baz di doné vérouyé", "enterlockreason": "Endiké rézon-an di vérouyaj ensi ki roun èstimasyon di so douré", "readonlytext": "Ajou ké mizajou di baz di doné sa atchwèlman bloké, probabman pou pèrmèt mentnans di baz-a, aprè sa, tout bagaj ké rantré andan lòrd.\n\nAdministratò sistèm ki vérouyé baz di doné té fourni èksplikasyon swivant :
    $1", @@ -314,7 +314,7 @@ "filenotfound": "Enposib di trouvé fiché-a « $1 ».", "unexpected": "Valò ki pa nòrmal : « $1 » = « $2 ».", "formerror": "Érò : enposib di soumèt fòrmilèr-a.", - "badarticleerror": "Sa aksyon pa pé sa éfèktchwé asou sa paj.", + "badarticleerror": "Sa aksyon pa pouvé fika éfèktchwé asou sa paj.", "cannotdelete": "Enposib di souprimé paj-a oben fiché-a « $1 ».\nSouprésyon-an pitèt ja té éfèktchwé pa rounòt moun.", "cannotdelete-title": "Enposib di souprimé paj-a « $1 »", "delete-hook-aborted": "Souprésyon anilé pa roun ègstansyon.\nPyès èksplikasyon té bay.", @@ -324,7 +324,7 @@ "title-invalid-empty": "Tit di paj doumandé sa vid oben ka kontni sèlman non-an di roun lèspas di non.", "title-invalid-utf8": "Tit di paj doumandé ka kontni roun sékans UTF-8 envalid.", "title-invalid-interwiki": "Paj sib ka kontni roun lyen interwiki ki nou pa pouvé itilizé annan tit-ya.", - "title-invalid-talk-namespace": "Tit di paj doumandé ka fè référans à roun paj di diskisyon ki pa pé ègzisté.", + "title-invalid-talk-namespace": "Tit di paj doumandé ka fè référans à roun paj di diskisyon ki pa pouvé ègzisté.", "title-invalid-characters": "Tit di paj doumandé ka kontni dé karaktèr ki pa valid : « $1 ».", "title-invalid-relative": "Tit ka kontni oun chimen roulatif. Tit-ya ki ka référansé dé paj roulativ (./, ../) pa valid pas li sa souvan itilizé pa navigatò di itilizatò-a.", "title-invalid-magic-tilde": "Tit di paj doumandé ka kontni roun sékans di tilde majik ki pa valid (~~~).", @@ -338,11 +338,11 @@ "actionthrottled": "Aksyon limité", "actionthrottledtext": "Pou briga kont abi-ya, itilizasyon-an di sa aksyon sa limité à roun sèrten nonm di fwè annan roun laps di tan asé kourt é zòt dépasé sa limit.\nSouplé, éséyé òkò annan tchèk minout.", "protectedpagetext": "Sa paj té protéjé pou anpéché so modifikasyon oben dé ròt aksyon.", - "viewsourcetext": "Zòt pé wè é kopyé kontni di sa paj.", + "viewsourcetext": "Zòt pouvé wè é kopyé kontni-a di sa paj.", "viewyourtext": "Zòt pouvé wè ké kopyé kontni-a di zòt modifikasyon à sa paj.", - "protectedinterface": "Sa paj ka fourni tèks d'entèrfas pou lojisyèl-a asou sa wiki é sa protéjé pou évité abi-ya.\nPou ajouté oben modifyé dé amòrfwazaj asou tout wiki, souplé, itilizé [https://translatewiki.net/ translatewiki.net], projè-a di réjyonalizasyon di MediaWiki.", + "protectedinterface": "Sa paj ka fourni tèks d'entèrfas pou lojisyèl-a asou sa wiki é sa protéjé pou évité abi-ya.\nPou ajouté oben modifyé dé anmòrfwézaj asou tout wiki, souplé, itilizé [https://translatewiki.net/ translatewiki.net], projè-a di réjyonalizasyon di MediaWiki.", "editinginterface": "Panga : zòt ka modifiyé oun paj itilizé pou kréyé tèks-a di lojisyèl.\nChanjman-yan asou sa paj ké répèrkité asou aparans di entèrfas itilizatò pou ròt itilizatò-ya di sa wiki.", - "translateinterface": "Pou ajouté oben modifyé dé amòrfwazaj pou tout wiki, souplé, itilizé [https://translatewiki.net/ translatewiki.net], projè-a di lokalizasyon lengwistik di MediaWiki.", + "translateinterface": "Pou ajouté oben modifyé dé anmòrfwézaj pou tout wiki, souplé, itilizé [https://translatewiki.net/ translatewiki.net], projè-a di lokalizasyon lengwistik di MediaWiki.", "cascadeprotected": "Sa paj protéjé kont modifikasyon-yan pas li sa transkliz pa {{PLURAL:$1|paj-a ki ka swiv, ki té protéjé|paj-ya ki ka swiv, ki té protéjé}} ké lòpsyon « protèksyon an kaskad » aktivé :\n$2", "namespaceprotected": "Zòt pa gen pèrmisyon-an di modifyé paj-ya di lèspas di non « $1 ».", "customcssprotected": "Zòt pa gen pèrmisyon-an di modifyé sa féy di stil CSS, pas li ka kontni paramèt pèrsonèl di rounòt itilizatò.", @@ -612,11 +612,11 @@ "template-semiprotected": "(sémi-protéjé)", "hiddencategories": "{{PLURAL:$1|Katégori kaché}} don sa paj ka fè parti :", "permissionserrors": "Éròr di pèrmisyon", - "permissionserrorstext-withaction": "Zòt pa pé $2, pou {{PLURAL:$1|rézon swivant}} :", + "permissionserrorstext-withaction": "Zòt pa pouvé $2, pou {{PLURAL:$1|rézon swivant}} :", "recreate-moveddeleted-warn": "Panga : zòt ka roukréyé oun paj ki té présédaman souprimé.\n\nAsouré-zòt ki li sa pertinan di pourswiv modifikasyon-yan asou sa paj.\nJournal dé souprésyon é dé déplasman pou sa paj sa afiché anba à tit di enfòrmasyon :", "moveddeleted-notice": "Sa paj té souprimé. \nJournal dé souprésyon, dé protèksyon é dé déplasman di paj-a sa afiché anba pou référans.", "content-model-wikitext": "wikitèks", - "undo-failure": "Sa modifikasyon pa pé défèt : sala ké antré an konfli ké modifikasyon-yan entèrmédyèr.", + "undo-failure": "Sa modifikasyon pa pouvé défèt : sala ké antré an konfli ké modifikasyon entèrmédjèr-ya.", "viewpagelogs": "Wè opérasyon-yan asou sa paj", "currentrev-asof": "Vèrsyon atchwèl daté di $1", "revisionasof": "Vèrsyon di $1", @@ -754,9 +754,9 @@ "linkstoimage-redirect": "$1 (roudirèksyon di fiché) $2", "sharedupload-desc-here": "Sa fiché ka provini di $1. Li pé sa itilizé pa dé ròt projè.\nSo dèskripsyon asou so [$2 paj di dèskripsyon] sa afiché anba.", "filepage-nofile": "Pyès fiché di sa non ka ègzisté.", - "upload-disallowed-here": "Zòt pa pé ranplasé sa fiché.", + "upload-disallowed-here": "Zòt pa pouvé ranplasé sa fiché.", "randompage": "Paj o azò", - "statistics": "Statistik", + "statistics": "Èstatistik", "double-redirect-fixer": "Korèktò di roudirèksyon", "nbytes": "$1 {{PLURAL:$1|òktè}}", "nmembers": "$1 manm{{PLURAL:$1|}}", @@ -868,7 +868,7 @@ "tooltip-ca-talk": "Diskisyon o sijè di sa paj di kontni", "tooltip-ca-edit": "Modifyé wikikod-a", "tooltip-ca-addsection": "Koumansé roun nouvèl sèksyon", - "tooltip-ca-viewsource": "Sa paj sa protéjé.\nZòt pé toutfwè vizwalizé sours-a.", + "tooltip-ca-viewsource": "Sa paj sa protéjé.\nZòt pouvé toutfwè vizwalizé sours-a.", "tooltip-ca-history": "Istorik vèrsyon-yan di sa paj", "tooltip-ca-protect": "Protéjé sa paj", "tooltip-ca-delete": "Souprimé sa paj", @@ -881,7 +881,7 @@ "tooltip-p-logo": "Vizité paj prensipal-a", "tooltip-n-mainpage": "Vizité paj prensipal-a di sit", "tooltip-n-mainpage-description": "Paj prensipal jénéral", - "tooltip-n-portal": "À propo di projè, sa ki zòt pé fè, koté trouvé enfòrmasyon-yan", + "tooltip-n-portal": "À propo di projè, sa ki zòt pouvé fè, koté trouvé enfòrmasyon-yan", "tooltip-n-currentevents": "Trouvé plis d'enfòrmasyon asou atchwalité an kour", "tooltip-n-recentchanges": "Lis di modifikasyon résant asou wiki-a", "tooltip-n-randompage": "Afiché roun paj o azò", diff --git a/languages/i18n/got.json b/languages/i18n/got.json index 45c12b56ba..24106ce591 100644 --- a/languages/i18n/got.json +++ b/languages/i18n/got.json @@ -12,25 +12,33 @@ "Amire80" ] }, + "tog-underline": "𐌲𐌰𐍅𐌹𐍃𐌰𐌹𐍃 𐌿𐍆𐍃𐍄𐍂𐌹𐌺𐍃:", "tog-hideminor": "𐌰𐍆𐍆𐌹𐌻𐌷 𐌻𐌴𐌹𐍄𐌹𐌻𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌰𐌽𐌳𐍅𐌰𐌹𐍂𐌸𐌰𐌹𐌶𐍉 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉", "tog-extendwatchlist": "𐌿𐍆𐍂𐌰𐌺𐌴𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽 𐌳𐌿 𐌱𐌰𐌽𐌳𐍅𐌾𐌰𐌽 𐌰𐌻𐌻𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃, 𐌽𐌹 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐌸𐍉𐍃 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐍉𐌽𐍃", "tog-usenewrc": "𐌺𐌿𐌽𐌾𐌴 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌰𐍆𐌰𐍂 𐌻𐌰𐌿𐌱𐌰 𐌹𐌽 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌹𐌼 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌼 𐌰𐌽𐌰 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽", "tog-watchcreations": "𐌰𐌽𐌰𐌰𐌹𐌰𐌿𐌺 𐌻𐌰𐌿𐌱𐌰𐌽𐍃 𐌸𐌰𐌽𐌶𐌴𐌹 𐌹𐌺 𐍃𐌺𐌰𐍀𐌾𐌰 𐌾𐌰𐌷 𐍆𐌰𐌾𐌻𐌰 𐌸𐍉𐌴𐌹 𐌹𐌺 𐌹𐌽𐌽𐌰𐍄𐌱𐌰𐌹𐍂 𐌳𐌿 𐌼𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽", + "tog-watchdefault": "𐌰𐌽𐌰𐌰𐌹𐌰𐌿𐌺 𐌻𐌰𐌿𐌱𐌰𐌽𐍃 𐌾𐌰𐌷 𐍆𐌰𐌾𐌻𐌰 𐌸𐍉𐌴𐌹 𐌹𐌺 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰 𐌳𐌿 𐌼𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽", "tog-watchmoves": "𐌱𐌹𐌰𐌹𐌰𐌿𐌺 𐌻𐌰𐌿𐌱𐌰𐌽𐍃 𐌾𐌰𐌷 𐍆𐌰𐌾𐌻𐌰 𐌸𐍉𐌴𐌹 𐌼𐌹𐌸𐍃𐌰𐍄𐌾𐌹𐍃 𐌳𐌿 𐌸𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽", + "tog-watchdeletion": "𐌰𐌽𐌰𐌰𐌹𐌰𐌿𐌺 𐌻𐌰𐌿𐌱𐌰𐌽𐍃 𐌾𐌰𐌷 𐍆𐌰𐌾𐌻𐌰 𐌸𐌰𐌹𐌼𐌴𐌹 𐌹𐌺 𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌾𐌰 𐌳𐌿 𐌼𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽", "tog-watchuploads": "𐌱𐌹𐌰𐌹𐌰𐌿𐌺 𐌽𐌹𐌿𐌾𐌰 𐍆𐌰𐌾𐌻𐌰 𐌸𐍉𐌴𐌹 𐌹𐌺 𐌰𐍄𐌱𐌰𐌹𐍂𐌰 𐌳𐌿 𐌼𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽", "tog-previewontop": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽 𐍆𐌰𐌿𐍂𐌰 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌰𐍂𐌺𐌰", "tog-previewonfirst": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽 𐌰𐍄 𐍆𐍂𐌿𐌼𐌹𐍃𐍄𐌰 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽", "tog-enotifwatchlistpages": "𐍃𐌰𐌽𐌳𐌴𐌹 𐌼𐌹𐌺 𐌴-𐌱𐍉𐌺𐍉𐍃 𐌸𐌰𐌽 𐌻𐌰𐌿𐍆𐍃 𐌸𐌰𐌿 𐍆𐌰𐌾𐌻 𐌰𐌽𐌰 𐌼𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌳𐌰", "tog-enotifusertalkpages": "𐍃𐌰𐌽𐌳𐌴𐌹 𐌼𐌹𐌺 𐌴-𐌱𐍉𐌺𐍉𐍃 𐌾𐌰𐌱𐌰𐌹 𐌼𐌴𐌹𐌽𐍃 𐌻𐌰𐌿𐍆𐍃 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌹𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌳𐌰", + "tog-enotifminoredits": "𐌾𐌰𐌷 𐍃𐌰𐌽𐌳𐌴𐌹 𐌼𐌹𐌺 𐌴-𐌱𐍉𐌺𐍉𐍃 𐌼𐌹𐌽𐌽𐌹𐌶𐌴𐌹𐌼 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌼 𐌻𐌰𐌿𐌱𐌴 𐌾𐌰𐌷 𐍆𐌰𐌾𐌻𐌴", "tog-shownumberswatching": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐍂𐌰𐌸𐌾𐍉𐌽 𐍅𐌹𐍄𐌰𐌽𐌳𐌰𐌹𐌶𐌴 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌴", "tog-oldsig": "𐌸𐌴𐌹𐌽𐌰 𐍅𐌹𐍃𐌰𐌽𐌳𐌴𐌹 𐌿𐍆𐌼𐌴𐌻𐌴𐌹𐌽𐍃", "tog-watchlisthideown": "𐌰𐍆𐍆𐌹𐌻𐌷 𐌼𐌴𐌹𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽𐍃", + "tog-watchlisthidebots": "𐌰𐍆𐍆𐌹𐌻𐌷 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌱𐌰𐌿𐍄𐌴 𐍆𐍂𐌰𐌼 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽", "tog-watchlisthideminor": "𐌰𐍆𐍆𐌹𐌻𐌷 𐌼𐌹𐌽𐌽𐌹𐌶𐌴𐌹𐌽𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽𐍃", "tog-watchlisthideliu": "𐌰𐍆𐍆𐌹𐌻𐌷 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌹𐌶𐌴 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌴 𐍆𐍂𐌰𐌼 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽", + "tog-ccmeonemails": "𐍃𐌰𐌽𐌳𐌴𐌹 𐌼𐌹𐌺 𐌺𐌰𐌿𐍀𐌹𐍉𐍃 𐌴-𐌱𐍉𐌺𐍉 𐌸𐍉𐌶𐌴𐌹 𐌹𐌺 𐍃𐌰𐌽𐌳𐌾𐌰 𐌳𐌿 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐌱𐍂𐌿𐌺𐌾𐌰𐌼", "tog-showhiddencats": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌰𐌽𐌰𐌻𐌰𐌿𐌲𐌽𐌰 𐌺𐌿𐌽𐌾𐌰", + "tog-useeditwarning": "𐍈𐍉𐍄𐌴𐌹 𐌼𐌹𐌺 𐌸𐌰𐌽 𐌹𐌺 𐌰𐍆𐌻𐌴𐌹𐌸𐌰 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆 𐌼𐌹𐌸 𐌿𐌽𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌽𐌰𐌹𐌼 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌼", "tog-prefershttps": "𐌱𐍂𐌿𐌺𐌴𐌹 𐍃𐌹𐌽𐍄𐌴𐌹𐌽𐍉 𐌰𐍂𐍅𐌾𐌰𐌹𐌶𐍉𐍃 𐌲𐌰𐍅𐌹𐍃𐌰𐌹𐍃 𐌸𐌰𐌽 𐌰𐍄𐌹𐌳𐌳𐌾𐌰", "underline-always": "𐍃𐌹𐌽𐍄𐌴𐌹𐌽𐍉", "underline-never": "𐌽𐌹 𐌰𐌹𐍅", + "editfont-sansserif": "𐍃𐌰𐌽𐍃-𐍃𐌰𐌹𐍂𐌹𐍆 𐍆𐌰𐌿𐌽𐍄", "editfont-serif": "𐍃𐌰𐌹𐍂𐌹𐍆 𐍆𐌰𐌿𐌽𐍄", "sunday": "𐌰𐍆𐌰𐍂𐍃𐌰𐌱𐌱𐌰𐍄𐍉", "monday": "𐌼𐌴𐌽𐌹𐌽𐍃 𐌳𐌰𐌲𐍃", @@ -99,6 +107,8 @@ "category-subcat-count": "{{PLURAL:$2|𐌸𐌰𐍄𐌰 𐌺𐌿𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐌸 𐌸𐌰𐍄𐌴𐌹𐌽𐌴𐌹 𐌹𐍆𐍄𐌿𐌼 𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽 𐌺𐌿𐌽𐌹|𐌸𐌰𐍄𐌰 𐌺𐌿𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐌸 {{PLURAL:$1|𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽 𐌺𐌿𐌽𐌹|𐌹𐍆𐍄𐌿𐌼𐌰 $1 𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽𐌰 𐌺𐌿𐌽𐌾𐌰}}, 𐌰𐌻𐌻𐌰𐌹𐌶𐌴 $2 𐌺𐌿𐌽𐌾𐌴.}}", "category-subcat-count-limited": "𐌸𐌰𐍄𐌰 𐌺𐌿𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐌸 𐌹𐍆𐍄𐌿𐌼𐍉𐌽/𐌹𐍆𐍄𐌿𐌼𐍉𐌽𐌰\n{{PLURAL:$1|𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽 𐌺𐌿𐌽𐌹|$1 𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽𐌰 𐌺𐌿𐌽𐌾𐌰}}.", "category-article-count": "{{PLURAL:$2|𐌸𐌰𐍄𐌰 𐌺𐌿𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐌸 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐌹𐍆𐍄𐌿𐌼𐌰𐌽 𐌻𐌰𐌿𐍆.|𐌹𐍆𐍄𐌿𐌼𐌰(𐌽𐍃) {{PLURAL:$1|𐌻𐌰𐌿𐍆𐍃 𐌹𐍃𐍄|$1 𐌻𐌰𐌿𐌱𐍉𐍃 𐍃𐌹𐌽𐌳}} 𐌹𐌽 𐌸𐌰𐌼𐌼𐌰 𐌺𐌿𐌽𐌾𐌰, 𐌰𐌻𐌻𐌰𐌹𐌶𐌴 $2 𐌻𐌰𐌿𐌱𐌴.}}", + "category-article-count-limited": "{{PLURAL:$1|𐌹𐍆𐍄𐌿𐌼𐍃 𐌻𐌰𐌿𐍆𐍃 𐌹𐍃𐍄|$1 𐌹𐍆𐍄𐌿𐌼𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃 𐍃𐌹𐌽𐌳}} 𐌹𐌽 𐌰𐌽𐌳𐍅𐌰𐌹𐍂𐌸𐌰𐌼𐌼𐌰 𐌺𐌿𐌽𐌾𐌰.", + "category-file-count": "{{PLURAL:$2|𐌸𐌰𐍄𐌰 𐌺𐌿𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐌸 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐌹𐍆𐍄𐌿𐌼 𐍆𐌰𐌾𐌻.|𐌹𐍆𐍄𐌿𐌼𐍉(𐌽𐌰) {{PLURAL:$1|𐍆𐌰𐌾𐌻 𐌹𐍃𐍄|$1 𐍆𐌰𐌾𐌻𐌰 𐍃𐌹𐌽𐌳}} 𐌹𐌽 𐌸𐌰𐌼𐌼𐌰 𐌺𐌿𐌽𐌾𐌰, 𐌰𐌻𐌻𐌰𐌹𐌶𐌴 $2 𐌻𐌰𐌿𐌱𐌴.}}", "broken-file-category": "𐌻𐌰𐌿𐌱𐍉𐍃 𐌼𐌹𐌸 𐌱𐍂𐌹𐌺𐌰𐌽𐌰𐌹𐌼 𐍆𐌰𐌾𐌻𐌰𐌲𐌰𐍅𐌹𐍃𐍃𐌹𐌼", "about": "𐌱𐌹", "article": "𐌷𐌰𐌱𐌰𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃", @@ -127,6 +137,7 @@ "history": "𐌻𐌰𐌿𐌱𐌰𐍃𐍀𐌹𐌻𐌻", "history_short": "𐍃𐍀𐌹𐌻𐌻", "history_small": "𐍃𐍀𐌹𐌻𐌻", + "updatedmarker": "𐌰𐌽𐌰𐌽𐌹𐌿𐌾𐌹𐌸𐍃 𐍆𐍂𐌰𐌼 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌼𐌼𐌰 𐍃𐌹𐌽𐌸𐌰 𐌸𐌰𐍄𐌴𐌹 𐌹𐌺 𐌲𐌰𐍅𐌴𐌹𐍃𐍉𐌳𐌰 𐌸𐌹𐍃 𐌻𐌰𐌿𐌱𐌹𐍃", "printableversion": "𐌿𐍃𐌼𐌴𐍂𐌴𐌹𐌽𐍃 𐌳𐌿 𐌿𐍃𐌼𐌴𐌻𐌾𐌰𐌽", "permalink": "𐌰𐌹𐍅𐌴𐌹𐌽𐌰 𐌲𐌰𐍅𐌹𐍃𐍃", "print": "𐌿𐍃𐌼𐌴𐌻𐌴𐌹", @@ -147,7 +158,7 @@ "talk": "𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌹", "views": "𐍃𐌹𐌿𐌽𐌴𐌹𐍃", "toolbox": "𐍃𐌰𐍂𐍅𐌰𐌽𐍃", - "tool-link-emailuser": "𐍃𐌰𐌽𐌳𐌴𐌹 𐌴-𐌱𐍉𐌺𐍉𐍃 𐌳𐌿 {{{{GENDER:$1|𐌼𐌰𐌽𐌽}}", + "tool-link-emailuser": "𐍃𐌰𐌽𐌳𐌴𐌹 𐌴-𐌱𐍉𐌺𐍉𐍃 𐌳𐌿 {{GENDER:$1|𐌼𐌰𐌽𐌽}}", "imagepage": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐍆𐌰𐌾𐌻𐌰𐌻𐌰𐌿𐍆", "mediawikipage": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐍅𐌰𐌿𐍂𐌳𐌰𐌻𐌰𐌿𐍆", "viewhelppage": "𐌰𐌽𐌳𐌷𐌿𐌻𐌴𐌹 𐌷𐌹𐌻𐍀𐌰𐌻𐌰𐌿𐍆", @@ -174,6 +185,7 @@ "helppage-top-gethelp": "𐌷𐌹𐌻𐍀𐌰", "mainpage": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃", "mainpage-description": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃", + "policy-url": "Project:𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃", "portal": "𐌲𐌰𐌵𐌿𐌼𐌸𐍃 𐌲𐌰𐌼𐌰𐌹𐌽𐌳𐌿𐌸𐌰𐌹𐍃", "portal-url": "Project:𐌲𐌰𐌵𐌿𐌼𐌸𐍃 𐌲𐌰𐌼𐌰𐌹𐌽𐌳𐌿𐌸𐌰𐌹𐍃", "privacy": "𐍃𐌿𐌽𐌳𐍂𐌰𐌻𐌴𐌹𐌺𐌴𐌹𐌽𐍃 𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃", @@ -203,6 +215,7 @@ "confirmable-no": "𐌽𐌴", "thisisdeleted": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌸𐌰𐌿 𐌲𐌰𐌵𐌹𐌿𐌾𐌰𐌽 $1?", "viewdeleted": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 $1?", + "restorelink": "{{PLURAL:$1|𐌰𐌹𐌽𐌰 𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌹𐌳𐌰 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃|$1 𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌹𐌳𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃}}", "site-rss-feed": "$1 RSS 𐍂𐌹𐌽𐌽𐍉", "site-atom-feed": "$1 𐌰𐍄𐌰𐌿𐌼 𐍂𐌹𐌽𐌽𐍉", "page-atom-feed": "\"$1\" 𐌰𐍄𐌰𐌿𐌼 𐍂𐌹𐌽𐌽𐍉", @@ -239,9 +252,11 @@ "mycustomjsonprotected": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 JSON 𐌻𐌰𐌿𐍆.", "mycustomjsprotected": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 JavaScript 𐌻𐌰𐌿𐍆.", "ns-specialprotected": "𐌿𐍃𐍃𐌹𐌽𐌳𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃 𐌽𐌹 𐌼𐌰𐌲𐌿𐌽 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌰.", + "titleprotected": "𐌸𐌰𐍄𐌰 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹 𐌼𐌿𐌽𐌸 𐌷𐌰𐌱𐌰𐌹𐌸 𐍆𐍂𐌰𐌼 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌰 𐍆𐍂𐌰𐌼 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳 [[User:$1|$1]].\n𐌲𐌹𐌱𐌰𐌽𐌰 𐍆𐌰𐌹𐍂𐌹𐌽𐌰 𐌹𐍃𐍄 $2.", "cannotlogoutnow-title": "𐌰𐍆𐌻𐌴𐌹𐌸𐌰𐌽 𐌽𐌿 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄", "cannotlogoutnow-text": "𐌸𐌰𐌽 $1 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰 𐌰𐍆𐌻𐌴𐌹𐌸𐌰𐌽 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄.", "welcomeuser": "𐍅𐌰𐌹𐌻𐌰 𐌰𐌽𐌳𐌰𐌽𐌴𐌼𐍃, $1!", + "welcomecreation-msg": "𐌸𐌴𐌹𐌽𐌰 𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐍃 𐌲𐌰𐍃𐌺𐍀𐌰𐌽𐌰 𐌹𐍃𐍄.\n𐌼𐌰𐌲𐍄 {{SITENAME}} [[Special:Preferences|𐍆𐍂𐌹𐌾𐍉𐌽𐍉𐍃 𐍅𐌰𐌹𐌷𐍄𐌹𐌽𐍃]] 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌾𐌰𐌱𐌰𐌹 𐍅𐌹𐌻𐌴𐌹𐍃.", "yourname": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉:", "userlogin-yourname": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉", "userlogin-yourname-ph": "𐌼𐌴𐌻𐌴𐌹 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉 𐌸𐌴𐌹𐌽", @@ -254,30 +269,67 @@ "createacct-yourpasswordagain-ph": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐌰𐍆𐍄𐍂𐌰", "userlogin-remembermypassword": "𐌲𐌰𐍆𐌰𐍃𐍄 𐌼𐌹𐌺 {{GENDER:𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌽𐌰|𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰}}", "userlogin-signwithsecure": "𐌱𐍂𐌿𐌺𐌴𐌹 𐌰𐍂𐌽𐌾𐌰𐌹𐌶𐍉𐍃 𐌲𐌰𐍅𐌹𐍃𐌰𐌹𐍃", + "cannotlogin-text": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄.", "cannotloginnow-title": "𐌽𐌿 𐌽𐌹 𐌼𐌰𐌲𐍄 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽", + "cannotloginnow-text": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄 𐌸𐌰𐌽 $1 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰.", + "cannotcreateaccount-title": "𐌼𐌰𐌷𐍄𐍃 𐌽𐌹 𐍅𐌰𐍃 𐌳𐌿 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌹𐌽𐍃", + "password-change-forbidden": "𐌽𐌹 𐌼𐌰𐌲𐍄 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌰 𐌰𐌽𐌰 𐌸𐌰𐌼𐌼𐌰 𐍅𐌹𐌺𐌾𐌰.", "login": "𐌰𐍄𐌲𐌰𐌲𐌲", - "nav-login-createaccount": "𐌰𐍄𐌲𐌰𐌲𐌲 / 𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽", + "nav-login-createaccount": "𐌰𐍄𐌲𐌰𐌲𐌲 / 𐍃𐌺𐌰𐍀𐌴𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽", "logout": "𐌰𐍆𐌻𐌴𐌹𐌸", "userlogout": "𐌰𐍆𐌻𐌴𐌹𐌸", - "userlogin-noaccount": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽?", + "userlogin-noaccount": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐍂𐌰𐌷𐌽𐌴𐌹𐌽?", "userlogin-joinproject": "𐌲𐌰𐌳𐌰𐌹𐌻𐌴𐌹 𐌹𐌽 𐌽𐌰𐍄𐌾𐌰𐍃𐍄𐌰𐌳𐌰 {{SITENAME}}", - "createaccount": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽", + "createaccount": "𐍃𐌺𐌰𐍀𐌴𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽", "userlogin-resetpassword-link": "𐌿𐍆𐌰𐍂𐌼𐌿𐌽𐌽𐍉𐌳𐌴𐍃 𐌸𐌴𐌹𐌽𐌰𐌼𐌼𐌰 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌰?", "userlogin-helplink2": "𐌷𐌹𐌻𐍀𐌰 𐌼𐌹𐌸 𐌰𐍄𐌲𐌰𐌲𐌲𐌰", + "userlogin-createanother": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌰𐌽𐌸𐌰𐍂𐌰 𐍂𐌰𐌷𐌽𐌴𐌹𐌽", "createacct-emailoptional": "𐌴-𐌱𐍉𐌺𐍉𐍃 (𐌼𐌰𐌷𐍄𐌴𐌹𐌲𐍉𐍃)", "createacct-email-ph": "𐌼𐌴𐌻𐌴𐌹 𐌸𐌴𐌹𐌽𐍉𐍃 𐌴-𐌱𐍉𐌺𐍉𐍃", "createacct-another-email-ph": "𐌼𐌴𐌻𐌴𐌹 𐌴-𐌱𐍉𐌺𐍉𐍃", + "createaccountmail-help": "𐌼𐌰𐌲 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰 𐌳𐌿 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐍂𐌰𐌷𐌽𐌴𐌹𐌽 𐌰𐌽𐌸𐌰𐍂𐌰𐌼𐌼𐌰 𐌼𐌰𐌽 𐌹𐌽𐌿𐌷 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐌻𐌰𐌹𐍃𐌾𐌰𐌽", + "createacct-realname": "𐍃𐌿𐌽𐌾𐌴𐌹𐌽 𐌽𐌰𐌼𐍉 (𐌼𐌰𐌷𐍄𐌴𐌹𐌲)", "createacct-reason": "𐌲𐍂𐌿𐌽𐌳𐌿𐍃", - "createacct-submit": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌸𐌴𐌹𐌽𐌰 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽", + "createacct-reason-ph": "𐌳𐌿𐍈𐌴 𐌸𐌿 𐍃𐌺𐌰𐍀𐌾𐌹𐍃 𐍂𐌰𐌷𐌽𐌴𐌹𐌽", + "createacct-submit": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌸𐌴𐌹𐌽𐌰 𐍂𐌰𐌷𐌽𐌴𐌹𐌽", + "createacct-another-submit": "𐍃𐌺𐌰𐍀𐌴𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽", + "createacct-another-continue-submit": "𐌸𐌰𐌹𐍂𐌷𐍅𐌹𐍃 𐌼𐌹𐌸 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌰𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌰𐌹𐍃", "createacct-benefit-heading": "{{SITENAME}} 𐍄𐌰𐍅𐌹𐌸 𐌹𐍃𐍄 𐍆𐍂𐌰𐌼 𐌼𐌰𐌽𐌽𐌰𐌼 𐍃𐍅𐌴 𐌸𐌿𐌺.", "createacct-benefit-body1": "{{PLURAL:$1|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃}}", "createacct-benefit-body2": "{{PLURAL:$1|𐌻𐌰𐌿𐍆𐍃|𐌻𐌰𐌿𐌱𐍉𐍃}}", + "badretype": "𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌰 𐌸𐍉𐌴𐌹 𐌸𐌿 𐌲𐌰𐌼𐌴𐌻𐌹𐌳𐌴𐍃 𐌽𐌹 𐌹𐌽𐌲𐌰𐌻𐌴𐌹𐌺𐍉𐌽𐌳.", + "usernameinprogress": "𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌹𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐍃 𐌸𐌰𐌼𐌼𐌰 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐌹𐌽 𐌾𐌿 𐍄𐍉𐌾𐌰𐌳𐌰. 𐌱𐌹𐌳𐌾𐌰𐌼 𐌸𐌿𐌺 𐌴𐌹 𐌱𐌹𐌳𐌰𐌹𐍃.", + "createacct-error": "𐌰𐌹𐍂𐌶𐌴𐌹 𐌹𐌽 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌰𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌰𐌹𐍃", + "createaccounterror": "𐌼𐌰𐌷𐍄𐍃 𐌽𐌹 𐍅𐌰𐍃 𐌳𐌿 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐍂𐌰𐌷𐌽𐌴𐌹𐌽: $1", + "nocookiesfornew": "𐌱𐍂𐌿𐌺𐌾𐌰𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐍃 𐌽𐌹 𐌲𐌰𐍃𐌺𐌰𐍀𐌰𐌽𐌰 𐌿𐌽𐍄𐌴 𐍅𐌴𐌹𐍃 𐌽𐌹 𐌼𐌰𐌷𐍄𐌴𐌳𐌿𐌼 𐌱𐍂𐌿𐌽𐌽𐌰𐌽 𐌲𐌰𐍃𐌹𐌲𐌻𐌾𐌰𐌽. 𐍅𐌹𐍃 𐌰𐍂𐌽𐌹𐌱𐌰 𐌸𐌰𐍄𐌴𐌹 𐌸𐌿 𐌰𐌽𐌳𐌻𐌴𐍄𐌹𐍃 𐌺𐍉𐌺𐍉𐍃, 𐌰𐍆𐍄𐍂𐌰𐌰𐌽𐌰𐌽𐌹𐌿𐌴𐌹 𐌻𐌰𐌿𐍆 𐌾𐌰𐌷 𐍃𐍉𐌺𐌴𐌹 𐌰𐍆𐍄𐍂𐌰.", + "nosuchuser": "𐌽𐌹𐍃𐍄 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐍃 𐌼𐌹𐌸 𐌽𐌰𐌼𐌹𐌽 \"$1\".\n𐌽𐌰𐌼𐌽𐌰 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌴 𐌼𐌰𐌲𐌿𐌽 𐌷𐌰𐌱𐌰𐌽 𐌷𐌰𐌿𐌱𐌹𐌳𐌹𐍃 𐌱𐍉𐌺𐍉𐍃.\n𐍃𐌰𐌹𐍈 𐌰𐍆𐍄𐍂𐌰 𐌸𐌴𐌹𐌽𐌰 𐌼𐌴𐌻𐌴𐌹𐌽𐍃, 𐌸𐌰𐌿 [[Special:CreateAccount|𐍃𐌺𐌰𐍀𐌴𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽]].", + "nouserspecified": "𐍃𐌺𐌰𐌻𐍄 𐌲𐌹𐌱𐌰𐌽 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉.", + "password-login-forbidden": "𐌱𐍂𐌿𐌺𐌴𐌹𐌽𐍃 𐌸𐌹𐍃 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐌹𐌽𐍃 𐌾𐌰𐌷 𐌸𐌹𐍃 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌹𐍃 𐍆𐌰𐌿𐍂𐌱𐌹𐌿𐌳𐌰𐌽𐌰 𐌹𐍃𐍄.", + "mailmypassword": "𐌰𐍆𐍄𐍂𐌰 𐍃𐌰𐍄𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳", + "emailconfirmlink": "𐌲𐌰𐍃𐌹𐌲𐌻𐌴𐌹 𐌸𐌴𐌹𐌽𐍉𐍃 𐌴-𐌱𐍉𐌺𐍉𐍃", + "emaildisabled": "𐍃𐌰 𐌽𐌰𐍄𐌾𐌰𐍃𐍄𐌰𐌸𐍃 𐌽𐌹 𐌼𐌰𐌲 𐍃𐌰𐌽𐌳𐌾𐌰𐌽 𐌴-𐌱𐍉𐌺𐍉𐍃.", + "accountcreatedtext": "𐌱𐍂𐌿𐌺𐌾𐌰𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐍃 [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌹]]) 𐌲𐌰𐍃𐌺𐌰𐍀𐌰𐌽𐌰 𐌹𐍃𐍄.", "loginlanguagelabel": "𐍂𐌰𐌶𐌳𐌰: $1", "pt-login": "𐌰𐍄𐌲𐌰𐌲𐌲", "pt-login-button": "𐌰𐍄𐌲𐌰𐌲𐌲", - "pt-createaccount": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽", + "pt-login-continue-button": "𐌸𐌰𐌹𐍂𐌷𐍅𐌹𐍃 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽", + "pt-createaccount": "𐍃𐌺𐌰𐍀𐌴𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽", "pt-userlogout": "𐌰𐍆𐌻𐌴𐌹𐌸", + "resetpass_header": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌰𐌹𐍃", + "oldpassword": "𐍆𐌰𐌹𐍂𐌽𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳:", + "botpasswords": "𐌱𐌰𐌿𐍄𐌹𐍃 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌰", + "botpasswords-existing": "𐍅𐌹𐍃𐌰𐌽𐌳𐍉𐌽𐌳𐌰 𐌱𐌰𐌿𐍄𐌹𐍃 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌰", + "botpasswords-label-appid": "𐌽𐌰𐌼𐍉 𐌱𐌰𐌿𐍄𐌹𐍃:", + "botpasswords-label-create": "𐍃𐌺𐌰𐍀𐌴𐌹", + "botpasswords-label-update": "𐌰𐌽𐌰𐌽𐌹𐌿𐌴𐌹", + "botpasswords-label-cancel": "𐍃𐍅𐌴𐌹𐌱", + "botpasswords-label-delete": "𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌴𐌹", + "botpasswords-label-grants-column": "𐌲𐌹𐌱𐌰𐌽", + "resetpass_forbidden": "𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐌽𐌹 𐌼𐌰𐌲 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌳𐌰", + "resetpass-submit-loggedin": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳", + "resetpass-submit-cancel": "𐍃𐍅𐌴𐌹𐌱", "passwordreset": "𐌰𐍆𐍄𐍂𐌰 𐍃𐌰𐍄𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳", + "passwordreset-username": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉:", "bold_sample": "𐍃𐍅𐌹𐌽𐌸𐍉𐍃 𐌱𐍉𐌺𐍉𐍃", "bold_tip": "𐍃𐍅𐌹𐌽𐌸𐍉𐍃 𐌱𐍉𐌺𐍉𐍃", "italic_sample": "𐍅𐍂𐌰𐌹𐌵𐍉𐍃 𐌱𐍉𐌺𐍉𐍃", @@ -308,9 +360,10 @@ "loginreqlink": "𐌰𐍄𐌲𐌰𐌲𐌲", "newarticle": "(𐌽𐌹𐍅𐌹)", "newarticletext": "𐌻𐌰𐌹𐍃𐍄𐌹𐌳𐌴𐍃 𐌲𐌰𐍅𐌹𐍃 𐌳𐌿 𐌻𐌰𐌿𐌱𐌰 𐍃𐌰𐌴𐌹 𐌽𐌹𐍃𐍄. 𐌳𐌿 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆, 𐌰𐌽 𐌰𐍃𐍄𐍉𐌳𐌴𐌹 𐌼𐌴𐌻𐌾𐌰𐌽 𐌹𐌽 𐌰𐍂𐌺𐌰𐌹 𐌿𐍆 (𐍃𐌰𐌹𐍈 [$1 𐌷𐌹𐌻𐍀𐌰𐌻𐌰𐌿𐍆] 𐌼𐌰𐌽𐌰𐌲𐌹𐌶𐌹𐌽 𐌺𐌿𐌽𐌸𐌾𐌰). 𐌾𐌰𐌱𐌰𐌹 𐌹𐍃 𐌷𐌴𐍂 𐌹𐌽 𐌰𐌹𐍂𐌶𐌴𐌹𐌽𐍃, 𐌲𐌰𐌲𐌲 𐌳𐌿 𐌹𐌱𐌿𐌺𐌰𐌷𐌰𐌿𐌱𐌹𐌳𐌹𐌻𐍉𐌽.", + "anontalkpagetext": "----\n𐌸𐌰𐍄𐌰 𐌹𐍃𐍄 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌰𐌻𐌰𐌿𐍆𐍃 𐌿𐌽𐌽𐌰𐌼𐌽𐌹𐌸𐌰𐌼𐌼𐌰 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳 𐍃𐌰𐌴𐌹 𐌽𐌰𐌿𐌷 𐌽𐌹 𐌲𐌰𐍃𐌺𐍉𐍀 𐍂𐌰𐌷𐌽𐌴𐌹𐌽, 𐌸𐌰𐌿 𐍃𐌰𐌴𐌹 𐌽𐌹 𐌱𐍂𐌿𐌺𐌾𐌹𐌸 𐌸𐌹𐍃.\n𐌹𐌽 𐌸𐌹𐍃 𐍃𐌺𐌿𐌻𐌳 𐌹𐍃𐍄 𐌿𐌽𐍃 𐌳𐌿 𐌱𐍂𐌿𐌺𐌾𐌰𐌽 𐍂𐌰𐌸𐌾𐍉𐌽𐍃 IP 𐌳𐌿 𐌺𐌿𐌽𐌽𐌰𐌽 𐌹𐌽𐌰/𐌹𐌾𐌰.\n𐌾𐌰𐌱𐌰𐌹 𐌸𐌿 𐌹𐍃 𐌿𐌽𐌽𐌰𐌼𐌽𐌹𐌸𐍃 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐍃 𐌾𐌰𐌷 𐌹𐍃𐍄 𐌸𐌿𐍃 𐍃𐍅𐌰𐍃𐍅𐌴 𐌿𐌽𐌲𐌰𐌷𐌰𐌷𐌾𐍉 𐍅𐌰𐌿𐍂𐌳𐌰 𐍅𐌴𐍃𐌿𐌽 𐌸𐌿𐍃, 𐌱𐌹𐌳𐌾𐌰𐌼 𐌸𐌿𐌺, [[Special:CreateAccount|𐍃𐌺𐌰𐍀𐌴𐌹 𐍂𐌰𐌷𐌽𐌴𐌹𐌽]] 𐌸𐌰𐌿 [[Special:UserLogin|𐌰𐍄𐌲𐌰𐌲𐌲]] 𐌴𐌹 𐌽𐌹 𐍃𐌹𐌾𐌰𐌹 𐌰𐌹𐍂𐌶𐌴𐌹𐌽𐍃 𐌼𐌹𐌸 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐌿𐌽𐌽𐌰𐌼𐌽𐌹𐌸𐌰𐌹𐌼 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌰𐌼 𐌹𐌽 𐌰𐌽𐌰𐍅𐌰𐌹𐍂𐌸𐌰.", "noarticletext": "𐌽𐌿 𐌽𐌹 𐍃𐌹𐌽𐌳 𐌱𐍉𐌺𐍉𐍃 𐌹𐌽 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰.\n𐌼𐌰𐌲𐍄 [[Special:Search/{{PAGENAME}}|𐍃𐍉𐌺𐌾𐌰𐌽 𐌸𐌰𐍄𐌰 𐌻𐌰𐌿𐌱𐌰-𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹]] 𐌹𐌽 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐌻𐌰𐌿𐌱𐌰𐌼, [{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 𐍃𐍉𐌺𐌾𐌰𐌽 𐌲𐌰𐌷𐌰𐌷𐌾𐍉 𐌲𐌰𐍆𐌰𐍃𐍄𐍉𐍃], 𐌰𐌹𐌸𐌸𐌰𐌿 [{{fullurl:{{FULLPAGENAME}}|action=edit}} 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆.]", "noarticletext-nopermission": "𐌽𐌿 𐌽𐌹 𐍃𐌹𐌽𐌳 𐌱𐍉𐌺𐍉𐍃 𐌹𐌽 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰.\n𐌼𐌰𐌲𐍄 [[Special:Search/{{PAGENAME}}|𐍃𐍉𐌺𐌾𐌰𐌽 𐌸𐌰𐍄𐌰 𐌻𐌰𐌿𐌱𐌰-𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹]] 𐌹𐌽 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐌻𐌰𐌿𐌱𐌰𐌼, 𐌸𐌰𐌿 [{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 𐍃𐍉𐌺𐌾𐌰𐌽 𐌲𐌰𐌷𐌰𐌷𐌾𐍉 𐌲𐌰𐍆𐌰𐍃𐍄𐍉𐍃], 𐌹𐌸 𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆.", - "userpage-userdoesnotexist-view": "𐌱𐍂𐌿𐌺𐌾𐌰𐌺𐌰𐍅𐍄𐍃𐌾𐍉 \"$1\" 𐌽𐌹𐍃𐍄 𐌰𐌽𐌰𐌼𐌴𐌻𐌹𐌳𐌰.", + "userpage-userdoesnotexist-view": "𐌱𐍂𐌿𐌺𐌾𐌰𐍂𐌰𐌷𐌽𐌴𐌹𐌽 \"$1\" 𐌽𐌹𐍃𐍄 𐌰𐌽𐌰𐌼𐌴𐌻𐌹𐌳𐌰.", "updated": "(𐌰𐌽𐌰𐌽𐌹𐍅𐌹𐌸)", "previewnote": "𐌲𐌰𐌼𐌹𐌽𐌸𐌴𐌹 𐌸𐌰𐍄𐌴𐌹 𐌸𐌰𐍄𐌰 𐌹𐍃𐍄 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽𐍃.\n𐌸𐌴𐌹𐌽𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌽𐌰𐌿𐌷 𐌽𐌹 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌽𐍉𐍃 𐍃𐌹𐌽𐌳!", "continue-editing": "𐌲𐌰𐌲𐌲 𐌳𐌿 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐍃𐍄𐌰𐌳𐌰", @@ -319,12 +372,14 @@ "editingsection": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1 (𐌳𐌰𐌹𐌻)", "editingcomment": "{{GENDER:𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌴𐌹}} $1 (𐌽𐌹𐌿𐌾𐌰 𐌳𐌰𐌹𐌻)", "yourdiff": "𐌲𐌰𐍃𐌺𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃", + "templatesused": "{{PLURAL:$1|𐍆𐌰𐌿𐍂𐌰𐌼𐌴𐌻𐌴𐌹𐌽𐍃 𐌱𐍂𐌿𐌺𐌹𐌸|𐍆𐌰𐌿𐍂𐌰𐌼𐌴𐌻𐌴𐌹𐌽𐍉𐍃 𐌱𐍂𐌿𐌺𐌹𐌳𐍉𐍃}} 𐌰𐌽𐌽𐌰 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰:", + "templatesusedpreview": "{{PLURAL:$1|𐍆𐌰𐌿𐍂𐌰𐌼𐌴𐌻𐌴𐌹𐌽𐍃|𐍆𐌰𐌿𐍂𐌰𐌼𐌴𐌻𐌴𐌹𐌽𐍉𐍃}} 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌰 𐌹𐌽 𐌸𐌹𐌶𐌰𐌹 𐍆𐌰𐌿𐍂𐌰𐍃𐌹𐌿𐌽𐌰𐌹:", "template-protected": "(𐌷𐌰𐌱𐌰𐌹𐌸 𐌼𐌿𐌽𐌳)", "template-semiprotected": "(𐌷𐌰𐌱𐌰𐌹𐌸 𐌷𐌰𐌻𐌱𐌰𐌼𐌿𐌽𐌸)", "hiddencategories": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌹𐍃𐍄 𐌲𐌰𐌳𐌰𐌹𐌻𐌰 {{PLURAL:$1|1 𐌰𐌽𐌰𐌻𐌰𐌿𐌲𐌽𐌹𐍃 𐌺𐌿𐌽𐌾𐌹𐍃|$1 𐌰𐌽𐌰𐌻𐌰𐌿𐌲𐌽𐌰𐌹𐌶𐌴 𐌺𐌿𐌽𐌾𐌴}}:‎", "permissionserrors": "𐌰𐌹𐍂𐌶𐌴𐌹 𐌰𐌽𐌳𐌻𐌴𐍄𐌹𐍃", "permissionserrorstext-withaction": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 $2, 𐌹𐌽 {{PLURAL:$1|𐌹𐍆𐍄𐌿𐌼𐌰𐌹𐌶𐍉𐍃 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃|𐌹𐍆𐍄𐌿𐌼𐌰𐌹𐌶𐍉 𐍅𐌰𐌹𐌷𐍄𐌴}}:", - "moveddeleted-notice": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌿𐍃𐌽𐌿𐌼𐌰𐌽𐍃 𐌹𐍃𐍄. 𐌿𐍃𐌽𐌿𐌼𐍄𐍃 𐌾𐌰𐌷 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽𐍃 𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹𐌽𐌰𐌹𐍃 𐌿𐍆 𐍃𐌹𐌽𐌳 𐌿𐍃𐍄𐌰𐌹𐌺𐌽𐌴𐌹𐌽𐌰𐌹.", + "moveddeleted-notice": "𐍃𐌰 𐌻𐌰𐌿𐍆𐍃 𐌿𐍃𐌽𐌿𐌼𐌰𐌽𐍃 𐌹𐍃𐍄. \n𐌿𐍃𐌽𐌿𐌼𐍄𐍃, 𐌼𐌿𐌽𐌳𐍃 𐌾𐌰𐌷 𐌻𐌰𐌿𐌲 𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹𐌽𐌰𐌹𐍃 𐍃𐌹𐌽𐌳 𐌿𐍆 𐌿𐍃𐍄𐌰𐌹𐌺𐌽𐌴𐌹𐌽𐌰𐌹.", "postedit-confirmation-created": "𐌻𐌰𐌿𐍆𐍃 𐌲𐌰𐍃𐌺𐌰𐍀𐌰𐌽𐍃 𐌹𐍃𐍄.", "edit-already-exists": "𐌽𐌹 𐍅𐌰𐍃 𐌼𐌰𐌷𐍄𐍃 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆. \n𐌾𐌿 𐌹𐍃𐍄.", "content-model-wikitext": "𐍅𐌹𐌺𐌹𐌱𐍉𐌺𐍉𐍃", @@ -345,6 +400,8 @@ "page_last": "𐍃𐍀𐌴𐌳𐌿𐌼𐌹𐍃𐍄", "histfirst": "𐍆𐌰𐌹𐍂𐌽𐌹𐍃𐍄", "histlast": "𐌽𐌹𐌿𐌾𐌹𐍃𐍄", + "history-feed-title": "𐌰𐍆𐍄𐍂𐌰𐍃𐌹𐌿𐌽𐌹𐍃𐍀𐌹𐌻𐌻", + "history-feed-description": "𐌰𐍆𐍄𐍂𐌰𐍃𐌹𐌿𐌽𐌹𐍃𐍀𐌹𐌻𐌻 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰 𐌰𐌽𐌰 𐌸𐌰𐌼𐌼𐌰 𐍅𐌹𐌺𐌾𐌰", "history-feed-item-nocomment": "$1 𐌰𐍄 $2", "rev-delundel": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐌰𐌽𐌰𐍃𐌹𐌿𐌽", "revdel-restore": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐌰𐌽𐌰𐍃𐌹𐌿𐌽", @@ -364,7 +421,8 @@ "nextn-title": "𐌰𐍆𐍄𐌿𐌼(𐌰) $1 {{PLURAL:$1|𐍄𐌰𐌿𐌹|𐍄𐍉𐌾𐌰}}", "shown-title": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 $1 {{PLURAL:$1|𐍄𐌰𐌿𐌹|𐍄𐍉𐌾𐌰}} 𐍈𐌰𐍂𐌾𐌰𐌼𐌼𐌴𐌷 𐌻𐌰𐌿𐌱𐌰.", "viewprevnext": "𐍃𐌹𐌿𐌽𐌴𐌹𐍃 ($1 {{int:pipe-separator}} $2) ($3)", - "searchmenu-new": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌻𐌰𐌿𐍆 \"[[:$1]]\" 𐌰𐌽𐌰 𐌸𐌹𐌶𐌰𐌹 𐍅𐌹𐌺𐌹! {{{{PLURAL:$2|0=|𐍃𐌰𐌹 𐌾𐌰𐌷 𐌻𐌰𐌿𐍆 𐌱𐌹𐌲𐌹𐍄𐌰𐌽𐌰 𐌸𐌴𐌹𐌽𐌰𐌹 𐍃𐍉𐌺𐌴𐌹𐌽𐌰𐌹.|𐍃𐌰𐌹 𐌾𐌰𐌷 𐍄𐍉𐌾𐌰 𐍃𐍉𐌺𐌴𐌹𐌽𐌰𐌹𐍃 𐌱𐌹𐌲𐌹𐍄𐌰𐌽𐌰.}}", + "searchmenu-exists": "𐌹𐍃𐍄 𐌻𐌰𐌿𐍆𐍃 𐌷𐌰𐌹𐍄𐌰𐌽𐍃 \"[[:$1]]\" 𐌰𐌽𐌰 𐌸𐌰𐌼𐌼𐌰 𐍅𐌹𐌺𐌾𐌰. {{PLURAL:$2|0=|𐍃𐌰𐌹𐍈 𐌾𐌰𐌷 𐌰𐌽𐌸𐌰𐍂𐌰 𐍄𐍉𐌾𐌰 𐍃𐍉𐌺𐌴𐌹𐌽𐌰𐌹𐍃 𐌸𐍉𐌴𐌹 𐌱𐌹𐌲𐌹𐍄𐌰𐌽𐌰 𐍃𐌹𐌽𐌳.}}", + "searchmenu-new": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌻𐌰𐌿𐍆 \"[[:$1]]\" 𐌰𐌽𐌰 𐌸𐌰𐌼𐌼𐌰 𐍅𐌹𐌺𐌾𐌰! {{{{PLURAL:$2|0=|𐍃𐌰𐌹 𐌾𐌰𐌷 𐌻𐌰𐌿𐍆 𐌱𐌹𐌲𐌹𐍄𐌰𐌽𐌰 𐌸𐌴𐌹𐌽𐌰𐌹 𐍃𐍉𐌺𐌴𐌹𐌽𐌰𐌹.|𐍃𐌰𐌹 𐌾𐌰𐌷 𐍄𐍉𐌾𐌰 𐍃𐍉𐌺𐌴𐌹𐌽𐌰𐌹𐍃 𐌱𐌹𐌲𐌹𐍄𐌰𐌽𐌰.}}", "searchprofile-articles": "𐌷𐌰𐌱𐌰𐌽𐌳𐌰𐌽𐍃 𐌻𐌰𐌿𐌱𐍉𐍃", "searchprofile-images": "𐌼𐌰𐌽𐌰𐌲𐌼𐌰𐌹𐌳𐌾𐌰", "searchprofile-everything": "𐌰𐌻𐌻", @@ -374,11 +432,12 @@ "searchprofile-everything-tooltip": "𐍃𐍉𐌺𐌴𐌹 𐌰𐌻𐌻 𐌸𐌰𐍄𐌰 (𐌾𐌰𐌷 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌰𐌻𐌰𐌿𐌱𐌰𐌽𐍃)", "searchprofile-advanced-tooltip": "𐍃𐍉𐌺𐌴𐌹 𐌹𐌽 𐌱𐌹𐌿𐌷𐍄𐌰𐌹𐌼 𐌽𐌰𐌼𐌰𐍂𐌿𐌼𐌰𐌼", "search-result-size": "$1 ({{PLURAL:$2|•𐌰• 𐍅𐌰𐌿𐍂𐌳|•$2• 𐍅𐌰𐌿𐍂𐌳𐌰}})", - "search-redirect": "(𐌰𐍆𐍄𐍂𐌰𐍅𐌴𐌹𐍄𐍃 𐍆𐍂𐌰𐌼 𐌸𐌰𐌼𐌼𐌰 $1)", + "search-result-category-size": "{{PLURAL:$1|1 𐌲𐌰𐌳𐌰𐌹𐌻𐌰|$1 𐌲𐌰𐌳𐌰𐌹𐌻𐌰𐌽𐍃}} ({{PLURAL:$2|1 𐌼𐌹𐌽𐌽𐌹𐌶𐍉 𐌺𐌿𐌽𐌹|$2 𐌼𐌹𐌽𐌽𐌹𐌶𐍉𐌽𐌰 𐌺𐌿𐌽𐌾𐌰}}, {{PLURAL:$3|1 𐍆𐌰𐌾𐌻|$3 𐍆𐌰𐌾𐌻𐌰}})", + "search-redirect": "(𐌰𐍆𐍄𐍂𐌰𐍄𐌰𐌿𐌷𐍄𐍃 𐍆𐍂𐌰𐌼 $1)", "search-section": "(𐍆𐌴𐍂𐌰 $1)", "search-suggest": "𐌲𐌰𐌼𐌰𐌽𐍄: $1", "searchall": "𐌰𐌻𐌻𐍃", - "search-showingresults": "{{ZPLURAL:$4|𐍄𐌰𐌿𐌹 $1 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃 $3|𐍄𐍉𐌾𐌰 $1 - $2 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃 $3}}", + "search-showingresults": "{{PLURAL:$4|𐍄𐌰𐌿𐌹 $1 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃 $3|𐍄𐍉𐌾𐌰 $1 - $2 𐍅𐌰𐌹𐌷𐍄𐌰𐌹𐍃 $3}}", "search-nonefound": "𐌽𐌹 𐍄𐌰𐌿𐌹 𐍅𐌰𐍃 𐍃𐌰𐌼𐌰𐌽𐌰 𐍃𐍅𐌰 𐍃𐍉𐌺𐌴𐌹𐌽.", "powersearch-legend": "𐍃𐍉𐌺𐌴𐌹", "preferences": "𐌼𐌴𐌹𐌽𐍉𐍃 𐍆𐍂𐌹𐌾𐍉𐌽𐍉𐍃 𐍅𐌰𐌹𐌷𐍄𐍃", @@ -390,9 +449,11 @@ "prefs-editwatchlist": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽", "saveprefs": "𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹", "searchresultshead": "𐍃𐍉𐌺𐌴𐌹", + "group-bot": "𐌱𐌰𐌿𐍄𐌰", "grouppage-bot": "{{ns:project}}:𐌱𐌰𐌿𐍄𐌰", "grouppage-sysop": "{{ns:project}}:𐍂𐌴𐌹𐌺𐍃", "right-writeapi": "𐌱𐍂𐌿𐌺𐌴𐌹𐌽𐍃 API 𐌼𐌴𐌻𐌴𐌹𐌽𐌰𐌹𐍃", + "newuserlogpage": "𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌹𐍃 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌰𐌹𐍃 𐌻𐌰𐌿𐌲", "rightslog": "𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌹𐍃 𐍂𐌰𐌹𐌷𐍄𐌴 𐌻𐌰𐌿𐌲", "action-edit": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆", "nchanges": "$1 {{PLURAL:$1|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃}}", @@ -406,7 +467,7 @@ "recentchanges-label-unpatrolled": "𐍃𐍉 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃 𐌽𐌰𐌿𐌷 𐌽𐌹𐍃𐍄 𐍅𐌰𐍂𐌳𐌹𐌳𐌰", "recentchanges-label-plusminus": "𐌻𐌰𐌿𐌱𐌰𐌼𐌹𐌺𐌹𐌻𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌹𐌳𐌰 𐌼𐌹𐌸 𐌸𐌹𐌶𐌰𐌹 𐍂𐌰𐌸𐌾𐍉𐌽 𐌱𐌹𐍄𐍉", "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (𐍃𐌰𐌹𐍈 𐌾𐌰𐌷[[Special:NewPages|𐍅𐌹𐌺𐍉 𐌽𐌹𐌿𐌾𐌰𐌹𐌶𐌴 𐌻𐌰𐌿𐌱𐌴]])", - "rcfilters-limit-title": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌳𐌿 𐌱𐌰𐌽𐌳𐍅𐌾𐌰𐌽", + "rcfilters-limit-title": "𐍄𐍉𐌾𐌰 𐌳𐌿 𐌱𐌰𐌽𐌳𐍅𐌾𐌰𐌽", "rcfilters-show-new-changes": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌽𐌹𐌿𐌾𐌰𐍃𐍄𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌽𐍃", "rcfilters-filter-editsbyself-label": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐍆𐍂𐌰𐌼 𐌸𐌿𐍃", "rcfilters-filter-editsbyother-label": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐍆𐍂𐌰𐌼 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼", @@ -450,7 +511,7 @@ "uploadbtn": "𐌰𐍄𐌱𐌰𐌹𐍂 𐍆𐌰𐌾𐌻", "uploadlogpage": "𐌰𐍄𐌱𐌰𐌹𐍂 𐌻𐌰𐌿𐌲", "filedesc": "𐌼𐌰𐌿𐍂𐌲𐌿𐍃 𐍃𐌺𐌴𐌹𐍂𐌴𐌹𐌽𐍃", - "watchthisupload": "Witan so seido", + "watchthisupload": "𐌰𐍄𐍅𐌹𐍄 𐌸𐌰𐌼𐌼𐌰 𐍆𐌰𐌾𐌻𐌰", "imgfile": "𐍆𐌰𐌾𐌻", "listfiles": "𐍆𐌰𐌾𐌻𐌰𐍅𐌹𐌺𐍉", "file-anchor-link": "𐍆𐌰𐌾𐌻", @@ -489,11 +550,12 @@ "newpages": "𐌽𐌹𐌿𐌾𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃", "move": "𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹", "movethispage": "𐌼𐌹𐌸𐍃𐌰𐍄𐌴𐌹 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆", + "pager-older-n": "{{PLURAL:$1|𐍆𐌰𐌹𐍂𐌽𐌹𐌶𐌰 1|𐍆𐌰𐌹𐍂𐌽𐌹𐌶𐌰𐌽𐍃 $1}}", "booksources": "𐌱𐍉𐌺𐌰𐌱𐍂𐌿𐌽𐌽𐌰𐌽𐍃", "booksources-search-legend": "𐍃𐍉𐌺𐌴𐌹 𐌱𐍉𐌺𐌰𐌱𐍂𐌿𐌽𐌽𐌰𐌽𐍃", "booksources-search": "𐍃𐍉𐌺𐌴𐌹", "specialloguserlabel": "𐍄𐌰𐌿𐌾𐌰𐌽𐌳𐍃:", - "speciallogtitlelabel": "Namo:", + "speciallogtitlelabel": "𐌼𐌿𐌽𐌳𐍂𐌴𐌹 (𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹 𐌸𐌰𐌿 {{ns:user}}:𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳):", "log": "𐌻𐌰𐌿𐌲𐌰", "all-logs-page": "𐌰𐌻𐌻𐌰 𐌰𐌽𐌳𐌰𐌿𐌲𐌾𐍉 𐌻𐌰𐌿𐌲𐌰", "allpages": "𐌰𐌻𐌻𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃", @@ -512,6 +574,7 @@ "unwatch": "𐌿𐌽𐍅𐌹𐍄", "watchlist-details": "{{PLURAL:$1|$1 𐌻𐌰𐌿𐍆𐍃|$1 𐌻𐌰𐌿𐌱𐍉𐍃}} 𐌰𐌽𐌰 𐌸𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽 (𐌾𐌰𐌷 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌴 𐌻𐌰𐌿𐌱𐍉𐍃)", "wlheader-showupdated": "𐌻𐌰𐌿𐌱𐍉𐍃 𐌸𐌰𐌹𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌹𐌳𐌰𐌹 𐍃𐌹𐌽𐌳 𐍆𐍂𐌰𐌼 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌼𐌼𐌰 𐌼𐌴𐌻𐌰 𐌸𐌰𐍄𐌴𐌹 𐌲𐌰𐍅𐌴𐌹𐍃𐍉𐌳𐌴𐍃 𐌱𐌰𐌽𐌳𐍅𐌹𐌳𐌰𐌹 𐍃𐌹𐌽𐌳 𐌹𐌽 𐍃𐍅𐌹𐌽𐌸𐌰𐌹𐌼 𐌱𐍉𐌺𐍉𐌼.", + "wlshowlast": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐍉𐍃 $1 𐍈𐌴𐌹𐌻𐍉𐍃, 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌹 $2 𐌳𐌰𐌲𐍉𐍃", "watching": "𐍅𐌹𐍄𐌰𐌽𐌳𐍃...", "unwatching": "𐌿𐌽𐍅𐌹𐍄𐌰𐌽𐌳𐍃...", "created": "𐌲𐌰𐍃𐌺𐌰𐍀𐌾𐌰𐌽", @@ -527,6 +590,8 @@ "rollbacklink": "𐌰𐍆𐍅𐌰𐌻𐍅𐌴𐌹", "rollbacklinkcount": "𐌰𐍆𐍅𐌰𐌻𐍅𐌴𐌹 $1 {{PLURAL:$1|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌽𐍃}}", "protectlogpage": "𐍆𐍂𐌹𐌸𐌿𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽𐍃", + "protectedarticle": "𐌲𐌰𐍆 \"[[$1]]\" 𐌼𐌿𐌽𐌳", + "modifiedarticleprotection": "𐌹𐌽𐌼𐌰𐌹𐌳𐌹𐌳𐌰 𐌷𐌰𐌿𐌷𐌹𐌸𐌰 𐌼𐌿𐌽𐌳𐌹𐍃 𐍆𐌰𐌿𐍂 \"[[$1]]\"", "prot_1movedto2": "[[$1]] 𐌼𐌹𐌸𐍃𐌰𐍄𐌹𐌸 𐌳𐌿 [[$2]]", "protect-default": "𐌰𐌽𐌳𐌻𐌴𐍄 𐌰𐌻𐌻𐌰𐌹𐌼 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌰𐌼", "protect-level-sysop": "𐌰𐌽𐌳𐌻𐌴𐍄𐌹𐌸 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐍂𐌴𐌹𐌺𐍃", @@ -549,16 +614,20 @@ "uctop": "(𐌷𐌰𐌿𐌱𐌹𐌸)", "month": "𐍆𐍂𐌰𐌼 𐌼𐌴𐌽𐍉𐌸 (𐌾𐌰𐌷 𐌰𐌹𐍂𐌹𐍃):", "year": "𐍆𐍂𐌰𐌼 𐌾𐌴𐍂𐌰 (𐌾𐌰𐌷 𐌰𐌹𐍂𐌹𐍃):", - "sp-contributions-newbies-sub": "𐌽𐌹𐌿𐌾𐌰𐌹𐌼 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌼", + "sp-contributions-newbies-sub": "𐌽𐌹𐌿𐌾𐌰𐌹𐌼 𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐌹𐌼", "sp-contributions-blocklog": "𐍆𐌰𐌿𐍂𐌳𐌰𐌼𐌼𐌴𐌹𐌽𐌰𐌹𐍃 𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽𐍃.", "sp-contributions-uploads": "𐌰𐍄𐌱𐌰𐌹𐍂𐌹𐌳𐍉𐍃 𐍅𐌰𐌹𐌷𐍄𐍃", + "sp-contributions-logs": "𐌻𐌰𐌿𐌲𐌰", "sp-contributions-talk": "𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌹", "sp-contributions-username": "IP 𐍃𐍄𐌰𐌸𐍃 𐌸𐌰𐌿 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉:", + "sp-contributions-toponly": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌸𐍉𐌶𐌴𐌹 𐍃𐌹𐌽𐌳 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐍉𐍃 𐌰𐍆𐍄𐍂𐌰𐍃𐌹𐌿𐌽𐌴𐌹𐍃", + "sp-contributions-newonly": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃 𐌸𐍉𐌶𐌴𐌹 𐍃𐌹𐌽𐌳 𐌻𐌰𐌿𐌱𐌹𐍃 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌴𐌹𐍃", "sp-contributions-submit": "𐍃𐍉𐌺𐌴𐌹", "whatlinkshere": "𐌰𐌻𐌻𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃 𐌸𐌰𐌹𐌴𐌹 𐌱𐍂𐌹𐌲𐌲𐌰𐌽𐌳 𐌸𐌿𐌺 𐌷𐌹𐌳𐍂𐌴", "whatlinkshere-title": "𐌻𐌰𐌿𐌱𐍉𐍃 𐌸𐌰𐌹𐌴𐌹 𐍄𐌰𐌹𐌺𐌽𐌾𐌰𐌽𐌳 𐌳𐌿 \"$1\"", "whatlinkshere-page": "𐌻𐌰𐌿𐍆𐍃:", "linkshere": "𐌹𐍆𐍄𐌿𐌼𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃 𐌱𐍂𐌹𐌲𐌲𐌰𐌽𐌳 𐌸𐌿𐌺 $2:", + "nolinkshere": "𐌽𐌹 𐌻𐌰𐌿𐌱𐍉𐍃 𐌲𐌰𐍅𐌹𐌳𐌰𐌽𐌳 𐌳𐌿 $2.", "isredirect": "𐌰𐌻𐌾𐌰𐍂 𐌱𐍂𐌹𐌲𐌲𐌰𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃", "istemplate": "𐍄𐍂𐌰𐌽𐍃𐌺𐌻𐌿𐍃𐌾𐍉", "isimage": "𐍆𐌰𐌾𐌻𐌰𐌲𐌰𐍅𐌹𐍃𐍃", @@ -587,6 +656,7 @@ "export": "𐌿𐍄𐌱𐌰𐌹𐍂 𐌻𐌰𐌿𐌱𐌰𐌽𐍃", "allmessages-filter-translate": "𐌲𐌰𐍃𐌺𐌴𐌹𐍂𐌴𐌹", "thumbnail-more": "\n𐌼𐌹𐌺𐌹𐌻𐌴𐌹", + "importlogpage": "𐌹𐌽𐌽𐌰𐍄𐌱𐌰𐌹𐍂 𐌻𐌰𐌿𐌲", "tooltip-pt-userpage": "{{GENDER:|Your user}} 𐌻𐌰𐌿𐍆𐍃", "tooltip-pt-mytalk": "{{GENDER:|𐌸𐌴𐌹𐌽𐍃}} 𐌻𐌰𐌿𐍆𐍃 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌹𐍃", "tooltip-pt-preferences": "{{GENDER:|Your}} 𐌲𐌰𐌻𐌴𐌹𐌺𐌰𐌽𐌳𐌴𐌹𐌽𐍃 𐍅𐌰𐌹𐌷𐍄𐍃", @@ -594,7 +664,7 @@ "tooltip-pt-mycontris": "A list of {{GENDER:|your}} 𐌱𐌹𐌰𐌿𐌺𐌰𐌹𐌽𐌴𐌹𐍃 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌹𐍃", "tooltip-pt-login": "𐍄𐌹𐌼𐍂𐌾𐌰𐌶𐌰 𐌳𐌿 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽, 𐌹𐌸 𐌽𐌹𐍃𐍄 𐍃𐌺𐌿𐌻𐌳 𐌸𐌿𐍃", "tooltip-pt-logout": "𐌰𐍆𐌻𐌴𐌹𐌸", - "tooltip-pt-createaccount": "𐌱𐌰𐍄𐌹𐌶𐍉 𐌹𐍃𐍄 𐌸𐌿𐍃 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽, 𐌹𐌸 𐍃𐌺𐌿𐌻𐌳 𐌽𐌹𐍃𐍄", + "tooltip-pt-createaccount": "𐌱𐌰𐍄𐌹𐌶𐍉 𐌹𐍃𐍄 𐌸𐌿𐍃 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐍂𐌰𐌷𐌽𐌴𐌹𐌽, 𐌹𐌸 𐍃𐌺𐌿𐌻𐌳 𐌽𐌹𐍃𐍄", "tooltip-ca-talk": "𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌹 𐌱𐌹 𐌷𐌰𐌱𐌰𐌽𐌳𐌰𐌽 𐌻𐌰𐌿𐍆", "tooltip-ca-edit": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆", "tooltip-ca-addsection": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹 𐌽𐌹𐌿𐌾𐌰 𐌳𐌰𐌹𐌻", @@ -639,15 +709,19 @@ "tooltip-undo": "\"𐌽𐌹𐌿𐍃𐌺𐌰𐍀𐌾𐌰𐌽\" 𐌱𐌰𐌺𐌼𐌰𐌹𐌳𐌾𐌹𐌸 𐌹𐌽𐌼𐌰𐌹𐌳𐌲𐌴𐌹𐌽𐍃 𐌾𐌰𐌷 𐌿𐍃𐌻𐌿𐌺𐍉𐌸 𐌼𐌰𐌹𐌳𐌾𐌰𐍆𐍉𐍂𐌼𐍉𐌽 𐍃𐍅𐌴 𐍆𐌰𐌿𐍂𐍃𐌰𐌹𐍈𐌰 𐌷𐌹𐍅𐌾𐌰. 𐌸𐌰𐍄𐌰 𐌻𐌴𐍄 𐌰𐌽𐌰𐌿𐌺𐌰𐌽𐌰𐌽 𐍃𐌰𐌿𐌸𐌰 𐌹𐌽 𐌹𐌽𐌽𐌰𐌷𐌰𐌻𐌳𐌰𐌰𐌽𐌲𐌰𐌱𐌰.", "tooltip-summary": "𐌼𐌴𐌻𐌴𐌹 𐌻𐌴𐌹𐍄𐌹𐌻𐌰 𐌰𐍆𐌼𐌰𐌿𐍂𐌲𐌴𐌹𐌽", "simpleantispam-label": "𐌰𐌽𐍄𐌹-𐍃𐍀𐌰𐌼 𐍃𐍉𐌺𐌴𐌹𐌽𐍃.\n𐌽𐌹 𐌼𐌴𐌻𐌴𐌹 𐌷𐌴𐍂!", + "pageinfo-title": "𐌹𐌽𐍆𐌰𐌿𐍂𐌼𐌰𐍄𐍃𐌾𐍉 𐍆𐌰𐌿𐍂 \"$1\"", "pageinfo-header-edits": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐍃𐍀𐌹𐌻𐌻", "pageinfo-header-restrictions": "𐌻𐌰𐌿𐌱𐌹𐍃 𐌼𐌿𐌽𐌳𐍃", "pageinfo-display-title": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌾𐌰", "pageinfo-article-id": "𐌻𐌰𐌿𐌱𐌹𐍃 𐌹𐌳", "pageinfo-robot-index": "𐌰𐌽𐌳𐌻𐌴𐍄𐌰𐌽", "pageinfo-robot-noindex": "𐌰𐌽𐌳𐌻𐌴𐍄𐌰𐌽 𐌽𐌹𐍃𐍄", + "pageinfo-watchers": "𐍂𐌰𐌸𐌾𐍉 𐌻𐌰𐌿𐌱𐌰𐍅𐌹𐍄𐌰𐌽𐌳𐌴", "pageinfo-subpages-name": "𐍂𐌰𐌸𐌾𐍉 𐌼𐌹𐌽𐌽𐌹𐌶𐌰𐌽𐌴 𐌻𐌰𐌿𐌱𐌴 𐌸𐌹𐍃 𐌻𐌰𐌿𐌹𐍃", "pageinfo-firstuser": "𐌻𐌰𐌿𐌱𐌰𐍃𐌺𐌰𐍀𐌾𐌰𐌽𐌳𐍃", + "pageinfo-firsttime": "𐌳𐌰𐌲𐍃 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌰𐌹𐍃 𐌻𐌰𐌿𐌱𐌹𐍃", "pageinfo-lastuser": "𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐍃", + "pageinfo-lasttime": "𐌳𐌰𐌲𐍃 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌹𐌶𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌰𐌹𐍃", "pageinfo-edits": "𐌰𐌻𐌻𐌰 𐍂𐌰𐌸𐌾𐍉 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉", "pageinfo-authors": "𐌰𐌻𐌻𐌰 𐍂𐌰𐌸𐌾𐍉 𐌼𐌹𐍃𐍃𐌰𐌻𐌴𐌹𐌺𐌰𐌹𐌶𐌴 𐌱𐍉𐌺𐌰𐍂𐌾𐌴", "pageinfo-recent-edits": "𐌰𐌽𐌳𐍅𐌰𐌹𐍂𐌸𐌰 𐍂𐌰𐌸𐌾𐍉 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉 (𐌹𐌽 $1)", @@ -690,6 +764,7 @@ "tags-source-header": "𐌱𐍂𐌿𐌽𐌽𐌰", "tags-actions-header": "𐍄𐍉𐌾𐌰", "tags-active-yes": "𐌾𐌰𐌹", + "tags-active-no": "𐌽𐌴", "tags-source-none": "𐌽𐌹 𐌾𐌿 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰", "tags-edit": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹", "tags-delete": "𐌿𐍃𐌽𐌹𐌼", @@ -715,7 +790,8 @@ "tags-deactivate-submit": "𐌿𐌽𐌲𐌰𐌵𐌹𐌿𐌴𐌹", "logentry-delete-delete": "$1 {{GENDER:$2|𐌿𐍃𐌽𐌰𐌼}} 𐌻𐌰𐌿𐍆 $3", "logentry-move-move": "$1 {{GENDER:$2|𐌼𐌹𐌸𐍃𐌰𐍄𐌹𐌳𐌰}} 𐌻𐌰𐌿𐍆 $3 𐌳𐌿 $4", - "logentry-newusers-create": "𐌱𐍂𐌿𐌺𐌾𐌰𐌺𐌰𐍅𐍄𐍃𐌾𐍉 $1 𐍅𐌰𐍃 𐌲𐌰𐍃𐌺𐌰𐍀𐌰𐌽𐌰", + "logentry-newusers-create": "𐌱𐍂𐌿𐌺𐌾𐌰𐍂𐌰𐌷𐌽𐌴𐌹𐌽𐍃 $1 𐍅𐌰𐍃 𐌲𐌰𐍃𐌺𐌰𐍀𐌰𐌽𐌰", + "logentry-upload-upload": "$1 {{GENDER:$2|𐌿𐍆𐌰𐍂𐌱𐌰𐍂}} $3", "rightsnone": "(𐌽𐌹)", "searchsuggest-search": "𐍃𐍉𐌺𐌴𐌹", "duration-days": "$1 {{PLURAL:$1|𐌳𐌰𐌲𐍃|𐌳𐌰𐌲𐍉𐍃}}" diff --git a/languages/i18n/he.json b/languages/i18n/he.json index 83c151d45a..cc40528837 100644 --- a/languages/i18n/he.json +++ b/languages/i18n/he.json @@ -2681,7 +2681,7 @@ "import-upload-username-prefix": "קידומת בינוויקי:", "import-assign-known-users": "הקצאת העריכות למשתמשים המקומיים כאשר משתמשים בשמות זהים קיימים באתר המקומי", "import-comment": "הערה:", - "importtext": "נא לייצא את הקובץ מאתר המקור באמצעות ב[[Special:Export|כלי הייצוא]].\nשמרו אותו למחשב שלכם והעלו אותו לכאן.", + "importtext": "נא לייצא את הקובץ מאתר המקור באמצעות [[Special:Export|כלי הייצוא]].\nיש לשמור אותו במחשב ולהעלות אותו לכאן.", "importstart": "ייבוא דפים...", "import-revision-count": "‏{{PLURAL:$1|גרסה אחת|$1 גרסאות}}", "importnopages": "אין דפים לייבוא.", @@ -2694,12 +2694,12 @@ "importsuccess": "הייבוא הושלם בהצלחה!", "importnosources": "לא הוגדרו אתרי ויקי שמהם ניתן לייבא, ואפשרות ההעלאה הישירה של דף עם היסטוריה מבוטלת.", "importnofile": "לא הועלה קובץ ייבוא.", - "importuploaderrorsize": "העלאת קובץ הייבוא נכשלה. הקובץ היה גדול יותר מגודל ההעלאה המותר.", - "importuploaderrorpartial": "העלאת קובץ הייבוא נכשלה. הקובץ הועלה באופן חלקי בלבד.", - "importuploaderrortemp": "העלאת קובץ הייבוא נכשלה. חסרה תיקייה זמנית.", + "importuploaderrorsize": "העלאת קובץ הייבוא נכשלה.\nהקובץ היה גדול יותר מגודל ההעלאה המותר.", + "importuploaderrorpartial": "העלאת קובץ הייבוא נכשלה.\nהקובץ הועלה באופן חלקי בלבד.", + "importuploaderrortemp": "העלאת קובץ הייבוא נכשלה.\nחסרה תיקייה זמנית.", "import-parse-failure": "שגיאה בפענוח ה־XML", "import-noarticle": "אין דף לייבוא!", - "import-nonewrevisions": "כל הגרסאות יובאו בעבר.", + "import-nonewrevisions": "לא יובאו גרסאות (כולן כבר קיימות, או שהן לא הועלו עקב שגיאות).", "xml-error-string": "$1 בשורה $2, עמודה $3 (בית מספר $4): $5", "import-upload": "העלאת קובץ XML", "import-token-mismatch": "נתוני ההתחברות אבדו.\n\nייתכן שנותקתם מהחשבון. '''אנא ודאו שאתם עדיין מחוברים לחשבון ונסו שוב.'''\nאם זה עדיין לא עובד, נסו [[Special:UserLogout|לצאת מהחשבון]] ולהיכנס אליו שנית, וודאו שהדפדפן שלכם מאפשר קבלת עוגיות מאתר זה.", @@ -2708,7 +2708,7 @@ "import-error-create": "לא ניתן לייבא את הדף \"$1\" כיוון שאין לך הרשאה ליצור אותו.", "import-error-interwiki": "לא ניתן לייבא את הדף \"$1\" כיוון ששמו שמור לקישור חיצוני (בינוויקי).", "import-error-special": "לא ניתן לייבא את הדף \"$1\" כיוון שהוא שייך למרחב שם מיוחד שלא יכול להכיל דפים.", - "import-error-invalid": "לא ניתן לייבא את הדף \"$1\" כיוון ששמו אינו תקין.", + "import-error-invalid": "לא ניתן לייבא את הדף \"$1\" כיוון ששמו אינו תקין באתר זה.", "import-error-unserialize": "לא ניתן היה לפענח את הגרסה $2 של הדף \"$1\". הגרסה מסומנת כאילו היא משתמשת במודל התוכן $3, אך קודדה כ{{GRAMMAR:תחילית|$4}}.", "import-error-bad-location": "גרסה $2 המשתמשת במודל התוכן $3 אינה ניתנת לשמירה ב‏‏֫דף \"$1\" באתר ויקי זה, כיוון שהמודל אינו נתמך בדף זה.", "import-options-wrong": "{{PLURAL:$2|אפשרות שגויה|אפשרויות שגויות}}: $1", @@ -2720,15 +2720,15 @@ "import-logentry-interwiki-detail": "{{PLURAL:$1|גרסה אחת של הדף $2 יובאה|$1 גרסאות של הדף $2 יובאו}}", "javascripttest": "בדיקת JavaScript", "javascripttest-pagetext-unknownaction": "הפעולה \"$1\" אינה ידועה.", - "javascripttest-qunit-intro": "ראו את [$1 תיעוד הבדיקות] באתר mediawiki.org.", + "javascripttest-qunit-intro": "ניתן לעיין ב[$1 תיעוד הבדיקות] באתר mediawiki.org.", "tooltip-pt-userpage": "דף {{GENDER:|המשתמש|המשתמשת}} שלך", - "tooltip-pt-anonuserpage": "דף המשתמש של משתמש אנונימי זה", + "tooltip-pt-anonuserpage": "דף המשתמש של כתובת IP זו", "tooltip-pt-mytalk": "דף השיחה שלך", - "tooltip-pt-anontalk": "דיון על העריכות שנעשו מכתובת ה־IP הזאת", + "tooltip-pt-anontalk": "דיון על העריכות שנעשו מכתובת IP זו", "tooltip-pt-preferences": "ההעדפות שלך", "tooltip-pt-watchlist": "רשימת הדפים {{GENDER:|שאתה עוקב|שאת עוקבת}} אחרי השינויים בהם", "tooltip-pt-mycontris": "רשימת העריכות שביצעת", - "tooltip-pt-anoncontribs": "רשימת העריכות שנעשו מכתובת ה־IP הזאת", + "tooltip-pt-anoncontribs": "רשימת העריכות שנעשו מכתובת IP זו", "tooltip-pt-login": "מומלץ להיכנס לחשבון, אך אין חובה לעשות זאת", "tooltip-pt-login-private": "יש להיכנס לחשבון כדי להשתמש באתר הוויקי הזה", "tooltip-pt-logout": "יציאה מהחשבון", @@ -2794,14 +2794,14 @@ "tooltip-summary": "תיאור קצר של השינויים שביצעת", "common.css": "/* הסגנונות הנכתבים כאן ישפיעו על כל העיצובים */", "print.css": "/* הסגנונות הנכתבים כאן ישפיעו על הפלט בהדפסה בלבד */", - "noscript.css": "/* הסגנונות הנכתבים כאן ישפיעו על משתמשים עם ג'אווה-סקריפט מבוטל */", + "noscript.css": "/* הסגנונות הנכתבים כאן ישפיעו על משתמשים עם ג'אווה־סקריפט מבוטל */", "group-autoconfirmed.css": "/* הסגנונות הנכתבים כאן ישפיעו על משתמשים ותיקים בלבד */", "group-user.css": "/* הסגנונות הנכתבים כאן ישפיעו על משתמשים רשומים בלבד */", "group-bot.css": "/* הסגנונות הנכתבים כאן ישפיעו על בוטים בלבד */", "group-sysop.css": "/* הסגנונות הנכתבים כאן ישפיעו על מפעילי מערכת בלבד */", "group-bureaucrat.css": "/* הסגנונות הנכתבים כאן ישפיעו על ביורוקרטים בלבד */", "common.json": "/* כל ה־JSON שנכתב כאן ייטען עבור כל המשתמשים בכל טעינת עמוד. */", - "common.js": "/* כל הסקריפטים שנכתבים כאן ייטענו עבור כל המשתמשים בכל טעינת עמוד. */", + "common.js": "/* כל הסקריפטים הנכתבים כאן ייטענו עבור כל המשתמשים בכל טעינת עמוד. */", "group-autoconfirmed.js": "/* כל הסקריפטים הנכתבים כאן ייטענו עבור משתמשים ותיקים בלבד */", "group-user.js": "/* כל הסקריפטים הנכתבים כאן ייטענו עבור משתמשים רשומים בלבד */", "group-bot.js": "/* כל הסקריפטים הנכתבים כאן ייטענו עבור בוטים בלבד */", @@ -2824,7 +2824,7 @@ "spam_reverting": "שחזור לגרסה אחרונה שלא כוללת קישורים ל־$1", "spam_blanking": "כל הגרסאות כוללות קישורים ל־$1, מרוקן את הדף", "spam_deleting": "כל הגרסאות כוללות קישורים ל־$1, מוחק את הדף", - "simpleantispam-label": "בדיקת אנטי־ספאם.\nאל תמלאו שדה זה!", + "simpleantispam-label": "בדיקת אנטי־ספאם.\nאין למלא שדה זה!", "pageinfo-title": "מידע על הדף \"$1\"", "pageinfo-not-current": "מצטערים, לא ניתן להציג את המידע הזה לגרסאות ישנות.", "pageinfo-header-basic": "מידע בסיסי", @@ -2860,7 +2860,7 @@ "pageinfo-magic-words": "{{PLURAL:$1|מילת קסם|מילות קסם}} ($1)", "pageinfo-hidden-categories": "{{PLURAL:$1|קטגוריה מוסתרת|קטגוריות מוסתרות}} ($1)", "pageinfo-templates": "{{PLURAL:$1|תבנית מוכללת|תבניות מוכללות}} ($1)", - "pageinfo-transclusions": "{{PLURAL:$1|דף|דפים}} שמוכלל בהם ($1)", + "pageinfo-transclusions": "{{PLURAL:$1|דף|דפים}} שמוכלל {{PLURAL:$1|בו|בהם}} ($1)", "pageinfo-toolboxlink": "מידע על הדף", "pageinfo-redirectsto": "מפנה אל", "pageinfo-redirectsto-info": "מידע", diff --git a/languages/i18n/inh.json b/languages/i18n/inh.json index 9d3187dd42..cd15ef661a 100644 --- a/languages/i18n/inh.json +++ b/languages/i18n/inh.json @@ -12,7 +12,8 @@ "ElizaMag", "Adam-Yourist", "Matma Rex", - "Tusholi" + "Tusholi", + "Kaganer" ] }, "tog-underline": "ТIатовжамá кIала така хьакхар:", @@ -218,8 +219,8 @@ "copyrightpage": "{{ns:project}}:Автора бокъонаш", "currentevents": "Карарча хана хинна хIамаш", "currentevents-url": "Project:Карарча хана хинна хӏамаш", - "disclaimers": "Бехктокхам тIацаэцар", - "disclaimerpage": "Project:Бехктокхам тIацаэцар", + "disclaimers": "Бехктокхам тӀацаэцар", + "disclaimerpage": "Project:Бехктокхам тӀацаэцар", "edithelp": "Хувцам бара новкъостал", "helppage-top-gethelp": "Новкъoстал", "mainpage": "Керттера оагӀув", @@ -254,9 +255,9 @@ "collapsible-expand": "хьадоаржаде", "confirmable-yes": "XӀау", "confirmable-no": "A", - "thisisdeleted": "БIаргтоха е юхаметтаоттае $1?", + "thisisdeleted": "БӀаргтоха е юхаметтаоттае $1?", "viewdeleted": "Хьажа $1?", - "restorelink": "{{PLURAL:$1|1=дIадaьккха нийсдар|$1 дIадaьккха нийсдараш}}", + "restorelink": "{{PLURAL:$1|1=дӀадaьккха нийсдар|$1 дӀадaьккха нийсдараш}}", "feedlinks": "Укх тайпара:", "site-rss-feed": "$1 — RSS-мугI", "site-atom-feed": "$1 — Atom-мугI", @@ -385,7 +386,7 @@ "preview": "Хьалххе бIаргтохар", "showpreview": "Хьалххе бIаргтохар", "showdiff": "Даь дола хувцамаш", - "anoneditwarning": "Теркам бе! Хьо автор хинна система чуваьннавац. Нагахьа санна Iа моллагIа хувцам бой, Хьа IP-адрес дийла массанен бIаргагуш хургда. Нагахьа санна Хьо [$1 хьачувоале] е [$2 дагара йоазув хьакхолле], нийсдараш (хувцамаш) бувзам болаш хургда Хьа доакъашхой цIерца, иштта кхыдола толажагIи гIойленагIи дола дикаьш хургда Хьона.", + "anoneditwarning": "Теркам бе! Хьо ражача дIаязвеннавац. Нагахьа санна Iа моллагIа хувцам бой, Хьа IP-цIай хьадийла массанена бIаргагуш хургда. Нагахьа санна Хьо [$1 ражача хьачувоале] е Iа [$2 дагара йоазув хьакхолле], хьа тоадар (хувцамаш) бувзам болаш хургда Хьа цIерца, иштта кхыдола толашагIеи гIойленагIеи дола дикаьш хургда Хьона.", "summary-preview": "Хувцама сурт оттадарах хьалхе бӀаргтохар:", "subject-preview": "Темах/кепакертах хьалххе бӀаргтохар:", "blockedtitle": "Доакъашхочун чIега техаб", @@ -598,7 +599,7 @@ "prefs-developertools": "Кийчдархочун кечалаш", "prefs-preview": "Хьалххе бIаргтохар", "prefs-advancedrc": "Кхыдола шердаь оттамаш", - "prefs-opt-out": "Алсамдалар тIацаэцар", + "prefs-opt-out": "Алсамдалар тӀацаэцар", "prefs-advancedrendering": "Кхыдола шердаь оттамаш", "prefs-advancedsearchoptions": "Шердаь оттамаш", "prefs-advancedwatchlist": "Кхыдола шердаь оттамаш", @@ -633,7 +634,7 @@ "right-createaccount": "доакъашхошта керда дагара йоазонаш кхоллар", "right-move": "оагIонай цIераш хувцар", "right-movefile": "файлай цӀераш хувцар", - "right-autoconfirmed": "IP-цIай тIара сухала доазув дар Iехадар", + "right-autoconfirmed": "ӀP-цӀай тӀара сухала доазув дар Ӏехадар", "right-writeapi": "дIаяздеш лелае API", "right-editsemiprotected": "оагIонаш тоаяр, лораяь йола иштта «{{int:protect-level-autoconfirmed}}»", "right-viewmywatchlist": "ший зема хьаязъяьрага хьажар", @@ -956,7 +957,7 @@ "protect-cascadeon": "Каскадни лорадар оттадаь йолча {{PLURAL:$1|1=кIалхагIа белгалъяь оагIон чу|кIалхагIа белгалъяь оагIонаш чу}} юкъеяьккха хилара бахьане ер оагIув хIанза лораяь я. Укх оагIон лорадара дарж хувцаро каскадни лорадар меттахдоаккхадац.", "protect-default": "Лорадар доацаш", "protect-fallback": "Могадаьд алхха ше «$1» волача доакъашхошта", - "protect-level-autoconfirmed": "Могадаьд алхха автохьатIаийца доакъашхошта", + "protect-level-autoconfirmed": "Могадаьд алхха автохьатӀаийца доакъашхошта", "protect-level-sysop": "Могадаьд алхха администраторашта", "protect-summary-cascade": "каскадни", "protect-expiring": "чакхъйоала $1 (UTC)", diff --git a/languages/i18n/io.json b/languages/i18n/io.json index 461be910da..f1e5433805 100644 --- a/languages/i18n/io.json +++ b/languages/i18n/io.json @@ -1627,6 +1627,7 @@ "monthsall": "omna", "confirmemail": "Konfirmez adreso di e-posto", "confirmemail_needlogin": "Vu mustas $1 pro konfirmar vua adreso di e-posto.", + "confirmemail_loggedin": "Vua adreso di e-posto konfirmesis nun.", "notificationemail_subject_changed": "L'adreso di e-posto en {{SITENAME}} modifikesis", "scarytranscludetoolong": "[URL es tro longa]", "deletedwhileediting": "'''Averto''': Ta pagino efacesis pos ke vu redakteskis!", diff --git a/languages/i18n/it.json b/languages/i18n/it.json index 6cb93ab970..9227202a06 100644 --- a/languages/i18n/it.json +++ b/languages/i18n/it.json @@ -117,7 +117,8 @@ "Manvydasz", "S4b1nuz E.656", "Daimona Eaytoy", - "Sarah Bernabei" + "Sarah Bernabei", + "Wedhro" ] }, "tog-underline": "Sottolinea i collegamenti:", @@ -1133,6 +1134,7 @@ "default": "predefinito", "prefs-files": "File", "prefs-custom-css": "CSS personalizzato", + "prefs-custom-json": "JSON personalizzato", "prefs-custom-js": "JavaScript personalizzato", "prefs-common-config": "CSS/JSON/JavaScript condiviso per tutti i temi:", "prefs-reset-intro": "È possibile usare questa pagina per reimpostare le proprie preferenze a quelle predefinite del sito.\nL'operazione non può essere annullata.", @@ -1274,6 +1276,7 @@ "right-editcontentmodel": "Modifica il modello di contenuto di una pagina", "right-editinterface": "Modifica l'interfaccia utente", "right-editusercss": "Modifica i file CSS di altri utenti", + "right-edituserjson": "Modifica i file JSON di altri utenti", "right-edituserjs": "Modifica i file JS di altri utenti", "right-editmyusercss": "Modifica il file CSS del proprio utente", "right-editmyuserjson": "Modifica il file JSON del proprio utente", @@ -1776,6 +1779,8 @@ "uploadstash-bad-path": "Il percorso non esiste.", "uploadstash-bad-path-invalid": "Il percorso non è valido.", "uploadstash-bad-path-unknown-type": "Tipo sconosciuto \"$1\".", + "uploadstash-file-not-found-no-thumb": "Non è stato possibile ottenere la miniatura.", + "uploadstash-file-not-found-no-remote-thumb": "Recupero della miniatura fallito: $1\nURL = $2", "uploadstash-zero-length": "Il file ha lunghezza zero.", "invalid-chunk-offset": "Offset della parte non valido.", "img-auth-accessdenied": "Accesso negato", @@ -1956,6 +1961,7 @@ "uncategorizedcategories": "Categorie prive di categorie", "uncategorizedimages": "File privi di categorie", "uncategorizedtemplates": "Template privi di categorie", + "uncategorized-categories-exceptionlist": "# Contiene un elenco di categorie che non dovrebbero figurare in Special:UncategorizedCategories. Una categoria per linea, a cominciare da \"*\". Le linee che iniziano per un altro carattere (spazi bianchi inclusi) saranno ignorate. Usa «#» per aggiungere commenti.", "unusedcategories": "Categorie vuote", "unusedimages": "File non utilizzati", "wantedcategories": "Categorie richieste", @@ -2576,6 +2582,8 @@ "ipb_blocked_as_range": "Errore: L'indirizzo IP $1 non è soggetto a blocco individuale e non può essere sbloccato. Il blocco è invece attivo a livello dell'intervallo $2, che può essere sbloccato.", "ip_range_invalid": "Intervallo di indirizzi IP non valido.", "ip_range_toolarge": "Non è possibile bloccare range superiori al /$1", + "ip_range_exceeded": "L'intervallo di IP supera il limite massimo. Intervallo contentito: /$1.", + "ip_range_toolow": "Gli intervalli di IP non sono consentiti, di fatto.", "proxyblocker": "Blocco dei proxy aperti", "proxyblockreason": "Questo indirizzo IP è stato bloccato perché risulta essere un proxy aperto. Si prega di contattare il proprio fornitore di accesso a Internet o il supporto tecnico e informarli di questo grave problema di sicurezza.", "sorbsreason": "Questo indirizzo IP è elencato come proxy aperto nella lista DNSBL utilizzata da {{SITENAME}}.", @@ -4067,6 +4075,7 @@ "unlinkaccounts-success": "L'utenza è stata scollegata.", "authenticationdatachange-ignored": "Il cambiamento dei dati di autenticazione non è stato gestito. Forse non è stato configurato nessun provider?", "userjsispublic": "Ricorda: le sottopagine JavaScript non devono contenere dati riservati poichè sono visualizzabili da altri utenti.", + "userjsonispublic": "Ricorda: le sottopagine JSON non dovrebbero contenere dati personali perché sono visibili agli altri utenti.", "usercssispublic": "Ricorda: le sottopagine CSS non devono contenere dati riservati poichè sono visualizzabili da altri utenti.", "restrictionsfield-badip": "Indirizzo IP o intervallo non valido: $1", "restrictionsfield-label": "Intervalli IP consentiti:", diff --git a/languages/i18n/ku-latn.json b/languages/i18n/ku-latn.json index abef8c8957..1438232370 100644 --- a/languages/i18n/ku-latn.json +++ b/languages/i18n/ku-latn.json @@ -505,7 +505,7 @@ "subject-preview": "Pêşdîtina mijarê:", "previewerrortext": "Wextê pêşdîtina guhertinên te, pirsgirekek derket.", "blockedtitle": "Bikarhêner hate astengkirin", - "blockedtext": "'''Navê te yê bikarhêneriyê an jî IP'ya te hate astengkirin.'''\n\nAstengkirin ji aliyê $1 ve pêkhat. Sedema astengkirina te ev e: ''$2''.\n\n* Destpêka astengkirinê: $8\n* Xelasbûna astengkirinê: $6\n* Astengkirin ji van re: $7\n\nTu dikarî bi $1 re an jî [[{{MediaWiki:Grouppage-sysop}}|koordînatorên]] din re ji bo astengkirinê bikevî têkiliyê. Tu nikarî 'Ji vê/vî bikarhênerê/î re e-name bişîne' bikarbînî heta di [[Special:Preferences|tercihên xwe]] de navnîşana e-nameyeke derbasdar bikarbînî û tu ji bo bikaranîna vê fonksiyonê nehatî astengkirin.\n\nIP'ya te ya niha $3 ye, û ID'ya astengkirina te #$5 e. Ji kerema xwe yek ji van hejmaran têxe nav peyama xwe.", + "blockedtext": "'''Navê te yê bikarhêneriyê an jî IP'ya te hate astengkirin.'''\n\nAstengkirin ji aliyê $1 ve pêk hat. Sedema astengkirina te ev e: ''$2''.\n\n* Destpêka astengkirinê: $8\n* Xelasbûna astengkirinê: $6\n* Astengkirin ji van re: $7\n\nTu dikarî bi $1 re an jî bi [[{{MediaWiki:Grouppage-sysop}}|koordînatorên]] din re ji bo astengkirinê bikevî têkiliyê. Tu nikarî 'Ji vê/vî bikarhênerê/î re e-name bişîne' bikar bînî heta ku di [[Special:Preferences|tercihên xwe]] de navnîşana e-nameyeke derbasdar bi kar bînî û tu ji bo bikaranîna vê fonksiyonê nehatî astengkirin.\n\nIP'ya te ya niha $3 ye, û ID'ya astengkirina te #$5 e. Ji kerema xwe yek ji van hejmaran têxe nav peyama xwe.", "autoblockedtext": "Navnîşana IP ya te otomatîk hate astengkirin, ji ber ku bikarhênerekî/e din wê bikartîne, yê niha ji $1 hate astengkirin.\nSedema astengkirinê ev e:\n\n: ''$2''\n\n*Destpêka astengkirinê: $8\n*Dawiya astengkirinê: $6\n\nEger tu difikirî ku ev astengkirin ne sererast e, ji kerema xwe bi $1 re an jî yekî din ji [[{{MediaWiki:Grouppage-sysop}}|koordînatoran]] re bipeyive.\n\nZanibe ku tu nikarî e-nameya bişînî heta tu di [[Special:Preferences|tercihên xwe]] de navnîşana e-nameyan binivîsînî û tu ji bo bikaranîna vê nehatî astengkirin.\n\n'''Heke tu bixwazî peyamekê bişînî, ji kerema xwe van tiştan têxe nav nameya xwe:'''\n\n*Koordînator, yê te astengkir: $1\n*Sedema astengkirinê: $2\n*ID'ya astengkirinê: #$5", "blockednoreason": "sedem nehatiye gotin", "whitelistedittext": "Ji bo guherandina rûpelan, $1 pêwîst e.", @@ -808,6 +808,7 @@ "right-move": "Rûpelan bigerîne", "right-upload": "Dosyeyan lê bar bike", "right-autoconfirmed": "Rûpelên nîv-parastî biguherîne", + "right-writeapi": "Bikaranîna write APIyê", "right-delete": "Rûpelan jê bibe", "right-bigdelete": "Rûpelên bi dîrokên pir dirêj jê bibe", "right-browsearchive": "Li rûpelên jêbirî bigerre", @@ -917,7 +918,7 @@ "recentchangeslinked-feed": "Guherandinên peywend", "recentchangeslinked-toolbox": "Guherandinên peywend", "recentchangeslinked-title": "Guherandinên têkildarî \"$1\"", - "recentchangeslinked-summary": "Ji bo ku guherandinên di rûpelên ku ji vê rûpelê re lînk dane de an jî rûpelên ku ji vê rûpelê hatine lînkdayîn bibînî navê rûpelê binivîse. (Ji bo ku endamên vê kategoriyê bibînî, Category:'navê kategoriyê' binivîse). Rûpelên ku di [[Special:Watchlist|lîsteya te ya şopandinê]] de ne bi nivîsa stûr têne nîşandan.", + "recentchangeslinked-summary": "Ji bo ku guherandinên di rûpelên ku ji vê rûpelê re lînk dane de an jî rûpelên ku ji vê rûpelê hatine lînkdayîn bibînî navê rûpelê binivîse. (Ji bo ku endamên vê kategoriyê bibînî, {{ns:category}}:'navê kategoriyê' binivîse). Rûpelên ku di [[Special:Watchlist|lîsteya te ya şopandinê]] de ne bi nivîsa stûr têne nîşandan.", "recentchangeslinked-page": "Navê rûpelê:", "recentchanges-page-added-to-category": "[[:$1]] li kategoriyê hate zêdekirin", "recentchanges-page-removed-from-category": "[[:$1]] ji kategoriyê hate jêbirin", @@ -1033,6 +1034,7 @@ "filehist-datetime": "Dîrok/Katjimêr", "filehist-thumb": "Thumbnail", "filehist-thumbtext": "Versiyona biçûkkirî yê $1", + "filehist-nothumb": "Rismê biçûk tine", "filehist-user": "Bikarhêner", "filehist-dimensions": "Mezinahî", "filehist-filesize": "Mezinahiya pelê", @@ -1042,6 +1044,7 @@ "nolinkstoimage": "Rûpelekî ku ji vî wêneyî re girêdankê çêdike nîne.", "linkstoimage-redirect": "$1 (beralîkirina pelê) $2", "sharedupload-desc-here": "Ev dosye ji $1 û dibe ku ji aliyê projeyên din ve jî hatibe bikaranîn.\nAgahdariya li ser [$2 rûpela danasîna dosyeyê] li jêr tê nîşandan.", + "filepage-nofile": "Dosyeyekê bi vê navê tine ye.", "filepage-nofile-link": "Dosyeyek bi vî navî tune ye, lê tu dikarî wê [$1 bar bikî].", "uploadnewversion-linktext": "Versiyoneke nû ya vê daneyê barbike", "shared-repo-from": "ji $1", @@ -1607,6 +1610,7 @@ "pageinfo-header-properties": "Taybetmendiyên rûpelê", "pageinfo-display-title": "Sernavê nîşan bide", "pageinfo-language": "Zimanê naveroka rûpelê", + "pageinfo-robot-noindex": "Destûr nehatiye dayîn", "pageinfo-watchers": "Hejmara şopînerên rûpelê", "pageinfo-redirects-name": "Hejmara beralîkirinên ber bi vê rûpelê ve", "pageinfo-subpages-name": "Binrûpelên vê rûpelê", @@ -1643,6 +1647,8 @@ "file-nohires": "Versyonekî jê mezintir tune.", "svg-long-desc": "Daneya SVG, mezinbûna rast: $1 × $2 pixel; mezinbûna daneyê: $3", "show-big-image": "Dosyeya orjînal", + "show-big-image-preview": "Mezinahiya vê pêşdîtinê: $1.", + "show-big-image-other": "{{PLURAL:$2|Resolusyona|Resolusyonên}} din: $1.", "show-big-image-size": "$1 × $2 pixel", "newimages": "Pêşangeha wêneyên nû", "imagelisttext": "Jêr lîsteyek ji $1 file'an heye, duxrekirin $2.", @@ -1780,7 +1786,10 @@ "watchlistedit-raw-titles": "Sernav:", "watchlistedit-raw-removed": "{{PLURAL:$1|1 gotar hate|$1 gotar hatin}} jêbirin:", "watchlistedit-clear-titles": "Sernav:", + "watchlisttools-clear": "Lîsteya şopandinê paqij bike", + "watchlisttools-view": "Guherandinên eleqedar bibîne", "watchlisttools-edit": "Lîsteya şopandinê bibîne û biguherîne", + "watchlisttools-raw": "Lîsteya şopandinê ya xam (netertîbkirî) biguherîne", "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|gotûbêj]])", "timezone-local": "Herêmî", "version": "Versiyon", @@ -1800,8 +1809,11 @@ "version-libraries-description": "Danasîn", "version-libraries-authors": "Xwedî", "redirect-submit": "Here", + "redirect-lookup": "Li vê bigere:", "redirect-user": "ID'ya Bikarhêner", "redirect-page": "ID'ya Rûpelê", + "redirect-revision": "Revizyona rûpelê", + "redirect-file": "Navê dosyeyê", "fileduplicatesearch-filename": "Navê dosyeyê:", "fileduplicatesearch-submit": "Lê bigere", "specialpages": "Rûpelên taybet", diff --git a/languages/i18n/lv.json b/languages/i18n/lv.json index 62bdb7dbb2..7138233300 100644 --- a/languages/i18n/lv.json +++ b/languages/i18n/lv.json @@ -511,6 +511,7 @@ "botpasswords-created-title": "Bota parole izveidota", "botpasswords-updated-title": "Bota parole atjaunināta", "botpasswords-deleted-title": "Bota parole dzēsta", + "botpasswords-restriction-failed": "Botu paroles ierobežojumi liedz Å¡o pieslēgÅ¡anos.", "resetpass_forbidden": "Paroles nav iespējams nomainÄ«t", "resetpass_forbidden-reason": "Paroles nav iespējams nomainÄ«t: $1", "resetpass-no-info": "Jums ir nepiecieÅ¡ams ieiet, lai tÅ«lÄ«t piekļūtu Å¡ai lapai.", @@ -1209,6 +1210,7 @@ "rcfilters-filter-minor-description": "Labojumi, kas atzÄ«mēti kā maznozÄ«mÄ«gi.", "rcfilters-filter-major-label": "NozÄ«mÄ«gi labojumi", "rcfilters-filter-major-description": "Labojumi, kas nav atzÄ«mēti kā maznozÄ«mÄ«gi.", + "rcfilters-filtergroup-watchlist": "Uzraugāmie raksti", "rcfilters-filter-watchlist-watchednew-description": "Izmaiņas uzraugāmajās lapās, kuras nav apmeklētas kopÅ¡ izmaiņu veikÅ¡anas.", "rcfilters-filter-watchlistactivity-unseen-label": "NeapskatÄ«tas izmaiņas", "rcfilters-filter-watchlistactivity-unseen-description": "Izmaiņas lapās, kuras nav apmeklētas kopÅ¡ izmaiņu veikÅ¡anas.", diff --git a/languages/i18n/mk.json b/languages/i18n/mk.json index 6d7f64e697..387dcb9388 100644 --- a/languages/i18n/mk.json +++ b/languages/i18n/mk.json @@ -2250,7 +2250,7 @@ "rollback-success": "Откажани уредувањата на {{GENDER:$3|$1}};; вратено на последната верзија на {{GENDER:$4|$2}}.", "rollback-success-notify": "Откажани уредувањата на $1;\nвратено на последната преработка на $2. [$3 Пок. промени]", "sessionfailure-title": "Седницата не успеа", - "sessionfailure": "Има проблем со вашата седница;\nоваа дејство е откажано како превентива против преземање седници.\nПоднесете го образецот повторно.", + "sessionfailure": "Се јави проблем со најавната седница;\nова дејство е откажано за да се спречи нејзина кражба.\nПоднесете го образецот повторно.", "changecontentmodel": "Промена на содржинскиот модел на страница", "changecontentmodel-legend": "Промена на содржински модел", "changecontentmodel-title-label": "Наслов на страницата", diff --git a/languages/i18n/nb.json b/languages/i18n/nb.json index 49d4e0cbb8..80d38b6aeb 100644 --- a/languages/i18n/nb.json +++ b/languages/i18n/nb.json @@ -671,7 +671,7 @@ "subject-preview": "ForhÃ¥ndsvisning av overskrift:", "previewerrortext": "En feil oppsto mens dine endringer skulle forhÃ¥ndsvises.", "blockedtitle": "Brukeren er blokkert", - "blockedtext": "'''Ditt brukernavn eller din IP-adresse har blitt blokkert.'''\n\nBlokkeringen ble utført av $1. Grunnen som ble oppgitt var ''$2''.\n\n* Blokkeringen begynte: $8\n* Blokkeringen utgÃ¥r: $6\n* Blokkering ment pÃ¥: $7\n\nDu kan kontakte $1 eller en annen [[{{MediaWiki:Grouppage-sysop}}|administrator]] for Ã¥ diskutere blokkeringen.\nDu kan ikke bruke «E-post til denne brukeren»-funksjonen med mindre du har oppgitt en gyldig e-postadresse i [[Special:Preferences|innstillingene dine]] og du ikke er blokkert fra Ã¥ sende e-post.\nDin nÃ¥værende IP-adresse er $3, og blokkerings-ID-en er #$5.\nVennligst ta all denne informasjonen ved henvendelser.", + "blockedtext": "Ditt brukernavn eller din IP-adresse har blitt blokkert.\n\nBlokkeringen ble utført av $1. Grunnen som ble oppgitt var $2.\n\n* Blokkeringen begynte: $8\n* Blokkeringen opphører: $6\n* Blokkeringen ment for: $7\n\nDu kan kontakte $1 eller en annen [[{{MediaWiki:Grouppage-sysop}}|administrator]] for Ã¥ diskutere blokkeringen.\nDu kan ikke bruke \"{{int:emailuser}}\"-funksjonen med mindre du har oppgitt en gyldig e-postadresse i [[Special:Preferences|innstillingene dine]] og du ikke har blitt blokkert fra Ã¥ sende e-post.\nDin nÃ¥værende IP-adresse er $3, og blokkerings-ID-en er #$5.\nVennligst ta med all denne informasjonen ved henvendelser.", "autoblockedtext": "Din IP-adresse har blitt automatisk blokkert fordi den ble brukt av en annen bruker som ble blokkert av $1.\nDen oppgitte grunnen var:\n\n:'''$2'''\n\n* Blokkeringen begynte: $8\n* Blokkeringen utgÃ¥r: $6\n* Blokkeringen er ment for: $7\n\nDu kan kontakte $1 eller en av de andre [[{{MediaWiki:Grouppage-sysop}}|administratorene]] for Ã¥ diskutere blokkeringen.\n\nMerk at du ikke kan bruke «E-post til denne brukeren»-funksjonen med mindre du har registrert en gyldig e-postadresse i [[Special:Preferences|innstillingene dine]].\n\nDin IP-adresse er $3, og blokkerings-ID-en er #$5.\nVennligst ta med all denne informasjonen ved henvendelser.", "systemblockedtext": "Ditt brukernavn eller IP-adresse har blitt blokkert automatisk av MediaWiki.\n\nBlokkeringen grunnes:\n\n:$2\n\n* Blokkeringen startet: $8\n* Blokkeringen gjelder til: $6\n* Blokkeringen er ment for: $7\n\nDin nÃ¥værende IP-adresse er $3.\nVennligst inkluder informasjonen over i alle spørsmÃ¥l du spør angÃ¥ende dette.", "blockednoreason": "ingen grunn gitt", @@ -1478,6 +1478,8 @@ "rcfilters-watchlist-showupdated": "Endringer til sider du ikke har besøkt siden endringene ble gjort vises med fet skrift.", "rcfilters-preference-label": "Skjul den forbedrede versjonen av siste endringer", "rcfilters-preference-help": "Fjerner grensesnittendringen fra 2017 og alle verktøyene som ble lagt fra og med da.", + "rcfilters-watchlist-preference-label": "Skjul den forbedrede versjonen av bevÃ¥kningslisten", + "rcfilters-watchlist-preference-help": "Ruller tilbake det omarbeidede grensesnittet fra 2017 og alle verktøy som ble lagt til da og etterpÃ¥.", "rcfilters-filter-showlinkedfrom-label": "Vis endringer pÃ¥ sider som lenkes fra", "rcfilters-filter-showlinkedfrom-option-label": "Sider som lenkes fra den valgte siden", "rcfilters-filter-showlinkedto-label": "Vis endringer pÃ¥ sider som lenker til", @@ -2006,6 +2008,7 @@ "apisandbox-dynamic-parameters-add-label": "Legg til parameter:", "apisandbox-dynamic-parameters-add-placeholder": "Parameternavn", "apisandbox-dynamic-error-exists": "En parameter med navn «$1» finnes fra før.", + "apisandbox-templated-parameter-reason": "Denne [[Special:ApiHelp/main#main/templatedparams|templated parameteren]] tilbys basert pÃ¥ {{PLURAL:$1|verdi|verdier}} av $2.", "apisandbox-deprecated-parameters": "UtgÃ¥tte parametre", "apisandbox-fetch-token": "Fyll inn nøkkelen automatisk", "apisandbox-add-multi": "Legg til", @@ -2238,6 +2241,9 @@ "dellogpage": "Slettelogg", "dellogpagetext": "Under er ei liste over nylige slettinger.", "deletionlog": "slettelogg", + "log-name-create": "Logg over nye sider", + "log-description-create": "Under er ei liste over nylige sideopprettelser.", + "logentry-create-create": "$1 {{GENDER:$2|opprettet}} side $3", "reverted": "Gjenopprettet en tidligere versjon", "deletecomment": "Årsak:", "deleteotherreason": "Annen/utdypende grunn:", @@ -4082,7 +4088,11 @@ "pagedata-text": "Denne siden gir et datagrensesnitt til sidene. Oppgi en sidetittel i URL-en, med undersidesyntaks.\n* Innholdsforhandlingen er basert pÃ¥ din klients Accept-header. Dette betyr at data for siden blir angitt pÃ¥ formatet som foretrekkes av din klient.", "pagedata-not-acceptable": "Ingen passende format funnet. Støttede MIME-typer: $1", "pagedata-bad-title": "Ugyldig tittel: $1.", + "unregistered-user-config": "For Ã¥ ivareta sikkerhet kan JavaScript, CSS and JSON ikks brukes i underliggende sider for uregistrerte brukere.", + "passwordpolicies": "Passord-regler", + "passwordpolicies-summary": "Det finnes en liste over gode passord-regler for brukergrupper definert i denne wikien.", "passwordpolicies-group": "Gruppe", + "passwordpolicies-policies": "Regler", "passwordpolicies-policy-minimalpasswordlength": "Passordet mÃ¥ være pÃ¥ minst $1 {{PLURAL:$1|tegn}}.", "passwordpolicies-policy-minimumpasswordlengthtologin": "Passordet mÃ¥ være pÃ¥ minst $1 {{PLURAL:$1|tegn}} for Ã¥ kunne logge inn", "passwordpolicies-policy-passwordcannotmatchusername": "Passordet kan ikke være det samme som brukernavnet", diff --git a/languages/i18n/nds-nl.json b/languages/i18n/nds-nl.json index 11d01f6869..45a2f754e5 100644 --- a/languages/i18n/nds-nl.json +++ b/languages/i18n/nds-nl.json @@ -187,7 +187,7 @@ "viewdeleted_short": "{{PLURAL:$1|Eén versie die vortedaon is|$1 versies die vortedaon bin}} bekieken", "protect": "Beveiligen", "protect_change": "wiezigen", - "unprotect": "Beveyliging wysigen", + "unprotect": "Beveiliging wysigen", "newpage": "Nieje zied", "talkpagelinktext": "Oaverleg", "specialpage": "Speciale syde", diff --git a/languages/i18n/nn.json b/languages/i18n/nn.json index 6cb12406cf..fde0384acb 100644 --- a/languages/i18n/nn.json +++ b/languages/i18n/nn.json @@ -883,6 +883,7 @@ "search-external": "Eksternt søk", "searchdisabled": "Søkjefunksjonen pÃ¥ {{SITENAME}} er slÃ¥tt av akkurat no.\nI mellomtida kan du søkje gjennom Google.\nVer merksam pÃ¥ at registra deira kan vera utdaterte.", "search-error": "Det oppstod ein feil under søket: $1", + "search-warning": "Det vart gjeve ei Ã¥tvaring under søket: $1", "preferences": "Innstillingar", "mypreferences": "Innstillingar", "prefs-edits": "Tal pÃ¥ endringar:", diff --git a/languages/i18n/pl.json b/languages/i18n/pl.json index 8726c46603..c6225ac9b6 100644 --- a/languages/i18n/pl.json +++ b/languages/i18n/pl.json @@ -2282,6 +2282,9 @@ "dellogpage": "Usunięte", "dellogpagetext": "Poniżej znajduje się lista ostatnio wykonanych usunięć.", "deletionlog": "rejestr usunięć", + "log-name-create": "Rejestr tworzenia stron", + "log-description-create": "Poniżej znajduje się lista ostatnio utworzonych stron.", + "logentry-create-create": "$1 {{GENDER:$2|utworzył|utworzyła|utworzył(a)}} stronę $3", "reverted": "Przywrócono poprzednią wersję", "deletecomment": "Powód:", "deleteotherreason": "Inny lub dodatkowy powód:", @@ -2920,6 +2923,7 @@ "pageinfo-category-subcats": "Liczba podkategorii", "pageinfo-category-files": "Liczba plików", "pageinfo-user-id": "ID użytkownika", + "pageinfo-file-hash": "Wartość skrótu", "markaspatrolleddiff": "oznacz edycję jako „sprawdzoną”", "markaspatrolledtext": "Oznacz tę stronę jako „sprawdzoną”", "markaspatrolledtext-file": "Oznacz tę wersję pliku jako „sprawdzoną”", @@ -3502,7 +3506,7 @@ "version-specialpages": "Strony specjalne", "version-parserhooks": "Haki analizatora składni (ang. parser hooks)", "version-variables": "Zmienne", - "version-editors": "Edytorzy", + "version-editors": "Edytory", "version-antispam": "Ochrona przed spamem", "version-other": "Pozostałe", "version-mediahandlers": "Wtyczki obsługi mediów", diff --git a/languages/i18n/pnb.json b/languages/i18n/pnb.json index 0b02f95ffe..989c83b24d 100644 --- a/languages/i18n/pnb.json +++ b/languages/i18n/pnb.json @@ -2413,7 +2413,7 @@ "table_pager_empty": "کوئی نتارہ نئیں", "autosumm-blank": "ایس صفے نوں خالی کرو", "autosumm-replace": "\"$1\" نال مواد بدلو", - "autoredircomment": "صفے نوں [[$1]] ول ریڈائرکٹ کرو", + "autoredircomment": "صفے نوں [[$1]] ول ریڈائرکٹ کیتا", "autosumm-new": "\"$1\" نال صفہ بنایا گیا۔", "autosumm-newblank": "خالی صفحہ بنایا", "lag-warn-normal": "$1 توں نویاں تبدیلیاں {{PLURAL:$1|سکنٹ}}", @@ -2499,6 +2499,7 @@ "tag-filter": "[[Special:Tags|Tag]] نتارا:", "tag-filter-submit": "فلٹر", "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ٹیگ|ٹیگز}}]]: $2)", + "tag-mw-new-redirect": "نواں مڑجوڑ", "tags-title": "ٹیگز", "tags-intro": "ایس صفے تے ٹیگ دی لسٹ اے جینوں سوفٹوئیر تبدیلی دا نشان لا سکدا اے۔", "tags-tag": "ٹیگ ناں", diff --git a/languages/i18n/ps.json b/languages/i18n/ps.json index 014088f013..7802628c9f 100644 --- a/languages/i18n/ps.json +++ b/languages/i18n/ps.json @@ -2272,9 +2272,9 @@ "siteuser": "د {{SITENAME}} کارن $1", "anonuser": "د {{SITENAME}} ورکنومی کارن $1", "lastmodifiedatby": "دا مخ وروستی ځل $3 لخوا په $2، $1 بدلون موندلی.", - "othercontribs": "نور کار پر اساس د $1.", + "othercontribs": "نور کار پر اساس $1.", "others": "نور", - "siteusers": "د {{SITENAME}} {{PLURAL:$2|کارن|کارنان}} $1", + "siteusers": "د {{SITENAME}} {{PLURAL:$2|د کارن|د کارنانو}} لکه $1", "anonusers": "د {{SITENAME}} {{PLURAL:$2|ورکنومی کارن|ورکنومي کارنان}} $1", "creditspage": "د دې مخ کرېډټونه", "simpleantispam-label": "سپام-ضد څارنه.\nدا برخه مه ډکوئ!", @@ -2985,6 +2985,8 @@ "limitreport-expansiondepth-value": "$1/$2", "limitreport-expensivefunctioncount": "د قیمتي پارسير فعالیت شمیرې", "limitreport-expensivefunctioncount-value": "$1/$2", + "limitreport-unstrip-depth": "د ناڅاپه بیاکتنې ژورتيا", + "limitreport-unstrip-size": "د نسکوریدو وروسته د پراخولو اندازه", "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|ټکۍ|ټکي}}", "expandtemplates": "کينډۍ غځول", "expand_templates_intro": "په دا ځانګړي مخ کي متن پاڼه ترلاسه کیږي کوم چي په ټول ډوله مخونو کي کارول کیږي دلته دا مخ بيا بیا وده کوي. د تحلیل دندو لکه {{#language:…}} او متغیرونه لکه {{CURRENTDAY}} هم سره نښلوي — په واقعیت کې، د ډلو دننه هر څه. دا خپله د ميډياويکي په اړونده مرحله کولو سره ترسره کيږي.", diff --git a/languages/i18n/pt-br.json b/languages/i18n/pt-br.json index 2f08a4e179..ca356b66eb 100644 --- a/languages/i18n/pt-br.json +++ b/languages/i18n/pt-br.json @@ -1617,7 +1617,7 @@ "uploadlogpagetext": "Segue listagem dos uploads de arquivos mais recentes.\nA [[Special:NewFiles|galeria de arquivos novos]] oferece uma listagem mais visual.", "filename": "Nome do arquivo", "filedesc": "Descrição do arquivo", - "fileuploadsummary": "Sumário:", + "fileuploadsummary": "Resumo:", "filereuploadsummary": "Alterações no arquivo:", "filestatus": "Status dos direitos autorais:", "filesource": "Fonte:", @@ -1646,7 +1646,7 @@ "tmp-write-error": "Erro ao alterar arquivo temporário.", "large-file": "É recomendável que os arquivos não sejam maiores que $1;\neste possui $2.", "largefileserver": "Este arquivo é maior do que o servidor está configurado para permitir.", - "emptyfile": "O arquivo enviado parece estar vazio.\nIsso pode ter ocorrido por um erro de digitação no nome do arquivo.\nVerifique se você realmente deseja enviar este arquivo.", + "emptyfile": "O arquivo enviado parece estar vazio.\nIsso pode ter ocorrido por um erro de digitação no nome.\nVerifique se você realmente deseja enviá-lo.", "windows-nonascii-filename": "O wiki não aceita nomes de arquivos com caracteres especiais.", "fileexists": "Já existe um arquivo com este nome.\nVerifique [[:$1]] caso não tenha certeza se deseja alterar o arquivo atual.\n[[$1|thumb]]", "filepageexists": "A página de descrição deste arquivo já foi criada em [[:$1]], mas atualmente não existe nenhum arquivo com este nome.\nO sumário que você inseriu não aparecerá na página de descrição.\nPara que ele apareça, será necessário editá-lo manualmente.\n[[$1|thumb]]", @@ -2141,7 +2141,7 @@ "categories-submit": "Exibir", "categoriespagetext": "{{PLURAL:$1|A seguinte categoria contém|As seguintes contém}} páginas ou mídia.\n[[Special:UnusedCategories|Categorias não utilizadas]] não são mostradas aqui.\nVeja também [[Special:WantedCategories|categorias pedidas]].", "categoriesfrom": "Listar categorias começando por:", - "deletedcontributions": "Edições eliminadas", + "deletedcontributions": "Contribuições eliminadas", "deletedcontributions-title": "Contribuições eliminadas", "sp-deletedcontributions-contribs": "contribuições", "linksearch": "Pesquisa de links externos", @@ -2512,7 +2512,7 @@ "ipbcreateaccount": "Prevenir a criação de contas", "ipbemailban": "Impedir usuário(a) de enviar e-mail", "ipbenableautoblock": "Bloquear automaticamente o endereço de IP mais recente usado por este(a) usuário(a) e todos os IPs subsequentes dos quais ele(a) tentar editar", - "ipbsubmit": "Bloquear este(a) usuário(a)", + "ipbsubmit": "Bloquear", "ipbother": "Outro período:", "ipboptions": "2 horas:2 hours,1 dia:1 day,3 dias:3 days,1 semana:1 week,2 semanas:2 weeks,1 mês:1 month,3 meses:3 months,6 meses:6 months,1 ano:1 year,indefinido:infinite", "ipbhidename": "Ocultar nome de usuário em edições e listas", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index f7038628d9..94ffcf6ab2 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -1600,7 +1600,7 @@ "rcfilters-savedqueries-rename": "Label for the menu option that edits a quick filter in [[Special:RecentChanges]]\n{{Identical|Rename}}", "rcfilters-savedqueries-setdefault": "Label for the menu option that sets a quick filter as default in [[Special:RecentChanges]]", "rcfilters-savedqueries-unsetdefault": "Label for the menu option that unsets a quick filter as default in [[Special:RecentChanges]]", - "rcfilters-savedqueries-remove": "Label for the menu option that removes a quick filter as default in [[Special:RecentChanges]]\n{{Identical|Remove}}", + "rcfilters-savedqueries-remove": "Label for the menu option that removes a quick filter as default in [[Special:RecentChanges]]\n{{Identical|Delete}}", "rcfilters-savedqueries-new-name-label": "Label for the input that holds the name of the new saved filters in [[Special:RecentChanges]]\n{{Identical|Name}}", "rcfilters-savedqueries-new-name-placeholder": "Placeholder for the input that holds the name of the new saved filters in [[Special:RecentChanges]]", "rcfilters-savedqueries-apply-label": "Label for the button to apply saving a new filter setting in [[Special:RecentChanges]]. This is for a small popup, please try to use a short string.", diff --git a/languages/i18n/ru.json b/languages/i18n/ru.json index 87c820f940..2b86286c57 100644 --- a/languages/i18n/ru.json +++ b/languages/i18n/ru.json @@ -886,9 +886,9 @@ "expansion-depth-exceeded-warning": "На странице превышен предел вложенности", "parser-unstrip-loop-warning": "Обнаружен незакрытый pre", "unstrip-depth-warning": "Превышен предел рекурсии ($1)", - "unstrip-depth-category": "Страницы где незаметная глубина превышена", - "unstrip-size-warning": "Unstrip превышен предел рекурсии ($1)", - "unstrip-size-category": "Страницы где незаметная разметка превышена", + "unstrip-depth-category": "Страницы с превышенным лимитом глубины Unstrip", + "unstrip-size-warning": "Превышен лимит размера Unstrip ($1)", + "unstrip-size-category": "Страницы с превышенным лимитом размера Unstrip", "converter-manual-rule-error": "Ошибка в ручном правиле преобразования языка", "undo-success": "Правка может быть отменена. Пожалуйста, просмотрите сравнение версий, чтобы убедиться, что это именно те изменения, которые вас интересуют, и нажмите «Записать страницу», чтобы изменения вступили в силу.", "undo-failure": "Правка не может быть отменена из-за несовместимости промежуточных изменений.", @@ -1131,7 +1131,7 @@ "recentchangesdays": "Количество дней, за которые показывать свежие правки:", "recentchangesdays-max": "(не более $1 {{PLURAL:$1|дня|дней}})", "recentchangescount": "Количество правок, по умолчанию отображаемое в списке свежих правок, истории страниц и в журналах:", - "prefs-help-recentchangescount": "Наибольшее значение: 1000", + "prefs-help-recentchangescount": "Максимальное значение: 1000", "prefs-help-watchlist-token2": "Это секретный ключ для веб-канала вашего списка наблюдений.\nЛюбой, кто знает его, сможет читать ваш список наблюдения, поэтому не сообщайте его другим.\nЕсли необходимо, [[Special:ResetTokens|вы можете сбросить его]].", "prefs-help-tokenmanagement": "Вы можете просмотреть и сбросить для своей учётной записи секретный ключ, который может получить доступ к веб-каналу вашего списка наблюдения. Любой, кто знает ключ, сможет прочитать ваш список наблюдения, поэтому не делитесь им ни с кем.", "savedprefs": "Настройки сохранены.", @@ -1560,7 +1560,7 @@ "rcfilters-view-namespaces-tooltip": "Результаты фильтра по пространствам имён", "rcfilters-view-tags-tooltip": "Фильтровать результаты, используя метки правок", "rcfilters-view-return-to-default-tooltip": "Вернуться в главное меню фильтров", - "rcfilters-view-tags-help-icon-tooltip": "Узнать больше о редакторе тегов", + "rcfilters-view-tags-help-icon-tooltip": "Подробнее о правках с метками", "rcfilters-liveupdates-button": "Обновлять автоматически", "rcfilters-liveupdates-button-title-on": "Отключить автоматические обновления", "rcfilters-liveupdates-button-title-off": "Показывать новые изменения сразу после их появления", @@ -2367,8 +2367,8 @@ "editcomment": "Было дано описание изменения: $1.", "revertpage": "Откат правок [[Special:Contributions/$2|$2]] ([[User talk:$2|обсуждение]]) к версии [[User:$1|$1]]", "revertpage-nouser": "Откат правок (имя участника скрыто) к версии {{GENDER:$1|[[User:$1|$1]]}}", - "rollback-success": "Откат правок {{GENDER:$3|$1}}; возврат к версии {{GENDER:$4|$2}}.", - "rollback-success-notify": "Откат правок $1; возврат к версии $2. [$3 Показать изменения]", + "rollback-success": "Откачены правки {{GENDER:$3|$1}}; возвращена последняя версия {{GENDER:$4|$2}}.", + "rollback-success-notify": "Откачены правки $1; возвращена последняя версия $2. [$3 Показать изменения]", "sessionfailure-title": "Ошибка сеанса", "sessionfailure": "Похоже, возникли проблемы с текущим сеансом работы;\nэто действие было отменено в целях предотвращения «захвата сеанса».\nПожалуйста, переотправьте форму.", "changecontentmodel": "Редактирование контентной модели страницы", @@ -2647,7 +2647,7 @@ "ip_range_invalid": "Недопустимый диапазон IP-адресов.", "ip_range_toolarge": "Блокировки диапазонов свыше /$1 запрещены.", "ip_range_exceeded": "IP-диапазон превышает максимальный диапазон. Допустимый диапазон: /$1.", - "ip_range_toolow": "Диапазоны IP не разрешены.", + "ip_range_toolow": "Диапазоны IP по сути запрещены.", "proxyblocker": "Блокировка прокси", "proxyblockreason": "Ваш IP-адрес заблокирован потому, что это открытый прокси-сервер. Пожалуйста, свяжитесь со своиим интернет-провайдером или службой поддержки, и сообщите им об этой серьёзной проблеме безопасности.", "sorbs": "DNSBL", @@ -4080,7 +4080,7 @@ "limitreport-expansiondepth-value": "$1/$2", "limitreport-expensivefunctioncount": "Количество «дорогих» функций анализатора", "limitreport-expensivefunctioncount-value": "$1/$2", - "limitreport-unstrip-depth": "Глубинная рекурсия Unstrip", + "limitreport-unstrip-depth": "Глубина рекурсии Unstrip", "limitreport-unstrip-depth-value": "$1/$2", "limitreport-unstrip-size": "Размер Unstrip после раскрытия включений", "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|байт|байта|байт}}", diff --git a/languages/i18n/sa.json b/languages/i18n/sa.json index 9880c2c493..513e64df22 100644 --- a/languages/i18n/sa.json +++ b/languages/i18n/sa.json @@ -24,7 +24,8 @@ "Macofe", "Matma Rex", "రహ్మానుద్దీన్", - "Fitoschido" + "Fitoschido", + "Charunandan16" ] }, "tog-underline": "परिसन्धेः अधो रेखाङ्कनम्:", @@ -1746,6 +1747,7 @@ "dellogpage": "अपाकरणानाम् आवलिः", "dellogpagetext": "सद्यः कालीनापमर्जितपुटानाम् आवली अधः अस्ति ।", "deletionlog": "अपमर्जनसूचिका ।", + "log-description-create": "नवीनतमानां पृष्ठरचनानाम् इयम् आवली", "reverted": "प्राचीनपुनरावृत्तिः पूर्ववत् कृता ।", "deletecomment": "कारणम् :", "deleteotherreason": "अपरं/अतिरिक्तं कारणम् :", diff --git a/languages/i18n/shn.json b/languages/i18n/shn.json index 6447d1363a..10e1ac24a9 100644 --- a/languages/i18n/shn.json +++ b/languages/i18n/shn.json @@ -1074,7 +1074,7 @@ "nchanges": "$1 {{PLURAL:$1|လႅၵ်ႈလၢႆႈ|ၸိူဝ်းလႅၵ်ႈလၢႆႈ}}", "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ၸဵမ်မိူဝ်ႈ ၵႂႃႇဢႅတ်ႇပွၵ်ႈၵမ်းလိုၼ်း}}", "enhancedrc-history": "ပိုၼ်း", - "recentchanges": "မီးလွင်ႈလႅၵ်ႈလၢႆႈပႆႇႁိုင်", + "recentchanges": "လွင်ႈလႅၵ်ႈလၢႆႈမႂ်ႇမႂ်ႇ", "recentchanges-legend": "ၵၼ်လိူၵ်ႈသၢင်ႈ လွင်ႈလႅၵ်ႈလၢႆႈဢၼ်ပူၼ်ႉမႃး", "recentchanges-summary": "ၸွမ်းတူၺ်းႁွႆး ဢၼ်ပဵၼ်ၵၢၼ် တိုၵ်ႉႁႃလႅၵ်ႈလၢႆႈၵႂႃႇ တွၼ်ႈတႃႇၼႃႈလိၵ်ႈ ဝီႇၶီႇၼႆႉ။", "recentchanges-noresult": "ၼႂ်းၵႃႈၶၢဝ်းယၢမ်း ဢၼ်ပၼ်ဝႆႉ တႃႇၵိုၵ်းတူၺ်း ပိူင်တႅၵ်ႈတႃႇတႅပ်းတတ်းၼၼ်ႉ ဢမ်ႇႁၼ်မီး လွင်ႈလႅၵ်ႈလၢႆႈသင်။", diff --git a/languages/i18n/sq.json b/languages/i18n/sq.json index 489667218c..c1be4c365c 100644 --- a/languages/i18n/sq.json +++ b/languages/i18n/sq.json @@ -37,7 +37,8 @@ "Fanjiayi", "Fitoschido", "Luanibraj", - "Matěj Suchánek" + "Matěj Suchánek", + "Bjakupi" ] }, "tog-underline": "Nënvizimi i lidhjes:", @@ -1360,6 +1361,8 @@ "rcfilters-watchlist-markseen-button": "Shenjo të gjitha ndryshimet si të para", "rcfilters-watchlist-edit-watchlist-button": "Redakto listën tuaj të faqeve të mbikëqyrura", "rcfilters-preference-label": "Fshih versionin e përmirësuar të Ndryshimeve të Fundit", + "rcfilters-watchlist-preference-label": "Fshehni versionin e permiresuar te Listes-vrojtuese", + "rcfilters-watchlist-preference-help": "E kthen nderfaqen e ri-dizajnit te 2017 dhe te gjitha mjetet atehere dhe qe nga ai moment.", "rcfilters-target-page-placeholder": "Shto një emër faqeje (ose kategorie)", "rcnotefrom": "Më poshtë {{PLURAL:$5|është shfaqur ndryshimi|janë shfaqur ndryshimet}} që nga $3, $4 (deri në $1).", "rclistfromreset": "Anulo përzgjedhjen e datës", @@ -2016,6 +2019,9 @@ "dellogpage": "Regjistri i grisjeve", "dellogpagetext": "Më poshtë është një listë e grisjeve më të fundit.", "deletionlog": "regjistrin e grisjeve", + "log-name-create": "Krijimi i faqes logjike", + "log-description-create": "Me poshte eshte nje liste e krimit te faqeve me te fundit", + "logentry-create-create": "$1{{GENDER:$2|created}} faqe $3", "reverted": "Kthehu tek një version i vjetër", "deletecomment": "Arsyeja:", "deleteotherreason": "Arsye tjetër:", diff --git a/languages/i18n/sr-ec.json b/languages/i18n/sr-ec.json index 1f30cdea31..b634673900 100644 --- a/languages/i18n/sr-ec.json +++ b/languages/i18n/sr-ec.json @@ -652,7 +652,7 @@ "subject-preview": "Преглед теме:", "previewerrortext": "Догодила се грешка приликом приказивања ваших измена.", "blockedtitle": "Корисник је блокиран", - "blockedtext": "Ваше корисничко име или IP адреса је блокирана.\n\nБлокирање је {{GENDER:$4|извршио|извршила}} $1.\nРазлог је $2.\n\n* Датум блокирања: $8\n* Блокирање истиче: $6\n* Име корисника: $7\n\nОбратите се {{GENDER:$4|кориснику|корисници}} $1 или [[{{MediaWiki:Grouppage-sysop}}|администратору]] да разјасните ствар.\nНе можете користити могућност „Пошаљи имејл овом кориснику“ ако нисте унели исправну имејл адресу у [[Special:Preferences|подешавањима]].\nВаша блокирана IP адреса је $3, а ID блокирања $5.\nНаведите све податке изнад при стварању било каквих упита.", + "blockedtext": "Ваше корисничко име или IP адреса је блокирана.\n\nБлокирање је {{GENDER:$4|извршио|извршила}} $1.\nРазлог је $2.\n\n* Почетак блокирања: $8\n* Истек блокирања: $6\n* Блокирани: $7\n\nМожете да се обратите {{GENDER:$4|кориснику|корисници}} $1 или [[{{MediaWiki:Grouppage-sysop}}|администратору]] ради дискусије о блокирању.\nНе можете да користите могућност „{{int:emailuser}}” осим ако сте унели валидну имејл адресу у својим [[Special:Preferences|подешавањима]] налога и нисте блокирани од коришћења исте.\nВаша тренутна IP адреса је $3, а ID блокирања #$5.\nНаведите све информације одозго при стварању било каквих упита.", "autoblockedtext": "Ваша IP адреса је блокирана јер ју је употребљавао други корисник, кога је {{GENDER:$4|блокирао|блокирала}} $1.\nРазлог:\n\n:$2\n\n* Датум блокирања: $8\n* Блокирање истиче: $6\n* Име корисника: $7\n\nОбратите се {{GENDER:$4|кориснику|корисници}} $1 или [[{{MediaWiki:Grouppage-sysop}}|администратору]] да разјасните ствар.\n\nНе можете користити могућност „Пошаљи имејл овом кориснику“ ако нисте унели исправну имејл адресу у [[Special:Preferences|подешавањима]].\n\nВаша блокирана IP адреса је $3, а ID $5.\nНаведите све податке изнад при стварању било каквих упита.", "blockednoreason": "разлог није наведен", "whitelistedittext": "За уређивање странице је потребно да будете $1.", @@ -1498,7 +1498,7 @@ "recentchangeslinked-feed": "Сродне измене", "recentchangeslinked-toolbox": "Сродне измене", "recentchangeslinked-title": "Сродне измене са „$1“", - "recentchangeslinked-summary": "Унесите име странице да бисте видели промене на страницама које су повезане са или са те странице. (Да бисте видели чланове неке категорије, унесите Категорија:Назив категорије). Промене на страницама које су на [[Special:Watchlist|вашем списку надгледања]] су '''подебљане'''.", + "recentchangeslinked-summary": "Унесите име странице да бисте видели промене на страницама које су повезане са или са те странице. (Да бисте видели чланове категорије, унесите {{ns:category}}:Име категорије). Промене на страницама које су на [[Special:Watchlist|Вашем списку надгледања]] су подебљане.", "recentchangeslinked-page": "Назив странице:", "recentchangeslinked-to": "Прикажи измене страница које су повезане с датом страницом", "recentchanges-page-added-to-category": "[[:$1]] је додата у категорију", @@ -2720,7 +2720,7 @@ "tooltip-ca-nstab-category": "Погледајте страницу категорија", "tooltip-minoredit": "Означите ову измену као мању", "tooltip-save": "Сачувајте своје измене", - "tooltip-publish": "Објавите Ваше измене", + "tooltip-publish": "Објавите своје измене", "tooltip-preview": "Прегледајте своје измене. Користите ово дугме пре чувања.", "tooltip-diff": "Погледајте које измене сте направили на тексту", "tooltip-compareselectedversions": "Погледаjте разлике између две изабране измене ове странице.", diff --git a/languages/i18n/tr.json b/languages/i18n/tr.json index e0083a597e..c10b50bfa0 100644 --- a/languages/i18n/tr.json +++ b/languages/i18n/tr.json @@ -448,6 +448,7 @@ "cascadeprotected": "Bu sayfa değişiklik yapılması engellenmiştir, çünkü \"kademeli\" seçeneği aktif hale getirilerek koruma altına alınan {{PLURAL:$1|sayfada|sayfalarda}} kullanılmaktadır:\n$2", "namespaceprotected": "'''$1''' alandındaki sayfaları düzenlemeye izniniz bulunmamaktadır.", "customcssprotected": "Bu sayfayı değiştirmeye yetkiniz bulunmamaktadır, çünkü bu sayfa başka bir kullanıcının kişisel ayarlarını içermektedir.", + "customjsonprotected": "Başka bir kullanıcının kişisel ayarlarını içerdiği için bu JSON sayfasını düzenleme izniniz yok.", "customjsprotected": "Bu Java Script sayfasını değiştirmeye yetkiniz bulunmamaktadır, çünkü bu sayfa başka bir kullanıcının kişisel ayarlarını içermektedir.", "mycustomcssprotected": "Bu CSS sayfasını değiştirmeye yetkiniz yok.", "mycustomjsonprotected": "Bu JSON sayfasını düzenleme izniniz yok.", @@ -609,6 +610,7 @@ "botpasswords-label-delete": "Sil", "botpasswords-label-resetpassword": "Parolayı sıfırla", "botpasswords-label-grants": "Geçerli ayrıcalıklar:", + "botpasswords-help-grants": "Hibeler, kullanıcı hesabınızın sahip olduğu haklara erişim izni verir. Burada bir hibe sağlamak, kullanıcı hesabınızın sahip olamayacağı herhangi bir haklara erişim sağlamaz. Daha fazla bilgi için [[Special:ListGrants|hibe tablosuna]] bakınız.", "botpasswords-label-grants-column": "Verilen", "botpasswords-bad-appid": "Bot ismi \"$1\" geçerli değil.", "botpasswords-insert-failed": "Bot adı \"$1\" eklenemedi. Zaten eklenmiş olmalı?", @@ -618,11 +620,12 @@ "botpasswords-updated-title": "Bot parolası güncellendi", "botpasswords-updated-body": "\"$2\" adlı {{GENDER:$2|kullanıcının}} \"$1\" adlı botunun bot parolası güncellendi.", "botpasswords-deleted-title": "Bot parolası silindi", - "botpasswords-deleted-body": "\"$2\" adlı kullanıcının \"$1\" adlı botunun bot parolası silindi.", - "botpasswords-newpassword": "$1 ile oturum açmak için yeni şifre: $2. Ä°lerde başvurmak için lütfen kaydedin.", + "botpasswords-deleted-body": "\"$2\" adlı {{GENDER:$2|kullanıcının}} \"$1\" adlı botunun bot parolası silindi.", + "botpasswords-newpassword": "$1 ile giriş yapılan yeni parola: $2. Lütfen bunu ileride başvurmak için kaydedin.
    (Kullanıcı adının, nihai kullanıcı adıyla aynı olmasını gerektiren eski botlar için kullanıcı adı olarak $3 ve şifre olarak da $4 kullanabilirsiniz.)", "botpasswords-no-provider": "BotPasswordsSessionProvider kullanılamaz.", "botpasswords-restriction-failed": "Bot parolası kısıtlamaları bu oturum açma işlemini önlemektedir.", "botpasswords-invalid-name": "Belirtilen kullanıcı adı bot parolası ayırıcısı içermiyor (\"$1\").", + "botpasswords-not-exist": "\"$1\" kullanıcısının \"$2\" adında bir bot şifresine sahip değil.", "botpasswords-needs-reset": "\"$1\" {{GENDER:$1|kullanıcısına}} ait \"$2\" adlı bot için bot parolası sıfırlanmalı.", "resetpass_forbidden": "Parolalar değiştirilememektedir", "resetpass_forbidden-reason": "Parolalar değiştirilemez: $1", @@ -651,6 +654,9 @@ "passwordreset-emailelement": "Kullanıcı adı: \n$1\n\nGeçici şifre: \n$2", "passwordreset-emailsentemail": "Eğer bu e-posta adresi hesabınızın bağlı olduğu adres ise, bir parola sıfırlama e-postası gönderilecektir.", "passwordreset-emailsentusername": "Eğer bu e-posta adresi hesabınızın bağlı olduğu adres ise, bir parola sıfırlama e-postası gönderilecektir.", + "passwordreset-nocaller": "Bir ziyaretçi sağlanmalıdır", + "passwordreset-nosuchcaller": "Ziyaretçi mevcut değil: $1", + "passwordreset-ignored": "Şifre sıfırlama işlenmedi. Belki de herhangi bir sağlayıcı yapılandırılmadı?", "passwordreset-invalidemail": "Geçersiz e-posta adresi", "passwordreset-nodata": "Ne bir kullanıcı adı ne de bir e-posta adresi verildi.", "changeemail": "E-posta adresini değiştir veya çıkar", @@ -717,7 +723,8 @@ "previewerrortext": "Yaptığınız değişikliklerin önizlemesi sırasında bir hata oluştu.", "blockedtitle": "Kullanıcı erişimi engellendi.", "blockedtext": "Kullanıcı adı veya IP adresiniz engellenmiştir.\n\nSizi engelleyen hizmetli: $1.
    \nEngelleme sebebi: $2.\n\n* Engellenmenin başlangıcı: $8\n* Engellenmenin bitişi: $6\n* Engellenme süresi: $7\n\nBelirtilen nedene göre engellenmenizin uygun olmadığını düşünüyorsanız, $1 ya da başka bir [[{{MediaWiki:Grouppage-sysop}}|hizmetli]] ile bu durumu görüşebilirsiniz. [[Special:Preferences|Tercihlerim]] kısmında geçerli bir e-posta adresi girmediyseniz \"Kullanıcıya e-posta gönder\" özelliğini kullanamazsınız, tercihlerinize e-posta adresinizi eklediğinizde e-posta gönderme hakkına sahip olacaksınız.\n
    Şu anki IP adresiniz $3, engellenme numaranız #$5.\n
    Bir hizmetliden durumunuz hakkında bilgi almak istediğinizde veya herhangi bir sorguda bu bilgiler gerekecektir, lütfen not ediniz.", - "autoblockedtext": "IP adresiniz otomatik olarak engellendi, çünkü $1 tarafından engellenmiş başka bir kullanıcı tarafından kullanılmaktaydı.\nBelirtilen sebep şudur:\n\n:''$2''\n\n* Engellemenin başlangıcı: $8\n* Engellemenin bitişi: $6\n* Bloke edilmesi istenen: $7\n\nEngelleme hakkında tartışmak için $1 ile veya diğer [[{{MediaWiki:Grouppage-sysop}}|hizmetlilerden]] biriyle irtibata geçebilirsiniz.\n\nNot, [[Special:Preferences|kullanıcı tercihlerinize]] geçerli bir e-posta adresi kaydetmediyseniz \"kullanıcıya e-posta gönder\" özelliğinden faydalanamayabilirsiniz ve bu özelliği kullanmaktan engellenmediniz.\n\nŞu anki IP numaranız $3 ve engellenme ID'niz #$5.\nLütfen yapacağınız herhangi bir sorguda yukarıdaki bütün detayları bulundurun.", + "autoblockedtext": "IP adresiniz otomatik olarak engellendi, çünkü $1 tarafından engellenmiş başka bir kullanıcı tarafından kullanılmaktaydı.\nBelirtilen sebep şudur:\n\n:$2\n\n* Engellemenin başlangıcı: $8\n* Engellemenin bitişi: $6\n* Bloke edilmesi istenen: $7\n\nEngelleme hakkında tartışmak için $1 ile veya diğer [[{{MediaWiki:Grouppage-sysop}}|hizmetlilerden]] biriyle irtibata geçebilirsiniz.\n\nNot, [[Special:Preferences|kullanıcı tercihlerinize]] geçerli bir e-posta adresi kaydetmediyseniz \"{{int:emailuser}}\" özelliğinden faydalanamayabilirsiniz ve bu özelliği kullanmaktan engellenmediniz.\n\nŞu anki IP numaranız $3 ve engellenme ID'niz #$5.\nLütfen yapacağınız herhangi bir sorguda yukarıdaki bütün detayları bulundurun.", + "systemblockedtext": "Kullanıcı adınız veya IP adresiniz MediaWiki tarafından otomatik olarak engellendi.\nSebebi:\n\n:$2\n\n* Engelin başlangıcı: $8\n* Engelin süresi: $6\n* Engellenmesi istenen: $7\n\nMevcut IP adresiniz $3.\nLütfen yukarıdaki tüm ayrıntıları, yaptığınız sorgularda belirtin.", "blockednoreason": "sebep verilmedi", "whitelistedittext": "Değişiklik yapabilmek için $1.", "confirmedittext": "Sayfa değiştirmeden önce e-posta adresinizi onaylamalısınız. Lütfen [[Special:Preferences|tercihler]] kısmından e-postanızı ekleyin ve onaylayın.", @@ -739,19 +746,22 @@ "blocked-notice-logextract": "Bu kullanıcı şuanda engellenmiş.\nSon engelleme günlüğü girdisi referans için aşağıda sağlanmıştır:", "clearyourcache": "Note: Kaydettikten sonra değişiklikleri görmek için tarayıcınızın önbelleğini temizlemeniz gerekebilir.\n* Firefox / Safari: Shift tuşuna basılıyken Yeniden yükle'ye tıklayın ya da Ctrl-F5 ya da Ctrl-R yapın (Mac için ⌘-R).\n* Google Chrome: Ctrl-Shift-R'ye basın. (Mac için ⌘-Shift-R)\n* Internet Explorer: Ctrl basılıyken Yenile'ye tıklayın ya da Ctrl-F5 yapın.\n* Opera: Araçlar → Tercihler'den önbelliği temizleyin.", "usercssyoucanpreview": "'''İpucu:''' Kaydetmeden önce \"{{int:showpreview}}\"e tıklayarak yeni CSSinizi deneyin.", + "userjsonyoucanpreview": "İpucu: kaydetmeden önce yeni JSON'unuzu test etmek için \"{{int:showpreview}}\" butonunu kullanın.", "userjsyoucanpreview": "'''İpucu:''' Kaydetmeden önce \"{{int:showpreview}}\"e tıklayarak yeni JavaScript'inizi test edin.", "usercsspreview": "'''Sadece kullanıcı CSS dosyanızın önizlemesini görüyorsun.''' '''Kullanıcı CSS dosyası henüz kaydolmadı!'''", + "userjsonpreview": "Sadece kullanıcı JSON yapılandırmanızı test ettiğiniz/önizleme yaptığınızı unutmayın.\nHenüz kaydedilmedi!", "userjspreview": "'''Sadece test ediyorsun ya da önizleme görüyorsun - kullanıcı JavaScript'i henüz kaydolmadı.'''", "sitecsspreview": "'''Sadece kullanıcı CSS dosyanızın önizlemesini görüyorsunuz.''' \n'''Henüz kaydedilmedi!'''", + "sitejsonpreview": "Sadece bu JSON yapılandırmasını önizlediğinizi unutmayın.\nHenüz kaydedilmedi!", "sitejspreview": "'''Sadece kullanıcı JavaScript kod dosyanızın önizlemesini görüyorsunuz.''' \n'''Henüz kaydedilmedi!'''", - "userinvalidconfigtitle": "'''Uyarı:''' \"$1\" adında bir tema yoktur. Özel .css ve .js sayfalarının adlarını küçük harf ile yazın, örneğin; \"{{ns:user}}:Örnek/Vector.css\" yerine \"{{ns:user}}:Örnek/vector.css\" yazın.", + "userinvalidconfigtitle": "Uyarı: \"$1\" adında bir tema yoktur. Özel .css, .json ve .js sayfalarının adlarını küçük harf ile yazın, örneğin; \"{{ns:user}}:Örnek/Vector.css\" yerine \"{{ns:user}}:Örnek/vector.css\" yazın.", "updated": "(Güncellendi)", "note": "'''Not: '''", "previewnote": "'''Bunun yalnızca bir ön izleme olduğunu unutmayın.'''\nYaptığınız değişiklikler henüz kaydedilmedi!", "continue-editing": "Düzenlemeye devam et", "previewconflict": "Bu önizleme metin düzenleme kutucuğunun üstünde, maddenin eğer değişikliklerinizi kaydetmeyi seçerseniz nasıl görüneceğini yansıtır.", "session_fail_preview": "Özür dileriz. Oturum verisi kaybından dolayı değişikliğinizi kaydedemedik.\n\nOturumunuzu kapatmış olabilirsiniz. Lütfen oturumunuzun açık olduğunu doğrulayıp tekrar deneyiniz.\nEğer sorun devam ederse, [[Special:UserLogout|oturumu kapatıp]] tekrar giriş yapmayı deneyin ve tarayıcınızın bu siteden çerezlere izin verip vermediğini kontrol edin.", - "session_fail_preview_html": "'''Üzgünüz! Oturum verisinin kaybolmasından dolayı düzenlemenizi işleme geçiremeyeceğiz.'''\n\n''Çünkü {{SITENAME}} sitesinde raw HTML etkindir, önizleme JavaScript saldırılarına önlem olarak gizlenmiştir.''\n\n'''Eğer bu haklı bir düzenleme girişimiyse, lütfen yeniden deneyin. Eğer hala çalışmazsa, [[Special:UserLogout|çıkış yapıp]] yeniden oturum açmayı deneyin.'''", + "session_fail_preview_html": "Üzgünüz! Düzenleme işleminiz, oturum verisi kaybı nedeniyle işlenemedi.\n\n{{SITENAME}} sayfasında ham HTML özelliği etkin olduğundan önizleme, JavaScript saldırılarına karşı bir önlem olarak gizlenir.\n\nBu yasal bir düzenleme girişimi ise lütfen tekrar deneyin.\nHâlâ çalışmıyorsa [[Special:UserLogout|çıkış yapmayı]] ve ardından tekrar giriş yapmayı deneyin ve tarayıcınızın bu sitedeki çerezlere izin verdiğini kontrol edin.", "token_suffix_mismatch": "'''Değişikliğiniz geri çevrildi çünkü alıcınız düzenleme kutucuğundaki noktalama işaretlerini bozdu.\nDeğişikliğiniz, sayfa metninde bozulmayı önlemek için geri çevrildi.\nEğer sorunlu bir web-tabanlı anonim proksi servisi kullanıyorsanız bu olay bazen gerçekleşebilir.'''", "edit_form_incomplete": "'''Değişiklik formu için bazı sunuculara erişilemedi; yaptığınız değişiklikler bozulmamıştır, gözden geçirip tekrar deneyiniz.'''", "editing": "\"$1\" sayfasını değiştirmektesiniz", @@ -763,15 +773,16 @@ "yourtext": "Sizin metniniz", "storedversion": "Kaydedilmiş metin", "editingold": "'''Uyarı: Sayfanın eski bir sürümünde değişiklik yapmaktasınız.'''\nKaydettiğinizde bu tarihli sürümden günümüze kadar olan değişiklikler yok olacaktır.", + "unicode-support-fail": "Görünüşe göre tarayıcınız Unicode'u desteklemiyor. Sayfaları düzenlemek için bu desteğe ihtiyacınız var. Bundan ötürü düzenlemeniz kaydedilmedi.", "yourdiff": "Karşılaştırma", "copyrightwarning": "'''Lütfen dikkat:''' {{SITENAME}} sitesine yapılan bütün katkılar $2 sözleşmesi kapsamındadır (ayrıntılar için $1'a bakınız).\nYaptığınız katkının başka katılımcılar tarafından acımasızca değiştirilmesini ve sınırsızca başka yerlere dağıtılmasını istemiyorsanız, katkıda bulunmayınız.
    \nAyrıca buraya katkıda bulunarak, bu katkının kendiniz tarafından yazıldığına ya da kamuya açık bir kaynaktan ya da başka bir özgür/ücretsiz kaynaktan kopyalandığına güvence vermiş oluyorsunuz. '''Buraya, telif sahibinin izni olmadan telif hakkı ile korunan eserleri eklemeyiz! '''", "copyrightwarning2": "Lütfen, {{SITENAME}} sitesine bulunacağınız tüm katkıların diğer üyeler tarafından düzenlenebileceğini, değiştirilebileceğini ya da silinebileceğini hatırlayın. Yazılarınızın merhametsizce değiştirilebilmesine rıza göstermiyorsanız buraya katkıda bulunmayın.
    \nAyrıca bu ekleyeceğiniz yazıyı sizin yazdığınızı ya da serbest kopyalama izni veren bir kaynaktan kopyaladığınızı bize taahhüt etmektesiniz (ayrıntılar için referans: $1).", "editpage-cannot-use-custom-model": "Bu sayfanın içerik modeli değiştirilemez.", "longpageerror": "'''Hata: Girdiğiniz metnin uzunluğu kabul edilebilir en fazla uzunluk olan {{PLURAL:$2|bir kilobayt|$2 kilobayt}}tan fazladır ve {{PLURAL:$1|bir kilobayt|$1 kilobayt}} büyüklüğündedir.'''\nDeğişikliğiniz kaydedilemez.", - "readonlywarning": "'''Uyarı: Bakım nedeniyle veritabanı şu anda kilitlenmiştir. Bu yüzden şu anda düzenlemelerinizi kaydetmek mümkün değildir.''' \nYaptığınız düzenlemeleri daha sonra kaydetmek isterseniz, yaptığınız düzenlemeleri bir metin dosyasına ya da herhangi bir şeye kopyala yapıştır yaparak saklayınız.\n\nKilitlemeyi yapan yetkili şu açıklamayı eklemiştir: $1", + "readonlywarning": "Uyarı: Bakım nedeniyle veritabanı şu anda kilitlenmiştir. Bu yüzden şu anda düzenlemelerinizi kaydetmek mümkün değildir. \nYaptığınız düzenlemeleri daha sonra kaydetmek isterseniz, yaptığınız düzenlemeleri bir metin dosyasına ya da herhangi bir şeye kopyala yapıştır yaparak saklayınız.\n\nKilitlemeyi yapan sistem yetkilisi şu açıklamayı eklemiştir: $1", "protectedpagewarning": "'''Uyarı: Bu sayfa koruma altına alınmıştır ve yalnızca hizmetli olanlar tarafından değiştirilebilir.'''\nSon günlük girdisi referans amaçlı aşağıda verilmiştir:", - "semiprotectedpagewarning": "'''Not:''' Bu sayfa sadece kayıtlı kullanıcı olanlar tarafından değiştirilebilir.\nSon günlük girdisi referans amaçlı aşağıda verilmiştir:", - "cascadeprotectedwarning": "'''UYARI:''' Bu sayfa sadece hizmetlilik yetkileri olan kullanıcıların değişiklik yapabileceği şekilde koruma altına alınmıştır. Çünkü \"kademeli\" seçeneği aktif hale getirilerek koruma altına alınan {{PLURAL:$1|sayfada|sayfada}} kullanılmaktadır:", + "semiprotectedpagewarning": "Not: Bu sayfa sadece otomatik onaylanmış kullanıcılar tarafından değiştirilebilir.\nSon günlük girdisi referans amaçlı aşağıda verilmiştir:", + "cascadeprotectedwarning": "Uyarı: Bu sayfa, yalnızca [[Special:ListGroupRights|belirli haklara]] sahip kullanıcıların bunu düzenleyebilmesi için korunmuştur çünkü \"kademeli\" seçeneği aktif hale getirilerek koruma altına alınan {{PLURAL:$1|sayfada|sayfada}} kullanılmaktadır:", "titleprotectedwarning": "'''Uyarı: Bu sayfa [[Special:ListGroupRights|özel hakları]] olanların oluşturabilmeleri için kilitlenmiştir.'''\nSon günlük girdisi referans amaçlı aşağıda verilmiştir:", "templatesused": "Bu sayfada kullanılan {{PLURAL:$1|şablon|şablonlar}}:", "templatesusedpreview": "Bu önizlemede kullanılan {{PLURAL:$1|şablon|şablonlar}}:", @@ -787,8 +798,10 @@ "permissionserrors": "İzin hatası", "permissionserrorstext": "Aşağıdaki {{PLURAL:$1|sebep|sebepler}}den dolayı, bunu yapmaya yetkiniz yok:", "permissionserrorstext-withaction": "Aşağıdaki {{PLURAL:$1|neden|nedenler}}den dolayı $2 yetkiniz yok:", + "contentmodelediterror": "Bu revizyonu, içerik modeli $1 olduğu için düzenleyemezsiniz. $2 sayfasının güncel içerik modelinden farklıdır", "recreate-moveddeleted-warn": "Uyarı: Daha önceden silinmiş bir sayfayı tekrar oluşturuyorsunuz.\n\nBu sayfayı düzenlemeye devam etmenin uygun olup olmadığını düşünmelisiniz.\nBu sayfanın silme ve taşıma günlüğü kolaylık için burada verilmiştir:", "moveddeleted-notice": "Bu sayfa silinmiş.\nSayfanın silme, koruma ve taşıma kaydı referans için aşağıda verilmiştir.", + "moveddeleted-notice-recent": "Üzgünüz, bu sayfa yakın zamanda silinmiştir (son 24 saat içinde).\nSayfa için silme, koruma ve taşıma kaydı referans amacıyla aşağıda verilmiştir.", "log-fulllog": "Tam günlüğü gör", "edit-hook-aborted": "Değişiklik çengelle durduruldu.\nBir açıklama verilmedi.", "edit-gone-missing": "Sayfa güncellenemiyor.\nSilinmiş görünüyor.", @@ -815,6 +828,7 @@ "content-json-empty-object": "Boş nesne", "content-json-empty-array": "Boş dizi", "deprecated-self-close-category": "Kendiliğinden geçersiz HTML etiketlerini kullanan sayfalar", + "deprecated-self-close-category-desc": "Sayfa, <b/> veya <span/> gibi kendiliğinden geçersiz HTML etiketleri içeriyor. Bunların davranışları yakında HTML5 belirtimiyle tutarlı olacak şekilde değişecektir, bu nedenle wikitext'deki kullanımları, kullanımdan kaldırılır.", "duplicate-args-warning": "Uyarı:[[:$1]] [[:$2]] şablonunu \"$3\" parametresi için birden fazla değerle çağırıyor. Sadece sağlanan son değer kullanılacak.", "duplicate-args-category": "Yinelenen şablon değişkenleri kullanan sayfalar", "duplicate-args-category-desc": "Sayfada içeren şablonları çağırmak için bu terimler kullanılır {{foo|bar=1|bar=2}} or {{foo|bar|1=baz}}.", @@ -826,6 +840,8 @@ "post-expand-template-argument-category": "Geçersiz şablon değiştirgenleri içeren sayfalar", "parser-template-loop-warning": "Şablon düğümü tespit edildi: [[$1]]", "template-loop-category": "Şablon döngülü sayfalar", + "template-loop-category-desc": "Sayfa bir şablon döngüsü içermektedir. Örneğin, kendini sürekli olarak çağıran bir şablon.", + "template-loop-warning": "Uyarı: Bu sayfa, bir şablon döngüsüne (sonsuz yinelemeli çağrı) neden olan [[:$1]] şablonunu çağırmaktadır.", "parser-template-recursion-depth-warning": "Şablon özyineleme yoğunluğu sınırı aşıldı ($1)", "language-converter-depth-warning": "Dil çevirici derinlik sınırı aşıldı ($1)", "node-count-exceeded-category": "Düğüm sayısı aşılan sayfalar", @@ -836,6 +852,7 @@ "expansion-depth-exceeded-warning": "Sayfa genişletme derinliği aşıldı", "parser-unstrip-loop-warning": "Yineleme döngüsü algılandı", "unstrip-depth-warning": "($1) yineleme sınırı aşıldı", + "unstrip-depth-category": "Sızıntı derinliği sınırının aşıldığı sayfalar", "converter-manual-rule-error": "Elle yapılandırma dil dönüşüm kuralı hatası tespit edildi", "undo-success": "Bu değişiklik geri alınabilir. Lütfen aşağıdaki karşılaştırmayı kontrol edin, gerçekten bu değişikliği yapmak istediğinizden emin olun ve sayfayı kaydederek bir önceki değişikliği geriye alın.", "undo-failure": "Değişikliklerin çakışması nedeniyle geri alma işlemi başarısız oldu.", diff --git a/languages/i18n/yi.json b/languages/i18n/yi.json index 25b82770d7..edde6a15fe 100644 --- a/languages/i18n/yi.json +++ b/languages/i18n/yi.json @@ -624,7 +624,7 @@ "previewerrortext": "א פעלער האט פאסירט ביים פרובירן פארויסקוקן אײַערע ענדערונגען.", "blockedtitle": "באַניצער איז בלאקירט", "blockedtext": "'''אייער באניצער נאמען אדער IP אדרעס איז געווארן בלאקירט.'''\n\nדעם בלאק האט $1 געמאכט פון וועגן ''$2''.\n\n* בלאקירן הייבט אן: $8\n* בלאקירן גייט אויס: $6\n* בלאק מכוון צו: $7\n\nאיר קענט זיך ווענדן צו $1 אדער צו אנדערע [[{{MediaWiki:Grouppage-sysop}}|אדמיניסטראטארן]] אדורכצורעדן דעם בלאק.\n\nגיט אכט אז איר קענט נישט ניצן די \"שיקט דעם באניצער א ע-פאסט\" אייגנקייט אויב האט איר נישט איינגעשטעלט אין אייערע [[Special:Preferences|קונטע פרעפערענצן]] א גילטיקן בליצפאסט אדרעסדאס אדער איר זענט בלאקירט פון שיקן בליצפאסט.\n\nאייער IP אדרעס איז $3, און דער בלאק האט נומער #$5. ביטע שיקט איינעם פון די צוויי (אדער זיי ביידע) ווען איר ווענדט זיך צו די אדמיניסטראטורן.", - "autoblockedtext": "אײַער [[IP אדרעס|אײַ־פּי־אַדרעס]] איז בלאָקירט געװאָרן אױטאָמאַטיש, צוליב דעם װאָס אַן אַנדער באַניצער װאָס איז בלאָקירט געװאָרן דורך $1 האָט זיך געניצט דעם דאָזיקן אײַ־פּי.\nדי אורזאַך פֿון דער בלאָקירונג איז:\n\n:'''$2'''\n\n* אנהייב פון דער בלאקירונג: $8\n* ענדע פון דער בלאָקירונג: $6\n* וועמען בלאקירט: ִ$7\n\nאיר קענט זיך פֿאַרבינדן דורכן בליצבריװ מיט $1 אָדער מיט יעדן אַנדערן [[{{MediaWiki:Grouppage-sysop}}|סיסאָפּ]] צו דיסקוטירן װעגן דער בלאָקירונג.\n\nאױב האָט איר ניט אַרײַנגעקלאַפּט אײַער בליצפּאָסט־אַדרעס אין אײַערע [[Special:Preferences|פּרעפֿערענצן]] אדער איר זענט בלאקירט פון שיקן בליצפאסט, קענט איר זיך ''נישט'' ניצן די אפציע \"שיקט דעם באניצער אן ע-פאסט\".\n\nאייער יעצטיגער IP אדרעס איז $3, און דער בלאָקירונג־נומער איז #$5.\nביטע צײכנט עס אָן בשעת איר װענדט זיך צו די סיסאָפּן.", + "autoblockedtext": "אײַער IP אדרעס איז בלאָקירט געװאָרן אױטאָמאַטיש, צוליב דעם װאָס אַן אַנדער באַניצער װאָס איז בלאָקירט געװאָרן דורך $1 האָט זיך געניצט דעם דאָזיקן אײַ־פּי.\nדי אורזאַך פֿון דער בלאָקירונג איז:\n\n:$2\n\n* אנהייב פון דער בלאקירונג: $8\n* ענדע פון דער בלאָקירונג: $6\n* וועמען בלאקירט: ִ$7\n\nאיר קענט זיך פֿאַרבינדן דורכן בליצבריװ מיט $1 אָדער מיט יעדן אַנדערן [[{{MediaWiki:Grouppage-sysop}}|סיסאָפּ]] צו דיסקוטירן װעגן דער בלאָקירונג.\n\nאיר טארט נישט ניצן די \"{{int:emailuser}}\" פֿונקציע נאר ווען איר האט א גילטיגן ע־פאסט אדרעס איינגעשריבן אין אייערע [[Special:Preferences|באניצער פרעפֿערענצן]] און איר זענט נישט געווארן בלאקירט פון ניצן אים.\n\nאייער יעצטיגער IP אדרעס איז $3, און דער בלאָקירונג־נומער איז #$5.\nביטע צײכנט עס אָן בשעת איר װענדט זיך צו די סיסאָפּן.", "blockednoreason": "קיין טעם נישט געגעבן", "whitelistedittext": "איר ברויכט צו $1 צו ענדערן בלעטער.", "confirmedittext": "אויף אייך ליגט קודם די פֿליכט צו באשטעטיגן אייער ע־פאסט אדרעס איידער איר רעדאַקטירט בלעטער.\nביטע שטעלט און באשטעטיגט אייער ע־פאסט אדרעס דורך אייערע [[Special:Preferences|באַניצער פרעפֿערענצן]] .", @@ -1365,7 +1365,7 @@ "recentchangeslinked-feed": "פֿאַרבונדענע ענדערונגען", "recentchangeslinked-toolbox": "פֿאַרבונדענע ענדערונגען", "recentchangeslinked-title": "ענדערונגען פֿארבונדן מיט $1", - "recentchangeslinked-summary": "גיט אריין א בלאטנאמען צו זען ענדערונגען צו בלעטער פארבונדן צו אדער פון יענעם בלאט. (צו זען מיטגליד בלעטער פון א קאטעגאריע גיט אריין ״קאטעגאריע:נאמען פון קאטעגאריע״). ענדערונגען צו בלעטער אויף [[Special:Watchlist|אייער אויפפאסונג ליסטע]] זענען געוויזן דיק.", + "recentchangeslinked-summary": "גיט אריין א בלאטנאמען צו זען ענדערונגען צו בלעטער פארבונדן צו אדער פון יענעם בלאט. (צו זען מיטגליד בלעטער פון א קאטעגאריע גיט אריין ״{{ns:category}}:נאמען פון קאטעגאריע״). ענדערונגען צו בלעטער אויף [[Special:Watchlist|אייער אויפפאסונג ליסטע]] זענען געוויזן דיק.", "recentchangeslinked-page": "בלאַט נאָמען:", "recentchangeslinked-to": "צייג ענדערונגען צו בלעטער פארבינדן צו דעם בלאט אנשטאט", "recentchanges-page-added-to-category": "[[:$1]] צוגעלייגט צו קאטעגאריע", diff --git a/languages/messages/MessagesKo.php b/languages/messages/MessagesKo.php index 42cc676e1f..5db206237d 100644 --- a/languages/messages/MessagesKo.php +++ b/languages/messages/MessagesKo.php @@ -78,6 +78,7 @@ $specialPageAliases = [ 'Allpages' => [ '모든문서' ], 'ApiHelp' => [ 'Api도움말' ], 'Ancientpages' => [ '오래된문서' ], + 'AutoblockList' => [ '자동차단목록' ], 'Badtitle' => [ '잘못된제목', '인식불가제목', '잘못된이름', '인식불가이름' ], 'Blankpage' => [ '빈문서' ], 'Block' => [ '차단', 'IP차단', '사용자차단' ], @@ -113,7 +114,7 @@ $specialPageAliases = [ 'LinkSearch' => [ '링크검색', '링크찾기' ], 'Listadmins' => [ '관리자', '관리자목록' ], 'Listbots' => [ '봇', '봇목록' ], - 'Listfiles' => [ '파일', '그림', '파일목록', '그림목록' ], + 'Listfiles' => [ '파일목록', '그림목록', '파일', '그림' ], 'Listgrouprights' => [ '사용자권한목록', '사용자권한', '권한목록' ], 'Listgrants' => [ '권한부여목록' ], 'Listredirects' => [ '넘겨주기목록' ], @@ -142,7 +143,9 @@ $specialPageAliases = [ 'Newimages' => [ '새파일', '새그림' ], 'Newpages' => [ '새문서' ], 'PagesWithProp' => [ '속성별문서' ], + 'PageData' => [ '문서데이터' ], 'PageLanguage' => [ '문서언어' ], + 'PasswordPolicies' => [ '비밀번호정책' ], 'PasswordReset' => [ '비밀번호재설정', '비밀번호초기화' ], 'PermanentLink' => [ '고유링크', '영구링크' ], 'Preferences' => [ '환경설정' ], diff --git a/languages/messages/MessagesZgh.php b/languages/messages/MessagesZgh.php new file mode 100644 index 0000000000..720b591a5a --- /dev/null +++ b/languages/messages/MessagesZgh.php @@ -0,0 +1,11 @@ +getID(); $content = $revision->getContent( Revision::RAW ); - $id = $id ? $id : ''; + $id = $id ?: ''; if ( $content === null ) { echo "Revision $id is broken, we have no content available\n"; diff --git a/maintenance/storage/recompressTracked.php b/maintenance/storage/recompressTracked.php index 49b8e0a69d..271cbf3dd6 100644 --- a/maintenance/storage/recompressTracked.php +++ b/maintenance/storage/recompressTracked.php @@ -226,7 +226,7 @@ class RecompressTracked { } $cmd .= ' --child' . ' --wiki ' . wfEscapeShellArg( wfWikiID() ) . - ' ' . call_user_func_array( 'wfEscapeShellArg', $this->destClusters ); + ' ' . wfEscapeShellArg( ...$this->destClusters ); $this->replicaPipes = $this->replicaProcs = []; for ( $i = 0; $i < $this->numProcs; $i++ ) { @@ -426,12 +426,12 @@ class RecompressTracked { $args = array_slice( $ids, 0, $this->orphanBatchSize ); $ids = array_slice( $ids, $this->orphanBatchSize ); array_unshift( $args, 'doOrphanList' ); - call_user_func_array( [ $this, 'dispatch' ], $args ); + $this->dispatch( ...$args ); } if ( count( $ids ) ) { $args = $ids; array_unshift( $args, 'doOrphanList' ); - call_user_func_array( [ $this, 'dispatch' ], $args ); + $this->dispatch( ...$args ); } $this->report( 'orphans', $i, $numOrphans ); diff --git a/package.json b/package.json index 2d425dd62e..36328e0a85 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "qunit": "grunt qunit", "doc": "jsduck", "postdoc": "grunt copy:jsduck", - "selenium": "./tests/selenium/selenium.sh", + "selenium": "bash ./tests/selenium/selenium.sh", "selenium-test": "wdio ./tests/selenium/wdio.conf.js" }, "devDependencies": { diff --git a/profileinfo.php b/profileinfo.php index 9ebd57b7a2..8bd37dd4cb 100644 --- a/profileinfo.php +++ b/profileinfo.php @@ -396,8 +396,8 @@ if ( isset( $_REQUEST['filter'] ) ) { return htmlspecialchars( '?' . wfArrayToCgi( [ - 'filter' => $_filter ? $_filter : $filter, - 'sort' => $_sort ? $_sort : $sort, + 'filter' => $_filter ?: $filter, + 'sort' => $_sort ?: $sort, 'expand' => implode( ',', array_keys( $_expand ) ) ] ) ); diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less index 09d223e584..11972de06c 100644 --- a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less +++ b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less @@ -5,7 +5,7 @@ @rcfilters-spinner-size: 12px; @rcfilters-head-min-height: 210px; @rcfilters-head-margin-bottom: 20px; -@rcfilters-wl-head-min-height: 300px; +@rcfilters-wl-head-min-height: 270px; // Corrections for the standard special page .client-js { diff --git a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.SavedLinksListItemWidget.js b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.SavedLinksListItemWidget.js index 060ead02d7..c13c2f79ac 100644 --- a/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.SavedLinksListItemWidget.js +++ b/resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.SavedLinksListItemWidget.js @@ -56,7 +56,7 @@ } ), new OO.ui.MenuOptionWidget( { data: 'delete', - icon: 'close', + icon: 'trash', label: mw.msg( 'rcfilters-savedqueries-remove' ) } ), new OO.ui.MenuOptionWidget( { diff --git a/resources/src/mediawiki.ui/components/inputs.less b/resources/src/mediawiki.ui/components/inputs.less index bbfd528204..4b8b1ee2ac 100644 --- a/resources/src/mediawiki.ui/components/inputs.less +++ b/resources/src/mediawiki.ui/components/inputs.less @@ -103,7 +103,6 @@ textarea.mw-ui-input { // // // Styleguide 1.2. -input[ type='number' ], .mw-ui-input-inline { display: inline-block; width: auto; diff --git a/tests/common/TestsAutoLoader.php b/tests/common/TestsAutoLoader.php index a79867913e..2cc56419e6 100644 --- a/tests/common/TestsAutoLoader.php +++ b/tests/common/TestsAutoLoader.php @@ -184,6 +184,10 @@ $wgAutoloadClasses += [ => "$testDir/phpunit/mocks/session/DummySessionBackend.php", 'DummySessionProvider' => "$testDir/phpunit/mocks/session/DummySessionProvider.php", 'MockMessageLocalizer' => "$testDir/phpunit/mocks/MockMessageLocalizer.php", + 'MockCompletionSearchEngine' => "$testDir/phpunit/mocks/search/MockCompletionSearchEngine.php", + 'MockSearchEngine' => "$testDir/phpunit/mocks/search/MockSearchEngine.php", + 'MockSearchResultSet' => "$testDir/phpunit/mocks/search/MockSearchResultSet.php", + 'MockSearchResult' => "$testDir/phpunit/mocks/search/MockSearchResult.php", # tests/suites 'ParserTestFileSuite' => "$testDir/phpunit/suites/ParserTestFileSuite.php", diff --git a/tests/parser/DjVuSupport.php b/tests/parser/DjVuSupport.php index 73d4a47f82..eede54e0f2 100644 --- a/tests/parser/DjVuSupport.php +++ b/tests/parser/DjVuSupport.php @@ -31,10 +31,10 @@ class DjVuSupport { public function __construct() { global $wgDjvuRenderer, $wgDjvuDump, $wgDjvuToXML, $wgFileExtensions, $wgDjvuTxt; - $wgDjvuRenderer = $wgDjvuRenderer ? $wgDjvuRenderer : '/usr/bin/ddjvu'; - $wgDjvuDump = $wgDjvuDump ? $wgDjvuDump : '/usr/bin/djvudump'; - $wgDjvuToXML = $wgDjvuToXML ? $wgDjvuToXML : '/usr/bin/djvutoxml'; - $wgDjvuTxt = $wgDjvuTxt ? $wgDjvuTxt : '/usr/bin/djvutxt'; + $wgDjvuRenderer = $wgDjvuRenderer ?: '/usr/bin/ddjvu'; + $wgDjvuDump = $wgDjvuDump ?: '/usr/bin/djvudump'; + $wgDjvuToXML = $wgDjvuToXML ?: '/usr/bin/djvutoxml'; + $wgDjvuTxt = $wgDjvuTxt ?: '/usr/bin/djvutxt'; if ( !in_array( 'djvu', $wgFileExtensions ) ) { $wgFileExtensions[] = 'djvu'; diff --git a/tests/parser/parserTests.txt b/tests/parser/parserTests.txt index b109e3967d..afddd78553 100644 --- a/tests/parser/parserTests.txt +++ b/tests/parser/parserTests.txt @@ -24649,6 +24649,17 @@ abc abc

    !! end +!! test +Padleft and padright with non-numerical length (T180403) +!! wikitext +{{padleft:abcdef|junk}} +{{padright:abcdef|junk}} +!! html/php +

    abcdef +abcdef +

    +!! end + !!test Special parser function !! wikitext diff --git a/tests/phan/config.php b/tests/phan/config.php index 5f712876c8..61d86bd658 100644 --- a/tests/phan/config.php +++ b/tests/phan/config.php @@ -305,8 +305,6 @@ return [ "PhanDeprecatedProperty", // approximate error count: 17 "PhanNonClassMethodCall", - // approximate error count: 11 - "PhanParamReqAfterOpt", // approximate error count: 888 "PhanParamSignatureMismatch", // approximate error count: 7 diff --git a/tests/phpunit/MediaWikiTestCase.php b/tests/phpunit/MediaWikiTestCase.php index 6bcbd938d8..5fddc3d71b 100644 --- a/tests/phpunit/MediaWikiTestCase.php +++ b/tests/phpunit/MediaWikiTestCase.php @@ -1023,7 +1023,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { * Should be called from addDBData(). * * @since 1.25 ($namespace in 1.28) - * @param string|title $pageName Page name or title + * @param string|Title $pageName Page name or title * @param string $text Page's content * @param int $namespace Namespace id (name cannot already contain namespace) * @return array Title object and page id diff --git a/tests/phpunit/includes/LinkerTest.php b/tests/phpunit/includes/LinkerTest.php index f9e2cc1733..4c508e3851 100644 --- a/tests/phpunit/includes/LinkerTest.php +++ b/tests/phpunit/includes/LinkerTest.php @@ -1,6 +1,5 @@ hideDeprecated( 'LinkBegin hook (used in hook-LinkBegin-closure)' ); $this->setMwGlobals( [ 'wgArticlePath' => '/wiki/$1', 'wgServer' => '//example.org', @@ -417,6 +417,7 @@ class LinkerTest extends MediaWikiLangTestCase { * @dataProvider provideLinkEndHook */ public function testLinkEndHook( $callback, $expected ) { + $this->hideDeprecated( 'LinkEnd hook (used in hook-LinkEnd-closure)' ); $this->setMwGlobals( [ 'wgArticlePath' => '/wiki/$1', ] ); @@ -427,54 +428,4 @@ class LinkerTest extends MediaWikiLangTestCase { $out = Linker::link( $title ); $this->assertEquals( $expected, $out ); } - - /** - * @covers Linker::getLinkColour - */ - public function testGetLinkColour() { - $this->hideDeprecated( 'Linker::getLinkColour' ); - $linkCache = MediaWikiServices::getInstance()->getLinkCache(); - $foobarTitle = Title::makeTitle( NS_MAIN, 'FooBar' ); - $redirectTitle = Title::makeTitle( NS_MAIN, 'Redirect' ); - $userTitle = Title::makeTitle( NS_USER, 'Someuser' ); - $linkCache->addGoodLinkObj( - 1, // id - $foobarTitle, - 10, // len - 0 // redir - ); - $linkCache->addGoodLinkObj( - 2, // id - $redirectTitle, - 10, // len - 1 // redir - ); - - $linkCache->addGoodLinkObj( - 3, // id - $userTitle, - 10, // len - 0 // redir - ); - - $this->assertEquals( - '', - Linker::getLinkColour( $foobarTitle, 0 ) - ); - - $this->assertEquals( - 'stub', - Linker::getLinkColour( $foobarTitle, 20 ) - ); - - $this->assertEquals( - 'mw-redirect', - Linker::getLinkColour( $redirectTitle, 0 ) - ); - - $this->assertEquals( - '', - Linker::getLinkColour( $userTitle, 20 ) - ); - } } diff --git a/tests/phpunit/includes/MediaWikiTest.php b/tests/phpunit/includes/MediaWikiTest.php index a8d1e33950..7d7e637673 100644 --- a/tests/phpunit/includes/MediaWikiTest.php +++ b/tests/phpunit/includes/MediaWikiTest.php @@ -154,4 +154,53 @@ class MediaWikiTest extends MediaWikiTestCase { $context->getOutput()->getRedirect() ); } + + /** + * Test a post-send job can not set cookies (T191537). + */ + public function testPostSendJobDoesNotSetCookie() { + // Prevent updates from running + $this->setMwGlobals( 'wgCommandLineMode', false ); + + $response = new WebResponse; + + // A job that attempts to set a cookie + $jobHasRun = false; + DeferredUpdates::addCallableUpdate( function () use ( $response, &$jobHasRun ) { + $jobHasRun = true; + $response->setCookie( 'JobCookie', 'yes' ); + $response->header( 'Foo: baz' ); + } ); + + $hookWasRun = false; + $this->setTemporaryHook( 'WebResponseSetCookie', function () use ( &$hookWasRun ) { + $hookWasRun = true; + return true; + } ); + + $logger = new TestLogger(); + $logger->setCollect( true ); + $this->setLogger( 'cookie', $logger ); + $this->setLogger( 'header', $logger ); + + $mw = new MediaWiki(); + $mw->doPostOutputShutdown(); + // restInPeace() might have been registered to a callback of + // register_postsend_function() and thus can not be triggered from + // PHPUnit. + if ( $jobHasRun === false ) { + $mw->restInPeace(); + } + + $this->assertTrue( $jobHasRun, 'post-send job has run' ); + $this->assertFalse( $hookWasRun, + 'post-send job must not trigger WebResponseSetCookie hook' ); + $this->assertEquals( + [ + [ 'info', 'ignored post-send cookie {cookie}' ], + [ 'info', 'ignored post-send header {header}' ], + ], + $logger->getBuffer() + ); + } } diff --git a/tests/phpunit/includes/Storage/RevisionStoreTest.php b/tests/phpunit/includes/Storage/RevisionStoreTest.php index 3749f294bf..61d0512542 100644 --- a/tests/phpunit/includes/Storage/RevisionStoreTest.php +++ b/tests/phpunit/includes/Storage/RevisionStoreTest.php @@ -29,9 +29,9 @@ class RevisionStoreTest extends MediaWikiTestCase { $WANObjectCache = null ) { return new RevisionStore( - $loadBalancer ? $loadBalancer : $this->getMockLoadBalancer(), - $blobStore ? $blobStore : $this->getMockSqlBlobStore(), - $WANObjectCache ? $WANObjectCache : $this->getHashWANObjectCache(), + $loadBalancer ?: $this->getMockLoadBalancer(), + $blobStore ?: $this->getMockSqlBlobStore(), + $WANObjectCache ?: $this->getHashWANObjectCache(), MediaWikiServices::getInstance()->getCommentStore(), MediaWikiServices::getInstance()->getActorMigration() ); diff --git a/tests/phpunit/includes/TitlePermissionTest.php b/tests/phpunit/includes/TitlePermissionTest.php index 4e342447c4..6600aa23c7 100644 --- a/tests/phpunit/includes/TitlePermissionTest.php +++ b/tests/phpunit/includes/TitlePermissionTest.php @@ -842,18 +842,23 @@ class TitlePermissionTest extends MediaWikiLangTestCase { * @covers Title::checkUserBlock */ public function testUserBlock() { - global $wgEmailConfirmToEdit, $wgEmailAuthentication; - $wgEmailConfirmToEdit = true; - $wgEmailAuthentication = true; + $this->setMwGlobals( [ + 'wgEmailConfirmToEdit' => true, + 'wgEmailAuthentication' => true, + ] ); $this->setUserPerm( [ "createpage", "move" ] ); $this->setTitle( NS_HELP, "test page" ); - # $short - $this->assertEquals( [ [ 'confirmedittext' ] ], + # $wgEmailConfirmToEdit only applies to 'edit' action + $this->assertEquals( [], $this->title->getUserPermissionsErrors( 'move-target', $this->user ) ); - $wgEmailConfirmToEdit = false; - $this->assertEquals( true, $this->title->userCan( 'move-target', $this->user ) ); + $this->assertContains( [ 'confirmedittext' ], + $this->title->getUserPermissionsErrors( 'edit', $this->user ) ); + + $this->setMwGlobals( 'wgEmailConfirmToEdit', false ); + $this->assertNotContains( [ 'confirmedittext' ], + $this->title->getUserPermissionsErrors( 'edit', $this->user ) ); # $wgEmailConfirmToEdit && !$user->isEmailConfirmed() && $action != 'createaccount' $this->assertEquals( [], diff --git a/tests/phpunit/includes/api/ApiQueryPrefixSearchTest.php b/tests/phpunit/includes/api/ApiQueryPrefixSearchTest.php new file mode 100644 index 0000000000..749f154604 --- /dev/null +++ b/tests/phpunit/includes/api/ApiQueryPrefixSearchTest.php @@ -0,0 +1,58 @@ +setMwGlobals( [ + 'wgSearchType' => MockCompletionSearchEngine::class, + ] ); + MockCompletionSearchEngine::clearMockResults(); + $results = []; + foreach ( range( 0, 10 ) as $i ) { + $title = "Search_Result_$i"; + $results[] = $title; + $this->editPage( $title, 'hi there' ); + } + MockCompletionSearchEngine::addMockResults( self::TEST_QUERY, $results ); + } + + public function offsetContinueProvider() { + return [ + 'no offset' => [ 2, 2, 0, 2 ], + 'with offset' => [ 7, 2, 5, 2 ], + 'past end, no offset' => [ null, 11, 0, 20 ], + 'past end, with offset' => [ null, 5, 6, 10 ], + ]; + } + + /** + * @dataProvider offsetContinueProvider + */ + public function testOffsetContinue( $expectedOffset, $expectedResults, $offset, $limit ) { + $response = $this->doApiRequest( [ + 'action' => 'query', + 'list' => 'prefixsearch', + 'pssearch' => self::TEST_QUERY, + 'psoffset' => $offset, + 'pslimit' => $limit, + ] ); + $result = $response[0]; + $this->assertArrayNotHasKey( 'warnings', $result ); + $suggestions = $result['query']['prefixsearch']; + $this->assertCount( $expectedResults, $suggestions ); + if ( $expectedOffset == null ) { + $this->assertArrayNotHasKey( 'continue', $result ); + } else { + $this->assertArrayHasKey( 'continue', $result ); + $this->assertEquals( $expectedOffset, $result['continue']['psoffset'] ); + } + } +} diff --git a/tests/phpunit/includes/api/ApiQuerySearchTest.php b/tests/phpunit/includes/api/ApiQuerySearchTest.php new file mode 100644 index 0000000000..0700cf77de --- /dev/null +++ b/tests/phpunit/includes/api/ApiQuerySearchTest.php @@ -0,0 +1,109 @@ + [ [], [] ], + 'has search results' => [ + [ 'Zomg' ], + [ $this->mockResult( 'Zomg' ) ], + ], + 'filters broken search results' => [ + [ 'A', 'B' ], + [ + $this->mockResult( 'a' ), + $this->mockResult( 'Zomg' )->setBrokenTitle( true ), + $this->mockResult( 'b' ), + ], + ], + 'filters results with missing revision' => [ + [ 'B', 'A' ], + [ + $this->mockResult( 'Zomg' )->setMissingRevision( true ), + $this->mockResult( 'b' ), + $this->mockResult( 'a' ), + ], + ], + ]; + } + + /** + * @dataProvider provideSearchResults + */ + public function testSearchResults( $expect, $hits, array $params = [] ) { + MockSearchEngine::addMockResults( 'my query', $hits ); + list( $response, $request ) = $this->doApiRequest( $params + [ + 'action' => 'query', + 'list' => 'search', + 'srsearch' => 'my query', + ] ); + $titles = []; + foreach ( $response['query']['search'] as $result ) { + $titles[] = $result['title']; + } + $this->assertEquals( $expect, $titles ); + } + + public function provideInterwikiResults() { + return [ + 'empty' => [ [], [] ], + 'one wiki response' => [ + [ 'utwiki' => [ 'Qwerty' ] ], + [ + SearchResultSet::SECONDARY_RESULTS => [ + 'utwiki' => new MockSearchResultSet( [ + $this->mockResult( 'Qwerty' )->setInterwikiPrefix( 'utwiki' ), + ] ), + ], + ] + ], + ]; + } + + /** + * @dataProvider provideInterwikiResults + */ + public function testInterwikiResults( $expect, $hits, array $params = [] ) { + MockSearchEngine::setMockInterwikiResults( $hits ); + list( $response, $request ) = $this->doApiRequest( $params + [ + 'action' => 'query', + 'list' => 'search', + 'srsearch' => 'my query', + 'srinterwiki' => true, + ] ); + if ( !$expect ) { + $this->assertArrayNotHasKey( 'interwikisearch', $response['query'] ); + return; + } + $results = []; + $this->assertArrayHasKey( 'interwikisearchinfo', $response['query'] ); + foreach ( $response['query']['interwikisearch'] as $wiki => $wikiResults ) { + $results[$wiki] = []; + foreach ( $wikiResults as $wikiResult ) { + $results[$wiki][] = $wikiResult['title']; + } + } + $this->assertEquals( $expect, $results ); + } + + public function setUp() { + parent::setUp(); + MockSearchEngine::clearMockResults(); + $this->registerMockSearchEngine(); + } + + private function registerMockSearchEngine() { + $this->setMwGlobals( [ + 'wgSearchType' => MockSearchEngine::class, + ] ); + } + + private function mockResult( $title ) { + return MockSearchResult::newFromtitle( Title::newFromText( $title ) ); + } + +} diff --git a/tests/phpunit/includes/db/LBFactoryTest.php b/tests/phpunit/includes/db/LBFactoryTest.php index fac34867d8..82ca66a5fb 100644 --- a/tests/phpunit/includes/db/LBFactoryTest.php +++ b/tests/phpunit/includes/db/LBFactoryTest.php @@ -630,35 +630,41 @@ class LBFactoryTest extends MediaWikiTestCase { '1@542#c47dcfb0566e7d7bc110a6128a45c93a', LBFactory::makeCookieValueFromCPIndex( 1, 542, $agentId ) ); + $this->assertSame( - 5, - LBFactory::getCPInfoFromCookieValue( "5", $time - 10 )['index'], + null, + LBFactory::getCPInfoFromCookieValue( "5#$agentId", $time - 10 )['index'], 'No time set' ); $this->assertSame( null, - LBFactory::getCPInfoFromCookieValue( "0", $time - 10 )['index'], + LBFactory::getCPInfoFromCookieValue( "5@$time", $time - 10 )['index'], + 'No agent set' + ); + $this->assertSame( + null, + LBFactory::getCPInfoFromCookieValue( "0@$time#$agentId", $time - 10 )['index'], 'Bad index' ); $this->assertSame( 2, - LBFactory::getCPInfoFromCookieValue( "2@$time", $time - 10 )['index'], + LBFactory::getCPInfoFromCookieValue( "2@$time#$agentId", $time - 10 )['index'], 'Fresh' ); $this->assertSame( 2, - LBFactory::getCPInfoFromCookieValue( "2@$time", $time + 9 - 10 )['index'], + LBFactory::getCPInfoFromCookieValue( "2@$time#$agentId", $time + 9 - 10 )['index'], 'Almost stale' ); $this->assertSame( null, - LBFactory::getCPInfoFromCookieValue( "0@$time", $time + 9 - 10 )['index'], + LBFactory::getCPInfoFromCookieValue( "0@$time#$agentId", $time + 9 - 10 )['index'], 'Almost stale; bad index' ); $this->assertSame( null, - LBFactory::getCPInfoFromCookieValue( "2@$time", $time + 11 - 10 )['index'], + LBFactory::getCPInfoFromCookieValue( "2@$time#$agentId", $time + 11 - 10 )['index'], 'Stale' ); @@ -669,7 +675,7 @@ class LBFactoryTest extends MediaWikiTestCase { ); $this->assertSame( null, - LBFactory::getCPInfoFromCookieValue( "5@$time", $time + 11 - 10 )['clientId'], + LBFactory::getCPInfoFromCookieValue( "5@$time#$agentId", $time + 11 - 10 )['clientId'], 'Stale (client ID)' ); } diff --git a/tests/phpunit/includes/linker/LinkRendererTest.php b/tests/phpunit/includes/linker/LinkRendererTest.php index 6d096c208b..c758ba62ee 100644 --- a/tests/phpunit/includes/linker/LinkRendererTest.php +++ b/tests/phpunit/includes/linker/LinkRendererTest.php @@ -131,6 +131,11 @@ class LinkRendererTest extends MediaWikiLangTestCase { . '(page does not exist)">
    ', $linkRenderer->makeLink( $foobar, new HtmlArmor( '' ) ) ); + + $this->assertEquals( + 'fragment', + $linkRenderer->makeLink( Title::newFromText( '#fragment' ) ) + ); } public function testGetLinkClasses() { diff --git a/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php b/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php index 4d98773890..fa4d804ee8 100644 --- a/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php +++ b/tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php @@ -103,11 +103,6 @@ class MessageBlobStoreTest extends PHPUnit\Framework\TestCase { $this->assertEquals( '{"foo":"Example"}', $blob, 'Generated blob' ); } - /** - * Seems to fail sometimes (T176097). - * - * @group Broken - */ public function testGetBlobCached() { $module = $this->makeModule( [ 'example' ] ); $rl = new ResourceLoader(); diff --git a/tests/phpunit/includes/search/SearchEnginePrefixTest.php b/tests/phpunit/includes/search/SearchEnginePrefixTest.php index 3f59295ab6..83df61a4bc 100644 --- a/tests/phpunit/includes/search/SearchEnginePrefixTest.php +++ b/tests/phpunit/includes/search/SearchEnginePrefixTest.php @@ -45,6 +45,9 @@ class SearchEnginePrefixTest extends MediaWikiLangTestCase { $this->insertPage( 'Talk:Example' ); $this->insertPage( 'User:Example' ); + $this->insertPage( 'Barcelona' ); + $this->insertPage( 'Barbara' ); + $this->insertPage( 'External' ); } protected function setUp() { @@ -238,7 +241,7 @@ class SearchEnginePrefixTest extends MediaWikiLangTestCase { ], ] ], [ [ - 'Exact match not on top (T72958)', + 'Exact match not in first result should be moved to the first result (T72958)', 'provision' => [ 'Barcelona', 'Bar', @@ -252,7 +255,7 @@ class SearchEnginePrefixTest extends MediaWikiLangTestCase { ], ] ], [ [ - 'Exact match missing (T72958)', + 'Exact match missing from results should be added as first result (T72958)', 'provision' => [ 'Barcelona', 'Barbara', @@ -266,7 +269,7 @@ class SearchEnginePrefixTest extends MediaWikiLangTestCase { ], ] ], [ [ - 'Exact match missing and not existing', + 'Exact match missing and not existing pages should be dropped', 'provision' => [ 'Exile', 'Exist', @@ -274,8 +277,6 @@ class SearchEnginePrefixTest extends MediaWikiLangTestCase { ], 'query' => 'Ex', 'results' => [ - 'Exile', - 'Exist', 'External', ], ] ], @@ -329,6 +330,21 @@ class SearchEnginePrefixTest extends MediaWikiLangTestCase { 'Redirect test', ], ] ], + [ [ + "Extra results must not be returned", + 'provision' => [ + 'Example', + 'Example Bar', + 'Example Foo', + 'Example Foo/Bar' + ], + 'query' => 'foo', + 'results' => [ + 'Example', + 'Example Bar', + 'Example Foo', + ], + ] ], ]; } @@ -337,16 +353,7 @@ class SearchEnginePrefixTest extends MediaWikiLangTestCase { * @covers PrefixSearch::searchBackend */ public function testSearchBackend( array $case ) { - $search = $stub = $this->getMockBuilder( SearchEngine::class ) - ->setMethods( [ 'completionSearchBackend' ] )->getMock(); - - $return = SearchSuggestionSet::fromStrings( $case['provision'] ); - - $search->expects( $this->any() ) - ->method( 'completionSearchBackend' ) - ->will( $this->returnValue( $return ) ); - - $search->setLimitOffset( 3 ); + $search = $this->mockSearchWithResults( $case['provision'] ); $results = $search->completionSearch( $case['query'] ); $results = $results->map( function ( SearchSuggestion $s ) { @@ -359,4 +366,43 @@ class SearchEnginePrefixTest extends MediaWikiLangTestCase { $case[0] ); } + + public function paginationProvider() { + $res = [ 'Example', 'Example Bar', 'Example Foo', 'Example Foo/Bar' ]; + return [ + 'With less than requested results no pagination' => [ + false, array_slice( $res, 0, 2 ), + ], + 'With same as requested results no pagination' => [ + false, array_slice( $res, 0, 3 ), + ], + 'With extra result returned offer pagination' => [ + true, $res, + ], + ]; + } + + /** + * @dataProvider paginationProvider + */ + public function testPagination( $hasMoreResults, $provision ) { + $search = $this->mockSearchWithResults( $provision ); + $results = $search->completionSearch( 'irrelevant' ); + + $this->assertEquals( $hasMoreResults, $results->hasMoreResults() ); + } + + private function mockSearchWithResults( $titleStrings, $limit = 3 ) { + $search = $stub = $this->getMockBuilder( SearchEngine::class ) + ->setMethods( [ 'completionSearchBackend' ] )->getMock(); + + $return = SearchSuggestionSet::fromStrings( $titleStrings ); + + $search->expects( $this->any() ) + ->method( 'completionSearchBackend' ) + ->will( $this->returnValue( $return ) ); + + $search->setLimitOffset( $limit ); + return $search; + } } diff --git a/tests/phpunit/includes/search/SearchEngineTest.php b/tests/phpunit/includes/search/SearchEngineTest.php index e8077769e1..5884d19343 100644 --- a/tests/phpunit/includes/search/SearchEngineTest.php +++ b/tests/phpunit/includes/search/SearchEngineTest.php @@ -84,10 +84,8 @@ class SearchEngineTest extends MediaWikiLangTestCase { $this->assertTrue( is_object( $results ) ); $matches = []; - $row = $results->next(); - while ( $row ) { + foreach ( $results as $row ) { $matches[] = $row->getTitle()->getPrefixedText(); - $row = $results->next(); } $results->free(); # Search is not guaranteed to return results in a certain order; @@ -173,7 +171,7 @@ class SearchEngineTest extends MediaWikiLangTestCase { public function testPhraseSearchHighlight() { $phrase = "smithee is one who smiths"; $res = $this->search->searchText( "\"$phrase\"" ); - $match = $res->next(); + $match = $res->getIterator()->current(); $snippet = "A " . $phrase . ""; $this->assertStringStartsWith( $snippet, $match->getTextSnippet( $res->termMatches() ), @@ -277,7 +275,7 @@ class SearchEngineTest extends MediaWikiLangTestCase { $this->mergeMwGlobalArrayValue( 'wgHooks', [ 'SearchResultsAugment' => [ [ $this, 'addAugmentors' ] ] ] ); $this->search->augmentSearchResults( $resultSet ); - for ( $result = $resultSet->next(); $result; $result = $resultSet->next() ) { + foreach ( $resultSet as $result ) { $id = $result->getTitle()->getArticleID(); $augmentData = "Result:$id:" . $result->getTitle()->getText(); $augmentData2 = "Result2:$id:" . $result->getTitle()->getText(); @@ -292,11 +290,10 @@ class SearchEngineTest extends MediaWikiLangTestCase { ->method( 'augmentAll' ) ->willReturnCallback( function ( SearchResultSet $resultSet ) { $data = []; - for ( $result = $resultSet->next(); $result; $result = $resultSet->next() ) { + foreach ( $resultSet as $result ) { $id = $result->getTitle()->getArticleID(); $data[$id] = "Result:$id:" . $result->getTitle()->getText(); } - $resultSet->rewind(); return $data; } ); $setAugmentors['testSet'] = $setAugmentor; @@ -310,4 +307,37 @@ class SearchEngineTest extends MediaWikiLangTestCase { } ); $rowAugmentors['testRow'] = $rowAugmentor; } + + public function testFiltersMissing() { + $availableResults = []; + foreach ( range( 0, 11 ) as $i ) { + $title = "Search_Result_$i"; + $availableResults[] = $title; + // pages not created must be filtered + if ( $i % 2 == 0 ) { + $this->editPage( $title ); + } + } + MockCompletionSearchEngine::addMockResults( 'foo', $availableResults ); + + $engine = new MockCompletionSearchEngine(); + $engine->setLimitOffset( 10, 0 ); + $results = $engine->completionSearch( 'foo' ); + $this->assertEquals( 5, $results->getSize() ); + $this->assertTrue( $results->hasMoreResults() ); + + $engine->setLimitOffset( 10, 10 ); + $results = $engine->completionSearch( 'foo' ); + $this->assertEquals( 1, $results->getSize() ); + $this->assertFalse( $results->hasMoreResults() ); + } + + private function editPage( $title ) { + $page = WikiPage::factory( Title::newFromText( $title ) ); + $page->doEditContent( + new WikitextContent( 'UTContent' ), + 'UTPageSummary', + EDIT_NEW | EDIT_SUPPRESS_RC + ); + } } diff --git a/tests/phpunit/includes/search/SearchNearMatchResultSetTest.php b/tests/phpunit/includes/search/SearchNearMatchResultSetTest.php new file mode 100644 index 0000000000..67493c4243 --- /dev/null +++ b/tests/phpunit/includes/search/SearchNearMatchResultSetTest.php @@ -0,0 +1,15 @@ +assertEquals( 0, $resultSet->numRows() ); + + $resultSet = new SearchNearMatchResultSet( Title::newMainPage() ); + $this->assertEquals( 1, $resultSet->numRows() ); + } +} diff --git a/tests/phpunit/includes/search/SearchResultSetTest.php b/tests/phpunit/includes/search/SearchResultSetTest.php new file mode 100644 index 0000000000..26a0672922 --- /dev/null +++ b/tests/phpunit/includes/search/SearchResultSetTest.php @@ -0,0 +1,61 @@ +assertEquals( 1, $resultSet->numRows() ); + $count = 0; + foreach ( $resultSet as $iterResult ) { + $this->assertEquals( $result, $iterResult ); + $count++; + } + $this->assertEquals( 1, $count ); + + $this->hideDeprecated( 'SearchResultSet::rewind' ); + $this->hideDeprecated( 'SearchResultSet::next' ); + $resultSet->rewind(); + $count = 0; + while ( false !== ( $iterResult = $resultSet->next() ) ) { + $this->assertEquals( $result, $iterResult ); + $count++; + } + $this->assertEquals( 1, $count ); + } + + /** + * @covers SearchResultSet::augmentResult + * @covers SearchResultSet::setAugmentedData + */ + public function testDelayedResultAugment() { + $result = SearchResult::newFromTitle( Title::newMainPage() ); + $resultSet = new MockSearchResultSet( [ $result ] ); + $resultSet->augmentResult( $result ); + $this->assertEquals( [], $result->getExtensionData() ); + $resultSet->setAugmentedData( 'foo', [ + $result->getTitle()->getArticleID() => 'bar' + ] ); + $this->assertEquals( [ 'foo' => 'bar' ], $result->getExtensionData() ); + } + + /** + * @covers SearchResultSet::shrink + * @covers SearchResultSet::count + * @covers SearchResultSet::hasMoreResults + */ + public function testHasMoreResults() { + $result = SearchResult::newFromTitle( Title::newMainPage() ); + $resultSet = new MockSearchResultSet( array_fill( 0, 3, $result ) ); + $this->assertEquals( 3, count( $resultSet ) ); + $this->assertFalse( $resultSet->hasMoreResults() ); + $resultSet->shrink( 3 ); + $this->assertFalse( $resultSet->hasMoreResults() ); + $resultSet->shrink( 2 ); + $this->assertTrue( $resultSet->hasMoreResults() ); + } +} diff --git a/tests/phpunit/includes/search/SearchResultTest.php b/tests/phpunit/includes/search/SearchResultTest.php new file mode 100644 index 0000000000..0e1e24c089 --- /dev/null +++ b/tests/phpunit/includes/search/SearchResultTest.php @@ -0,0 +1,38 @@ +assertEquals( [], $result->getExtensionData(), 'starts empty' ); + + $data = [ 'hello' => 'world' ]; + $result->setExtensionData( function () use ( &$data ) { + return $data; + } ); + $this->assertEquals( $data, $result->getExtensionData(), 'can set extension data' ); + $data['this'] = 'that'; + $this->assertEquals( $data, $result->getExtensionData(), 'refetches from callback' ); + } + + /** + * @covers SearchResult::getExtensionData + * @covers SearchResult::setExtensionData + */ + public function testExtensionDataArrayBC() { + $result = SearchResult::newFromTitle( Title::newMainPage() ); + $data = [ 'hello' => 'world' ]; + $this->hideDeprecated( 'SearchResult::setExtensionData with array argument' ); + $this->assertEquals( [], $result->getExtensionData(), 'starts empty' ); + $result->setExtensionData( $data ); + $this->assertEquals( $data, $result->getExtensionData(), 'can set extension data' ); + $data['this'] = 'that'; + $this->assertNotEquals( $data, $result->getExtensionData(), 'shouldnt hold any reference' ); + + $result->setExtensionData( $data ); + $this->assertEquals( $data, $result->getExtensionData(), 'can replace extension data' ); + } +} diff --git a/tests/phpunit/includes/session/SessionTest.php b/tests/phpunit/includes/session/SessionTest.php index f84d435f77..a74056d0ca 100644 --- a/tests/phpunit/includes/session/SessionTest.php +++ b/tests/phpunit/includes/session/SessionTest.php @@ -358,7 +358,7 @@ class SessionTest extends MediaWikiTestCase { $logger->clearBuffer(); // Unserializable data - $iv = \MWCryptRand::generate( 16, true ); + $iv = random_bytes( 16 ); list( $encKey, $hmacKey ) = TestingAccessWrapper::newFromObject( $session )->getSecretKeys(); $ciphertext = openssl_encrypt( 'foobar', 'aes-256-ctr', $encKey, OPENSSL_RAW_DATA, $iv ); $sealed = base64_encode( $iv ) . '.' . base64_encode( $ciphertext ); diff --git a/tests/phpunit/includes/specials/SpecialSearchTest.php b/tests/phpunit/includes/specials/SpecialSearchTest.php index f0a5726699..196321caed 100644 --- a/tests/phpunit/includes/specials/SpecialSearchTest.php +++ b/tests/phpunit/includes/specials/SpecialSearchTest.php @@ -262,8 +262,8 @@ class SpecialSearchTestMockResultSet extends SearchResultSet { $this->containedSyntax = $containedSyntax; } - public function numRows() { - return count( $this->results ); + public function expandResults() { + return $this->results; } public function getTotalHits() { diff --git a/tests/phpunit/languages/SpecialPageAliasTest.php b/tests/phpunit/languages/SpecialPageAliasTest.php index 0bb6a4d293..d406c88933 100644 --- a/tests/phpunit/languages/SpecialPageAliasTest.php +++ b/tests/phpunit/languages/SpecialPageAliasTest.php @@ -7,12 +7,14 @@ * @group SpecialPageAliases * @group SystemTest * @group medium + * @todo This should be a structure test * * @author Katie Filbert < aude.wiki@gmail.com > */ class SpecialPageAliasTest extends MediaWikiTestCase { /** + * @coversNothing * @dataProvider validSpecialPageAliasesProvider */ public function testValidSpecialPageAliases( $code, $specialPageAliases ) { diff --git a/tests/phpunit/mocks/MockMessageLocalizer.php b/tests/phpunit/mocks/MockMessageLocalizer.php index 143a419f05..4d35930730 100644 --- a/tests/phpunit/mocks/MockMessageLocalizer.php +++ b/tests/phpunit/mocks/MockMessageLocalizer.php @@ -37,7 +37,7 @@ class MockMessageLocalizer implements MessageLocalizer { $args = func_get_args(); /** @var Message $message */ - $message = call_user_func_array( 'wfMessage', $args ); + $message = wfMessage( ...$args ); if ( $this->languageCode !== null ) { $message->inLanguage( $this->languageCode ); diff --git a/tests/phpunit/mocks/search/MockCompletionSearchEngine.php b/tests/phpunit/mocks/search/MockCompletionSearchEngine.php new file mode 100644 index 0000000000..ac8a5dc702 --- /dev/null +++ b/tests/phpunit/mocks/search/MockCompletionSearchEngine.php @@ -0,0 +1,42 @@ +getText(); + self::$results[$normalized] = $result; + } + + public function completionSearchBackend( $search ) { + if ( !isset( self::$results[$search] ) ) { + return SearchSuggestionSet::emptySuggestionSet(); + } + $results = array_slice( self::$results[$search], $this->offset, $this->limit ); + + return SearchSuggestionSet::fromStrings( $results ); + } +} diff --git a/tests/phpunit/mocks/search/MockSearchEngine.php b/tests/phpunit/mocks/search/MockSearchEngine.php new file mode 100644 index 0000000000..2b7ea4760a --- /dev/null +++ b/tests/phpunit/mocks/search/MockSearchEngine.php @@ -0,0 +1,45 @@ +getLinkCache(); + foreach ( $results as $result ) { + // TODO: better page ids? Does it matter? + $lc->addGoodLinkObj( mt_rand(), $result->getTitle() ); + } + } + + /** + * @param SearchResultSet[][] $interwikiResults + */ + public static function setMockInterwikiResults( array $interwikiResults ) { + self::$interwikiResults = $interwikiResults; + } + + protected function doSearchText( $term ) { + if ( isset( self::$results[ $term ] ) ) { + $results = array_slice( self::$results[ $term ], $this->offset, $this->limit ); + } else { + $results = []; + } + return new MockSearchResultSet( $results, self::$interwikiResults ); + } +} diff --git a/tests/phpunit/mocks/search/MockSearchResult.php b/tests/phpunit/mocks/search/MockSearchResult.php new file mode 100644 index 0000000000..d92d39a634 --- /dev/null +++ b/tests/phpunit/mocks/search/MockSearchResult.php @@ -0,0 +1,32 @@ +isMissingRevision; + } + public function setMissingRevision( $isMissingRevision ) { + $this->isMissingRevision = $isMissingRevision; + return $this; + } + + public function isBrokenTitle() { + return $this->isBrokenTitle; + } + + public function setBrokenTitle( $isBrokenTitle ) { + $this->isBrokenTitle = $isBrokenTitle; + return $this; + } + + public function getInterwikiPrefix() { + return $this->interwikiPrefix; + } + + public function setInterwikiPrefix( $interwikiPrefix ) { + $this->interwikiPrefix = $interwikiPrefix; + return $this; + } +} diff --git a/tests/phpunit/mocks/search/MockSearchResultSet.php b/tests/phpunit/mocks/search/MockSearchResultSet.php new file mode 100644 index 0000000000..20e2a9fb68 --- /dev/null +++ b/tests/phpunit/mocks/search/MockSearchResultSet.php @@ -0,0 +1,37 @@ +results = $results; + $this->interwikiResults = $interwikiResults; + } + + public function numRows() { + return count( $this->results ); + } + + public function hasInterwikiResults( $type = self::SECONDARY_RESULTS ) { + return isset( $this->interwikiResults[$type] ) && + count( $this->interwikiResults[$type] ) > 0; + } + + public function getInterwikiResults( $type = self::SECONDARY_RESULTS ) { + if ( $this->hasInterwikiResults( $type ) ) { + return $this->interwikiResults[$type]; + } else { + return null; + } + } +} diff --git a/tests/phpunit/structure/AvailableRightsTest.php b/tests/phpunit/structure/AvailableRightsTest.php index 6c2ff024e1..ea132e9a7b 100644 --- a/tests/phpunit/structure/AvailableRightsTest.php +++ b/tests/phpunit/structure/AvailableRightsTest.php @@ -35,6 +35,9 @@ class AvailableRightsTest extends PHPUnit\Framework\TestCase { return $rights; } + /** + * @coversNothing + */ public function testAvailableRights() { $missingRights = array_diff( $this->getAllVisibleRights(), diff --git a/tests/phpunit/structure/ContentHandlerSanityTest.php b/tests/phpunit/structure/ContentHandlerSanityTest.php index c8bcd60de3..c75a9d02a3 100644 --- a/tests/phpunit/structure/ContentHandlerSanityTest.php +++ b/tests/phpunit/structure/ContentHandlerSanityTest.php @@ -32,6 +32,7 @@ class ContentHandlerSanityTest extends MediaWikiTestCase { } /** + * @coversNothing * @dataProvider provideHandlers * @param ContentHandler $handler */ diff --git a/tests/phpunit/structure/ExtensionJsonValidationTest.php b/tests/phpunit/structure/ExtensionJsonValidationTest.php index 60c97ccfac..dea8f5a541 100644 --- a/tests/phpunit/structure/ExtensionJsonValidationTest.php +++ b/tests/phpunit/structure/ExtensionJsonValidationTest.php @@ -19,6 +19,8 @@ /** * Validates all loaded extensions and skins using the ExtensionRegistry * against the extension.json schema in the docs/ folder. + * + * @coversNothing */ class ExtensionJsonValidationTest extends PHPUnit\Framework\TestCase { diff --git a/tests/phpunit/structure/ResourcesTest.php b/tests/phpunit/structure/ResourcesTest.php index 62ddacebfe..2090e29b77 100644 --- a/tests/phpunit/structure/ResourcesTest.php +++ b/tests/phpunit/structure/ResourcesTest.php @@ -11,6 +11,7 @@ * @copyright © 2012, Niklas Laxström * @copyright © 2012, Santhosh Thottingal * @copyright © 2012, Timo Tijhof + * @coversNothing */ class ResourcesTest extends MediaWikiTestCase { diff --git a/tests/phpunit/structure/StructureTest.php b/tests/phpunit/structure/StructureTest.php index 4df791ecd8..82302b1758 100644 --- a/tests/phpunit/structure/StructureTest.php +++ b/tests/phpunit/structure/StructureTest.php @@ -9,6 +9,7 @@ class StructureTest extends MediaWikiTestCase { * Verify all files that appear to be tests have file names ending in * Test. If the file names do not end in Test, they will not be run. * @group medium + * @coversNothing */ public function testUnitTestFileNamesEndWithTest() { if ( wfIsWindows() ) { diff --git a/tests/phpunit/suites/ExtensionsTestSuite.php b/tests/phpunit/suites/ExtensionsTestSuite.php index 02934fa7bd..7d1d3311d6 100644 --- a/tests/phpunit/suites/ExtensionsTestSuite.php +++ b/tests/phpunit/suites/ExtensionsTestSuite.php @@ -45,6 +45,9 @@ class ExtensionsTestSuite extends PHPUnit_Framework_TestSuite { * when no extensions with tests are used. */ class DummyExtensionsTest extends MediaWikiTestCase { + /** + * @coversNothing + */ public function testNothing() { $this->assertTrue( true ); } diff --git a/tests/selenium/selenium.sh b/tests/selenium/selenium.sh index 4a5c254839..f6bb944e0b 100755 --- a/tests/selenium/selenium.sh +++ b/tests/selenium/selenium.sh @@ -3,10 +3,13 @@ set -euo pipefail # Check the command before running in background so # that it can actually fail and have a descriptive error hash chromedriver -chromedriver --url-base=/wd/hub --port=4444 & +chromedriver --url-base=wd/hub --port=4444 & +CHROME_DRIVER_PID=$! +echo chromedriver running with PID $CHROME_DRIVER_PID # Make sure it is killed to prevent file descriptors leak function kill_chromedriver() { - killall chromedriver > /dev/null + # Use kill instead of killall to increase chances of this working on Windows + kill $CHROME_DRIVER_PID > /dev/null } trap kill_chromedriver EXIT npm run selenium-test diff --git a/tests/selenium/specs/page.js b/tests/selenium/specs/page.js index dfc6fa1ae8..069a6aa3fd 100644 --- a/tests/selenium/specs/page.js +++ b/tests/selenium/specs/page.js @@ -10,8 +10,8 @@ describe( 'Page', function () { var content, name; - function getTestString() { - return Math.random().toString() + '-öäü-♠♣♥♦'; + function getTestString( suffix = 'defaultsuffix' ) { + return Math.random().toString() + '-Iñtërnâtiônàlizætiøn☃-' + suffix; } before( function () { @@ -22,8 +22,8 @@ describe( 'Page', function () { beforeEach( function () { browser.deleteCookie(); - content = getTestString(); - name = getTestString(); + content = getTestString( 'beforeEach-content' ); + name = getTestString( 'beforeEach-name' ); } ); it( 'should be creatable', function () { @@ -36,7 +36,7 @@ describe( 'Page', function () { } ); it( 'should be re-creatable', function () { - let initialContent = getTestString(); + let initialContent = getTestString( 'initialContent' ); // create browser.call( function () { @@ -63,11 +63,12 @@ describe( 'Page', function () { } ); // edit - EditPage.edit( name, content ); + let editContent = getTestString( 'editContent' ); + EditPage.edit( name, editContent ); // check assert.strictEqual( EditPage.heading.getText(), name ); - assert.strictEqual( EditPage.displayedContent.getText(), content ); + assert.strictEqual( EditPage.displayedContent.getText(), editContent ); } ); it( 'should have history', function () {