Merge "Disable WebResponse setters for post-send processing"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 13 Jun 2018 13:21:51 +0000 (13:21 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 13 Jun 2018 13:21:51 +0000 (13:21 +0000)
245 files changed:
.travis.yml
RELEASE-NOTES-1.31
RELEASE-NOTES-1.32
composer.json
docs/hooks.txt
includes/AjaxResponse.php
includes/AuthPlugin.php
includes/Category.php
includes/DummyLinker.php
includes/EditPage.php
includes/GlobalFunctions.php
includes/Linker.php
includes/MWNamespace.php
includes/MediaWiki.php
includes/MediaWikiServices.php
includes/MergeHistory.php
includes/Message.php
includes/MovePage.php
includes/OutputPage.php
includes/ServiceWiring.php
includes/Setup.php
includes/SiteConfiguration.php
includes/Storage/RevisionRecord.php
includes/Title.php
includes/WebResponse.php
includes/Xml.php
includes/XmlSelect.php
includes/api/ApiQueryLinks.php
includes/api/ApiQuerySearch.php
includes/api/ApiQueryTokens.php
includes/api/ApiQueryUserContribs.php
includes/auth/ButtonAuthenticationRequest.php
includes/cache/GenderCache.php
includes/cache/localisation/LocalisationCache.php
includes/changes/RecentChange.php
includes/changetags/ChangeTags.php
includes/collation/IcuCollation.php
includes/db/DatabaseOracle.php
includes/exception/MWExceptionHandler.php
includes/filerepo/FileRepo.php
includes/filerepo/RepoGroup.php
includes/htmlform/HTMLForm.php
includes/htmlform/HTMLFormField.php
includes/htmlform/fields/HTMLCheckMatrix.php
includes/http/CurlHttpRequest.php
includes/installer/DatabaseUpdater.php
includes/installer/Installer.php
includes/installer/WebInstaller.php
includes/installer/i18n/ar.json
includes/installer/i18n/ba.json
includes/installer/i18n/be-tarask.json
includes/installer/i18n/bg.json
includes/installer/i18n/cs.json
includes/installer/i18n/de.json
includes/installer/i18n/en.json
includes/installer/i18n/es.json
includes/installer/i18n/eu.json
includes/installer/i18n/fa.json
includes/installer/i18n/fi.json
includes/installer/i18n/fr.json
includes/installer/i18n/gl.json
includes/installer/i18n/he.json
includes/installer/i18n/hrx.json
includes/installer/i18n/hu.json
includes/installer/i18n/ia.json
includes/installer/i18n/id.json
includes/installer/i18n/it.json
includes/installer/i18n/ja.json
includes/installer/i18n/ko.json
includes/installer/i18n/ksh.json
includes/installer/i18n/lij.json
includes/installer/i18n/mk.json
includes/installer/i18n/ms.json
includes/installer/i18n/nap.json
includes/installer/i18n/nb.json
includes/installer/i18n/nl.json
includes/installer/i18n/pl.json
includes/installer/i18n/pms.json
includes/installer/i18n/pt-br.json
includes/installer/i18n/pt.json
includes/installer/i18n/qqq.json
includes/installer/i18n/ru.json
includes/installer/i18n/sco.json
includes/installer/i18n/sv.json
includes/installer/i18n/tl.json
includes/installer/i18n/uk.json
includes/installer/i18n/vi.json
includes/installer/i18n/zh-hans.json
includes/installer/i18n/zh-hant.json
includes/interwiki/Interwiki.php
includes/json/FormatJson.php
includes/libs/ArrayUtils.php
includes/libs/CryptHKDF.php
includes/libs/CryptRand.php
includes/libs/MemoizedCallable.php
includes/libs/StatusValue.php
includes/libs/StringUtils.php
includes/libs/filebackend/FileBackend.php
includes/libs/filebackend/SwiftFileBackend.php
includes/libs/jsminplus.php
includes/libs/lockmanager/DBLockManager.php
includes/libs/lockmanager/MemcLockManager.php
includes/libs/lockmanager/RedisLockManager.php
includes/libs/mime/IEContentAnalyzer.php
includes/libs/objectcache/CachedBagOStuff.php
includes/libs/objectcache/MultiWriteBagOStuff.php
includes/libs/objectcache/WANObjectCache.php
includes/libs/rdbms/ChronologyProtector.php
includes/libs/rdbms/database/DBConnRef.php
includes/libs/rdbms/database/Database.php
includes/libs/rdbms/database/DatabaseSqlite.php
includes/libs/rdbms/lbfactory/LBFactory.php
includes/libs/rdbms/lbfactory/LBFactoryMulti.php
includes/libs/rdbms/lbfactory/LBFactorySimple.php
includes/libs/rdbms/lbfactory/LBFactorySingle.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/libs/redis/RedisConnRef.php
includes/linker/LinkRenderer.php
includes/logging/LogEventsList.php
includes/logging/TagLogFormatter.php
includes/media/BitmapHandler.php
includes/media/SvgHandler.php
includes/page/Article.php
includes/parser/CoreParserFunctions.php
includes/parser/Parser.php
includes/parser/ParserDiffTest.php
includes/parser/ParserOutput.php
includes/password/BcryptPassword.php
includes/password/EncryptedPassword.php
includes/password/Pbkdf2Password.php
includes/poolcounter/PoolCounterWorkViaCallback.php
includes/registration/ExtensionRegistry.php
includes/resourceloader/ResourceLoaderContext.php
includes/search/SearchNearMatchResultSet.php
includes/search/SearchResult.php
includes/search/SearchResultSet.php
includes/search/SqlSearchResultSet.php
includes/services/ServiceContainer.php
includes/session/Session.php
includes/skins/BaseTemplate.php
includes/skins/QuickTemplate.php
includes/specialpage/AuthManagerSpecialPage.php
includes/specialpage/ChangesListSpecialPage.php
includes/specialpage/LoginSignupSpecialPage.php
includes/specialpage/SpecialPage.php
includes/specials/SpecialBlock.php
includes/specials/SpecialBotPasswords.php
includes/specials/SpecialEmailuser.php
includes/specials/SpecialMIMEsearch.php
includes/specials/SpecialPageLanguage.php
includes/specials/SpecialPrefixindex.php
includes/specials/SpecialProtectedpages.php
includes/specials/SpecialProtectedtitles.php
includes/specials/SpecialVersion.php
includes/specials/pagers/AllMessagesTablePager.php
includes/specials/pagers/ProtectedPagesPager.php
includes/specials/pagers/ProtectedTitlesPager.php
includes/upload/UploadBase.php
includes/upload/UploadFromChunks.php
includes/utils/MWCryptRand.php
includes/widget/search/BasicSearchResultSetWidget.php
includes/widget/search/SimpleSearchResultSetWidget.php
languages/Language.php
languages/data/CrhExceptions.php
languages/data/Names.php
languages/i18n/be-tarask.json
languages/i18n/bg.json
languages/i18n/bn.json
languages/i18n/ca.json
languages/i18n/ce.json
languages/i18n/cu.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/gcr.json
languages/i18n/gor.json
languages/i18n/got.json
languages/i18n/he.json
languages/i18n/hu.json
languages/i18n/inh.json
languages/i18n/ku-latn.json
languages/i18n/lfn.json
languages/i18n/nap.json
languages/i18n/nn.json
languages/i18n/oc.json
languages/i18n/pa.json
languages/i18n/pl.json
languages/i18n/pms.json
languages/i18n/pnb.json
languages/i18n/ps.json
languages/i18n/pt-br.json
languages/i18n/ru.json
languages/i18n/sa.json
languages/i18n/shn.json
languages/i18n/skr-arab.json
languages/i18n/sq.json
languages/i18n/sr-ec.json
languages/i18n/sw.json
languages/i18n/ta.json
languages/i18n/to.json
languages/i18n/wa.json
languages/i18n/yi.json
languages/i18n/zh-hans.json
languages/messages/MessagesKo.php
languages/messages/MessagesZgh.php [new file with mode: 0644]
maintenance/backup.inc
maintenance/populateInterwiki.php
maintenance/storage/checkStorage.php
maintenance/storage/recompressTracked.php
package.json
profileinfo.php
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.less
tests/common/TestsAutoLoader.php
tests/parser/DjVuSupport.php
tests/parser/parserTests.txt
tests/phan/config.php
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/includes/LinkerTest.php
tests/phpunit/includes/Storage/RevisionStoreTest.php
tests/phpunit/includes/TitlePermissionTest.php
tests/phpunit/includes/api/ApiQuerySearchTest.php [new file with mode: 0644]
tests/phpunit/includes/db/LBFactoryTest.php
tests/phpunit/includes/interwiki/InterwikiTest.php
tests/phpunit/includes/libs/IEUrlExtensionTest.php
tests/phpunit/includes/linker/LinkRendererTest.php
tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php
tests/phpunit/includes/search/SearchEngineTest.php
tests/phpunit/includes/search/SearchNearMatchResultSetTest.php [new file with mode: 0644]
tests/phpunit/includes/search/SearchResultSetTest.php [new file with mode: 0644]
tests/phpunit/includes/search/SearchResultTest.php [new file with mode: 0644]
tests/phpunit/includes/session/SessionTest.php
tests/phpunit/includes/specials/SpecialSearchTest.php
tests/phpunit/languages/SpecialPageAliasTest.php
tests/phpunit/languages/classes/LanguageCrhTest.php
tests/phpunit/mocks/MockMessageLocalizer.php
tests/phpunit/mocks/search/MockSearchEngine.php [new file with mode: 0644]
tests/phpunit/mocks/search/MockSearchResult.php [new file with mode: 0644]
tests/phpunit/mocks/search/MockSearchResultSet.php [new file with mode: 0644]
tests/phpunit/structure/AvailableRightsTest.php
tests/phpunit/structure/ContentHandlerSanityTest.php
tests/phpunit/structure/ExtensionJsonValidationTest.php
tests/phpunit/structure/ResourcesTest.php
tests/phpunit/structure/StructureTest.php
tests/phpunit/suites/ExtensionsTestSuite.php
tests/selenium/selenium.sh
tests/selenium/specs/page.js

index 73e4af5..e15fc55 100644 (file)
@@ -37,6 +37,9 @@ matrix:
       php: hhvm-3.21
     - env: dbtype=mysql dbuser=root
       php: hhvm-3.18
+  allow_failures:
+    - php: hhvm-3.24
+    - php: hhvm-3.21
 
 services:
   - mysql
index 6f242fb..8d5bab5 100644 (file)
@@ -12,6 +12,9 @@ production.
 * (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.
index 4e2bdfa..36e1f35 100644 (file)
@@ -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
@@ -89,6 +90,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 +158,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 +192,18 @@ 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.
 
 === Other changes in 1.32 ===
 * …
index 99a3f64..7eb4265 100644 (file)
@@ -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"
index 8c84509..fcd3e07 100644 (file)
@@ -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 <edit result="Failure"> 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
@@ -1886,9 +1895,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 +1981,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 +2016,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 <a> tag should have (raw HTML); null means
@@ -2025,7 +2034,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 <a> element
 with HTML attributes $attribs and contents $html will be returned.  If you
@@ -2207,11 +2216,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 +2380,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 <li>
 &$attribs: associative array of other HTML attributes for the <li> element.
   Currently only data attributes reserved to MediaWiki are allowed
@@ -2611,7 +2620,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 +2657,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 +2688,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 +2751,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 +2848,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 +2867,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' => <any module dependency you might have>
-       );
+        ];
   For QUnit framework, the mediawiki.tests.qunit.testrunner dependency will be
   added to any module.
 &$ResourceLoader: object
@@ -2866,8 +2878,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 +2927,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 +3015,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 +3199,7 @@ $pager: The UsersPager instance
 
 'SpecialListusersFormatRow': Called right before the end of
 UsersPager::formatRow().
-&$item: HTML to be returned. Will be wrapped in <li></li> after the hook finishes
+&$item: HTML to be returned. Will be wrapped in an <li> after the hook finishes
 $row: Database row object
 
 'SpecialListusersHeader': Called after adding the submit button in
@@ -3260,8 +3276,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 +3289,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 +3303,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' => '<preference-name>',
                'label-message' => '<message-key>',
-       )
+        ]
 
 'SpecialSearchCreateLink': Called when making the message to create a page or
 go to the existing page.
@@ -3303,7 +3319,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 +3378,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 +3398,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 +3411,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 +3475,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 +3549,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 +3562,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 +3623,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 +3641,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 +3655,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 +3698,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 +3726,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 +3792,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 +3808,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 +3836,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 +3884,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 +3935,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 +4010,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
index 3e42c08..0c11505 100644 (file)
@@ -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' );
 
index b73ecbd..e12db24 100644 (file)
@@ -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';
        }
 
        /**
index 46b86d8..2cf44b8 100644 (file)
@@ -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(
index 9aa6aeb..2f5455e 100644 (file)
@@ -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,
@@ -107,7 +99,7 @@ class DummyLinker {
                Title $title,
                $file,
                $label = '',
-               $alt,
+               $alt = '',
                $align = 'right',
                $params = [],
                $framed = false,
index 22c29d6..644b625 100644 (file)
@@ -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;
        }
 
index 335451e..d9996f4 100644 (file)
@@ -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'];
        }
index 3ee442d..ec61984 100644 (file)
@@ -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:
@@ -504,7 +481,7 @@ class Linker {
         * @param string $manualthumb
         * @return string
         */
-       public static function makeThumbLinkObj( Title $title, $file, $label = '', $alt,
+       public static function makeThumbLinkObj( Title $title, $file, $label = '', $alt = '',
                $align = 'right', $params = [], $framed = false, $manualthumb = ""
        ) {
                $frameParams = [
@@ -826,7 +803,7 @@ class Linker {
                        $key = strtolower( $name );
                }
 
-               return self::linkKnown( SpecialPage::getTitleFor( $name ), wfMessage( $key )->text() );
+               return self::linkKnown( SpecialPage::getTitleFor( $name ), wfMessage( $key )->escaped() );
        }
 
        /**
index bfbd557..73fdd82 100644 (file)
@@ -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;
        }
 
        /**
index 7fb59d5..bcc3633 100644 (file)
@@ -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
index ac98683..dbb18a7 100644 (file)
@@ -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() {
index 0e9bb46..4c655eb 100644 (file)
@@ -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 );
                        }
                }
 
index fb6dcc5..84ab7ca 100644 (file)
@@ -1128,7 +1128,7 @@ class Message implements MessageSpecifier, Serializable {
         *
         * @return string
         */
-       protected function replaceParameters( $message, $type = 'before', $format ) {
+       protected function replaceParameters( $message, $type, $format ) {
                // A temporary marker for $1 parameters that is only valid
                // in non-attribute contexts. However if the entire message is escaped
                // then we don't want to use it because it will be mangled in all contexts
index 1e9570d..614ea7d 100644 (file)
@@ -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 );
                        }
                }
 
index c51f6f8..405be1d 100644 (file)
@@ -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 .= '<li>';
-                               $text .= call_user_func_array( [ $this, 'msg' ], $error )->plain();
+                               $text .= $this->msg( ...$error )->plain();
                                $text .= "</li>\n";
                        }
                        $text .= '</ul>';
                } else {
                        $text .= "<div class=\"permissions-errors\">\n" .
-                                       call_user_func_array( [ $this, 'msg' ], reset( $errors ) )->plain() .
+                                       $this->msg( ...reset( $errors ) )->plain() .
                                        "\n</div>";
                }
 
@@ -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;
index ace64ab..3f8ba18 100644 (file)
@@ -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 ) {
index e2fab45..41d5945 100644 (file)
@@ -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,
index 6bd179a..8e77956 100644 (file)
@@ -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;
                }
        }
index ff0a70d..66ec2c0 100644 (file)
@@ -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" );
index 9711749..91d8de4 100644 (file)
@@ -2553,7 +2553,10 @@ class Title implements LinkTarget {
                        return $errors;
                }
 
-               if ( $wgEmailConfirmToEdit && !$user->isEmailConfirmed() ) {
+               if ( $wgEmailConfirmToEdit
+                       && !$user->isEmailConfirmed()
+                       && $action === 'edit'
+               ) {
                        $errors[] = [ 'confirmedittext' ];
                }
 
index 82fe99e..0e5999d 100644 (file)
@@ -277,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;
        }
 
        /**
@@ -346,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;
        }
 
        /**
index 4f2720e..af38740 100644 (file)
@@ -124,11 +124,11 @@ class Xml {
         * content you have is already valid xml.
         *
         * @param string $element Element name
-        * @param array $attribs Array of attributes
+        * @param array|null $attribs Array of attributes
         * @param string $contents Content of the element
         * @return string
         */
-       public static function tags( $element, $attribs = null, $contents ) {
+       public static function tags( $element, $attribs, $contents ) {
                return self::openElement( $element, $attribs ) . $contents . "</$element>";
        }
 
index 89f2f41..5d7406c 100644 (file)
@@ -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;
        }
 
        /**
index 67bf619..144c758 100644 (file)
@@ -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;
index 7d46a5f..87913e6 100644 (file)
@@ -142,10 +142,9 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
                $terms = $wgContLang->convertForSearchResult( $matches->termMatches() );
                $titles = [];
                $count = 0;
-               $result = $matches->next();
                $limit = $params['limit'];
 
-               while ( $result ) {
+               foreach ( $matches as $result ) {
                        if ( ++$count > $limit ) {
                                // We've reached the one extra which shows that there are
                                // additional items to be had. Stop here...
@@ -155,7 +154,6 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
 
                        // Silently skip broken and missing titles
                        if ( $result->isBrokenTitle() || $result->isMissingRevision() ) {
-                               $result = $matches->next();
                                continue;
                        }
 
@@ -172,8 +170,6 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
                        } else {
                                $titles[] = $result->getTitle();
                        }
-
-                       $result = $matches->next();
                }
 
                // Here we assume interwiki results do not count with
@@ -301,8 +297,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 +317,6 @@ class ApiQuerySearch extends ApiQueryGeneratorBase {
                                                // pagination info so just bail out
                                                break;
                                        }
-
-                                       $result = $interwikiMatches->next();
                                }
                        }
                        if ( $totalhits !== null ) {
index e86fdf3..8854aac 100644 (file)
@@ -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() );
                }
index 420d138..fdcaa76 100644 (file)
@@ -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 ) {
index d274e18..1268e68 100644 (file)
@@ -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 ) {
index 1ec39a5..7228814 100644 (file)
@@ -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;
                }
        }
 
index dd9e8e1..90108eb 100644 (file)
@@ -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;
                }
 
index 60fe850..94dcd07 100644 (file)
@@ -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 );
index 0c81144..d019f41 100644 (file)
@@ -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
index d92c215..5f401a5 100644 (file)
@@ -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;
        }
 }
index 3362f0f..f4f04f1 100644 (file)
@@ -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;
        }
 
        /**
index 79f0a23..9039cfc 100644 (file)
@@ -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
index 70068b9..3d9a904 100644 (file)
@@ -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;
        }
index 0056181..fa4567e 100644 (file)
@@ -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;
                        }
                }
index 785d30f..e72faa0 100644 (file)
@@ -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' );
index cd4d4b7..a701575 100644 (file)
@@ -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;
index df44626..d885c9d 100644 (file)
@@ -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 ) {
index a8fbed0..f457b21 100644 (file)
@@ -149,13 +149,6 @@ class CurlHttpRequest extends MWHttpRequest {
                        return false;
                }
 
-               if ( version_compare( PHP_VERSION, '5.6.0', '<' ) ) {
-                       if ( strval( ini_get( 'open_basedir' ) ) !== '' ) {
-                               $this->logger->debug( "Cannot follow redirects when open_basedir is set\n" );
-                               return false;
-                       }
-               }
-
                return true;
        }
 }
index 4fc04db..1cd76b9 100644 (file)
@@ -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;
index 05da0db..0890bc4 100644 (file)
@@ -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;
        }
 
index 8fb9807..018754b 100644 (file)
@@ -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 '<a href="' . htmlspecialchars( $url ) . '">' .
-                       htmlspecialchars( $linkText ) .
-                       '</a>';
+               return Html::element( 'a', [ 'href' => $url ], $linkText );
        }
 
        /**
index cb6051f..d853009 100644 (file)
        "config-install-interwiki-exists": "<strong>تحذير:</strong> يبدو أن جدول الإنترويكي به إدخالات بالفعل. تخطي القائمة الافتراضي.",
        "config-install-stats": "بدء الإحصاءات",
        "config-install-keys": "توليد المفاتيح السرية",
-       "config-insecure-keys": "<strong>تحذير:</strong> {{PLURAL:$2|مفتاح الأمان|مفاتيح الأمان}} ($1) التي تم إنشاؤها أثناء التثبيت ليست آمنة تماما; جرب تغيير{{PLURAL:$2|ه|هم}} يدويا.",
        "config-install-updates": "منع تشغيل التحديثات غير الضرورية",
        "config-install-updates-failed": "<strong>خطأ:</strong> إدخال مفاتيح التحديث إلى الجداول فشلت بسبب الخطأ التالي: $1",
        "config-install-sysop": "إنشاء حساب مستخدم إداري",
index 6fcaca2..6d9a3c6 100644 (file)
        "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": "<strong>Хата:</strong> Яңыртыуға асҡыс ҡуйыу түбәндәге хата менән тамамланды: $1",
        "config-install-sysop": "Администратор иҫәп яҙмаһын булдырыу",
index 0402ef5..da060da 100644 (file)
        "config-install-interwiki-exists": "'''Папярэджаньне''': выглядае, што табліца інтэрвікі ўжо запоўненая.\nСьпіс па змоўчваньні прапушчаны.",
        "config-install-stats": "Ініцыялізацыі статыстыкі",
        "config-install-keys": "Стварэньне сакрэтных ключоў",
-       "config-insecure-keys": "<strong>Папярэджаньне:</strong> {{PLURAL:$2|1=Ключ бясьпекі $1 створаны|Ключы бясьпекі $1 створаныя}} падчас усталяваньня, {{PLURAL:$2|1=не зьяўляецца паўнасьцю бясьпечным|не зьяўляюцца поўнасьцю бясьпечнымі}}. Рэкамэндуецца зьмяніць {{PLURAL:$2|1=яго ўручную|іх уручную}}.",
        "config-install-updates": "Прадухіленьне запуску непатрэбных абнаўленьняў",
        "config-install-updates-failed": "<strong>Памылка</strong>: устаўка ключоў абнаўленьня ў табліцы завершылася наступнай памылкай: $1",
        "config-install-sysop": "Стварэньне рахунку адміністратара",
index 829a910..3988ada 100644 (file)
        "config-install-interwiki-exists": "<strong>Внимание:</strong> Таблицата с междууикита изглежда вече съдържа данни.\nПропускане на списъка по подразбиране.",
        "config-install-stats": "Инициализиране на статистиките",
        "config-install-keys": "Генериране на тайни ключове",
-       "config-insecure-keys": "<strong>Внимание:</strong> {{PLURAL:$2|Сигурният ключ, създаден по време на инсталацията, не е напълно надежден|Сигурните ключове, създадени по време на инсталацията, не са напълно надеждни}} $1 . Обмислете да {{PLURAL:$2|го|ги}} смените ръчно.",
        "config-install-updates": "Предотвратяване стартирането на ненужни актуализации",
        "config-install-updates-failed": "<strong>Грешка:</strong> Вмъкването на обновяващи ключове в таблиците се провали по следната причина: $1",
        "config-install-sysop": "Създаване на администраторска сметка",
index ba75bd3..056531e 100644 (file)
        "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": "<strong>Chyba:</strong> 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",
index 88d0344..7a448a7 100644 (file)
        "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": "<strong>Fehler:</strong> Das Einfügen von Aktualisierungsschlüssel in die Tabellen ist mit dem folgenden Fehler fehlgeschlagen: $1",
        "config-install-sysop": "Administratorkonto wird erstellt",
index 005fef6..dbc1849 100644 (file)
        "config-install-interwiki-exists": "<strong>Warning:</strong> 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": "<strong>Warning:</strong> {{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": "<strong>Error:</strong> Inserting update keys into tables failed with the following error: $1",
        "config-install-sysop": "Creating administrator user account",
index 09fce89..921844d 100644 (file)
        "config-install-interwiki-exists": "<strong>Advertencia:</strong> 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": "<strong>Advertencia:</strong> {{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": "<strong>Error:</strong> 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",
index 5c9a3af..f840b49 100644 (file)
        "config-install-interwiki-exists": "<strong>Oharra:</strong> Interwikiko taula badirudi sarrerak dituela. \nTaula estandarra saltatzen.",
        "config-install-stats": "Estatistikak hasten",
        "config-install-keys": "Gako sekretuak sortzen",
-       "config-insecure-keys": "<strong>Oharra:</strong> ($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": "<strong>Errore</strong> Sartzea eguneratze-gakoak taulen barruan huts egin du hurrengo errorearekin: $1",
        "config-install-sysop": "Administratzaile kontua sortzen",
index 3ef8df0..31febc0 100644 (file)
        "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": "<strong>خطا:</strong> قراردادن کلیدهای به روز رسانی به داخل جداول با خطای روبرو مواجه شد: $1",
        "config-install-sysop": "ایجاد حساب کاربری مدیر",
index 151dfa6..64dfa20 100644 (file)
        "config-install-interwiki-exists": "<strong>Varoitus:</strong> interwiki-taulussa on jo tietueita, ohitetaan oletuslista.",
        "config-install-stats": "Alustetaan tilastoja",
        "config-install-keys": "Muodostetaan salausavaimia",
-       "config-insecure-keys": "<strong>Varoitus:</strong> 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": "<strong>Virhe:</strong> Päivitysavainten lisääminen taulukoihin epäonnistui seuraavalla virheellä: $1",
        "config-install-sysop": "Luodaan ylläpitäjän tiliä",
index 4bda25c..6259731 100644 (file)
        "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": "<strong>Erreur :</strong> 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",
index 7ad449d..45bb959 100644 (file)
        "config-install-interwiki-exists": "<strong>Atención:</strong> 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": "<strong>Atención:</strong> {{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": "<strong>Error:</strong> 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",
index 8c4d352..bc860d9 100644 (file)
        "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": "<strong>שגיאה:</strong> הוספת מפתחות עדכון לטבלאות נכשל עם השגיאה הבאה: $1",
        "config-install-sysop": "יצירת חשבון מפעיל",
index 2e077b2..2c357c1 100644 (file)
        "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 <code>allow_url_fopen</code> ist niet verfüchbar.",
index 10011ba..d9b6108 100644 (file)
        "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",
index 9ba487c..e71a6bb 100644 (file)
        "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": "<strong>Error:</strong> 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",
index 5cae965..eb6f51c 100644 (file)
        "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": "<strong>Kesalahan:</strong> Memasukkan kunci pembaruan ke dalam tabel gagal dengan kode kesalahan: $1",
        "config-install-sysop": "Membuat akun pengguna pengurus",
index 79845cf..b9b52b6 100644 (file)
        "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": "<strong>Errore:</strong> 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",
index 8b6a78a..f5e65a5 100644 (file)
        "config-install-interwiki-exists": "<strong>警告:</strong> ウィキ間テーブルは既に登録されているようです。\n既定のテーブルを無視します。",
        "config-install-stats": "統計情報の初期化",
        "config-install-keys": "秘密鍵の生成",
-       "config-insecure-keys": "<strong>警告:</strong> インストール中に生成されたセキュアキー ($1) は完璧に安全ではありません。手動で変更することを検討してください。",
        "config-install-updates": "不要な更新を実行するのを防ぐ",
        "config-install-updates-failed": "<strong>エラー:</strong> 更新キーをテーブルに挿入する際に失敗しました。以下のエラーが起こっています: $1",
        "config-install-sysop": "管理者アカウントの作成",
index 5e8d4dc..e0a9c8b 100644 (file)
        "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 설정",
        "config-install-interwiki-exists": "<strong>경고:</strong> 인터위키 테이블이 이미 항목을 갖고 있는 것 같습니다.\n기본 목록을 건너뜁니다.",
        "config-install-stats": "통계를 초기화하는 중",
        "config-install-keys": "보안 키를 만드는 중",
-       "config-insecure-keys": "<strong>경고:</strong> 설치 중에 생성한 {{PLURAL:$2|보안 키}} ($1)는 완전히 안전하지 {{PLURAL:$2|않습니다}}. 직접 바꾸는 것을 고려하세요.",
        "config-install-updates": "불필요한 업데이트 실행 방지",
        "config-install-updates-failed": "<strong>오류:</strong> 다음 오류로 테이블 안에 업데이트 키를 넣기에 실패했습니다: $1",
        "config-install-sysop": "관리자 사용자 계정을 만드는 중",
index 33ccabd..5ac7ec6 100644 (file)
        "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": "<strong>Dä:</strong> 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.",
index 8d05b79..69821ec 100644 (file)
        "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": "<strong>Erô:</strong> 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ô",
index 1e712b0..303e82e 100644 (file)
        "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": "<strong>Грешка:</strong> Вметнувањето на подновни клучеви во табелите не успеа, со следнава грешка: $1",
        "config-install-sysop": "Создавање на администраторска корисничка сметка",
index 28b497f..334d3a0 100644 (file)
        "config-install-interwiki-list": "Fail <code>interwiki.list</code> tidak dapat dibaca.",
        "config-install-interwiki-exists": "<strong>Amaran:</strong> Jadual antara wiki nampaknya sudah ada entri. Senarai asali dilangkau.",
        "config-install-keys": "Menjana kunci-kunci rahsia",
-       "config-insecure-keys": "<strong>Amaran:</strong> {{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",
index 2f2ae1e..7977427 100644 (file)
        "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": "<strong>Errore:</strong> 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",
index c67d04e..a3d69c9 100644 (file)
        "config-install-interwiki-exists": "<strong>Advarsel:</strong> 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": "<strong>Advarsel:</strong> {{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": "<strong>Feil:</strong> Innsetting av oppdateringsnøkler i tabellene mislyktes med følgende feilmelding: $1",
        "config-install-sysop": "Oppretter brukerkonto for administrator",
index 7bcd391..6011a8b 100644 (file)
        "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": "<strong>Fout:</strong> het toevoegen van updatesleutels aan tabellen is mislukt met de volgende fout: $1",
        "config-install-sysop": "Account voor beheerder aanmaken",
index d395f83..0f70dfb 100644 (file)
        "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": "<strong>Błąd:</strong> Wstawianie kluczy aktualizacji d0 tabeli nie powiodło się z powodu następującego błędu: $1",
        "config-install-sysop": "Tworzenie konta administratora",
index bcdf1a7..a06e044 100644 (file)
        "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 <code>allow_url_fopen</code> a l'é pa disponìbil.",
index 60898d9..e0216b3 100644 (file)
        "config-install-interwiki-exists": "<strong>Aviso:</strong> 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": "<strong>Aviso:</strong> {{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": "<strong>Error:</strong> 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",
index 9593ebe..c1fc5d8 100644 (file)
        "config-install-interwiki-exists": "<strong>Aviso:</strong> 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": "<strong>Aviso:</strong> {{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": "<strong>Erro:</strong> 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",
index 0779204..d9edde5 100644 (file)
        "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}}",
index aeda43a..ef38b51 100644 (file)
        "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": "<strong>Ошибка:</strong> Вставка ключей обновления в таблицы завершилась со следующей ошибкой: $1",
        "config-install-sysop": "Создание учётной записи администратора",
index 5b60540..b489ca3 100644 (file)
        "config-install-interwiki-exists": "<strong>Warnishment:</strong> 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": "<strong>Warnishment:</strong> {{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": "<strong>Mistak:</strong> Insertin update keys intae the buirds failed wi the folleain mistak: $1",
        "config-install-sysop": "Makin admeenistrâter uiser accoont",
index a691824..c0ae4f0 100644 (file)
        "config-install-interwiki-exists": "<strong>Varning:</strong> 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": "<strong>Fel:</strong> Infogning av uppdateringsnycklar i tabeller misslyckades med följande fel:$1",
        "config-install-sysop": "Skapar administratörskonto",
index 6298cb7..0249bae 100644 (file)
        "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 <code>allow_url_fopen</code>",
index b1e69df..a40bf1b 100644 (file)
        "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": "<strong>Помилка:</strong> Вставка оновленних ключів в таблиці не вдалося через таку помилку:$1",
        "config-install-sysop": "Створення облікового запису адміністратора",
index 0ecd688..d69a260 100644 (file)
        "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": "<strong>Cảnh báo:</strong> {{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": "<strong>Lỗi:</strong> 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",
index d22c566..c46478d 100644 (file)
        "config-install-interwiki-exists": "<strong>警告:</strong>跨wiki数据表似乎已有内容,跳过默认列表。",
        "config-install-stats": "初始化统计",
        "config-install-keys": "生成密钥中",
-       "config-insecure-keys": "<strong>警告:</strong>在安装过程中生成的{{PLURAL:$2|安全密钥}}($1){{PLURAL:$2|并}}不一定安全。请考虑手动更改{{PLURAL:$2|它|它们}}。",
        "config-install-updates": "防止运行不需要的更新",
        "config-install-updates-failed": "<strong>错误:</strong>表格中插入更新关键字失败并出现如下错误:$1",
        "config-install-sysop": "正在创建管理员用户帐号",
index a54f66b..4854877 100644 (file)
        "config-install-interwiki-exists": "<strong>警告:</strong> interwiki 資料表內已有資料,略過建立預設資料。",
        "config-install-stats": "初始化統計資訊",
        "config-install-keys": "產生秘密金鑰中",
-       "config-insecure-keys": "<strong>警告:</strong>在安裝過程中所產生的 $2 組安全金鑰($1)並不完全安全。請考慮手動更改。",
        "config-install-updates": "略過執行不需要的更新",
        "config-install-updates-failed": "<strong>錯誤:</strong> 插入更新鍵值至資料表失敗,並出現以下錯誤:$1",
        "config-install-sysop": "正在建立管理員使用者帳號",
index 657849a..e6a943d 100644 (file)
@@ -66,6 +66,7 @@ class Interwiki {
         * @return bool Whether it exists
         */
        public static function isValidInterwiki( $prefix ) {
+               wfDeprecated( __METHOD__, '1.28' );
                return MediaWikiServices::getInstance()->getInterwikiLookup()->isValidInterwiki( $prefix );
        }
 
@@ -78,6 +79,7 @@ class Interwiki {
         * @return Interwiki|null|bool
         */
        public static function fetch( $prefix ) {
+               wfDeprecated( __METHOD__, '1.28' );
                return MediaWikiServices::getInstance()->getInterwikiLookup()->fetch( $prefix );
        }
 
@@ -88,6 +90,7 @@ class Interwiki {
         * @since 1.26
         */
        public static function invalidateCache( $prefix ) {
+               wfDeprecated( __METHOD__, '1.28' );
                MediaWikiServices::getInstance()->getInterwikiLookup()->invalidateCache( $prefix );
        }
 
@@ -101,6 +104,7 @@ class Interwiki {
         * @since 1.19
         */
        public static function getAllPrefixes( $local = null ) {
+               wfDeprecated( __METHOD__, '1.28' );
                return MediaWikiServices::getInstance()->getInterwikiLookup()->getAllPrefixes( $local );
        }
 
index b99b0b8..1ab17a0 100644 (file)
@@ -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
index 0413ea0..e238887 100644 (file)
@@ -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;
                                }
index c41aab3..0478a33 100644 (file)
@@ -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 );
index f7702dd..a1bbd09 100644 (file)
  * @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 );
        }
 }
index 14462f1..e9d1fc1 100644 (file)
@@ -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 );
                }
 
index 6f348c2..3bdafe1 100644 (file)
@@ -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;
        }
 
index 7915ccf..d91ac85 100644 (file)
@@ -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 )
                                        ] );
index 2d4a772..785cb72 100644 (file)
@@ -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();
                }
index 3cd973e..2f7bc1e 100644 (file)
@@ -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() ) {
index e3c2d75..08e9d69 100644 (file)
@@ -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;
index 564616d..aec9f25 100644 (file)
@@ -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
index ebd72de..f1f749f 100644 (file)
@@ -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 );
index ea9dde7..a624f0a 100644 (file)
@@ -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 );
index e9fb11f..802ed2d 100644 (file)
@@ -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';
                        }
index ae434c1..dbab593 100644 (file)
@@ -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)
index b030522..edd5fbc 100644 (file)
@@ -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() );
        }
 }
index 97e0456..927a1e3 100644 (file)
@@ -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() );
        }
 
        /**
index f5cef9e..72ca590 100644 (file)
@@ -43,6 +43,8 @@ class ChronologyProtector implements LoggerAwareInterface {
        protected $key;
        /** @var string Hash of client parameters */
        protected $clientId;
+       /** @var string[] Map of client information fields for logging */
+       protected $clientInfo;
        /** @var int|null Expected minimum index of the last write to the position store */
        protected $waitForPosIndex;
        /** @var int Max seconds to wait on positions to appear */
@@ -81,6 +83,9 @@ class ChronologyProtector implements LoggerAwareInterface {
                        : md5( $client['ip'] . "\n" . $client['agent'] );
                $this->key = $store->makeGlobalKey( __CLASS__, $this->clientId, 'v2' );
                $this->waitForPosIndex = $posIndex;
+
+               $this->clientInfo = $client + [ 'clientId' => '' ];
+
                $this->logger = new NullLogger();
        }
 
@@ -308,7 +313,7 @@ class ChronologyProtector implements LoggerAwareInterface {
                                                [
                                                        'cpPosIndex' => $this->waitForPosIndex,
                                                        'waitTimeMs' => $waitedMs
-                                               ]
+                                               ] + $this->clientInfo
                                        );
                                } else {
                                        $this->logger->warning(
@@ -317,7 +322,7 @@ class ChronologyProtector implements LoggerAwareInterface {
                                                        'cpPosIndex' => $this->waitForPosIndex,
                                                        'indexReached' => $indexReached,
                                                        'waitTimeMs' => $waitedMs
-                                               ]
+                                               ] + $this->clientInfo
                                        );
                                }
                        } else {
index dedf6ea..b414a2a 100644 (file)
@@ -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() {
index 16e654f..57e5907 100644 (file)
@@ -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 ) {
index 2125c70..4b925e6 100644 (file)
@@ -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 );
        }
 
        /**
index 52c2df7..130a097 100644 (file)
@@ -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
                }
 
index cfa2647..30074ec 100644 (file)
@@ -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 );
                }
        }
 }
index 0d7b812..6a6bb8d 100644 (file)
@@ -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 );
                }
        }
 }
index 587ab23..2c1a782 100644 (file)
@@ -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 );
                }
        }
 }
index 221bca4..6b271a7 100644 (file)
@@ -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 );
                                }
                        }
                }
index ede35fa..bbcb267 100644 (file)
@@ -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." );
index 160d2d1..d096b00 100644 (file)
@@ -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;
                }
@@ -245,7 +245,7 @@ class LinkRenderer {
         * @return string
         */
        public function makePreloadedLink(
-               LinkTarget $target, $text = null, $classes, array $extraAttribs = [], array $query = []
+               LinkTarget $target, $text = null, $classes = '', array $extraAttribs = [], array $query = []
        ) {
                // Run begin hook
                $ret = $this->runBeginHook( $target, $text, $extraAttribs, $query, true );
@@ -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;
                        }
index 9e4a630..40498cd 100644 (file)
@@ -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;
        }
index 230d13b..8458e0b 100644 (file)
  * @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;
        }
+
 }
index cda037c..e2d32cf 100644 (file)
@@ -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 );
index a589dbf..a9c7b4f 100644 (file)
@@ -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
index c865d4e..1abf974 100644 (file)
@@ -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() );
                                        }
                                }
                        }
index 7f6dbe5..42d5db7 100644 (file)
@@ -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 '<span class="error">' .
                                        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 '<span class="error">' .
                                wfMessage( 'duplicate-defaultsort',
                                        // Message should be parsed, but these params should only be escaped.
index 8df5b5b..d3eff8a 100644 (file)
@@ -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 <nowiki> 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()->markNoConversion( $url, true ),
                                true, 'free',
                                $this->getExternalLinkAttribs( $url ), $this->mTitle );
                        # Register it in the output object...
@@ -1894,7 +1895,7 @@ class Parser {
                                list( $dtrail, $trail ) = Linker::splitTrail( $trail );
                        }
 
-                       $text = $this->getConverterLanguage()->markNoConversion( $text );
+                       $text = $this->getTargetLanguage()->markNoConversion( $text );
 
                        $url = Sanitizer::cleanUrl( $url );
 
@@ -2360,7 +2361,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 +2642,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 +3186,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 +3436,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
index 353825a..93f4246 100644 (file)
@@ -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 ) {
index 9ec6cf8..265d151 100644 (file)
@@ -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
index f811e3f..4ba34ef 100644 (file)
@@ -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
index 0ea3c63..d1774ba 100644 (file)
@@ -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'],
index 541fd0e..6065045 100644 (file)
@@ -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() ) {
index 834b8b1..aed52d1 100644 (file)
@@ -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;
        }
index a3684e8..c58b55e 100644 (file)
@@ -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
index d41198a..3ceb915 100644 (file)
@@ -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
index 3141797..42bc62d 100644 (file)
@@ -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;
        }
 }
index dc294c3..2f20d9d 100644 (file)
@@ -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" );
+               }
        }
-
 }
index e3eb4c2..eb57559 100644 (file)
@@ -24,7 +24,7 @@
 /**
  * @ingroup Search
  */
-class SearchResultSet {
+class SearchResultSet implements IteratorAggregate {
 
        /**
         * Types of interwiki results
@@ -54,7 +54,7 @@ class SearchResultSet {
         * as an array.
         * @var SearchResult[]
         */
-       private $results;
+       protected $results;
 
        /**
         * Set of result's extra data, indexed per result id
@@ -65,7 +65,16 @@ class SearchResultSet {
         */
        protected $extraData = [];
 
+       /** @var ArrayIterator|null Iterator supporting BC iteration methods */
+       private $bcIterator;
+
        public function __construct( $containedSyntax = 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;
        }
 
@@ -171,20 +180,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;
        }
 
        /**
@@ -258,15 +286,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 +310,8 @@ class SearchResultSet {
        public function getOffset() {
                return null;
        }
+
+       final public function getIterator() {
+               return new ArrayIterator( $this->extractResults() );
+       }
 }
index 53d09e8..022dc0a 100644 (file)
@@ -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() {
index 4c52693..c98b7da 100644 (file)
@@ -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 {
index 024bf9a..e9a03f2 100644 (file)
@@ -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':
index d1bea8d..c1c856d 100644 (file)
@@ -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;
index aa20e20..296c133 100644 (file)
@@ -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;
        }
 
        /**
index 81e13f0..557bd9c 100644 (file)
@@ -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: '
index 0622584..831644e 100644 (file)
@@ -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,
index 45e9684..3082101 100644 (file)
@@ -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() ),
index 317aa0d..5db8066 100644 (file)
@@ -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
index efe354a..bc632b1 100644 (file)
@@ -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;
                }
index f03565a..2d3a0cc 100644 (file)
@@ -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
index f322ac4..0e93194 100644 (file)
@@ -204,7 +204,7 @@ class SpecialEmailUser extends UnlistedSpecialPage {
                $nu = User::newFromName( $target );
                $error = self::validateTarget( $nu, $sender );
 
-               return $error ? $error : $nu;
+               return $error ?: $nu;
        }
 
        /**
index a54d72d..f43ed9b 100644 (file)
@@ -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 );
 
index e3485ff..3741272 100644 (file)
@@ -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(
index 3ca3a85..6848d2c 100644 (file)
@@ -138,11 +138,11 @@ class SpecialPrefixindex extends SpecialAllPages {
        }
 
        /**
-        * @param int $namespace Default NS_MAIN
+        * @param int $namespace
         * @param string $prefix
         * @param string $from List all pages from this name (default false)
         */
-       protected function showPrefixChunk( $namespace = NS_MAIN, $prefix, $from = null ) {
+       protected function showPrefixChunk( $namespace, $prefix, $from = null ) {
                global $wgContLang;
 
                if ( $from === null ) {
index 26f4da5..4b1b344 100644 (file)
@@ -92,7 +92,7 @@ class SpecialProtectedpages extends SpecialPage {
         *   cascadeOnly, noRedirect
         * @return string Input form
         */
-       protected function showOptions( $namespace, $type = 'edit', $level, $sizetype,
+       protected function showOptions( $namespace, $type, $level, $sizetype,
                $size, $filters
        ) {
                $formDescriptor = [
index 2770bc5..00bfba9 100644 (file)
@@ -112,7 +112,7 @@ class SpecialProtectedtitles extends SpecialPage {
         * @return string
         * @private
         */
-       function showOptions( $namespace, $type = 'edit', $level ) {
+       function showOptions( $namespace, $type, $level ) {
                $formDescriptor = [
                        'namespace' => [
                                'class' => 'HTMLSelectNamespace',
index 911c9a6..35c5689 100644 (file)
@@ -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,
index e6a0f0b..35c9931 100644 (file)
@@ -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 );
 
index 3b69698..0d4b5ab 100644 (file)
@@ -44,8 +44,8 @@ class ProtectedPagesPager extends TablePager {
         * @param bool $noredirect
         * @param LinkRenderer $linkRenderer
         */
-       function __construct( $form, $conds = [], $type, $level, $namespace,
-               $sizetype = '', $size = 0, $indefonly = false, $cascadeonly = false, $noredirect = false,
+       function __construct( $form, $conds, $type, $level, $namespace,
+               $sizetype, $size, $indefonly, $cascadeonly, $noredirect,
                LinkRenderer $linkRenderer
        ) {
                $this->mForm = $form;
index 8f172f8..ed437be 100644 (file)
@@ -26,7 +26,7 @@ class ProtectedTitlesPager extends AlphabeticPager {
 
        public $mForm, $mConds;
 
-       function __construct( $form, $conds = [], $type, $level, $namespace,
+       function __construct( $form, $conds, $type, $level, $namespace,
                $sizetype = '', $size = 0
        ) {
                $this->mForm = $form;
index 6a471ba..87b96ac 100644 (file)
@@ -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 {
index 68bcb9d..ee6f250 100644 (file)
@@ -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() );
        }
 }
index 5818958..0fc45f7 100644 (file)
@@ -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 );
        }
 }
index e236640..8521e68 100644 (file)
@@ -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 "<ul class='mw-search-results'>" . implode( '', $hits ) . "</ul>";
index d0c259f..248099a 100644 (file)
@@ -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();
                        }
                }
 
index da7bc94..bffed7f 100644 (file)
@@ -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;
@@ -3554,7 +3554,7 @@ class Language {
         * @return string
         */
        private function truncateInternal(
-               $string, $length, $ellipsis = '...', $adjustLength = true, $measureLength, $getSubstring
+               $string, $length, $ellipsis, $adjustLength, $measureLength, $getSubstring
        ) {
                if ( !is_callable( $measureLength ) || !is_callable( $getSubstring ) ) {
                        throw new InvalidArgumentException( 'Invalid callback provided' );
@@ -4471,7 +4471,7 @@ class Language {
         * @throws MWException
         * @return string $prefix . $mangledCode . $suffix
         */
-       public static function getFileName( $prefix = 'Language', $code, $suffix = '.php' ) {
+       public static function getFileName( $prefix, $code, $suffix = '.php' ) {
                if ( !self::isValidBuiltInCode( $code ) ) {
                        throw new MWException( "Invalid language code \"$code\"" );
                }
index c759220..fcba6dc 100644 (file)
@@ -126,7 +126,6 @@ class CrhExceptions {
                'beyude' => 'бейуде', 'beyüde' => 'бейуде',
                'curat' => 'джурьат', 'cürat' => 'джурьат',
                'mesul' => 'месуль', 'mesül' => 'месуль',
-               'yetsin' => 'етсин', 'etsin' => 'етсин',
        ];
 
        # map Cyrillic to Latin and back, simple string match only (no regex)
@@ -367,7 +366,7 @@ class CrhExceptions {
                'козь' => 'köz', '-юнджи' => '-ünci', '-юнджиде' => '-üncide', '-юнджиден' => '-ünciden',
 
                # originally L2C, here swapped
-               'еÑ\82Ñ\81ин' => 'etsin', 'лÑ\8cнаÑ\8f' => 'lnaya', 'лÑ\8cное' => 'lnoye', 'лÑ\8cнÑ\8bй' => 'lnıy', 'лÑ\8cний' => 'lniy',
+               'льная' => 'lnaya', 'льное' => 'lnoye', 'льный' => 'lnıy', 'льний' => 'lniy',
                'льская' => 'lskaya', 'льский' => 'lskiy', 'льское' => 'lskoye', 'ополь' => 'opol',
                'щее' => 'şçeye', 'щий' => 'şçiy', 'щая' => 'şçaya', 'цепс' => 'tseps',
 
@@ -389,8 +388,8 @@ class CrhExceptions {
                'му([иэИЭ])' => 'mü$1',
 
                # originally L2C, here swapped
-               'роль$1' => 'rol([^ü])',
-               'усть$1' => 'üst([^ü])',
+               'роль$1' => 'rol([^ü]|'.self::WB.')',
+               'усть$1' => 'üst([^ü]|'.self::WB.')',
 
                # more prefixes
                'ком-кок' => 'köm-kök',
@@ -460,6 +459,10 @@ class CrhExceptions {
                        '/'.self::WB.'Джонкю'.self::WB.'/u' => 'Cönkü',
                        '/'.self::WB.'ДЖОНКЮ'.self::WB.'/u' => 'CÖNKÜ',
 
+                       '/'.self::WB.'куркчи/u' => 'kürkçi',
+                       '/'.self::WB.'Куркчи/u' => 'Kürkçi',
+                       '/'.self::WB.'КУРКЧИ/u' => 'KÜRKÇI',
+
                        '/'.self::WB.'устке'.self::WB.'/u' => 'üstke',
                        '/'.self::WB.'Устке'.self::WB.'/u' => 'Üstke',
                        '/'.self::WB.'УСТКЕ'.self::WB.'/u' => 'ÜSTKE',
@@ -615,13 +618,21 @@ class CrhExceptions {
                        '/'.self::WB.'Mer'.self::WB.'/u' => 'Мэр',
                        '/'.self::WB.'MER'.self::WB.'/u' => 'МЭР',
 
-                       '/'.self::WB.'джонк/u' => 'cönk',
-                       '/'.self::WB.'Джонк/u' => 'Cönk',
-                       '/'.self::WB.'ДЖОНК/u' => 'CÖNK',
+                       '/'.self::WB.'cönk/u' => 'джонк',
+                       '/'.self::WB.'Cönk/u' => 'Джонк',
+                       '/'.self::WB.'CÖNK/u' => 'ДЖОНК',
 
-                       '/'.self::WB.'куркчи/u' => 'kürkçi',
-                       '/'.self::WB.'Куркчи/u' => 'Kürkçi',
-                       '/'.self::WB.'КУРКЧИ/u' => 'KÜRKÇI',
+                       # (y)etsin -> етсин/этсин
+                       # note that target starts with CYRILLIC е/Е!
+                       '/yetsin/u' => 'етсин',
+                       '/Yetsin/u' => 'Етсин',
+                       '/YETSİN/u' => 'ЕТСИН',
+
+                       # note that target starts with LATIN e/E!
+                       # (other transformations will determine CYRILLIC е/э as needed)
+                       '/etsin/u' => 'eтсин',
+                       '/Etsin/u' => 'Eтсин',
+                       '/ETSİN/u' => 'EТСИН',
 
                        # буква Ё - первый заход
                        # расставляем Ь после согласных
@@ -666,10 +677,6 @@ class CrhExceptions {
                        '/(['.Crh::L_F.'])l(['.Crh::L_CONS_LC.']|'.self::WB.')/u' => '$1ль$2',
                        '/(['.Crh::L_F_UC.'])L(['.Crh::L_CONS.']|'.self::WB.')/u' => '$1ЛЬ$2',
 
-                       '/etsin'.self::WB.'/u' => 'етсин',
-                       '/Etsin'.self::WB.'/u' => 'Етсин',
-                       '/ETSİN'.self::WB.'/u' => 'ЕТСИН',
-
                        # относятся к началу слова
                        '/'.self::WB.'ts/u' => 'ц',
                        '/'.self::WB.'T[sS]/u' => 'Ц',
index af844ee..3a96283 100644 (file)
@@ -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)
index 3635025..a5bc6a4 100644 (file)
        "filetype-unwanted-type": "<strong>«.$1»</strong> — непажаданы тып файла.\n{{PLURAL:$3|1=Пажаданым тыпам файла зьяўляецца|Пажаданымі тыпамі файлаў зьяўляюцца:}} $2.",
        "filetype-banned-type": "<strong>«.$1»</strong> — {{PLURAL:$4|1=забаронены тып файлаў|забароненыя тыпы файлаў}}.\n{{PLURAL:$3|1=Дазволены тып файлаў|Дазволеныя тыпы файлаў}}: $2.",
        "filetype-missing": "Файл ня мае пашырэньня (напрыклад, «.jpg»).",
-       "empty-file": "Ð\94аÑ\81ланÑ\8b Ð\92амі файл пусты.",
-       "file-too-large": "Ð\94аÑ\81ланÑ\8b Ð\92амі файл занадта вялікі.",
-       "filename-tooshort": "Назва файла занадта кароткая.",
+       "empty-file": "Ð\94аÑ\81ланÑ\8b Ð²амі файл пусты.",
+       "file-too-large": "Ð\94аÑ\81ланÑ\8b Ð²амі файл занадта вялікі.",
+       "filename-tooshort": "Назва файлу занадта кароткая.",
        "filetype-banned": "Гэты тып файла забаронены.",
        "verification-error": "Гэты файл не прайшоў вэрыфікацыю.",
        "hookaborted": "Прапанаваная Вамі зьмена была адхіленая апрацоўшчыкам пашырэньня.",
index 0e77bdc..ade421b 100644 (file)
        "version-other": "Други",
        "version-mediahandlers": "Обработчици на медия",
        "version-hooks": "Куки",
-       "version-parser-extensiontags": "Ð\95Ñ\82икеÑ\82и от парсерни разширения",
+       "version-parser-extensiontags": "Тагове от парсерни разширения",
        "version-parser-function-hooks": "Куки в парсерни функции",
        "version-hook-name": "Име на куката",
        "version-hook-subscribedby": "Ползвана от",
        "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 пароли}}"
 }
index 8ad5aed..7e76d0e 100644 (file)
        "anontalkpagetext": "----\n<em>এটি একটি বেনামী ব্যবহারকারীর আলাপের পাতা, যিনি এখনও কোন অ্যাকাউন্ট তৈরি করেননি, কিংবা তিনি অ্যাকাউন্টটি ব্যবহার করছেন না।</em>\nআমরা তাই সাংখ্যিক আইপি ঠিকানা ব্যবহার করে তাঁকে শনাক্ত করছি।\nএকাধিক ব্যবহারকারী এরকম একটি আইপি ঠিকানা ব্যবহার করতে পারেন।\nআপনি যদি একজন বেনামী ব্যবহারকারী হয়ে থাকেন এবং যদি অনুভব করেন যে আপনার প্রতি অপ্রাসঙ্গিক মন্তব্য করা হয়েছে, তাহলে অন্যান্য বেনামী ব্যবহারকারীর সাথে ভবিষ্যতে বিভ্রান্তি এড়াতে অনুগ্রহ করে [[Special:CreateAccount|একটি অ্যাকাউন্ট তৈরি করুন]] অথবা  [[Special:UserLogin|অ্যাকাউন্টে প্রবেশ করুন]]।",
        "noarticletext": "বর্তমানে এই পাতায় কোন লেখা নেই।\nআপনি চাইলে অন্যান্য পাতায় [[Special:Search/{{PAGENAME}}| এই শিরোনামটি অনুসন্ধান করতে পারেন]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} এ সম্পর্কিত লগ অনুসন্ধান করতে পারেন], \nকিংবা [{{fullurl:{{FULLPAGENAME}}|action=edit}} এই পাতাটি তৈরি করতে পারেন]</span>।",
        "noarticletext-nopermission": "বর্তমানে এই পাতায় কোন লেখা নেই।\nআপনি চাইলে অন্য পাতায় [[Special:Search/{{PAGENAME}}| শিরোনামটি অনুসন্ধান করতে পারেন]], অথবা <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} সম্পর্কিত লগ অনুসন্ধান করতে পারেন]</span>, কিন্তু আপনার এই পাতাটি তৈরী করার অনুমতি নেই।",
-       "missing-revision": "\"{{FULLPAGENAME}}\" এর #$1তম সংস্করণটি প্রদর্শন সম্ভব নয়।\n\nসাধারণত মুছে ফেলা হয়েছে এমন পাতার মেয়াদ উত্তীর্ণ ইতিহাস পাতার লিংক ওপেন করার কারণে এটি হতে পারে। \n[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} অপসারণ লগে] বিস্তারিত তথ্য জানা যাবে।",
+       "missing-revision": "\"{{FULLPAGENAME}}\" এর #$1তম সংস্করণটি প্রদর্শন সম্ভব নয়।\n\nসাধারণত মুছে ফেলা হয়েছে এমন পাতার মেয়াদ উত্তীর্ণ ইতিহাসের সংযোগ অনুসরণ করার কারণে এটি হতে পারে। \n[{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} অপসারণ লগে] বিস্তারিত তথ্য জানা যাবে।",
        "userpage-userdoesnotexist": "\"<nowiki>$1</nowiki>\" নামের কোন ব্যবহারকারী অ্যাকাউন্ট নিবন্ধিত হয়নি। অনুগ্রহ করে পরীক্ষা করে দেখুন আপনি এই পাতাটি সৃষ্টি/সম্পাদনা করতে চান কি না।",
        "userpage-userdoesnotexist-view": "ব্যবহারকারী অ্যাকাউন্ট \"$1\" অনিবন্ধিত।",
        "blocked-notice-logextract": "এই ব্যবহারকারী বর্তমানে অবরুদ্ধ রয়েছেন।\nসূত্রের জন্য সাম্প্রতিক বাধাদান লগের ভুক্তিটি নিচে দেওয়া হল:",
index 2ba5bc6..fdadfc5 100644 (file)
@@ -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",
        "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.",
        "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.",
        "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",
        "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:<em>$2</em>\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": "<strong>S'ha procedit al blocatge del vostre compte d'usuari o la vostra adreça IP.</strong>\n\nEl blocatge l'ha dut a terme l'usuari $1.\nEl motiu donat és <em>$2</em>.\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:<em>$2</em>\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:<em>$2</em>\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.",
        "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": "<strong>Nota:</strong> Després de desar, possiblement necessitareu refrescar la memòria cau del vostre navegador per a veure'n els canvis.\n* <strong>Firefox / Safari:</strong> Premeu <em>Shift</em> i alhora cliqueu el botó <em>Actualitza</em>, o pressioneu <em>Ctrl+F5</em> o <em>Ctrl+R</em> (<em>⌘+R</em> en un Mac)\n* <strong>Google Chrome:</strong> Premeu <em>Ctrl+Shift+R</em> (<em>⌘+Shift+R</em> en un Mac)\n* <strong>Internet Explorer:</strong> Premeu <em>Ctrl</em> i alhora cliqueu a <em>Actualitza</em> o pressioneu <em>Ctrl+F5</em>\n* <strong>Opera:</strong> Aneu a <em>Menú → Preferències</em> (<em>Opera → Preferències</em> en un Mac) i llavors a <em>Privadesa i seguretat → Neteja dades de navegació → Imatges i fitxers en memòria cau</em>.",
        "usercssyoucanpreview": "'''Consell:''' Utilitzeu el botó \"{{int:showpreview}}\" per provar el vostre nou CSS abans de desar-lo.",
+       "userjsonyoucanpreview": "<strong>Consell:</strong> 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!'''",
        "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": "<strong>Avís: La base de dades està blocada per manteniment, de manera que no podreu desar els canvis ara mateix.</strong>\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": "<strong>Avís:</strong> 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": "<strong>Atenció:</strong> 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}}:",
        "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": "<strong>Avís</strong>: 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",
        "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}}.",
        "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",
        "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:",
        "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",
        "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 <strong>negreta</strong>.",
+       "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 <strong>negreta</strong>.",
        "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",
        "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 <code><nowiki>{{</nowiki>#language:…}}</code>, i les variables predefinides, com <code><nowiki>{{</nowiki>CURRENTDAY}}</code> &mdash;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",
        "expand_templates_preview": "Previsualitza",
        "expand_templates_preview_fail_html": "<em>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.</em>\n\n<strong>Si això és un intent de previsualització legítim, torneu-ho a provar.</strong>\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": "<em>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.</em>\n\n<strong>Si això és un intent de previsualització legítim, [[Special:UserLogin|inicieu una sessió]] i torneu-ho a provar.</strong>",
-       "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",
        "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"
 }
index 14deacc..b703394 100644 (file)
        "nowiki_sample": "Кхуза хӀоттаде хийца оьшуш доцу йоза",
        "nowiki_tip": "Тергал ца бо вики-бáрамхlоттор",
        "image_sample": "Example.jpg",
-       "image_tip": "ЧоÑ\85Ñ\8c Ð¹Ð¾Ð»Ñ\83 Ñ\84айл",
+       "image_tip": "Файл Ñ\87Ñ\83йиллаÑ\80",
        "media_sample": "Example.ogg",
        "media_tip": "Хьажорг медиа-файлан тӀе",
        "sig_tip": "Хьан куьгтаlор аъ хlоттина хан",
        "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": "Нисдар юхадаккха цало, иза доцу делла я дӀаяьккхина дела.",
        "uploaddisabled": "Чуяккхар магийна дац",
        "copyuploaddisabled": "URL тӀера чуяккхар дӀадайина ду.",
        "uploaddisabledtext": "Файлаш чуяхар дӀадайина ду.",
+       "uploaded-href-attribute-svg": "Элементаш <a> тӀетовжа (href) мега data: (файл чуйиллар) тӀе, хьажорг http:// я https:// я фрагмент (#, оцу документ тӀехь). Кхечу элементашна, масала <image>  санна, data: а, фрагмент а бен цамагийна. \nСурт чудийлла хьажа SVG форматехь. Карина <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploadscriptednamespace": "ХӀокху SVG-файлан цӀерийн меттиг нийса яц '<nowiki>$1</nowiki>'",
        "upload-source": "ДIайолалун файл",
        "sourcefilename": "ДIайолалун файл:",
        "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<code><nowiki>{{#language:…}}</nowiki></code> кхочуш дан тайп\n<code><nowiki>{{CURRENTDAY}}</nowiki></code>.",
        "expand_templates_title": "АгӀона {{FULLPAGENAME}} корта кхин а:",
index f258241..a6f49ec 100644 (file)
@@ -8,7 +8,8 @@
                        "ОйЛ",
                        "아라",
                        "Илья Драконов",
-                       "Vvs-dm"
+                       "Vvs-dm",
+                       "Matěj Suchánek"
                ]
        },
        "tog-oldsig": "твои нꙑнѣшьн҄ь аѵтографъ :",
        "userexists": "сѫщє польꙃєватєлꙗ имѧ пьса ⁙\nбѫди добръ · ино сѥ иꙁобрѧщи",
        "loginerror": "въхода блаꙁна",
        "createacct-error": "мѣста сътворѥниꙗ блаꙁна",
-       "loginsuccess": "'''нꙑнѣ тꙑ {{GENDER|въшьлъ|въшьла}} въ {{grammar:locative|{{SITENAME}}}} подь имьньмъ ⁖ $1 ⁖.'''",
+       "loginsuccess": "'''нꙑнѣ тꙑ {{GENDER:|въшьлъ|въшьла}} въ {{grammar:locative|{{SITENAME}}}} подь имьньмъ ⁖ $1 ⁖.'''",
        "mailmypassword": "нова таина слова оуставлѥниѥ",
        "accountcreated": "мѣсто сътворєно ѥстъ",
        "accountcreatedtext": "польꙃєватєльско мѣсто [[{{ns:User}}:$1|$1]] ([[{{ns:User talk}}:$1|бєсѣда]]) сътворєно бѣ",
index cd6217c..0d44d82 100644 (file)
@@ -64,7 +64,8 @@
                        "Obzord",
                        "Alp Er Tunqa",
                        "Baloch Khan",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "Alireza Ivaz"
                ]
        },
        "tog-underline": "خط کشیدن زیر پیوندها:",
index 2484110..060a61b 100644 (file)
        "rcfilters-watchlist-showupdated": "Muutokset sivuihin, joilla et ole vieraillut sen jälkeen kun muutokset on tehty, on <strong>lihavoitu</strong> 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": "<strong>Sivut, joihin linkitetään</strong> valitulta sivulta",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Sivut, jotka linkittävät</strong> valitulle sivulle",
        "rcfilters-target-page-placeholder": "Anna sivun nimi (tai luokka)",
        "rcnotefrom": "Alla ovat muutokset <strong>$3, $4</strong> lähtien. (Enintään <strong>$1</strong> näytetään.)",
        "rclistfromreset": "Tyhjennä ajankohdan valinta",
        "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}}"
 }
index 126208a..2660604 100644 (file)
        "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.",
        "viewyourtext": "Zòt pouvé wè ké kopyé kontni-a di <strong>zòt modifikasyon</strong> à 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": "<strong>Panga :</strong> 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 « <strong>$1</strong> ».",
        "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ò.",
        "filepage-nofile": "Pyès fiché di sa non ka ègzisté.",
        "upload-disallowed-here": "Zòt pa pé 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|}}",
index 5381285..a5dd902 100644 (file)
@@ -7,7 +7,8 @@
                        "Matma Rex",
                        "NoiX180",
                        "Zhoelyakin",
-                       "Amire80"
+                       "Amire80",
+                       "Matěj Suchánek"
                ]
        },
        "tog-underline": "Garisiyi totibawa wumbuta",
        "hidden-category-category": "Dalala wanto-wanto'o",
        "category-subcat-count": "{{PLURAL:$2|Kategori boti woluwo subkategori|Kategori boti woluwo {{PLURAL:$1|subkategori|$1 subkategori}} lonto nga'amila $2.}}",
        "category-subcat-count-limited": "Kategori boti woluwo {{PLURAL:$1|subkategori|$1 subkategori}}",
-       "category-article-count": "{{PLURAL:$2|Kategori botiye o tuwango halaman.|Woluwo {{PLURAL:$|$1 halaman}} to delomo kategori, lonto $2 nga'amila.}}",
+       "category-article-count": "{{PLURAL:$2|Kategori botiye o tuwango halaman.|Woluwo {{PLURAL:$1|$1 halaman}} to delomo kategori, lonto $2 nga'amila.}}",
        "category-article-count-limited": "Kategori boti woluwo {{PLURAL:$1|halaman|$1 halaman}} to delomo kategori",
        "category-file-count": "{{PLURAL:$2|To kategori boti woluwo berkas {{PLURAL:$1|berkas|$1 berkas}} to delomo kategori, lonto nga'amila $2}}",
        "category-file-count-limited": "Woluwo {{PLURAL:$1|berkas|S1 berkas}} to delomo kategori.",
index 45c12b5..8e5df68 100644 (file)
        "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": "𐌼𐌴𐌽𐌹𐌽𐍃 𐌳𐌰𐌲𐍃",
        "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": "𐌷𐌰𐌱𐌰𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃",
        "history": "𐌻𐌰𐌿𐌱𐌰𐍃𐍀𐌹𐌻𐌻",
        "history_short": "𐍃𐍀𐌹𐌻𐌻",
        "history_small": "𐍃𐍀𐌹𐌻𐌻",
+       "updatedmarker": "𐌰𐌽𐌰𐌽𐌹𐌿𐌾𐌹𐌸𐍃 𐍆𐍂𐌰𐌼 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌼𐌼𐌰 𐍃𐌹𐌽𐌸𐌰 𐌸𐌰𐍄𐌴𐌹 𐌹𐌺 𐌲𐌰𐍅𐌴𐌹𐍃𐍉𐌳𐌰 𐌸𐌹𐍃 𐌻𐌰𐌿𐌱𐌹𐍃",
        "printableversion": "𐌿𐍃𐌼𐌴𐍂𐌴𐌹𐌽𐍃 𐌳𐌿 𐌿𐍃𐌼𐌴𐌻𐌾𐌰𐌽",
        "permalink": "𐌰𐌹𐍅𐌴𐌹𐌽𐌰 𐌲𐌰𐍅𐌹𐍃𐍃",
        "print": "𐌿𐍃𐌼𐌴𐌻𐌴𐌹",
        "helppage-top-gethelp": "𐌷𐌹𐌻𐍀𐌰",
        "mainpage": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
        "mainpage-description": "𐌰𐌽𐌰𐍃𐍄𐍉𐌳𐌴𐌹𐌽𐌹𐌻𐌰𐌿𐍆𐍃",
+       "policy-url": "Project:𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃",
        "portal": "𐌲𐌰𐌵𐌿𐌼𐌸𐍃 𐌲𐌰𐌼𐌰𐌹𐌽𐌳𐌿𐌸𐌰𐌹𐍃",
        "portal-url": "Project:𐌲𐌰𐌵𐌿𐌼𐌸𐍃 𐌲𐌰𐌼𐌰𐌹𐌽𐌳𐌿𐌸𐌰𐌹𐍃",
        "privacy": "𐍃𐌿𐌽𐌳𐍂𐌰𐌻𐌴𐌹𐌺𐌴𐌹𐌽𐍃 𐌲𐌰𐍂𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃",
        "confirmable-no": "𐌽𐌴",
        "thisisdeleted": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌸𐌰𐌿 𐌲𐌰𐌵𐌹𐌿𐌾𐌰𐌽 $1?",
        "viewdeleted": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 $1?",
+       "restorelink": "{{PLURAL:$1|𐌰𐌹𐌽𐌰 𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌹𐌳𐌰 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃|$1 𐍆𐍂𐌰𐌵𐌹𐍃𐍄𐌹𐌳𐍉𐍃 𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃}}",
        "site-rss-feed": "$1 RSS 𐍂𐌹𐌽𐌽𐍉",
        "site-atom-feed": "$1 𐌰𐍄𐌰𐌿𐌼 𐍂𐌹𐌽𐌽𐍉",
        "page-atom-feed": "\"$1\" 𐌰𐍄𐌰𐌿𐌼 𐍂𐌹𐌽𐌽𐍉",
        "mycustomjsonprotected": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 JSON 𐌻𐌰𐌿𐍆.",
        "mycustomjsprotected": "𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐌳𐌿 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 JavaScript 𐌻𐌰𐌿𐍆.",
        "ns-specialprotected": "𐌿𐍃𐍃𐌹𐌽𐌳𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃 𐌽𐌹 𐌼𐌰𐌲𐌿𐌽 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽𐌳𐌰.",
+       "titleprotected": "𐌸𐌰𐍄𐌰 𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹 𐌼𐌿𐌽𐌸 𐌷𐌰𐌱𐌰𐌹𐌸 𐍆𐍂𐌰𐌼 𐌲𐌰𐍃𐌺𐌰𐍆𐍄𐌰 𐍆𐍂𐌰𐌼 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳 [[User:$1|$1]].\n𐌲𐌹𐌱𐌰𐌽𐌰 𐍆𐌰𐌹𐍂𐌹𐌽𐌰 𐌹𐍃𐍄 <em>$2</em>.",
        "cannotlogoutnow-title": "𐌰𐍆𐌻𐌴𐌹𐌸𐌰𐌽 𐌽𐌿 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄",
        "cannotlogoutnow-text": "𐌸𐌰𐌽 $1 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰 𐌰𐍆𐌻𐌴𐌹𐌸𐌰𐌽 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄.",
        "welcomeuser": "𐍅𐌰𐌹𐌻𐌰 𐌰𐌽𐌳𐌰𐌽𐌴𐌼𐍃, $1!",
        "createacct-yourpasswordagain-ph": "𐌼𐌴𐌻𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳 𐌰𐍆𐍄𐍂𐌰",
        "userlogin-remembermypassword": "𐌲𐌰𐍆𐌰𐍃𐍄 𐌼𐌹𐌺 {{GENDER:𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌽𐌰|𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰}}",
        "userlogin-signwithsecure": "𐌱𐍂𐌿𐌺𐌴𐌹 𐌰𐍂𐌽𐌾𐌰𐌹𐌶𐍉𐍃 𐌲𐌰𐍅𐌹𐍃𐌰𐌹𐍃",
+       "cannotlogin-text": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄.",
        "cannotloginnow-title": "𐌽𐌿 𐌽𐌹 𐌼𐌰𐌲𐍄 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽",
+       "cannotloginnow-text": "𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽 𐌼𐌰𐌷𐍄𐍃 𐌽𐌹𐍃𐍄 𐌸𐌰𐌽 $1 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰.",
+       "password-change-forbidden": "𐌽𐌹 𐌼𐌰𐌲𐍄 𐌹𐌽𐌼𐌰𐌹𐌳𐌾𐌰𐌽 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌰 𐌰𐌽𐌰 𐌸𐌰𐌼𐌼𐌰 𐍅𐌹𐌺𐌾𐌰.",
        "login": "𐌰𐍄𐌲𐌰𐌲𐌲",
        "nav-login-createaccount": "𐌰𐍄𐌲𐌰𐌲𐌲 / 𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "logout": "𐌰𐍆𐌻𐌴𐌹𐌸",
        "createacct-emailoptional": "𐌴-𐌱𐍉𐌺𐍉𐍃 (𐌼𐌰𐌷𐍄𐌴𐌹𐌲𐍉𐍃)",
        "createacct-email-ph": "𐌼𐌴𐌻𐌴𐌹 𐌸𐌴𐌹𐌽𐍉𐍃 𐌴-𐌱𐍉𐌺𐍉𐍃",
        "createacct-another-email-ph": "𐌼𐌴𐌻𐌴𐌹 𐌴-𐌱𐍉𐌺𐍉𐍃",
+       "createacct-realname": "𐍃𐌿𐌽𐌾𐌴𐌹𐌽 𐌽𐌰𐌼𐍉 (𐌼𐌰𐌷𐍄𐌴𐌹𐌲)",
        "createacct-reason": "𐌲𐍂𐌿𐌽𐌳𐌿𐍃",
        "createacct-submit": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌸𐌴𐌹𐌽𐌰 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "createacct-benefit-heading": "{{SITENAME}} 𐍄𐌰𐍅𐌹𐌸 𐌹𐍃𐍄 𐍆𐍂𐌰𐌼 𐌼𐌰𐌽𐌽𐌰𐌼 𐍃𐍅𐌴 𐌸𐌿𐌺.",
        "createacct-benefit-body1": "{{PLURAL:$1|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃}}",
        "createacct-benefit-body2": "{{PLURAL:$1|𐌻𐌰𐌿𐍆𐍃|𐌻𐌰𐌿𐌱𐍉𐍃}}",
+       "badretype": "𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌰 𐌸𐍉𐌴𐌹 𐌸𐌿 𐌲𐌰𐌼𐌴𐌻𐌹𐌳𐌴𐍃 𐌽𐌹 𐌹𐌽𐌲𐌰𐌻𐌴𐌹𐌺𐍉𐌽𐌳.",
+       "nouserspecified": "𐍃𐌺𐌰𐌻𐍄 𐌲𐌹𐌱𐌰𐌽 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐍉.",
+       "password-login-forbidden": "𐌱𐍂𐌿𐌺𐌴𐌹𐌽𐍃 𐌸𐌹𐍃 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽𐌰𐌼𐌹𐌽𐍃 𐌾𐌰𐌷 𐌸𐌹𐍃 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳𐌹𐍃 𐍆𐌰𐌿𐍂𐌱𐌹𐌿𐌳𐌰𐌽𐌰 𐌹𐍃𐍄.",
+       "mailmypassword": "𐌰𐍆𐍄𐍂𐌰 𐍃𐌰𐍄𐌴𐌹 𐌲𐌰𐌼𐍉𐍄𐌰𐍅𐌰𐌿𐍂𐌳",
+       "emailconfirmlink": "𐌲𐌰𐍃𐌹𐌲𐌻𐌴𐌹 𐌸𐌴𐌹𐌽𐍉𐍃 𐌴-𐌱𐍉𐌺𐍉𐍃",
+       "emaildisabled": "𐍃𐌰 𐌽𐌰𐍄𐌾𐌰𐍃𐍄𐌰𐌸𐍃 𐌽𐌹 𐌼𐌰𐌲 𐍃𐌰𐌽𐌳𐌾𐌰𐌽 𐌴-𐌱𐍉𐌺𐍉𐍃.",
        "loginlanguagelabel": "𐍂𐌰𐌶𐌳𐌰: $1",
        "pt-login": "𐌰𐍄𐌲𐌰𐌲𐌲",
        "pt-login-button": "𐌰𐍄𐌲𐌰𐌲𐌲",
+       "pt-login-continue-button": "𐌸𐌰𐌹𐍂𐌷𐍅𐌹𐍃 𐌰𐍄𐌲𐌰𐌲𐌲𐌰𐌽",
        "pt-createaccount": "𐍃𐌺𐌰𐍀𐌴𐌹 𐌺𐌰𐍅𐍄𐍃𐌾𐍉𐌽",
        "pt-userlogout": "𐌰𐍆𐌻𐌴𐌹𐌸",
+       "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": "𐍅𐍂𐌰𐌹𐌵𐍉𐍃 𐌱𐍉𐌺𐍉𐍃",
        "loginreqlink": "𐌰𐍄𐌲𐌰𐌲𐌲",
        "newarticle": "(𐌽𐌹𐍅𐌹)",
        "newarticletext": "𐌻𐌰𐌹𐍃𐍄𐌹𐌳𐌴𐍃 𐌲𐌰𐍅𐌹𐍃 𐌳𐌿 𐌻𐌰𐌿𐌱𐌰 𐍃𐌰𐌴𐌹 𐌽𐌹𐍃𐍄. 𐌳𐌿 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆, 𐌰𐌽 𐌰𐍃𐍄𐍉𐌳𐌴𐌹 𐌼𐌴𐌻𐌾𐌰𐌽 𐌹𐌽 𐌰𐍂𐌺𐌰𐌹 𐌿𐍆 (𐍃𐌰𐌹𐍈 [$1 𐌷𐌹𐌻𐍀𐌰𐌻𐌰𐌿𐍆] 𐌼𐌰𐌽𐌰𐌲𐌹𐌶𐌹𐌽 𐌺𐌿𐌽𐌸𐌾𐌰). 𐌾𐌰𐌱𐌰𐌹 𐌹𐍃 𐌷𐌴𐍂 𐌹𐌽 𐌰𐌹𐍂𐌶𐌴𐌹𐌽𐍃, 𐌲𐌰𐌲𐌲 𐌳𐌿 <strong>𐌹𐌱𐌿𐌺𐌰𐌷𐌰𐌿𐌱𐌹𐌳𐌹𐌻𐍉𐌽</strong>.",
+       "anontalkpagetext": "----\n<em>𐌸𐌰𐍄𐌰 𐌹𐍃𐍄 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌰𐌻𐌰𐌿𐍆𐍃 𐌿𐌽𐌽𐌰𐌼𐌽𐌹𐌸𐌰𐌼𐌼𐌰 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳 𐍃𐌰𐌴𐌹 𐌽𐌰𐌿𐌷 𐌽𐌹 𐌲𐌰𐍃𐌺𐍉𐍀 𐌰𐌺𐌰𐍅𐌽𐍄, 𐌸𐌰𐌿 𐍃𐌰𐌴𐌹 𐌽𐌹 𐌱𐍂𐌿𐌺𐌾𐌹𐌸 𐌸𐌹𐍃.<em>\n𐌹𐌽 𐌸𐌹𐍃 𐍃𐌺𐌿𐌻𐌳 𐌹𐍃𐍄 𐌿𐌽𐍃 𐌳𐌿 𐌱𐍂𐌿𐌺𐌾𐌰𐌽 𐍂𐌰𐌸𐌾𐍉𐌽𐍃 IP 𐌳𐌿 𐌺𐌿𐌽𐌽𐌰𐌽 𐌹𐌽𐌰/𐌹𐌾𐌰.\n𐌾𐌰𐌱𐌰𐌹 𐌸𐌿 𐌹𐍃 𐌿𐌽𐌽𐌰𐌼𐌽𐌹𐌸𐍃 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐍃 𐌾𐌰𐌷 𐌹𐍃𐍄 𐌸𐌿𐍃 𐍃𐍅𐌰𐍃𐍅𐌴 𐌿𐌽𐌲𐌰𐌷𐌰𐌷𐌾𐍉 𐍅𐌰𐌿𐍂𐌳𐌰 𐍅𐌴𐍃𐌿𐌽 𐌸𐌿𐍃, 𐌱𐌹𐌳𐌾𐌰𐌼 𐌸𐌿𐌺, [[Special:CreateAccount|𐍃𐌺𐌰𐍀𐌴𐌹 𐌰𐌺𐌰𐍅𐌽𐍄]] 𐌸𐌰𐌿 [[Special:UserLogin|𐌰𐍄𐌲𐌰𐌲𐌲]] 𐌴𐌹 𐌽𐌹 𐍃𐌹𐌾𐌰𐌹 𐌰𐌹𐍂𐌶𐌴𐌹𐌽𐍃 𐌼𐌹𐌸 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐌿𐌽𐌽𐌰𐌼𐌽𐌹𐌸𐌰𐌹𐌼 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌰𐌼 𐌹𐌽 𐌰𐌽𐌰𐍅𐌰𐌹𐍂𐌸𐌰.",
        "noarticletext": "𐌽𐌿 𐌽𐌹 𐍃𐌹𐌽𐌳 𐌱𐍉𐌺𐍉𐍃 𐌹𐌽 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰.\n𐌼𐌰𐌲𐍄 [[Special:Search/{{PAGENAME}}|𐍃𐍉𐌺𐌾𐌰𐌽 𐌸𐌰𐍄𐌰 𐌻𐌰𐌿𐌱𐌰-𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹]] 𐌹𐌽 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐌻𐌰𐌿𐌱𐌰𐌼,  <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 𐍃𐍉𐌺𐌾𐌰𐌽 𐌲𐌰𐌷𐌰𐌷𐌾𐍉 𐌲𐌰𐍆𐌰𐍃𐍄𐍉𐍃], 𐌰𐌹𐌸𐌸𐌰𐌿 [{{fullurl:{{FULLPAGENAME}}|action=edit}} 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆.]</ span>",
        "noarticletext-nopermission": "𐌽𐌿 𐌽𐌹 𐍃𐌹𐌽𐌳 𐌱𐍉𐌺𐍉𐍃 𐌹𐌽 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰.\n𐌼𐌰𐌲𐍄 [[Special:Search/{{PAGENAME}}|𐍃𐍉𐌺𐌾𐌰𐌽 𐌸𐌰𐍄𐌰 𐌻𐌰𐌿𐌱𐌰-𐌿𐍆𐌰𐍂𐌼𐌴𐌻𐌹]] 𐌹𐌽 𐌰𐌽𐌸𐌰𐍂𐌰𐌹𐌼 𐌻𐌰𐌿𐌱𐌰𐌼, 𐌸𐌰𐌿 <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} 𐍃𐍉𐌺𐌾𐌰𐌽 𐌲𐌰𐌷𐌰𐌷𐌾𐍉 𐌲𐌰𐍆𐌰𐍃𐍄𐍉𐍃]</span>, 𐌹𐌸 𐌽𐌹 𐌷𐌰𐌱𐌰𐌹𐍃 𐌰𐌽𐌳𐌻𐌴𐍄 𐍃𐌺𐌰𐍀𐌾𐌰𐌽 𐌸𐌰𐌽𐌰 𐌻𐌰𐌿𐍆.",
        "userpage-userdoesnotexist-view": "𐌱𐍂𐌿𐌺𐌾𐌰𐌺𐌰𐍅𐍄𐍃𐌾𐍉 \"$1\" 𐌽𐌹𐍃𐍄 𐌰𐌽𐌰𐌼𐌴𐌻𐌹𐌳𐌰.",
        "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": "𐍅𐌹𐌺𐌹𐌱𐍉𐌺𐍉𐍃",
        "page_last": "𐍃𐍀𐌴𐌳𐌿𐌼𐌹𐍃𐍄",
        "histfirst": "𐍆𐌰𐌹𐍂𐌽𐌹𐍃𐍄",
        "histlast": "𐌽𐌹𐌿𐌾𐌹𐍃𐍄",
+       "history-feed-title": "𐌰𐍆𐍄𐍂𐌰𐍃𐌹𐌿𐌽𐌹𐍃𐍀𐌹𐌻𐌻",
+       "history-feed-description": "𐌰𐍆𐍄𐍂𐌰𐍃𐌹𐌿𐌽𐌹𐍃𐍀𐌹𐌻𐌻 𐌸𐌰𐌼𐌼𐌰 𐌻𐌰𐌿𐌱𐌰 𐌰𐌽𐌰 𐌸𐌰𐌼𐌼𐌰 𐍅𐌹𐌺𐌾𐌰",
        "history-feed-item-nocomment": "$1 𐌰𐍄 $2",
        "rev-delundel": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐌰𐌽𐌰𐍃𐌹𐌿𐌽",
        "revdel-restore": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹 𐌰𐌽𐌰𐍃𐌹𐌿𐌽",
        "nextn-title": "𐌰𐍆𐍄𐌿𐌼(𐌰) $1 {{PLURAL:$1|𐍄𐌰𐌿𐌹|𐍄𐍉𐌾𐌰}}",
        "shown-title": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 $1 {{PLURAL:$1|𐍄𐌰𐌿𐌹|𐍄𐍉𐌾𐌰}} 𐍈𐌰𐍂𐌾𐌰𐌼𐌼𐌴𐌷 𐌻𐌰𐌿𐌱𐌰.",
        "viewprevnext": "𐍃𐌹𐌿𐌽𐌴𐌹𐍃 ($1 {{int:pipe-separator}} $2) ($3)",
+       "searchmenu-exists": "<strong>𐌹𐍃𐍄 𐌻𐌰𐌿𐍆𐍃 𐌷𐌰𐌹𐍄𐌰𐌽𐍃 \"[[:$1]]\" 𐌰𐌽𐌰 𐌸𐌰𐌼𐌼𐌰 𐍅𐌹𐌺𐌾𐌰.</strong> {{PLURAL:$2|0=|𐍃𐌰𐌹𐍈 𐌾𐌰𐌷 𐌰𐌽𐌸𐌰𐍂𐌰 𐍄𐍉𐌾𐌰 𐍃𐍉𐌺𐌴𐌹𐌽𐌰𐌹𐍃 𐌸𐍉𐌴𐌹 𐌱𐌹𐌲𐌹𐍄𐌰𐌽𐌰 𐍃𐌹𐌽𐌳.}}",
        "searchmenu-new": "<strong>𐍃𐌺𐌰𐍀𐌴𐌹 𐌻𐌰𐌿𐍆 \"[[:$1]]\" 𐌰𐌽𐌰 𐌸𐌹𐌶𐌰𐌹 𐍅𐌹𐌺𐌹!</strong> {{{{PLURAL:$2|0=|𐍃𐌰𐌹 𐌾𐌰𐌷 𐌻𐌰𐌿𐍆 𐌱𐌹𐌲𐌹𐍄𐌰𐌽𐌰 𐌸𐌴𐌹𐌽𐌰𐌹 𐍃𐍉𐌺𐌴𐌹𐌽𐌰𐌹.|𐍃𐌰𐌹 𐌾𐌰𐌷 𐍄𐍉𐌾𐌰 𐍃𐍉𐌺𐌴𐌹𐌽𐌰𐌹𐍃 𐌱𐌹𐌲𐌹𐍄𐌰𐌽𐌰.}}",
        "searchprofile-articles": "𐌷𐌰𐌱𐌰𐌽𐌳𐌰𐌽𐍃 𐌻𐌰𐌿𐌱𐍉𐍃",
        "searchprofile-images": "𐌼𐌰𐌽𐌰𐌲𐌼𐌰𐌹𐌳𐌾𐌰",
        "searchprofile-everything-tooltip": "𐍃𐍉𐌺𐌴𐌹 𐌰𐌻𐌻 𐌸𐌰𐍄𐌰 (𐌾𐌰𐌷 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌰𐌻𐌰𐌿𐌱𐌰𐌽𐍃)",
        "searchprofile-advanced-tooltip": "𐍃𐍉𐌺𐌴𐌹 𐌹𐌽 𐌱𐌹𐌿𐌷𐍄𐌰𐌹𐌼 𐌽𐌰𐌼𐌰𐍂𐌿𐌼𐌰𐌼",
        "search-result-size": "$1 ({{PLURAL:$2|•𐌰• 𐍅𐌰𐌿𐍂𐌳|•$2• 𐍅𐌰𐌿𐍂𐌳𐌰}})",
+       "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",
        "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|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍃|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐍉𐍃}}",
        "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": "𐌰𐌻𐌻𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃",
        "unwatch": "𐌿𐌽𐍅𐌹𐍄",
        "watchlist-details": "{{PLURAL:$1|$1 𐌻𐌰𐌿𐍆𐍃|$1 𐌻𐌰𐌿𐌱𐍉𐍃}} 𐌰𐌽𐌰 𐌸𐌴𐌹𐌽𐌰𐌹 𐍅𐌹𐍄𐌰𐍅𐌹𐌺𐍉𐌽 (𐌾𐌰𐌷 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌴 𐌻𐌰𐌿𐌱𐍉𐍃)",
        "wlheader-showupdated": "𐌻𐌰𐌿𐌱𐍉𐍃 𐌸𐌰𐌹𐌴𐌹 𐌹𐌽𐌼𐌰𐌹𐌳𐌹𐌳𐌰𐌹 𐍃𐌹𐌽𐌳 𐍆𐍂𐌰𐌼 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌼𐌼𐌰 𐌼𐌴𐌻𐌰 𐌸𐌰𐍄𐌴𐌹 𐌲𐌰𐍅𐌴𐌹𐍃𐍉𐌳𐌴𐍃 𐌱𐌰𐌽𐌳𐍅𐌹𐌳𐌰𐌹 𐍃𐌹𐌽𐌳 𐌹𐌽 <strong>𐍃𐍅𐌹𐌽𐌸𐌰𐌹𐌼 𐌱𐍉𐌺𐍉𐌼</strong>.",
+       "wlshowlast": "𐌱𐌰𐌽𐌳𐍅𐌴𐌹 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐍉𐍃 $1 𐍈𐌴𐌹𐌻𐍉𐍃, 𐌰𐍆𐍄𐌿𐌼𐌹𐍃𐍄𐌰𐌹 $2 𐌳𐌰𐌲𐍉𐍃",
        "watching": "𐍅𐌹𐍄𐌰𐌽𐌳𐍃...",
        "unwatching": "𐌿𐌽𐍅𐌹𐍄𐌰𐌽𐌳𐍃...",
        "created": "𐌲𐌰𐍃𐌺𐌰𐍀𐌾𐌰𐌽",
        "rollbacklink": "𐌰𐍆𐍅𐌰𐌻𐍅𐌴𐌹",
        "rollbacklinkcount": "𐌰𐍆𐍅𐌰𐌻𐍅𐌴𐌹 $1 {{PLURAL:$1|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽|𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹𐌽𐌹𐌽𐍃}}",
        "protectlogpage": "𐍆𐍂𐌹𐌸𐌿𐌲𐌰𐍆𐌰𐍃𐍄𐌰𐌹𐌽𐍃",
+       "protectedarticle": "𐌲𐌰𐍆 \"[[$1]]\" 𐌼𐌿𐌽𐌳",
+       "modifiedarticleprotection": "𐌹𐌽𐌼𐌰𐌹𐌳𐌹𐌳𐌰 𐌷𐌰𐌿𐌷𐌹𐌸𐌰 𐌼𐌿𐌽𐌳𐌹𐍃 𐍆𐌰𐌿𐍂 \"[[$1]]\"",
        "prot_1movedto2": "[[$1]] 𐌼𐌹𐌸𐍃𐌰𐍄𐌹𐌸 𐌳𐌿 [[$2]]",
        "protect-default": "𐌰𐌽𐌳𐌻𐌴𐍄 𐌰𐌻𐌻𐌰𐌹𐌼 𐌱𐍂𐌿𐌺𐌾𐌰𐌽𐌳𐌰𐌼",
        "protect-level-sysop": "𐌰𐌽𐌳𐌻𐌴𐍄𐌹𐌸 𐌸𐌰𐍄𐌰𐌹𐌽𐌴𐌹 𐍂𐌴𐌹𐌺𐍃",
        "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": "𐌹𐍆𐍄𐌿𐌼𐌰𐌹 𐌻𐌰𐌿𐌱𐍉𐍃 𐌱𐍂𐌹𐌲𐌲𐌰𐌽𐌳 𐌸𐌿𐌺  <strong>$2</strong>:",
+       "nolinkshere": "𐌽𐌹 𐌻𐌰𐌿𐌱𐍉𐍃 𐌲𐌰𐍅𐌹𐌳𐌰𐌽𐌳 𐌳𐌿 <strong>$2</strong>.",
        "isredirect": "𐌰𐌻𐌾𐌰𐍂 𐌱𐍂𐌹𐌲𐌲𐌰𐌽𐌳𐍃 𐌻𐌰𐌿𐍆𐍃",
        "istemplate": "𐍄𐍂𐌰𐌽𐍃𐌺𐌻𐌿𐍃𐌾𐍉",
        "isimage": "𐍆𐌰𐌾𐌻𐌰𐌲𐌰𐍅𐌹𐍃𐍃",
        "export": "𐌿𐍄𐌱𐌰𐌹𐍂 𐌻𐌰𐌿𐌱𐌰𐌽𐍃",
        "allmessages-filter-translate": "𐌲𐌰𐍃𐌺𐌴𐌹𐍂𐌴𐌹",
        "thumbnail-more": "\n𐌼𐌹𐌺𐌹𐌻𐌴𐌹",
+       "importlogpage": "𐌹𐌽𐌽𐌰𐍄𐌱𐌰𐌹𐍂 𐌻𐌰𐌿𐌲",
        "tooltip-pt-userpage": "{{GENDER:|Your user}} 𐌻𐌰𐌿𐍆𐍃",
        "tooltip-pt-mytalk": "{{GENDER:|𐌸𐌴𐌹𐌽𐍃}} 𐌻𐌰𐌿𐍆𐍃 𐌲𐌰𐍅𐌰𐌿𐍂𐌳𐌾𐌹𐍃",
        "tooltip-pt-preferences": "{{GENDER:|Your}} 𐌲𐌰𐌻𐌴𐌹𐌺𐌰𐌽𐌳𐌴𐌹𐌽𐍃 𐍅𐌰𐌹𐌷𐍄𐍃",
        "tooltip-undo": "\"𐌽𐌹𐌿𐍃𐌺𐌰𐍀𐌾𐌰𐌽\" 𐌱𐌰𐌺𐌼𐌰𐌹𐌳𐌾𐌹𐌸 𐌹𐌽𐌼𐌰𐌹𐌳𐌲𐌴𐌹𐌽𐍃 𐌾𐌰𐌷 𐌿𐍃𐌻𐌿𐌺𐍉𐌸 𐌼𐌰𐌹𐌳𐌾𐌰𐍆𐍉𐍂𐌼𐍉𐌽 𐍃𐍅𐌴 𐍆𐌰𐌿𐍂𐍃𐌰𐌹𐍈𐌰 𐌷𐌹𐍅𐌾𐌰. 𐌸𐌰𐍄𐌰 𐌻𐌴𐍄 𐌰𐌽𐌰𐌿𐌺𐌰𐌽𐌰𐌽 𐍃𐌰𐌿𐌸𐌰 𐌹𐌽 𐌹𐌽𐌽𐌰𐌷𐌰𐌻𐌳𐌰𐌰𐌽𐌲𐌰𐌱𐌰.",
        "tooltip-summary": "𐌼𐌴𐌻𐌴𐌹 𐌻𐌴𐌹𐍄𐌹𐌻𐌰 𐌰𐍆𐌼𐌰𐌿𐍂𐌲𐌴𐌹𐌽",
        "simpleantispam-label": "𐌰𐌽𐍄𐌹-𐍃𐍀𐌰𐌼 𐍃𐍉𐌺𐌴𐌹𐌽𐍃.\n<strong>𐌽𐌹</strong> 𐌼𐌴𐌻𐌴𐌹 𐌷𐌴𐍂!",
+       "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)",
        "tags-source-header": "𐌱𐍂𐌿𐌽𐌽𐌰",
        "tags-actions-header": "𐍄𐍉𐌾𐌰",
        "tags-active-yes": "𐌾𐌰𐌹",
+       "tags-active-no": "𐌽𐌴",
        "tags-source-none": "𐌽𐌹 𐌾𐌿 𐌱𐍂𐌿𐌺𐌾𐌰𐌳𐌰",
        "tags-edit": "𐌹𐌽𐌼𐌰𐌹𐌳𐌴𐌹",
        "tags-delete": "𐌿𐍃𐌽𐌹𐌼",
        "logentry-delete-delete": "$1 {{GENDER:$2|𐌿𐍃𐌽𐌰𐌼}} 𐌻𐌰𐌿𐍆 $3",
        "logentry-move-move": "$1 {{GENDER:$2|𐌼𐌹𐌸𐍃𐌰𐍄𐌹𐌳𐌰}} 𐌻𐌰𐌿𐍆 $3 𐌳𐌿 $4",
        "logentry-newusers-create": "𐌱𐍂𐌿𐌺𐌾𐌰𐌺𐌰𐍅𐍄𐍃𐌾𐍉 $1 𐍅𐌰𐍃 𐌲𐌰𐍃𐌺𐌰𐍀𐌰𐌽𐌰",
+       "logentry-upload-upload": "$1 {{GENDER:$2|𐌿𐍆𐌰𐍂𐌱𐌰𐍂}} $3",
        "rightsnone": "(𐌽𐌹)",
        "searchsuggest-search": "𐍃𐍉𐌺𐌴𐌹",
        "duration-days": "$1 {{PLURAL:$1|𐌳𐌰𐌲𐍃|𐌳𐌰𐌲𐍉𐍃}}"
index 37efd6e..7dc33b5 100644 (file)
        "thumbnail_error_remote": "הודעת שגיאה של $1:\n$2",
        "djvu_page_error": "דף ה־DjVu מחוץ לטווח",
        "djvu_no_xml": "לא ניתן היה לקבל את ה־XML עבור קובץ ה־DjVu",
-       "thumbnail-temp-create": "×\9c×\90 ×\94צ×\9c×\99×\97×\94 ×\99צ×\99רת ×§×\95×\91×¥ ×ª×\9e×\95× ×\94 ×\9e×\9e×\95×\96ערת זמני",
+       "thumbnail-temp-create": "×\9c×\90 ×\94×\99×\99ת×\94 ×\90פשר×\95ת ×\9c×\99צ×\95ר ×\90ת ×§×\95×\91×¥ ×\94ת×\9e×\95× ×\94 ×\94×\9e×\9e×\95×\96ערת ×\94זמני",
        "thumbnail-dest-create": "לא הייתה אפשרות לשמור את התמונה הממוזערת אל יעדה",
        "thumbnail_invalid_params": "פרמטרים שגויים לתמונה הממוזערת",
        "thumbnail_toobigimagearea": "קובץ בגודל של יותר מ־$1",
        "thumbnail_dest_directory": "לא ניתן היה ליצור את תיקיית היעד",
        "thumbnail_image-type": "סוג התמונה אינו נתמך",
-       "thumbnail_gd-library": "הגדרת הספריה GD אינה שלמה: חסרה הפונקציה $1",
+       "thumbnail_gd-library": "×\94×\92×\93רת ×\94ספר×\99×\99×\94 GD ×\90×\99× ×\94 ×©×\9c×\9e×\94: ×\97סר×\94 ×\94פ×\95נקצ×\99×\94 $1",
        "thumbnail_image-size-zero": "נראה שקובץ התמונה הוא בגודל אפס.",
        "thumbnail_image-missing": "נראה שהקובץ הבא חסר: $1",
        "thumbnail_image-failure-limit": "היו לאחרונה ניסיונות רבים מדי ($1 או יותר) ליצור את התמונה הממוזערת הזאת. נא לנסות שוב מאוחר יותר.",
        "import-upload-username-prefix": "קידומת בינוויקי:",
        "import-assign-known-users": "הקצאת העריכות למשתמשים המקומיים כאשר משתמשים בשמות זהים קיימים באתר המקומי",
        "import-comment": "הערה:",
-       "importtext": "נא לייצא את הקובץ מאתר המקור באמצעות ב[[Special:Export|כלי הייצוא]].\nשמרו אותו למחשב שלכם והעלו אותו לכאן.",
+       "importtext": "נא לייצא את הקובץ מאתר המקור באמצעות [[Special:Export|כלי הייצוא]].\nיש לשמור אותו במחשב ולהעלות אותו לכאן.",
        "importstart": "ייבוא דפים...",
        "import-revision-count": "&rlm;{{PLURAL:$1|גרסה אחת|$1 גרסאות}}",
        "importnopages": "אין דפים לייבוא.",
        "importsuccess": "הייבוא הושלם בהצלחה!",
        "importnosources": "לא הוגדרו אתרי ויקי שמהם ניתן לייבא, ואפשרות ההעלאה הישירה של דף עם היסטוריה מבוטלת.",
        "importnofile": "לא הועלה קובץ ייבוא.",
-       "importuploaderrorsize": "העלאת קובץ הייבוא נכשלה. הקובץ היה גדול יותר מגודל ההעלאה המותר.",
-       "importuploaderrorpartial": "העלאת קובץ הייבוא נכשלה. הקובץ הועלה באופן חלקי בלבד.",
-       "importuploaderrortemp": "העלאת קובץ הייבוא נכשלה. חסרה תיקייה זמנית.",
+       "importuploaderrorsize": "העלאת קובץ הייבוא נכשלה.\nהקובץ היה גדול יותר מגודל ההעלאה המותר.",
+       "importuploaderrorpartial": "העלאת קובץ הייבוא נכשלה.\nהקובץ הועלה באופן חלקי בלבד.",
+       "importuploaderrortemp": "העלאת קובץ הייבוא נכשלה.\nחסרה תיקייה זמנית.",
        "import-parse-failure": "שגיאה בפענוח ה־XML",
        "import-noarticle": "אין דף לייבוא!",
-       "import-nonewrevisions": "×\9b×\9c ×\94×\92רס×\90×\95ת ×\99×\95×\91×\90×\95 ×\91×¢×\91ר.",
+       "import-nonewrevisions": "×\9c×\90 ×\99×\95×\91×\90×\95 ×\92רס×\90×\95ת (×\9b×\95×\9c×\9f ×\9b×\91ר ×§×\99×\99×\9e×\95ת, ×\90×\95 ×©×\94×\9f ×\9c×\90 ×\94×\95×¢×\9c×\95 ×¢×§×\91 ×©×\92×\99×\90×\95ת).",
        "xml-error-string": "$1 בשורה $2, עמודה $3 (בית מספר $4): $5",
        "import-upload": "העלאת קובץ XML",
        "import-token-mismatch": "נתוני ההתחברות אבדו.\n\nייתכן שנותקתם מהחשבון. '''אנא ודאו שאתם עדיין מחוברים לחשבון ונסו שוב.'''\nאם זה עדיין לא עובד, נסו [[Special:UserLogout|לצאת מהחשבון]] ולהיכנס אליו שנית, וודאו שהדפדפן שלכם מאפשר קבלת עוגיות מאתר זה.",
        "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|אפשרות שגויה|אפשרויות שגויות}}: <nowiki>$1</nowiki>",
        "import-logentry-interwiki-detail": "{{PLURAL:$1|גרסה אחת של הדף $2 יובאה|$1 גרסאות של הדף $2 יובאו}}",
        "javascripttest": "בדיקת JavaScript",
        "javascripttest-pagetext-unknownaction": "הפעולה \"$1\" אינה ידועה.",
-       "javascripttest-qunit-intro": "ר×\90×\95 ×\90ת [$1 תיעוד הבדיקות] באתר mediawiki.org.",
+       "javascripttest-qunit-intro": "× ×\99ת×\9f ×\9c×¢×\99×\99×\9f ×\91[$1 תיעוד הבדיקות] באתר mediawiki.org.",
        "tooltip-pt-userpage": "דף {{GENDER:|המשתמש|המשתמשת}} שלך",
-       "tooltip-pt-anonuserpage": "×\93×£ ×\94×\9eשת×\9eש ×©×\9c ×\9eשת×\9eש ×\90× ×\95× ×\99×\9e×\99 ×\96×\94",
+       "tooltip-pt-anonuserpage": "×\93×£ ×\94×\9eשת×\9eש ×©×\9c ×\9bת×\95×\91ת IP ×\96×\95",
        "tooltip-pt-mytalk": "דף השיחה שלך",
-       "tooltip-pt-anontalk": "דיון על העריכות שנעשו מכתובת ה־IP הזאת",
+       "tooltip-pt-anontalk": "דיון על העריכות שנעשו מכתובת IP זו",
        "tooltip-pt-preferences": "ההעדפות שלך",
        "tooltip-pt-watchlist": "רשימת הדפים {{GENDER:|שאתה עוקב|שאת עוקבת}} אחרי השינויים בהם",
        "tooltip-pt-mycontris": "רשימת העריכות שביצעת",
index 2f14407..97b169e 100644 (file)
        "botpasswords-restriction-failed": "A botjelszó-korlátozások megakadályozzák ezt a bejelentkezést.",
        "botpasswords-invalid-name": "A megadott felhasználónév nem tartalmazza a botjelszó-elválasztót („$1”).",
        "botpasswords-not-exist": "A(z) „$1” felhasználó nem rendelkezik „$2” nevű botjelszóval.",
+       "botpasswords-needs-reset": "„$1” {{GENDER:$1|felhasználó}} „$2” botjának jelszavát vissza kell állítani.",
        "resetpass_forbidden": "A jelszavak nem változtathatók meg",
        "resetpass_forbidden-reason": "A jelszavakat nem változtathatóak meg: $1",
        "resetpass-no-info": "Be kell jelentkezned, hogy közvetlenül elérd ezt a lapot.",
        "rcfilters-watchlist-showupdated": "Az újabb változtatások, amiket még nem néztél meg, <strong>vastagítva</strong> láthatók, kitöltött jelzőkkel.",
        "rcfilters-preference-label": "A friss változtatások fejlesztett változatának elrejtése",
        "rcfilters-preference-help": "A 2017-es felületátdolgozás és minden azóta hozzáadott eszköz visszaállítása.",
+       "rcfilters-watchlist-preference-label": "A Figyelőlista fejlesztett változatának elrejtése",
+       "rcfilters-watchlist-preference-help": "A 2017-es felületátdolgozás és minden azóta hozzáadott eszköz visszaállítása.",
        "rcfilters-filter-showlinkedfrom-label": "A következő lapra hivatkozó lapok változtatásainak megjelenítése",
        "rcfilters-filter-showlinkedfrom-option-label": "A kiválasztott <strong>lapról</strong> hivatkozott lapok",
        "rcfilters-filter-showlinkedto-label": "A következő lapról hivatkozott lapok változtatásainak megjelenítése",
        "dellogpage": "Törlési napló",
        "dellogpagetext": "Itt láthatók a legutóbb törölt lapok.",
        "deletionlog": "törlési napló",
+       "log-name-create": "Laplétrehozási napló",
+       "log-description-create": "Itt láthatók a legutóbb létrehozott lapok.",
+       "logentry-create-create": "$1 {{GENDER:$2|létrehozta}} a következő lapot: $3",
        "reverted": "Visszaállítva a korábbi változatra",
        "deletecomment": "Ok:",
        "deleteotherreason": "További indoklás:",
        "passwordpolicies-policy-minimumpasswordlengthtologin": "A jelszónak legalább $1 karakterből kell állnia a bejelentkezéshez",
        "passwordpolicies-policy-passwordcannotmatchusername": "A jelszó nem lehet azonos a felhasználónévvel",
        "passwordpolicies-policy-passwordcannotmatchblacklist": "A jelszó nem lehet azonos a feketelistán szereplő jelszavakkal.",
-       "passwordpolicies-policy-maximalpasswordlength": "A jelszó legfeljebb $1 karakter hosszú lehet"
+       "passwordpolicies-policy-maximalpasswordlength": "A jelszó legfeljebb $1 karakter hosszú lehet",
+       "passwordpolicies-policy-passwordcannotbepopular": "A jelszó nem {{PLURAL:$1|lehet a gyakran használt jelszó|szerepelhet a(z) $1 leggyakrabban használt jelszó listáján}}"
 }
index 69b73bf..bf3d2df 100644 (file)
@@ -12,7 +12,8 @@
                        "ElizaMag",
                        "Adam-Yourist",
                        "Matma Rex",
-                       "Tusholi"
+                       "Tusholi",
+                       "Kaganer"
                ]
        },
        "tog-underline": "ТIатовжамá кIала така хьакхар:",
        "copyrightpage": "{{ns:project}}:Автора бокъонаш",
        "currentevents": "Карарча хана хинна хIамаш",
        "currentevents-url": "Project:Карарча хана хинна хӏамаш",
-       "disclaimers": "Бехктокхам тIацаэцар",
-       "disclaimerpage": "Project:Бехктокхам тIацаэцар",
+       "disclaimers": "Бехктокхам тӀацаэцар",
+       "disclaimerpage": "Project:Бехктокхам тӀацаэцар",
        "edithelp": "Хувцам бара новкъостал",
        "helppage-top-gethelp": "Новкъoстал",
        "mainpage": "Керттера оагӀув",
        "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",
        "prefs-developertools": "Кийчдархочун кечалаш",
        "prefs-preview": "Хьалххе бIаргтохар",
        "prefs-advancedrc": "Кхыдола шердаь оттамаш",
-       "prefs-opt-out": "Алсамдалар тIацаэцар",
+       "prefs-opt-out": "Алсамдалар тӀацаэцар",
        "prefs-advancedrendering": "Кхыдола шердаь оттамаш",
        "prefs-advancedsearchoptions": "Шердаь оттамаш",
        "prefs-advancedwatchlist": "Кхыдола шердаь оттамаш",
        "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": "ший зема хьаязъяьрага хьажар",
        "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)",
        "undelete-search-submit": "Хьалáха",
        "namespace": "ЦIерий моттигаш:",
        "invert": "Хержар юхадаккха",
-       "tooltip-invert": "Ð\9eÑ\82Ñ\82ае ÐµÑ\80 Ð±ÐµÐ»Ð³Ð°Ð»Ð¾, Ñ\85еÑ\80жа Ñ\86IеÑ\80ий Ð°Ñ\80е Ñ\87Ñ\83 Ð° (белгалÑ\8aÑ\8fÑ\8c Ñ\8fле Ð²IаÑ\88агIÑ\8aÑ\8eвзаенна Ñ\86IеÑ\80ий Ð°Ñ\80е Ñ\87Ñ\83 Ð°), Ð¾Ð°Ð³IонаÑ\88 Ñ\82Iа Ð° Ð´Ð°Ñ\8c хувцамаш къайладоахаргдолаш",
+       "tooltip-invert": "Ð\9eÑ\82Ñ\82ае ÐµÑ\80 Ð±ÐµÐ»Ð³Ð°Ð»Ð¾, Ñ\85еÑ\80жа Ñ\86IеÑ\80ий Ð¼ÐµÑ\82Ñ\82ига Ð´Ð¾Ð°Ð·Ð¾Ð½ Ñ\87Ñ\83Ñ\85Ñ\8c (белгалÑ\8aÑ\8fÑ\8c Ñ\8fле Ð²IаÑ\88агIÑ\8aÑ\8eвзаеннаÑ\87а Ñ\86IеÑ\80ий Ð¼ÐµÑ\82Ñ\82игаÑ\88ка Ð°) Ð¾Ð°Ð³IонаÑ\88 Ñ\82Iа Ð´Ð°Ñ\8c Ð´Ð¾Ð»Ð° хувцамаш къайладоахаргдолаш",
        "namespace_association": "ВIашагIйийхка моттиг",
-       "tooltip-namespace_association": "Оттае ер белгало, иштта хержа цIерий ареца вIашагIъювзаенна дувца оттадара цIерий аре (е кхыяр) юкъейоаккхаргйолаш",
+       "tooltip-namespace_association": "Оттае ер белгало, иштта хьахержача цIерий меттигаца вIашагIъювзаенна дувцара цIерий моттиг (е кхыяр) юкъейоаккхаргйолаш",
        "blanknamespace": "(Кертера)",
        "contributions": "{{GENDER:$1|Доакъашхочун}} къахьегам",
        "contributions-title": "{{GENDER:$1|Доакъашхочун}} $1 къахьегам",
index abef8c8..1438232 100644 (file)
        "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.",
        "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",
        "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 <strong>stûr</strong> 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 <strong>stûr</strong> 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",
        "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ê",
        "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",
        "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ê",
        "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.",
        "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",
        "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",
index 9e3d542..f2c9726 100644 (file)
@@ -12,7 +12,8 @@
                        "Angel Blaise",
                        "Fitoschido",
                        "Robin van der Vliet",
-                       "Mafcadio"
+                       "Mafcadio",
+                       "Matěj Suchánek"
                ]
        },
        "tog-underline": "Sulini de lias:",
        "logentry-delete-restore": "$1 {{GENDER:$2|restora}} paje $3 ($4)",
        "logentry-delete-restore-nocount": "$1 {{GENDER:$2|restora}} paje $3",
        "restore-count-revisions": "{{PLURAL:$|1 revisa|$1 revisas}}",
-       "restore-count-files": "{{PLURAL:$|1 fix|$1 fixes}}",
+       "restore-count-files": "{{PLURAL:$1|1 fix|$1 fixes}}",
        "logentry-delete-event": "$1 {{GENDER:$2|cambia}} la vidablia de {{PLURAL:$5|un entrada|$5 entradas}} de rejistra en $3: $4",
        "logentry-delete-revision": "$1 {{GENDER:$2|cambia}} la vidablia de {{PLURAL:$5|un revisa|$5 revisas}} en paje $3: $4",
        "logentry-delete-event-legacy": "$1 {{GENDER:$2|cambia}} la vidablia de entradas de rejistra en $3",
index 4ef38de..fb977f9 100644 (file)
@@ -16,7 +16,8 @@
                        "Nemo bis",
                        "S4b1nuz E.656",
                        "Ruthven",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "Sannita"
                ]
        },
        "tog-underline": "Sottolinia 'e jonte:",
        "readonly": "Database arrestato",
        "enterlockreason": "Miette 'o mutivo 'e blocco, nzieme a 'o mumento quanno se penza ca 'o blocco se sarrà fernuto",
        "readonlytext": "Mo mmo 'o database s'è arrestato pe n'operazione semprice 'e manutenzione e nun se ponno azzeccà cagnamiente o pàggene nove. Quanno sarrà fernuta, atanno 'a paggena addeventarrà nurmale.\n\nL'ammenistratore 'e sistema c'ha fatto 'o blocco, nce dà sta spiegazione: $1",
-       "missing-article": "'O database nun trova 'o testo 'e na paggena c'adda stà, c' 'o nomme \"$1\" $2.\n\nNormalmente, chesto succere quanno s'è richiamato, a partire d' 'a cronologgia o pùre a 'o confronto tra verzione, nu cullegamento a na paggena scancellata, a nu confronto tra verziune inesistente o a nu confronto tra verziune re-pulezzate d' 'a cronologgia.\n\n'N caso cuntrario, può darse pure nu sbaglio dint'o software.\nPer piacere, mannate na mmasciata ccà all'[[Special:ListUsers/sysop|amministratore]] annummenanno l'URL 'n quistiona.",
+       "missing-article": "'O database nun trova 'o testo 'e na paggena ca c'avess' a stà, c' 'o nomme \"$1\" $2.\n\nNurmalmente, chisto succere quanno s'è richiammato na cronologgia o pùre a nu confronto tra verzione 'e a na paggena scancellata.\n\n'N caso cuntrario, può darse pure nu sbaglio dint'o software.\nPe ppiacere, mannate na mmasciata ccà all'[[Special:ListUsers/sysop|amministratore]] annummenanno l'URL 'n quistiona.",
        "missingarticle-rev": "(nummero 'e verzione: $1)",
        "missingarticle-diff": "(Diff: $1, $2)",
        "readonly_lag": "'O database s'è arrestato automaticamente pe' tramente ca 'e servers 'e database schiave sincronizzano c' 'o server masto.",
        "cascadeprotected": "Sta paggena è stata prutetta 'a 'o cangamento pecché trascluse int'a {{PLURAL:$1|sta paggena, che è prutetta|sti paggene, che songo prutette}} quann' 'a l'ozione \"ricurziva\" è attiva:\n$2",
        "namespaceprotected": "Nun avite permesso a cagnà 'e paggene dint'a stu namespace '''$1'''.",
        "customcssprotected": "Nun v'è permesso 'a cagnà sta paggena CSS, pecché cuntene 'e mpustaziune perzunale 'e n'at'utente.",
+       "customjsonprotected": "Nun v'è permesso 'a cagnà sta paggena JSON, pecché cuntene 'e mpustaziune perzunale 'e n'at'utente.",
        "customjsprotected": "Nun v'è permesso 'a cagnà sta paggena JavaScript, pecché cuntene 'e mpustaziune perzunale 'e n'at'utente.",
        "mycustomcssprotected": "Nun v'è permesso 'a cagnà sta paggena CSS.",
+       "mycustomjsonprotected": "Nun v'è permesso 'a cagnà sta paggena JSON.",
        "mycustomjsprotected": "Nun v'è licenzia pe cagnà sta paggena JavaScript.",
        "myprivateinfoprotected": "Nun v'è licenzia pe cagnà 'a nfurmaziona privata vuosta.",
        "mypreferencesprotected": "Nun v'è licenzia 'a cagnà 'e preferenze tuoje.",
        "nosuchusershort": "Nun ce stanno utente cu o nòmme \"$1\". Cuntrolla si scrivìste buòno.",
        "nouserspecified": "Tiene 'a dìcere nu nomme pricìso.",
        "login-userblocked": "Chist'utente è bloccato. Nun se può effettuà 'o login.",
-       "wrongpassword": "'A password nzertàta nun è bbona.\nPe' piacere pruvate n'ata vota.",
+       "wrongpassword": "'A password nzertàta nun è bbona. Pe' piacere, pruvate n'ata vota.",
        "wrongpasswordempty": "'A password nzertàta è abbacante.\nPe' piacere pruvate n'ata vota.",
        "passwordtooshort": "'E password hann'avé minimo {{PLURAL:$1|nu carattere|$1 carattere}}.",
        "passwordtoolong": "'E password nun ponno essere cchiù luonghe 'e {{PLURAL:$1|nu carattere|$1 carattere}}.",
-       "passwordtoopopular": "'E parole comune nun se ponno ausà pe' ve fà na password. Sciglite na password cchiù unica.",
+       "passwordtoopopular": "'E parole comune nun se ponno ausà comme password. Scigliteve na password cchiù tosta.",
        "password-name-match": "'A password adda essere diverza 'a 'o nomme utente.",
        "password-login-forbidden": "L'uso 'e stu nomme utente e password è stato proibito.",
        "mailmypassword": "Riabbìa 'a password",
        "botpasswords-existing": "Password bot esistente",
        "botpasswords-createnew": "Crèa na password bot nòva",
        "botpasswords-editexisting": "Cagna na password bot esistente",
+       "botpasswords-label-needsreset": "('a password adda esse cangiata)",
        "botpasswords-label-appid": "Nomme d' 'o bot:",
        "botpasswords-label-create": "Crèa",
        "botpasswords-label-update": "Agghiuorna",
        "botpasswords-insert-failed": "Nun se pò azzeccà 'o nomme bot \"$1\". Fosse stato già azzeccato?",
        "botpasswords-update-failed": "Se scassaje a carrecà 'o nomme bot \"$1\". È stato scancellato?",
        "botpasswords-created-title": "Password bot criata",
-       "botpasswords-created-body": "'A password bot \"$1\" 'a ll'utente \"$2\" fuje criata.",
+       "botpasswords-created-body": "'A password pe' 'o bot \"$1\" 'e ll'{{GENDER:$2|utente}} \"$2\" fuje criata.",
        "botpasswords-updated-title": "Password bot agghiurnata",
-       "botpasswords-updated-body": "'A password bot \"$1\" 'a ll'utente \"$2\" fuje agghiurnata.",
+       "botpasswords-updated-body": "'A password pe' 'o bot \"$1\" 'e ll'{{GENDER:$2|utente}} \"$2\" fuje agghiurnata.",
        "botpasswords-deleted-title": "Password bot scancellata",
-       "botpasswords-deleted-body": "'A password bot \"$1\" 'a ll'utente \"$2\" è stata scancellata.",
+       "botpasswords-deleted-body": "'A password pe' 'o bot \"$1\" 'e ll'{{GENDER:$2|utente}} \"$2\" è stata scancellata.",
        "botpasswords-newpassword": "'A password nòva pe' puté trasì cu <strong>$1</strong> è <strong>$2</strong>. <em>Pe' piacere signatevello chesto pe' ve ffà conzurtaziune future.</em> <br>('E bott viecchie addò servisse nu nomme utente comm'a chell' 'e l'utente, putite ancora ausà <strong>$3</strong> comm' 'o nomm' 'utente e <strong>$4</strong> comm' 'a password.)",
        "botpasswords-no-provider": "BotPasswordsSessionProvider nun è disponibbele.",
        "botpasswords-restriction-failed": "'E restriziune 'e password bot nun ve permettessero st'acciesso.",
        "botpasswords-invalid-name": "'O nomme utente nnecato nun cuntenesse nu spartetóre 'e bot password (\"$1\").",
        "botpasswords-not-exist": "L'utente \"$1\" nun téne na password bot chiammata \"$2\".",
+       "botpasswords-needs-reset": "'A password pe' 'o bot \"$1\" 'e ll'{{GENDER:$2|utente}} \"$2\" adda esse cangiata.",
        "resetpass_forbidden": "'E password nun se ponno cagnà",
        "resetpass_forbidden-reason": "'E password nun se ponno cagnà: $1",
        "resetpass-no-info": "Avite 'a trasì ('o login) pe ffà l'acciesso a sta paggena direttamente.",
        "savechanges": "Sarva 'e cagnamiénte",
        "publishpage": "Pubbreca paggena",
        "publishchanges": "Pubbreca 'e cagnamiente",
+       "savearticle-start": "Sarva 'a paggena...",
+       "savechanges-start": "Sarva 'e cagnamiénte...",
+       "publishpage-start": "Pubbreca 'a paggena...",
+       "publishchanges-start": "Pubbreca 'e cagnamiente...",
        "preview": "Anteprimma",
        "showpreview": "Vire anteprimma",
        "showdiff": "Fa veré 'e cagnamiente",
        "anonpreviewwarning": "''Nun avite fatto 'o login. Sarvann' 'a paggena, l'indirizzo IP d' 'o vuosto sarrà riggistrato dint'a cronologgia.''",
        "missingsummary": "'''Attenziò:''' nun s'è specificato l'oggetto 'e stu cagnamiento. Clicann' 'a \"$1\" n'ata vota 'o cagnamiento sarrà sarvato cu l'oggetto abbacante.",
        "selfredirect": "<strong>Attenziò:</strong> State crianno nu redirect a 'o stesso articolo.\nPuò darse c'avites specificato 'o pizzo sbagliato p' 'o redirect, o ca stavate cagnanno 'o pizzo sbagliato.\nSi cliccate \"$1\" n'ata vota, si criarrà 'o redirect.",
-       "missingcommenttext": "Pe' piacere scrivete nu commento ccà abbascio.",
+       "missingcommenttext": "Pe' piacere, scrivete nu commento.",
        "missingcommentheader": "<strong>Arricurdateve:</strong> nun s'è specificato l'oggetto/titolo pe stu commento. Clicann' 'a \"$1\" n'ata vota 'o cagnamiento sarrà sarvato c' 'o titolo/oggetto abbacante.",
        "summary-preview": "Anteprimma'e l'oggetto:",
        "subject-preview": "Anteprimma 'e l'oggetto:",
        "previewerrortext": "È succiesso n'errore quanno se steva a ffà pre-veré 'e cagnamiente vuoste.",
        "blockedtitle": "Utente bloccato.",
        "blockedtext": "<strong>'O nomme utente o ll'IP vuosto è stato bloccato.</strong>\n\n'O blocco è stato mpustato 'a $1. 'O mutivo d' 'o blocco è chisto: ''$2''\n\n* Abbiàta d' 'o blocco: $8\n* Ammaturità d' 'o blocco: $6\n* Tiempo 'e blocco: $7\n\nPutite cuntattà $1 o n'atu [[{{MediaWiki:Grouppage-sysop}}|ammenistratore]] pe discutere d'ô blocco.\n\nVedite c' 'a funzione \"{{int:emailuser}}\" nun è attiva si nun s'ave riggistrato 'o ndirizzo e-mail buono dint' 'e [[Special:Preferences|preferenze]] o pùre si ll'uso 'e tale funzione è stato bloccato.\n\n'O ndirizzo IP 'e mo è $3, 'o nummero ID d' 'o blocco è #$5.\nPe piacere avite 'a specificà tutte sti dettaglie quanno facite carche dumanna.",
-       "autoblockedtext": "Ll'IP vuosto è stato bloccato pecché 'o steva piglianno n'atu utente, ch'è stato bloccato pe' $1.\n\n'O mutivo d' 'o blocco è chesto:\n\n:''$2''\n\n* Abbiàta d' 'o blocco: $8\n* Ammaturità d' 'o blocco: $6\n* Tiempo 'e blocco: $7\n\nPutite cuntattà $1 o n'atu [[{{MediaWiki:Grouppage-sysop}}|ammenistratore]] pe' discutere 'o blocco.\n\nVedite c' 'a funzione 'Scrivete a ll'utente' nun è attiva si nun s'è riggistrato 'o ndirizzo e-mail buono dint' 'e [[Special:Preferences|preferenze]] o pùre si ll'uso 'e tale funzione è stato bloccato.\n\n'O ndirizzo IP attuale è $3, 'o nummero ID d' 'o blocco è #$5.\nPe' piacere avite 'e specificà tutte sti dettaglie ccà ncoppa quanno facite cocche dumanna.",
+       "autoblockedtext": "Ll'IP vuosto è stato bloccato pecché 'o steva ausanno n'atu utente, ch'è stato bloccato 'a $1.\n\n'O mutivo d' 'o blocco è chesto:\n\n:''$2''\n\n* 'O blocco è abbiate: $8\n* 'O blocco fernesce: $6\n* Tiempo 'e blocco: $7\n\nPutite cuntattà $1 o n'atu [[{{MediaWiki:Grouppage-sysop}}|ammenistratore]] pe' discutere chisto blocco.\n\nVedite c' 'a funzione \"Scrivete a ll'utente\" è attiva sule si avite messe 'nu ndirizzo e-mail buono dint' 'e vostre [[Special:Preferences|preferenze]] e si nun siete state bloccato.\n\n'O ndirizzo IP attuale vostro è $3, 'o nummero ID d' 'o blocco è #$5.\n\nPe' piacere avite 'e specificà tutte sti dettaglie ccà ncoppa quanno facite cocche dumanna.",
        "systemblockedtext": "'O nomme utente d' 'o vuosto o ll'IP address songo stati automaticamente bluccati 'a MediaWiki.\n'O mutivo fosse chesto:\n\n:<em>$2</em>\n\n* Inizio d' 'o blocco: $8\n* Ammatura 'o blocco: $6\n* Intervall' 'e blocco: $7\n\n'O indirizzo IP fusse $3.\nPe piacere, facite specifice tutt' 'e ddettaglie ccà quanno iate a fà na richiesta 'e chiarimiente.",
        "blockednoreason": "nisciuna ragione è stata indicata",
        "whitelistedittext": "Pe' cagnà 'e ppaggene è necessario $1.",
        "blocked-notice-logextract": "St'utente è bloccato mò.\nL'urdemo elemento d' 'o riggistro 'e blocche è ripurtato ccà abbascio p'avé nu riferimento:",
        "clearyourcache": "<strong>Nota:</strong> aroppo sarvate putisse necessità 'e pulezzà 'a caché d' 'o navigatóre pe' vedé 'e cagnamiente. \n*<strong>Firefox / Safari</strong>: sprémme 'o buttóne maiuscole e ffà clic ncopp'a ''Recarreca'', o pure spremme ''Ctrl-F5'' o ''Ctrl-R'' (''⌘-R'' ncopp'a Mac)\n*<strong>Google Chrome''': spremme ''Ctrl-Shift-R'' (''⌘-Shift-R'' ncopp'a nu Mac)\n*<strong>Internet Explorer</strong>: spremme 'o buttóne ''Ctrl'' pe' tramente ca faie click ncopp'a ''Refresh'', o pure spremmere ''Ctrl-F5''\n* <strong>Opera:</strong> Vaje addò 'o <em>Menu → Mpustaziune</em> (<em>Opera → Mpustaziune</em> ncopp' 'o Mac) e po' ncopp'a <em>Privacy & sicurezza → Pulezza date d' 'o browser → Immaggene e file d' 'a cache</em>.",
        "usercssyoucanpreview": "'''Cunziglio:''' spremme 'o buttone 'Vide anteprimma' pe' pruvà 'o CSS nuovo apprimma d' 'o sarvà.",
+       "userjsonyoucanpreview": "<strong>Cunziglio:</strong> premme 'o buttone \"{{int:showpreview}}\" pe' pruvà 'o JSON nuovo apprimma d' 'o sarvà.",
        "userjsyoucanpreview": "'''Cunziglio:''' spremme 'o buttone 'Vide anteprimma' pe' pruvà 'o JavaScript nuovo apprimma d' 'o sarvà.",
        "usercsspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o CSS perzunale. 'E cagnamiente nun so' state ancora sarvate!'''",
+       "userjsonpreview": "<strong>Arricuordate ca chest'è sulamente n'anteprimma p' 'o JSON perzunale. 'E cagnamiente nun so' state ancora sarvate!</strong>",
        "userjspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o JavaScript perzunale. 'E cagnamiente nun so' state ancora sarvate!'''",
        "sitecsspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o CSS. 'E cagnamiente nun so' state ancora sarvate!'''",
+       "sitejsonpreview": "<strong>Arricuordate ca chest'è sulamente n'anteprimma d' 'a configurazzione d' 'o JSON. 'E cagnamiente nun so' state ancora sarvate!</strong>",
        "sitejspreview": "'''Arricuordate ca chest'è sulamente n'anteprimma p' 'o codece JavaScript. 'E cagnamiente nun so' state ancora sarvate!'''",
-       "userinvalidconfigtitle": "'''Attenziò:''' Nun esiste nisciuna skin c' 'o nomme \"$1\". Vide ch' 'e paggene .css e .js personalezzate teneno nu titolo n minucola, p'esempio {{ns:user}}:Esempio/vector.css e nun {{ns:user}}:Esempio/Vector.css.",
+       "userinvalidconfigtitle": "<strong>Attenziò:</strong> Nun esiste nisciuna skin c' 'o nomme \"$1\". Vide ch' 'e paggene .css e .js personalezzate teneno nu titolo ca minuscola, p'esempio {{ns:user}}:Esempio/vector.css (e no {{ns:user}}:Esempio/Vector.css).",
        "updated": "(Agghiurnato)",
        "note": "'''Nota:'''",
        "previewnote": "'''Chesta è sola n'anteprimma; 'e cagnamiénte â paggena nun songo ancora sarvate!'''",
        "yourtext": "'O testo vuosto",
        "storedversion": "A verziona int'a memoria",
        "editingold": "'''Attenziò: staje cagnanno na verziona nun agghiurnata d' 'a paggena. Si 'a sarve accussì, tutte 'e cagnamiente fatte aropp'a sta verziona sarranno sperdute.'''",
+       "unicode-support-fail": "Pare ca 'o browser vostro nun tene 'o supporto pe Unicode. 'E cagnamiente nun so' state sarvate, pecché Unicode è obbligatorio 'a tenè pe mudificà 'e paggene.",
        "yourdiff": "Differenze",
        "copyrightwarning": "Pe' piacere tenite a mmente ca tutte 'e contribbute a {{SITENAME}} songo cunziderate pubbrecate dint'e térmene d'uso d' 'a licienza $2 (vedite $1 pe n'avé cchiù dettaglie).\nSi nun vulite ca 'e testi vuoste fossero cagnate e distribuite 'a uno qualunque senza lémmeto, nun 'e mannate ccà.<br />\nMannanno stu testo dichiarate pùre, sott'a responsabilità vuosta, ch'è stato scritto 'a vuje perzunalmente o pure ca è stato copiato 'a na fonte n pubblico dominio o similarmente libbera.\n'''Nun mannate materiale prutetto 'a copyright senz'avé autorizzaziona!'''",
        "copyrightwarning2": "Pe' piacere tenite a mmente ca tutte 'e contribbute a {{SITENAME}} se ponno cagnà, alterà, o distribbuì pe l'ati cuntribbuttòre.\n\nSi nun vulite ca 'e teste vuoste fossero cagnàte spenzieratamente, nun 'e mannate ccà.<br />\nMannanno stu testo dichiarate pùre, sott'a responsabilità vosta, ch'è stato scritto 'a vuje perzunalmente o pure ca è stato copiato 'a na fonte n pubblico dominio o similarmente libbera (vedete $1 pe' n'avé dettaglie).\n'''Nun mannate materiale prutetto 'a copyright senza n'avé autorizzaziona!'''",
        "longpageerror": "'''Errore: 'o testo mannato è luongo {{PLURAL:$1|1|$1}} kilobyte, ch'è cchiù grosso d' 'a diminziona massima cunzentita ({{PLURAL:$2|1|$2}} kilobyte).'''\n'O testo nun se pò sarvà.",
        "readonlywarning": "<strong>Attenziò</strong>: 'o database è bloccato pe se ffà 'a manutenzione. P' 'o mumento nun se ponno sarvà 'e cagnamiente fatte.\nPe' nun 'e sperdere, copia sti cuntenute dint'a nu file 'e testo e sarvatillo pe' tramente c'aspiette 'o sblocco d' 'o database.\n\nL'ammenistratore 'e sistema ca mpustaje 'o blocco ave scritto sta spiegazione: $1.",
        "protectedpagewarning": "'''Attenziò: sta paggena è stata bloccata 'n modo tale ca sulamente l'utente ch' 'e privilegge d'ammenistratore 'a ponno cagnà.'''\nL'urdemo elemento d' 'o riggistro è scritto ccà abbascio pe' n'avé riferimento:",
-       "semiprotectedpagewarning": "'''Nota:''' Sta paggena è stata bloccata 'n modo ca sulamente l'utente riggistrate 'a ponno cagnà.\nL'urdemo elemento d' 'o riggistro è scritto ccà abbascio pe n'avé nfurmazione:",
+       "semiprotectedpagewarning": "<strong>Nota:</strong> Sta paggena è stata bloccata 'n modo ca sulamente l'utente autoconfermati 'a ponno cagnà. L'urdemo elemento d' 'o riggistro è scritto ccà abbascio pe n'avé nfurmazione:",
        "cascadeprotectedwarning": "<strong>Attenziò:</strong> Sta paggena è stata bloccata 'n modo ca sulamente l'utente ch' 'e [[Special:ListGroupRights|privilegge specifiche]] 'a ponno cagnà. Chesto succiere pecché 'a paggena è appennuta dint'a {{PLURAL:$1|la paggena innecata ccà abbascio, ch'è stata prutetta|'e paggene innecate ccà abbascio, che so' state prutette}} sciglienno 'a prutezione \"ricurziva\":",
        "titleprotectedwarning": "'''Attenziò: sta paggena è stata bloccata 'n modo ca fossero necessarie [[Special:ListGroupRights|deritte specifici]] p' 'a crià.'''\nL'urdemo elemento d' 'o riggistro è riportato ccà abbascio pe nfurmazione:",
        "templatesused": "{{PLURAL:$1|Template|Templates}} ausate 'a chesta paggena:",
        "contentmodelediterror": "Vuje nun putite cagnà sta verziona pecché 'o mudello d' 'e cuntenute è <code>$1</code>, ca cagnasse nu poco nfacc' 'o mudello d' 'a paggena  <code>$2</code> 'e mo.",
        "recreate-moveddeleted-warn": "'''Attenziò: staje a crià na paggena scancellata già.'''\n\nVire si è bbuono 'e cuntinuà a cagnà sta paggena. L'elenco ch' 'e relative scancellamiente e spustamente s'è scritto ccà abbascio pe' ffà comodo:",
        "moveddeleted-notice": "Sta paggena è stata scancellata.\n'A lista d' 'e relative scancellamiente e spustamente sta cca 'bbascio pe' n'avé 'nfurmazione.",
-       "moveddeleted-notice-recent": "Scusate, sta mmasciata è stata scancellata mo mo (dint'a sti 24 ore).\n\nL'aziune 'e scancellazione e spustamento pe' sta paggena so dispunibbele ccà p' 'a cumpretezza.",
+       "moveddeleted-notice-recent": "Scusate, sta paggena è stata scancellata mo mo (dint'a sti 24 ore).\n\nTutte l'azziune 'e scancellazione e spustamento pe' sta paggena so dispunibbele ccà pe' cumpretezza.",
        "log-fulllog": "Vide log sano",
        "edit-hook-aborted": "'O cagnamiento è stato annullato 'a 'o «hook».\nNun dette spiegazione nisciuna.",
        "edit-gone-missing": "Nun se può agghiurnà 'a paggena.\nPare ch' 'è stata scancellata.",
        "postedit-confirmation-created": "'A paggena è stata criata.",
        "postedit-confirmation-restored": "'A paggena è stata arripigliata.",
        "postedit-confirmation-saved": "'O cagnamiento è stato sarvato.",
+       "postedit-confirmation-published": "'E cagnamiente so' state pubbricate.",
        "edit-already-exists": "Nun se può crià na paggena nova.\nEsiste già.",
        "defaultmessagetext": "Mmasciata 'e testo predefinita",
        "content-failed-to-parse": "Nun se può analizzare $2 p' 'o mudello $1: $3",
index 6cb1240..fde0384 100644 (file)
        "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:",
index b2250c5..0810158 100644 (file)
@@ -20,7 +20,8 @@
                        "Fitoschido",
                        "Vriullop",
                        "Unuaiga",
-                       "Guilhelma"
+                       "Guilhelma",
+                       "Matěj Suchánek"
                ]
        },
        "tog-underline": "Soslinhar los ligams :",
        "title-invalid-characters": "Lo títol  de la pagina demandada conten de caractèrs invalids : « $1 ».",
        "title-invalid-relative": "Lo títol conten un camin relatiu. Los títols relatius (./, ../) son pas valids perque los navigadors web pòdon pas sovent i arribar.",
        "title-invalid-magic-tilde": "Lo títol de la pagina sollicitada conten una sequéncia de tildas pas valida (<nowiki>~~~</nowiki>).",
-       "title-invalid-too-long": "Lo títol de la pagina sollicitada es tròp long. A pas d’excedir  $ 1  {{PLURALA:$1|byte|bytes}} en codificacion UTF-8.",
+       "title-invalid-too-long": "Lo títol de la pagina sollicitada es tròp long. A pas d’excedir $1 {{PLURAL:$1|byte|bytes}} en codificacion UTF-8.",
        "title-invalid-leading-colon": "Lo títol de la pagina sollicitada conten dos ponches a la debuta.",
        "perfcached": "Las donadas seguendas son en cache e benlèu, son pas a jorn. Un maximum de {{PLURAL:$1|un resultat|$1 resultats}} es disponible dins lo cache.",
        "perfcachedts": "Las donadas seguendas son en cache e benlèu, son pas a jorn. Un maximum de {{PLURAL:$1|un resultat|$1 resultats}} es disponible dins lo cache.",
index 621a0af..e9ed794 100644 (file)
@@ -26,7 +26,8 @@
                        "Tow",
                        "Sony dandiwal",
                        "Stephanecbisson",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "Matěj Suchánek"
                ]
        },
        "tog-underline": "ਲਿੰਕ ਹੇਠ-ਲਾਈਨ:",
        "newpageletter": "ਨ",
        "boteditletter": "ਬੋਟ",
        "number_of_watching_users_pageview": "[$1 ਵੇਖ ਰਹੇ ਹਨ {{PLURAL:$1|ਯੂਜ਼ਰ}}]",
-       "rc-change-size-new": "$1 {{PLURAL:$|ਬਾਈਟ|ਬਾਈਟਾਂ}} ਤਬਦੀਲੀ ਤੋਂ ਬਾਅਦ",
+       "rc-change-size-new": "$1 {{PLURAL:$1|ਬਾਈਟ|ਬਾਈਟਾਂ}} ਤਬਦੀਲੀ ਤੋਂ ਬਾਅਦ",
        "newsectionsummary": "/* $1 */ ਨਵਾਂ ਭਾਗ",
        "rc-enhanced-expand": "ਵੇਰਵੇ ਵੇਖਾਓ",
        "rc-enhanced-hide": "ਵੇਰਵਾ ਲੁਕਾਓ",
index 8726c46..c6225ac 100644 (file)
        "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:",
        "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ą”",
        "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",
index ef43e18..3f5a2e7 100644 (file)
@@ -19,7 +19,8 @@
                        "Macofe",
                        "Matma Rex",
                        "Fitoschido",
-                       "Paolo Castellina"
+                       "Paolo Castellina",
+                       "Matěj Suchánek"
                ]
        },
        "tog-underline": "Anliure con la sotliniadura",
        "largefileserver": "St'archivi-sì a resta pì gròss che lòn che la màchina sentral a përmet.",
        "emptyfile": "L'archivi che a l'ha pen-a carià a smija veujd.\nSòn a podrìa esse rivà përchè che chiel a l'ha scrivù mal ël nòm dl'archivi midem.\nPër piasì che a contròla se a l'é pro cost l'archivi che a veul carié.",
        "windows-nonascii-filename": "Sta wiki-sì a manten pa ij nòm d'archivi con caràter speciaj.",
-       "fileexists": "N'archivi con ës nòm-sì a-i é già, për piasì che a contròla <strong>[[:$1]]</strong> se {{GENDER|a}} l'é pa sigur dë vorèj cangelo.\n[[$1|thumb]]",
+       "fileexists": "N'archivi con ës nòm-sì a-i é già, për piasì che a contròla <strong>[[:$1]]</strong> se {{GENDER:|a}} l'é pa sigur dë vorèj cangelo.\n[[$1|thumb]]",
        "filepageexists": "La pàgina ëd descrission për st'archivi-sì a l'é già stàita creà an <strong>[[:$1]]</strong>, mach ch'a-i é gnun archivi ch'as ciama parèj.\nLòn ch'a buta për somari as ës-ciairerà nen ant la pàgina ëd descrission.\nPër podèj buté sò somari a l'ha da modifichesse la pàgina a man.\n[[$1|thumb]]",
        "fileexists-extension": "N'archivi con ës nòm-sì a-i é già: [[$2|thumb]]\n* Nòm dl'archivi ch'as carìa: <strong>[[:$1]]</strong>\n* Nòm dl'archivi ch'a-i é già: <strong>[[:$2]]</strong>\nVeul-lo dle vire dovré un nòm pi esplìssit?",
        "fileexists-thumbnail-yes": "L'archivi a jë smija a na ''figurin-a''. [[$1|thumb]]\nPër piasì, ch'a contròla l'archivi <strong>[[:$1]]</strong>.\nS'a l'é la midema figura a amzura pijn-a, a veul dì ch'a fa nen dë manca dë carié na figurin-a.",
index 0b02f95..989c83b 100644 (file)
        "table_pager_empty": "کوئی نتارہ نئیں",
        "autosumm-blank": "ایس صفے نوں خالی کرو",
        "autosumm-replace": "\"$1\" نال مواد بدلو",
-       "autoredircomment": "صفے نوں [[$1]] ول ریڈائرکٹ کرو",
+       "autoredircomment": "صفے نوں [[$1]] ول ریڈائرکٹ کیتا",
        "autosumm-new": "\"$1\" نال صفہ بنایا گیا۔",
        "autosumm-newblank": "خالی صفحہ بنایا",
        "lag-warn-normal": "$1 توں نویاں تبدیلیاں {{PLURAL:$1|سکنٹ}}",
        "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": "ٹیگ ناں",
index 014088f..7802628 100644 (file)
        "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دا برخه <strong>مه</strong> ډکوئ!",
        "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": "په دا ځانګړي مخ کي متن پاڼه ترلاسه کیږي کوم چي په ټول ډوله مخونو کي کارول کیږي دلته دا مخ بيا بیا وده کوي. د تحلیل دندو لکه <code><nowiki>{{</nowiki>#language:…}}</code> او متغیرونه لکه <code><nowiki>{{</nowiki>CURRENTDAY}}</code> هم سره نښلوي — په واقعیت کې، د ډلو دننه هر څه. دا خپله د ميډياويکي په اړونده مرحله کولو سره ترسره کيږي.",
index 2f08a4e..ca356b6 100644 (file)
        "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:",
        "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 <strong>[[:$1]]</strong> 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 <strong>[[:$1]]</strong>, 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]]",
        "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",
        "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",
index e0846b2..2b86286 100644 (file)
        "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": "Правка не может быть отменена из-за несовместимости промежуточных изменений.",
        "recentchangesdays": "Количество дней, за которые показывать свежие правки:",
        "recentchangesdays-max": "(не более $1 {{PLURAL:$1|дня|дней}})",
        "recentchangescount": "Количество правок, по умолчанию отображаемое в списке свежих правок, истории страниц и в журналах:",
-       "prefs-help-recentchangescount": "Ð\9dаиболÑ\8cÑ\88ее значение: 1000",
+       "prefs-help-recentchangescount": "Ð\9cакÑ\81ималÑ\8cное значение: 1000",
        "prefs-help-watchlist-token2": "Это секретный ключ для веб-канала вашего списка наблюдений.\nЛюбой, кто знает его, сможет читать ваш список наблюдения, поэтому не сообщайте его другим.\nЕсли необходимо, [[Special:ResetTokens|вы можете сбросить его]].",
        "prefs-help-tokenmanagement": "Вы можете просмотреть и сбросить для своей учётной записи секретный ключ, который может получить доступ к веб-каналу вашего списка наблюдения. Любой, кто знает ключ, сможет прочитать ваш список наблюдения, поэтому не делитесь им ни с кем.",
        "savedprefs": "Настройки сохранены.",
        "rcfilters-view-namespaces-tooltip": "Результаты фильтра по пространствам имён",
        "rcfilters-view-tags-tooltip": "Фильтровать результаты, используя метки правок",
        "rcfilters-view-return-to-default-tooltip": "Вернуться в главное меню фильтров",
-       "rcfilters-view-tags-help-icon-tooltip": "УзнаÑ\82Ñ\8c Ð±Ð¾Ð»Ñ\8cÑ\88е Ð¾ Ñ\80едакÑ\82оÑ\80е Ñ\82егов",
+       "rcfilters-view-tags-help-icon-tooltip": "Ð\9fодÑ\80обнее Ð¾ Ð¿Ñ\80авкаÑ\85 Ñ\81 Ð¼ÐµÑ\82ками",
        "rcfilters-liveupdates-button": "Обновлять автоматически",
        "rcfilters-liveupdates-button-title-on": "Отключить автоматические обновления",
        "rcfilters-liveupdates-button-title-off": "Показывать новые изменения сразу после их появления",
        "rcfilters-watchlist-showupdated": "Изменения страниц, которые вы не посещали с того момента, как они изменились, выделены <strong>жирным</strong> и отмечены полным маркером.",
        "rcfilters-preference-label": "Скрыть улучшенную версию «Свежих правок»",
        "rcfilters-preference-help": "Откатывает редизайн интерфейса 2017 года и все инструменты, добавленные с тех пор.",
+       "rcfilters-watchlist-preference-label": "Скрыть улучшенную версию Списка наблюдения",
+       "rcfilters-watchlist-preference-help": "Отменяет редизайн интерфейса 2017 года и все инструменты, добавленные тогда и позднее.",
        "rcfilters-filter-showlinkedfrom-label": "Показать правки на ссылаемых страницах",
        "rcfilters-filter-showlinkedfrom-option-label": "<strong>Страницы, на которые ссылается</strong> выбранная",
        "rcfilters-filter-showlinkedto-label": "Показать правки на ссылающихся страницах",
        "apisandbox-continue": "Продолжить",
        "apisandbox-continue-clear": "Очистить",
        "apisandbox-continue-help": "{{int:apisandbox-continue}} [https://www.mediawiki.org/wiki/API:Query#Continuing_queries продолжит] последний запрос; {{int:apisandbox-continue-clear}} очистит связанные с продолжением параметры.",
-       "apisandbox-param-limit": "Введите <kbd>максимальное</kbd> использование максимального предела.",
+       "apisandbox-param-limit": "Введите <kbd>max</kbd> для использования максимального предела.",
        "apisandbox-multivalue-all-namespaces": "$1 (Все пространства имён)",
        "apisandbox-multivalue-all-values": "$1 (Все значения)",
        "booksources": "Источники книг",
        "dellogpage": "Журнал удалений",
        "dellogpagetext": "Ниже приведён журнал последних удалений.",
        "deletionlog": "журнал удалений",
+       "log-name-create": "Журнал создания страниц",
+       "log-description-create": "Ниже приведён список самых свежих созданий страниц.",
+       "logentry-create-create": "$1 {{GENDER:$2|создал|создала}} страницу $3",
        "reverted": "Откачено к ранней версии",
        "deletecomment": "Причина:",
        "deleteotherreason": "Другая причина/дополнение:",
        "editcomment": "Было дано описание изменения: <em>$1</em>.",
        "revertpage": "Откат правок [[Special:Contributions/$2|$2]] ([[User talk:$2|обсуждение]]) к версии [[User:$1|$1]]",
        "revertpage-nouser": "Откат правок (имя участника скрыто) к версии {{GENDER:$1|[[User:$1|$1]]}}",
-       "rollback-success": "Ð\9eÑ\82каÑ\82 Ð¿Ñ\80авок {{GENDER:$3|$1}}; Ð²Ð¾Ð·Ð²Ñ\80аÑ\82 Ðº Ð²ÐµÑ\80Ñ\81ии {{GENDER:$4|$2}}.",
-       "rollback-success-notify": "Ð\9eÑ\82каÑ\82 Ð¿Ñ\80авок $1; Ð²Ð¾Ð·Ð²Ñ\80аÑ\82 Ðº Ð²ÐµÑ\80Ñ\81ии $2. [$3 Показать изменения]",
+       "rollback-success": "Ð\9eÑ\82каÑ\87енÑ\8b Ð¿Ñ\80авки {{GENDER:$3|$1}}; Ð²Ð¾Ð·Ð²Ñ\80аÑ\89ена Ð¿Ð¾Ñ\81леднÑ\8fÑ\8f Ð²ÐµÑ\80Ñ\81иÑ\8f {{GENDER:$4|$2}}.",
+       "rollback-success-notify": "Ð\9eÑ\82каÑ\87енÑ\8b Ð¿Ñ\80авки $1; Ð²Ð¾Ð·Ð²Ñ\80аÑ\89ена Ð¿Ð¾Ñ\81леднÑ\8fÑ\8f Ð²ÐµÑ\80Ñ\81иÑ\8f $2. [$3 Показать изменения]",
        "sessionfailure-title": "Ошибка сеанса",
        "sessionfailure": "Похоже, возникли проблемы с текущим сеансом работы;\nэто действие было отменено в целях предотвращения «захвата сеанса».\nПожалуйста, переотправьте форму.",
        "changecontentmodel": "Редактирование контентной модели страницы",
        "ip_range_invalid": "Недопустимый диапазон IP-адресов.",
        "ip_range_toolarge": "Блокировки диапазонов свыше /$1 запрещены.",
        "ip_range_exceeded": "IP-диапазон превышает максимальный диапазон. Допустимый диапазон: /$1.",
-       "ip_range_toolow": "Ð\94иапазонÑ\8b IP Ð½Ðµ Ñ\80азÑ\80еÑ\88ены.",
+       "ip_range_toolow": "Ð\94иапазонÑ\8b IP Ð¿Ð¾ Ñ\81Ñ\83Ñ\82и Ð·Ð°Ð¿Ñ\80еÑ\89ены.",
        "proxyblocker": "Блокировка прокси",
        "proxyblockreason": "Ваш IP-адрес заблокирован потому, что это открытый прокси-сервер. Пожалуйста, свяжитесь со своиим интернет-провайдером или службой поддержки, и сообщите им об этой серьёзной проблеме безопасности.",
        "sorbs": "DNSBL",
        "limitreport-expansiondepth-value": "$1/$2",
        "limitreport-expensivefunctioncount": "Количество «дорогих» функций анализатора",
        "limitreport-expensivefunctioncount-value": "$1/$2",
-       "limitreport-unstrip-depth": "Ð\93лÑ\83биннаÑ\8f Ñ\80екÑ\83Ñ\80Ñ\81иÑ\8f Unstrip",
+       "limitreport-unstrip-depth": "Ð\93лÑ\83бина Ñ\80екÑ\83Ñ\80Ñ\81ии Unstrip",
        "limitreport-unstrip-depth-value": "$1/$2",
        "limitreport-unstrip-size": "Размер Unstrip после раскрытия включений",
        "limitreport-unstrip-size-value": "$1/$2 {{PLURAL:$2|байт|байта|байт}}",
index 9880c2c..513e64d 100644 (file)
@@ -24,7 +24,8 @@
                        "Macofe",
                        "Matma Rex",
                        "రహ్మానుద్దీన్",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "Charunandan16"
                ]
        },
        "tog-underline": "परिसन्धेः अधो रेखाङ्कनम्:",
        "dellogpage": "अपाकरणानाम् आवलिः",
        "dellogpagetext": "सद्यः कालीनापमर्जितपुटानाम् आवली अधः अस्ति ।",
        "deletionlog": "अपमर्जनसूचिका ।",
+       "log-description-create": "नवीनतमानां पृष्ठरचनानाम् इयम् आवली",
        "reverted": "प्राचीनपुनरावृत्तिः पूर्ववत् कृता ।",
        "deletecomment": "कारणम् :",
        "deleteotherreason": "अपरं/अतिरिक्तं कारणम् :",
index 6447d13..10e1ac2 100644 (file)
        "nchanges": "$1 {{PLURAL:$1|လႅၵ်ႈလၢႆႈ|ၸိူဝ်းလႅၵ်ႈလၢႆႈ}}",
        "enhancedrc-since-last-visit": "$1 {{PLURAL:$1|ၸဵမ်မိူဝ်ႈ ၵႂႃႇဢႅတ်ႇပွၵ်ႈၵမ်းလိုၼ်း}}",
        "enhancedrc-history": "ပိုၼ်း",
-       "recentchanges": "á\80\99á\80®á\80¸á\80\9cá\80½á\80\84á\80ºá\82\88á\80\9cá\82\85á\81µá\80ºá\82\88á\80\9cá\81¢á\82\86á\82\88á\80\95á\82\86á\82\87á\82\81á\80­á\80¯á\80\84á\80º",
+       "recentchanges": "á\80\9cá\80½á\80\84á\80ºá\82\88á\80\9cá\82\85á\81µá\80ºá\82\88á\80\9cá\81¢á\82\86á\82\88á\80\99á\82\82á\80ºá\82\87á\80\99á\82\82á\80ºá\82\87",
        "recentchanges-legend": "ၵၼ်လိူၵ်ႈသၢင်ႈ လွင်ႈလႅၵ်ႈလၢႆႈဢၼ်ပူၼ်ႉမႃး",
        "recentchanges-summary": "ၸွမ်းတူၺ်းႁွႆး ဢၼ်ပဵၼ်ၵၢၼ် တိုၵ်ႉႁႃလႅၵ်ႈလၢႆႈၵႂႃႇ တွၼ်ႈတႃႇၼႃႈလိၵ်ႈ ဝီႇၶီႇၼႆႉ။",
        "recentchanges-noresult": "ၼႂ်းၵႃႈၶၢဝ်းယၢမ်း ဢၼ်ပၼ်ဝႆႉ တႃႇၵိုၵ်းတူၺ်း ပိူင်တႅၵ်ႈတႃႇတႅပ်းတတ်းၼၼ်ႉ ဢမ်ႇႁၼ်မီး လွင်ႈလႅၵ်ႈလၢႆႈသင်။",
index aa14a38..7e80c08 100644 (file)
        "delete-legend": "مٹاؤ",
        "historyaction-submit": "ݙِکھاؤ",
        "dellogpage": "مٹاوݨ آلی لاگ",
+       "log-name-create": "ورقہ بݨاوݨ آلی لاگ",
        "deletecomment": "سبب:",
        "rollbacklink": "واپس",
        "rollbacklinkcount": "واپس $1 {{PLURAL:$1|تبدیلی|تبدیلیاں}}",
index bb34091..c1be4c3 100644 (file)
@@ -36,7 +36,9 @@
                        "Denisa",
                        "Fanjiayi",
                        "Fitoschido",
-                       "Luanibraj"
+                       "Luanibraj",
+                       "Matěj Suchánek",
+                       "Bjakupi"
                ]
        },
        "tog-underline": "Nënvizimi i lidhjes:",
        "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 <strong>$3, $4</strong> (deri në <strong>$1</strong>).",
        "rclistfromreset": "Anulo përzgjedhjen e datës",
        "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:",
        "importlogpage": "Regjistri i importeve",
        "importlogpagetext": "Importimet administrative të faqeve me historik redaktimi nga wiki-t e tjera.",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|version|versione}} u importuan",
-       "import-logentry-interwiki-detail": "$1 {{PLURAL:$!1|version|versione}} u importuan nga $2",
+       "import-logentry-interwiki-detail": "$1 {{PLURAL:$1|version|versione}} u importuan nga $2",
        "javascripttest": "Duke testuar JavaScript",
        "javascripttest-pagetext-unknownaction": "Veprim i panjohur \"$1\".",
        "javascripttest-qunit-intro": "Shiko [$1 dokumentacionin e testimit] në mediawiki.org.",
index 1f30cde..f34bbc3 100644 (file)
        "tooltip-ca-nstab-category": "Погледајте страницу категорија",
        "tooltip-minoredit": "Означите ову измену као мању",
        "tooltip-save": "Сачувајте своје измене",
-       "tooltip-publish": "Објавите Ваше измене",
+       "tooltip-publish": "Објавите своје измене",
        "tooltip-preview": "Прегледајте своје измене. Користите ово дугме пре чувања.",
        "tooltip-diff": "Погледајте које измене сте направили на тексту",
        "tooltip-compareselectedversions": "Погледаjте разлике између две изабране измене ове странице.",
index fafb19f..38f8e66 100644 (file)
        "whatlinkshere-page": "Ukurasa:",
        "linkshere": "Kurasa zifuatazo zimeunganishwa na '''$1''':",
        "nolinkshere": "Hakuna kurasa zilizounganishwa na '''$2'''.",
-       "nolinkshere-ns": "!!FUZZY!!!!FUZZY!!Hakuna kurasa zilizounganishwa na '''$2''' katika eneo la wiki lililochaguliwa.",
+       "nolinkshere-ns": "Hakuna kurasa zilizounganishwa na '''$2''' katika eneo la wiki lililochaguliwa.",
        "isredirect": "elekeza ukurasa",
        "istemplate": "jumuisho",
        "isimage": "kiungo cha faili",
index 891f425..ea4f828 100644 (file)
@@ -52,7 +52,8 @@
                        "Info-farmer",
                        "Rakeshonwiki",
                        "Kaartic",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "Matěj Suchánek"
                ]
        },
        "tog-underline": "அடிக்கோடிட்டத்தை இணை:",
        "nmembers": "$1 {{PLURAL:$1|உறுப்பினர்|உறுப்பினர்கள்}}",
        "nmemberschanged": "$1 → $2 {{PLURAL:$2|உறுப்பினர்|உறுப்பினர்கள்}}",
        "nrevisions": "{{PLURAL:$1|ஒரு திருத்தம்|$1 திருத்தங்கள்}}",
-       "nimagelinks": "$1 {{PLURAL:$!|பக்கத்தில்|பக்கங்களில்}} பயன்படுத்தப்பட்டது",
+       "nimagelinks": "$1 {{PLURAL:$1|பக்கத்தில்|பக்கங்களில்}} பயன்படுத்தப்பட்டது",
        "ntransclusions": "$1 {{PLURAL:$1|பக்கத்தில்|பக்கங்களில்}} பயன்படுத்தப்பட்டது",
        "specialpage-empty": "இந்தப் புகாருக்குகந்த முடிவுகள் எதுவுமில்லை.",
        "lonelypages": "உறவிலிப் பக்கங்கள்",
index 882964e..422b905 100644 (file)
        "sp-contributions-talk": "Alea",
        "whatlinkshere": "Ngaahi fehokotaki ki heni",
        "whatlinkshere-page": "Peesi:",
-       "linkshere": "!!FUZZY!!ʻOku fehokotaki ki heni ʻa e ngaahi peesi:",
-       "nolinkshere": "!!FUZZY!!ʻOku ʻikai ha ngaahi kupu fehokotaki ki heni.",
+       "linkshere": "ʻOku fehokotaki ki heni ʻa e ngaahi peesi:",
+       "nolinkshere": "ʻOku ʻikai ha ngaahi kupu fehokotaki ki heni.",
        "isredirect": "Peesi leʻei",
        "istemplate": "kātoi",
        "whatlinkshere-links": "← fehokotaki",
index 125e1d1..de47edf 100644 (file)
@@ -17,7 +17,7 @@
        "tog-newpageshidepatrolled": "Èn nén mostrer el djivêye des novelès pådjes les cenes dedja patrouyeyes",
        "tog-hidecategorization": "Èn nén mostrer les categorijhaedjes des pådjes",
        "tog-extendwatchlist": "Ragrandi l' djivêye po mostrer tos les candjmints, nén seulmint les dierins",
-       "tog-usenewrc": "Relére par pådje dins les dierins candjmints et l' djivêye des shuvous (i fåt JavaScript)",
+       "tog-usenewrc": "Rashonner par pådje dins les dierins candjmints et l' djivêye des shuvous (i fåt JavaScript)",
        "tog-numberheadings": "Limerotaedje otomatike des tites",
        "tog-showtoolbar": "Mostrer l' bår d' usteyes e môde candjmint",
        "tog-editondblclick": "Candjî les pådjes avou on dobe-clitch",
@@ -36,7 +36,7 @@
        "tog-enotifminoredits": "M' emiler eto po les ptits candjmints des pådjes u des fitchîs",
        "tog-enotifrevealaddr": "Mostrer mi adresse emile dins les emiles di notifiaedje",
        "tog-shownumberswatching": "Mostrer l' nombe d' uzeus ki shuvèt l' pådje",
-       "tog-oldsig": "Siné pol moumint:",
+       "tog-oldsig": "Siné pol moumint :",
        "tog-fancysig": "Sinateure avou do tecse wiki (sins loyén otomatike)",
        "tog-uselivepreview": "Eployî l' préveyaedje abeye",
        "tog-forceeditsummary": "M' advierti cwand dji lai vude on rascourti",
@@ -46,6 +46,7 @@
        "tog-watchlisthideliu": "Èn nén mostrer les candjmints fwait pa des uzeus edjîstrés",
        "tog-watchlisthideanons": "Èn nén mostrer les candjmints fwait pa des uzeus anonimes",
        "tog-watchlisthidepatrolled": "Èn nén mostrer les candjmints ddja patrouyîs",
+       "tog-watchlisthidecategorization": "Catchî l' categorijhaedje des pådjes",
        "tog-ccmeonemails": "M' evoyî ene copeye des emiles ki dj' evoye ås ôtes",
        "tog-diffonly": "Èn nén håyner l' contnou del pådje pa dzo l' pådje des diferinces",
        "tog-showhiddencats": "Mostrer les categoreyes mucheyes",
        "tog-useeditwarning": "M' advierti cwand dji cwite ene pådje k' a des candjmints nén schapés",
        "underline-always": "Tofer",
        "underline-never": "Måy",
-       "underline-default": "Valixhance do betchteu",
+       "underline-default": "Valixhance del pea u do betchteu",
        "editfont-style": "Stîle del fonte pol boesse di tecse",
+       "editfont-sansserif": "Fonte Sans-serif",
+       "editfont-serif": "Fonte Serif",
        "sunday": "dimegne",
        "monday": "londi",
        "tuesday": "mårdi",
        "searcharticle": "Potchî",
        "history": "Istwere del pådje",
        "history_short": "Istwere",
+       "history_small": "Istwere",
        "updatedmarker": "candjî dispoy mi dierinne vizite",
        "printableversion": "Modêye sicrirece-amiståve",
        "permalink": "Hårdêye viè cisse modêye ci",
        "view": "Vey",
        "view-foreign": "Vey so $1",
        "edit": "Candjî",
+       "edit-local": "Candjî l' discrijhaedje locå",
        "create": "Ahiver",
+       "create-local": "Radjouter on discrijhaedje locå",
        "delete": "Disfacer",
        "undelete_short": "Rapexhî {{PLURAL:$1|on candjmint|$1 candjmints}}",
        "viewdeleted_short": "Vey {{PLURAL:$1|on candjmint disfacé|$1 candjmints disfacés}}",
        "copyrightpage": "{{ns:project}}:Abondroets",
        "currentevents": "Actouwålités",
        "currentevents-url": "Project:Actouwålités",
+       "disclaimers": "Adviertances",
+       "disclaimerpage": "Project: Djeneråles adviertances",
        "edithelp": "Aidance",
        "helppage-top-gethelp": "Aidance",
        "mainpage": "Mwaisse pådje",
        "mainpage-description": "Mwaisse pådje",
        "portal": "Inte di nozôtes",
        "portal-url": "Project:Inte di nozôtes",
+       "privacy": "Politike des scretès dinêyes",
+       "privacypage": "Project: Politike des scretès dinêyes",
        "badaccess": "Åk n' a nén stî avou les permissions",
        "badaccess-groups": "L' accion ki vos avoz dmandé est limitêye ås uzeus {{PLURAL:$2|do groupe|des groupes}}: $1.",
        "versionrequired": "I vs fåt l' modêye $1 di MediaWiki",
        "perfcachedts": "Les dnêyes ki shuvèt c' est ene copeye e muchete, ey elle ont stî metowes a djoû pol dierin côp li $1. Li muchete a-st on macsimom {{PLURAL:$4|d' on rzultat|di $4 rizultats}}.",
        "viewsource": "Vey côde sourdant",
        "viewsource-title": "Côde sourdant di «$1»",
-       "viewsourcetext": "Loukîz li contnou d' l’ årtike, et s’ li rcopyî si vos vloz, por vos bouter dsu foû des fyis:",
-       "protectedinterface": "Cisse pådje ci dene on tecse d' eterface pol programe, eyet elle a stî protedjeye po s' waeranti siconte des abus.",
+       "viewsourcetext": "Vos ploz rwaitî et rcopyî li contnou di cisse pådje ci.",
+       "viewyourtext": "Vos ploz rwaitî et rcopyî li contnou d' <strong>vosse ovraedje</strong> so cisse pådje ci.",
+       "protectedinterface": "Cisse pådje ci dene on tecse d' eterface pol programe, eyet elle a stî protedjeye po s' waeranti siconte des abus. Po radjouter u candjî des ratournaedjes so tos les wikis, i vos fåt eployî [https://translatewiki.net/ translatewiki.net], li pordjet d' ratournaedje coinrece da MediaWiki.",
        "editinginterface": "<strong>Asteme:</strong> Vos estoz ki candje ene pådje eployeye po fé l' tecse po l' eterface do programe.\nLes candjmints ki vos frîz vont candjî l' rivnance di l' eterface po ls ôtes uzeus do wiki.",
+       "translateinterface": "Po radjouter u candjî des ratournaedjes so tos les wikis, eployîz [https://translatewiki.net/ translatewiki.net], li pordjet d' ratournaedje coinrece da MediaWiki.",
        "cascadeprotected": "Cisse pådje ci a stî protedjeye siconte des candjmints, pask' ele est eploye ådvins {{PLURAL:$1|del pådje shuvante k' est protedjeye|des pådjes shuvantes ki sont protedjeyes}} avou l' tchuze «e cascåde» en alaedje:\n$2",
        "logouttext": "<strong>Vos vs avoz dislodjî.</strong>\n\nNotez ki des pådjes k' i gn a si pôrént continouwer a vey come si vos estîz elodjî, disk' a tant ki vos vudrîz l' muchete di vosse betchteu waibe.",
        "welcomeuser": "Bénvnowe, $1!",
        "page_first": "prumî",
        "page_last": "dierin",
        "histlegend": "Tchoezi les modêyes a comparer: clitchîz so les botons radio des deus modêyes\nki vos vloz comparer et s' tchôkîz sol tape «enter» ou clitchîz sol\nboton do dzo.<br />\nLedjinde: '''({{int:cur}})''' = diferince avou l' modêye d' asteure, '''({{int:last}})''' = diferince avou l' modêye di dvant, '''{{int:minoreditletter}}''' = pitit candjmint d' rén do tot.",
-       "history-fieldset-title": "Naivyî l' istwere des candjmints",
+       "history-fieldset-title": "Cachî dins l' istwere des candjmints",
        "history-show-deleted": "Disfacés seulmint",
-       "histfirst": "li pus vî",
-       "histlast": "li dierin",
+       "histfirst": "les pus vîs",
+       "histlast": "les dierins",
        "historysize": "({{PLURAL:$1|1 octet|$1 octets}})",
        "historyempty": "(vude)",
        "history-feed-title": "Istwere des modêyes",
        "recentchanges-legend-heading": "<strong>Ledjinde:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (vey eto l' [[Special:NewPages|djivêye des nouvès pådjes]])",
        "recentchanges-submit": "Vey",
-       "rcnotefrom": "Chal pa dzo les candjmints dispoy li '''$2''' (disk' a '''$1''' di mostrés).",
+       "rcnotefrom": "Chal pa dzo {{PLURAL:$5|li candjmint fwait|les candjmints fwaits}} dispoy li <strong>$3, $4</strong> (afitchîs disk a <strong>$1</strong>).",
        "rclistfrom": "Mostrer les candjmints k' i gn a yeu a pårti do $3 $2",
        "rcshowhideminor": "$1 candjmints mineurs",
        "rcshowhideminor-show": "Mostrer",
        "recentchangeslinked-feed": "Candjmints aloyîs",
        "recentchangeslinked-toolbox": "Candjmints aloyîs",
        "recentchangeslinked-title": "Candjmints aloyîs a «$1»",
-       "recentchangeslinked-summary": "Çouchal c' est ene djivêye des candjmints k' ont stî fwaits dierinnmint a des pådjes aloyeyes a pårti d' ene pådje dinêye (ou mimbes d' ene categoreye dinêye).\nLes pådjes ki [[Special:Watchlist|vos shuvoz]] sont-st e '''cråssès letes'''.",
+       "recentchangeslinked-summary": "Intrez on no d' pådje po vey les candjmints k' ont stî fwaits dierinnmint a des pådjes aloyeyes a pårti u viè cisse pådje ci (po vey les mimbes d' ene categoreye dinêye, intrez {{ns:category}}:No del categoreye). Les pådjes ki [[Special:Watchlist|vos shuvoz]] et k' ont stî candjeyes sont-st e <strong>cråssès letes</strong>.",
        "recentchangeslinked-page": "No del pådje:",
        "recentchangeslinked-to": "Mostere les candjmints des pådjes avou on loyén viè l' pådje dinêye purade k' å rviè",
        "upload": "Eberweter on fitchî",
        "contributions-title": "Djivêye des ovraedjes di l' {{GENDER:$1|uzeu|uzeuse}} $1",
        "mycontris": "Mi ovraedje",
        "anoncontribs": "Mi ovraedje",
-       "contribsub2": "Po l' uzeu $1 ($2)",
+       "contribsub2": "Po {{GENDER:$3|$1}} ($2)",
        "nocontribs": "Nou candjmint di trové ki corespondreut a ç' critere la.",
        "uctop": "(dierinne)",
        "month": "dispu l' moes (et pus timpe)",
index 25b8277..edde6a1 100644 (file)
        "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:<em>$2</em>\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|באַניצער פרעפֿערענצן]] .",
        "recentchangeslinked-feed": "פֿאַרבונדענע ענדערונגען",
        "recentchangeslinked-toolbox": "פֿאַרבונדענע ענדערונגען",
        "recentchangeslinked-title": "ענדערונגען פֿארבונדן מיט $1",
-       "recentchangeslinked-summary": "גיט אריין א בלאטנאמען צו זען ענדערונגען צו בלעטער פארבונדן צו אדער פון יענעם בלאט. (צו זען מיטגליד בלעטער פון א קאטעגאריע גיט אריין ״קאטעגאריע:נאמען פון קאטעגאריע״). ענדערונגען צו בלעטער אויף [[Special:Watchlist|אייער אויפפאסונג ליסטע]] זענען געוויזן <strong>דיק</strong>.",
+       "recentchangeslinked-summary": "גיט אריין א בלאטנאמען צו זען ענדערונגען צו בלעטער פארבונדן צו אדער פון יענעם בלאט. (צו זען מיטגליד בלעטער פון א קאטעגאריע גיט אריין ״{{ns:category}}:נאמען פון קאטעגאריע״). ענדערונגען צו בלעטער אויף [[Special:Watchlist|אייער אויפפאסונג ליסטע]] זענען געוויזן <strong>דיק</strong>.",
        "recentchangeslinked-page": "בלאַט נאָמען:",
        "recentchangeslinked-to": "צייג ענדערונגען צו בלעטער פארבינדן צו דעם בלאט אנשטאט",
        "recentchanges-page-added-to-category": "[[:$1]] צוגעלייגט צו קאטעגאריע",
index f409dcc..5bb1a43 100644 (file)
        "whatlinkshere": "链入页面",
        "whatlinkshere-title": "链接至“$1”的页面",
        "whatlinkshere-page": "页面:",
-       "linkshere": "以下页面链接至<strong>$1</strong>:",
-       "nolinkshere": "没有页面链接至<strong>$1</strong>。",
+       "linkshere": "以下页面链接至<strong>$2</strong>:",
+       "nolinkshere": "没有页面链接至<strong>$2</strong>。",
        "nolinkshere-ns": "在所选的名字空间内没有页面链接到<strong>$2</strong>。",
        "isredirect": "重定向页面",
        "istemplate": "嵌入",
index 42cc676..5db2062 100644 (file)
@@ -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 (file)
index 0000000..720b591
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+/** Standard Moroccan Amazigh (ⵜⴰⵎⴰⵣⵉⵖⵜ ⵜⴰⵏⴰⵡⴰⵢⵜ / tamaziɣt tanawayt)
+ *
+ * To improve a translation please visit https://translatewiki.net
+ *
+ * @ingroup Language
+ * @file
+ *
+ */
+
+$fallback = 'kab';
index 0fdd417..21d9bb1 100644 (file)
@@ -142,7 +142,7 @@ class BackupDumper extends Maintenance {
                        require_once $file;
                }
                $register = [ $class, 'register' ];
-               call_user_func_array( $register, [ $this ] );
+               $register( $this );
        }
 
        function execute() {
index 1b05e1e..acc66c5 100644 (file)
@@ -24,6 +24,8 @@
  * @author Katie Filbert < aude.wiki@gmail.com >
  */
 
+use MediaWiki\MediaWikiServices;
+
 require_once __DIR__ . '/Maintenance.php';
 
 class PopulateInterwiki extends Maintenance {
@@ -119,6 +121,7 @@ TEXT
                        }
                }
 
+               $lookup = MediaWikiServices::getInstance()->getInterwikiLookup();
                foreach ( $data as $d ) {
                        $prefix = $d['prefix'];
 
@@ -142,7 +145,7 @@ TEXT
                                );
                        }
 
-                       Interwiki::invalidateCache( $prefix );
+                       $lookup->invalidateCache( $prefix );
                }
 
                $this->output( "Interwiki links are populated.\n" );
index bd0556a..0ec24af 100644 (file)
@@ -502,7 +502,7 @@ class CheckStorage {
        function importRevision( &$revision, &$importer ) {
                $id = $revision->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";
index 49b8e0a..271cbf3 100644 (file)
@@ -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 );
index 2d425dd..36328e0 100644 (file)
@@ -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": {
index 9ebd57b..8bd37dd 100644 (file)
@@ -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 ) )
                                ] )
                );
index 09d223e..11972de 100644 (file)
@@ -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 {
index a798679..4ecd383 100644 (file)
@@ -184,6 +184,9 @@ $wgAutoloadClasses += [
                => "$testDir/phpunit/mocks/session/DummySessionBackend.php",
        'DummySessionProvider' => "$testDir/phpunit/mocks/session/DummySessionProvider.php",
        'MockMessageLocalizer' => "$testDir/phpunit/mocks/MockMessageLocalizer.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",
index 73d4a47..eede54e 100644 (file)
@@ -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';
index b109e39..afddd78 100644 (file)
@@ -24649,6 +24649,17 @@ abc
 <span typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"padright:","function":"padright"},"params":{"1":{"wt":"3"},"2":{"wt":"abcde"}},"i":0}}]}'>abc</span></p>
 !! end
 
+!! test
+Padleft and padright with non-numerical length (T180403)
+!! wikitext
+{{padleft:abcdef|junk}}
+{{padright:abcdef|junk}}
+!! html/php
+<p>abcdef
+abcdef
+</p>
+!! end
+
 !!test
 Special parser function
 !! wikitext
index 5f71287..61d86bd 100644 (file)
@@ -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
index 6bcbd93..5fddc3d 100644 (file)
@@ -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
index f9e2cc1..4c508e3 100644 (file)
@@ -1,6 +1,5 @@
 <?php
 
-use MediaWiki\MediaWikiServices;
 
 /**
  * @group Database
@@ -370,6 +369,7 @@ class LinkerTest extends MediaWikiLangTestCase {
         * @dataProvider provideLinkBeginHook
         */
        public function testLinkBeginHook( $callback, $expected ) {
+               $this->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 )
-               );
-       }
 }
index 3749f29..61d0512 100644 (file)
@@ -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()
                );
index 4e34244..6600aa2 100644 (file)
@@ -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/ApiQuerySearchTest.php b/tests/phpunit/includes/api/ApiQuerySearchTest.php
new file mode 100644 (file)
index 0000000..0700cf7
--- /dev/null
@@ -0,0 +1,109 @@
+<?php
+
+/**
+ * @group medium
+ * @covers ApiQuerySearch
+ */
+class ApiQuerySearchTest extends ApiTestCase {
+       public function provideSearchResults() {
+               return [
+                       'empty search result' => [ [], [] ],
+                       '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 ) );
+       }
+
+}
index fac3486..82ca66a 100644 (file)
@@ -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)'
                );
        }
index 6b7aa85..947be75 100644 (file)
@@ -113,7 +113,7 @@ class InterwikiTest extends MediaWikiTestCase {
                $this->assertSame( true, $interwiki->isLocal(), 'isLocal' );
                $this->assertSame( false, $interwiki->isTranscludable(), 'isTranscludable' );
 
-               Interwiki::invalidateCache( 'de' );
+               $interwikiLookup->invalidateCache( 'de' );
                $this->assertNotSame( $interwiki, $interwikiLookup->fetch( 'de' ), 'invalidate cache' );
        }
 
index 03c7b0c..9ec660e 100644 (file)
 
 /**
  * Tests for IEUrlExtension::findIE6Extension
- * @todo tests below for findIE6Extension should be split into...
- *    ...a dataprovider and test method.
  */
 class IEUrlExtensionTest extends PHPUnit\Framework\TestCase {
 
        use MediaWikiCoversValidator;
 
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testSimple() {
-               $this->assertEquals(
-                       'y',
-                       IEUrlExtension::findIE6Extension( 'x.y' ),
-                       'Simple extension'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testSimpleNoExt() {
-               $this->assertEquals(
-                       '',
-                       IEUrlExtension::findIE6Extension( 'x' ),
-                       'No extension'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testEmpty() {
-               $this->assertEquals(
-                       '',
-                       IEUrlExtension::findIE6Extension( '' ),
-                       'Empty string'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testQuestionMark() {
-               $this->assertEquals(
-                       '',
-                       IEUrlExtension::findIE6Extension( '?' ),
-                       'Question mark only'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testExtQuestionMark() {
-               $this->assertEquals(
-                       'x',
-                       IEUrlExtension::findIE6Extension( '.x?' ),
-                       'Extension then question mark'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testQuestionMarkExt() {
-               $this->assertEquals(
-                       'x',
-                       IEUrlExtension::findIE6Extension( '?.x' ),
-                       'Question mark then extension'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testInvalidChar() {
-               $this->assertEquals(
-                       '',
-                       IEUrlExtension::findIE6Extension( '.x*' ),
-                       'Extension with invalid character'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testInvalidCharThenExtension() {
-               $this->assertEquals(
-                       'x',
-                       IEUrlExtension::findIE6Extension( '*.x' ),
-                       'Invalid character followed by an extension'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testMultipleQuestionMarks() {
-               $this->assertEquals(
-                       'c',
-                       IEUrlExtension::findIE6Extension( 'a?b?.c?.d?e?f' ),
-                       'Multiple question marks'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testExeException() {
-               $this->assertEquals(
-                       'd',
-                       IEUrlExtension::findIE6Extension( 'a?b?.exe?.d?.e' ),
-                       '.exe exception'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testExeException2() {
-               $this->assertEquals(
-                       'exe',
-                       IEUrlExtension::findIE6Extension( 'a?b?.exe' ),
-                       '.exe exception 2'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testHash() {
-               $this->assertEquals(
-                       '',
-                       IEUrlExtension::findIE6Extension( 'a#b.c' ),
-                       'Hash character preceding extension'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testHash2() {
-               $this->assertEquals(
-                       '',
-                       IEUrlExtension::findIE6Extension( 'a?#b.c' ),
-                       'Hash character preceding extension 2'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testDotAtEnd() {
-               $this->assertEquals(
-                       '',
-                       IEUrlExtension::findIE6Extension( '.' ),
-                       'Dot at end of string'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testTwoDots() {
-               $this->assertEquals(
-                       'z',
-                       IEUrlExtension::findIE6Extension( 'x.y.z' ),
-                       'Two dots'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testScriptQuery() {
-               $this->assertEquals(
-                       'php',
-                       IEUrlExtension::findIE6Extension( 'example.php?foo=a&bar=b' ),
-                       'Script with query'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testEscapedScriptQuery() {
-               $this->assertEquals(
-                       '',
-                       IEUrlExtension::findIE6Extension( 'example%2Ephp?foo=a&bar=b' ),
-                       'Script with urlencoded dot and query'
-               );
-       }
-
-       /**
-        * @covers IEUrlExtension::findIE6Extension
-        */
-       public function testEscapedScriptQueryDot() {
-               $this->assertEquals(
-                       'y',
-                       IEUrlExtension::findIE6Extension( 'example%2Ephp?foo=a.x&bar=b.y' ),
-                       'Script with urlencoded dot and query with dot'
+       public function provideFindIE6Extension() {
+               return [
+                       // url, expected, message
+                       [ 'x.y', 'y', 'Simple extension' ],
+                       [ 'x', '', 'No extension' ],
+                       [ '', '', 'Empty string' ],
+                       [ '?', '', 'Question mark only' ],
+                       [ '.x?', 'x', 'Extension then question mark' ],
+                       [ '?.x', 'x', 'Question mark then extension' ],
+                       [ '.x*', '', 'Extension with invalid character' ],
+                       [ '*.x', 'x', 'Invalid character followed by an extension' ],
+                       [ 'a?b?.c?.d?e?f', 'c', 'Multiple question marks' ],
+                       [ 'a?b?.exe?.d?.e', 'd', '.exe exception' ],
+                       [ 'a?b?.exe', 'exe', '.exe exception 2' ],
+                       [ 'a#b.c', '', 'Hash character preceding extension' ],
+                       [ 'a?#b.c', '', 'Hash character preceding extension 2' ],
+                       [ '.', '', 'Dot at end of string' ],
+                       [ 'x.y.z', 'z', 'Two dots' ],
+                       [ 'example.php?foo=a&bar=b', 'php', 'Script with query' ],
+                       [ 'example%2Ephp?foo=a&bar=b', '', 'Script with urlencoded dot and query' ],
+                       [ 'example%2Ephp?foo=a.x&bar=b.y', 'y', 'Script with urlencoded dot and query with dot' ],
+               ];
+       }
+
+       /**
+        * @covers IEUrlExtension::findIE6Extension
+        * @dataProvider provideFindIE6Extension
+        */
+       public function testFindIE6Extension( $url, $expected, $message ) {
+               $this->assertEquals(
+                       $expected,
+                       IEUrlExtension::findIE6Extension( $url ),
+                       $message
                );
        }
 }
index 6d096c2..c758ba6 100644 (file)
@@ -131,6 +131,11 @@ class LinkRendererTest extends MediaWikiLangTestCase {
                        . '(page does not exist)"><script>evil()</script></a>',
                        $linkRenderer->makeLink( $foobar, new HtmlArmor( '<script>evil()</script>' ) )
                );
+
+               $this->assertEquals(
+                       '<a href="#fragment">fragment</a>',
+                       $linkRenderer->makeLink( Title::newFromText( '#fragment' ) )
+               );
        }
 
        public function testGetLinkClasses() {
index 4d98773..fa4d804 100644 (file)
@@ -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();
index e807776..2561fd0 100644 (file)
@@ -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 <span class='searchmatch'>" . $phrase . "</span>";
                $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;
diff --git a/tests/phpunit/includes/search/SearchNearMatchResultSetTest.php b/tests/phpunit/includes/search/SearchNearMatchResultSetTest.php
new file mode 100644 (file)
index 0000000..67493c4
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+
+class SearchNearMatchResultSetTest extends PHPUnit\Framework\TestCase {
+       /**
+        * @covers SearchNearMatchResultSet::__construct
+        * @covers SearchNearMatchResultSet::numRows
+        */
+       public function testNumRows() {
+               $resultSet = new SearchNearMatchResultSet( null );
+               $this->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 (file)
index 0000000..9eeee63
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+
+class SearchResultSetTest extends MediaWikiTestCase {
+       /**
+        * @covers SearchResultSet::getIterator
+        * @covers SearchResultSet::next
+        * @covers SearchResultSet::rewind
+        */
+       public function testIterate() {
+               $result = SearchResult::newFromTitle( Title::newMainPage() );
+               $resultSet = new MockSearchResultSet( [ $result ] );
+               $this->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() );
+       }
+}
diff --git a/tests/phpunit/includes/search/SearchResultTest.php b/tests/phpunit/includes/search/SearchResultTest.php
new file mode 100644 (file)
index 0000000..0e1e24c
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+class SearchResultTest extends MediawikiTestCase {
+       /**
+        * @covers SearchResult::getExtensionData
+        * @covers SearchResult::setExtensionData
+        */
+       public function testExtensionData() {
+               $result = SearchResult::newFromTitle( Title::newMainPage() );
+               $this->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' );
+       }
+}
index f84d435..a74056d 100644 (file)
@@ -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 );
index f0a5726..196321c 100644 (file)
@@ -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() {
index 0bb6a4d..d406c88 100644 (file)
@@ -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 ) {
index 11c1097..84a4c46 100644 (file)
  */
 class LanguageCrhTest extends LanguageClassesTestCase {
        /**
-        * @dataProvider provideAutoConvertToAllVariants
+        * @dataProvider provideAutoConvertToAllVariantsByWord
         * @covers Language::autoConvertToAllVariants
+        *
+        * Test individual words and test minimal contextual transforms
+        * by creating test strings "<cyrillic> <latin>" and
+        * "<latin> <cyrillic>" and then converting to all variants.
         */
-       public function testAutoConvertToAllVariants( $result, $value ) {
+       public function testAutoConvertToAllVariantsByWord( $cyrl, $lat ) {
+               $value = $lat;
+               $result = [
+                       'crh'      => $value,
+                       'crh-cyrl' => $cyrl,
+                       'crh-latn' => $lat,
+                       ];
+               $this->assertEquals( $result, $this->getLang()->autoConvertToAllVariants( $value ) );
+
+               $value = $cyrl;
+               $result = [
+                       'crh'      => $value,
+                       'crh-cyrl' => $cyrl,
+                       'crh-latn' => $lat,
+                       ];
+               $this->assertEquals( $result, $this->getLang()->autoConvertToAllVariants( $value ) );
+
+               $value = $cyrl . ' ' . $lat;
+               $result = [
+                       'crh'      => $value,
+                       'crh-cyrl' => $cyrl . ' ' . $cyrl,
+                       'crh-latn' => $lat . ' ' . $lat,
+                       ];
+               $this->assertEquals( $result, $this->getLang()->autoConvertToAllVariants( $value ) );
+
+               $value = $lat . ' ' . $cyrl;
+               $result = [
+                       'crh'      => $value,
+                       'crh-cyrl' => $cyrl . ' ' . $cyrl,
+                       'crh-latn' => $lat . ' ' . $lat,
+                       ];
                $this->assertEquals( $result, $this->getLang()->autoConvertToAllVariants( $value ) );
        }
 
-       public static function provideAutoConvertToAllVariants() {
+       public static function provideAutoConvertToAllVariantsByWord() {
+               return [
+                       // general words, covering more of the alphabet
+                       [ 'рузгярнынъ', 'ruzgârnıñ' ], [ 'Париж', 'Parij' ], [ 'чёкюч', 'çöküç' ],
+                       [ 'элифбени', 'elifbeni' ], [ 'полициясы', 'politsiyası' ], [ 'хусусында', 'hususında' ],
+                       [ 'акъшамларны', 'aqşamlarnı' ], [ 'опькеленюв', 'öpkelenüv' ],
+                       [ 'кулюмсиреди', 'külümsiredi' ], [ 'айтмайджагъым', 'aytmaycağım' ],
+                       [ 'козьяшсыз', 'közyaşsız' ],
+
+                       // exception words
+                       [ 'инструменталь', 'instrumental' ], [ 'гургуль', 'gürgül' ], [ 'тюшюнмемек', 'tüşünmemek' ],
+
+                       // specific problem words
+                       [ 'куню', 'künü' ], [ 'сюргюнлиги', 'sürgünligi' ], [ 'озю', 'özü' ], [ 'этти', 'etti' ],
+                       [ 'эсас', 'esas' ], [ 'дёрт', 'dört' ], [ 'кельди', 'keldi' ], [ 'км²', 'km²' ],
+                       [ 'юзь', 'yüz' ], [ 'АКъШ', 'AQŞ' ], [ 'ШСДжБнен', 'ŞSCBnen' ], [ 'июль', 'iyül' ],
+                       [ 'ишгъаль', 'işğal' ], [ 'ишгъальджилерине', 'işğalcilerine' ], [ 'район', 'rayon' ],
+                       [ 'районынынъ', 'rayonınıñ' ], [ 'Ногъай', 'Noğay' ], [ 'Юрьтю', 'Yürtü' ],
+                       [ 'ватандан', 'vatandan' ], [ 'ком-кок', 'köm-kök' ], [ 'АКЪКЪЫ', 'AQQI' ],
+                       [ 'ДАГЪГЪА', 'DAĞĞA' ], [ '13-юнджи', '13-ünci' ], [ 'ДЖУРЬМЕК', 'CÜRMEK' ],
+                       [ 'джумлеси', 'cümlesi' ], [ 'ильи', 'ilyi' ], [ 'Ильи', 'İlyi' ], [ 'бруцел', 'brutsel' ],
+                       [ 'коцюб', 'kotsüb' ], [ 'плацен', 'platsen' ], [ 'эпицентр', 'epitsentr' ],
+
+                       // -tsin- words
+                       [ 'кетсин', 'ketsin' ], [ 'кирлетсин', 'kirletsin' ], [ 'этсин', 'etsin' ],
+                       [ 'етсин', 'yetsin' ], [ 'этсинлерми', 'etsinlermi' ], [ 'принцини', 'printsini' ],
+                       [ 'медицина', 'meditsina' ], [ 'Щетсин', 'Şçetsin' ], [ 'Щекоцины', 'Şçekotsinı' ],
+
+                       // regex pattern words
+                       [ 'коюнден', 'köyünden' ], [ 'аньге', 'ange' ],
+
+                       // multi part words
+                       [ 'эки юз', 'eki yüz' ],
+
+                       // affix patterns
+                       [ 'койнинъ', 'köyniñ' ], [ 'Авджыкойде', 'Avcıköyde' ], [ 'экваториаль', 'ekvatorial' ],
+                       [ 'Джанкой', 'Canköy' ], [ 'усть', 'üst' ], [ 'роль', 'rol' ], [ 'буюк', 'büyük' ],
+                       [ 'джонк', 'cönk' ],
+
+                       // Roman numerals vs Initials, part 1 - Roman numeral initials without spaces
+                       [ 'А.Б.Дж.Д.М. Къадырова XII', 'A.B.C.D.M. Qadırova XII' ],
+                       // Roman numerals vs Initials, part 2 - Roman numeral initials with spaces
+                       [ 'Г. Х. Ы. В. X. Л. Меметов III',  'G. H. I. V. X. L. Memetov III' ],
+
+                       // ALL CAPS, made up acronyms
+                       [ 'НЪАБ', 'ÑAB' ], [ 'КЪЫДЖ', 'QIC' ], [ 'ГЪУК', 'ĞUK' ], [ 'ДЖОТ', 'COT' ], [ 'ДЖА', 'CA' ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideAutoConvertToAllVariantsByString
+        * @covers Language::autoConvertToAllVariants
+        *
+        * Run tests that require some context (like Roman numerals) or with
+        * many-to-one mappings, or other asymmetric results (like smart quotes)
+        */
+       public function testAutoConvertToAllVariantsByString( $result, $value ) {
+               $this->assertEquals( $result, $this->getLang()->autoConvertToAllVariants( $value ) );
+       }
+
+       public static function provideAutoConvertToAllVariantsByString() {
                return [
-                       [ // general words, covering more of the alphabet
-                               [
-                                       'crh'      => 'рузгярнынъ ruzgârnıñ Париж Parij',
-                                       'crh-cyrl' => 'рузгярнынъ рузгярнынъ Париж Париж',
-                                       'crh-latn' => 'ruzgârnıñ ruzgârnıñ Parij Parij',
-                               ],
-                               'рузгярнынъ ruzgârnıñ Париж Parij'
-                       ],
-                       [ // general words, covering more of the alphabet
-                               [
-                                       'crh'      => 'чёкюч çöküç элифбени elifbeni полициясы politsiyası',
-                                       'crh-cyrl' => 'чёкюч чёкюч элифбени элифбени полициясы полициясы',
-                                       'crh-latn' => 'çöküç çöküç elifbeni elifbeni politsiyası politsiyası',
-                               ],
-                               'чёкюч çöküç элифбени elifbeni полициясы politsiyası'
-                       ],
-                       [ // general words, covering more of the alphabet
-                               [
-                                       'crh'      => 'хусусында hususında акъшамларны aqşamlarnı опькеленюв öpkelenüv',
-                                       'crh-cyrl' => 'хусусында хусусында акъшамларны акъшамларны опькеленюв опькеленюв',
-                                       'crh-latn' => 'hususında hususında aqşamlarnı aqşamlarnı öpkelenüv öpkelenüv',
-                               ],
-                               'хусусында hususında акъшамларны aqşamlarnı опькеленюв öpkelenüv'
-                       ],
-                       [ // general words, covering more of the alphabet
-                               [
-                                       'crh'      => 'кулюмсиреди külümsiredi айтмайджагъым aytmaycağım козьяшсыз közyaşsız',
-                                       'crh-cyrl' => 'кулюмсиреди кулюмсиреди айтмайджагъым айтмайджагъым козьяшсыз козьяшсыз',
-                                       'crh-latn' => 'külümsiredi külümsiredi aytmaycağım aytmaycağım közyaşsız közyaşsız',
-                               ],
-                               'кулюмсиреди külümsiredi айтмайджагъым aytmaycağım козьяшсыз közyaşsız'
-                       ],
-                       [ // exception words
-                               [
-                                       'crh'      => 'инструменталь instrumental гургуль gürgül тюшюнмемек tüşünmemek',
-                                       'crh-cyrl' => 'инструменталь инструменталь гургуль гургуль тюшюнмемек тюшюнмемек',
-                                       'crh-latn' => 'instrumental instrumental gürgül gürgül tüşünmemek tüşünmemek',
-                               ],
-                               'инструменталь instrumental гургуль gürgül тюшюнмемек tüşünmemek'
-                       ],
-                       [ // recent problem words, part 1
-                               [
-                                       'crh'      => 'künü куню sürgünligi сюргюнлиги özü озю etti этти esas эсас dört дёрт',
-                                       'crh-cyrl' => 'куню куню сюргюнлиги сюргюнлиги озю озю этти этти эсас эсас дёрт дёрт',
-                                       'crh-latn' => 'künü künü sürgünligi sürgünligi özü özü etti etti esas esas dört dört',
-                               ],
-                               'künü куню sürgünligi сюргюнлиги özü озю etti этти esas эсас dört дёрт'
-                       ],
-                       [ // recent problem words, part 2
-                               [
-                                       'crh'      => 'keldi кельди km² км² yüz юзь AQŞ АКъШ ŞSCBnen ШСДжБнен iyül июль',
-                                       'crh-cyrl' => 'кельди кельди км² км² юзь юзь АКъШ АКъШ ШСДжБнен ШСДжБнен июль июль',
-                                       'crh-latn' => 'keldi keldi km² km² yüz yüz AQŞ AQŞ ŞSCBnen ŞSCBnen iyül iyül',
-                               ],
-                               'keldi кельди km² км² yüz юзь AQŞ АКъШ ŞSCBnen ШСДжБнен iyül июль'
-                       ],
-                       [ // recent problem words, part 3
-                               [
-                                       'crh'      => 'işğal ишгъаль işğalcilerine ишгъальджилерине rayon район üst усть',
-                                       'crh-cyrl' => 'ишгъаль ишгъаль ишгъальджилерине ишгъальджилерине район район усть усть',
-                                       'crh-latn' => 'işğal işğal işğalcilerine işğalcilerine rayon rayon üst üst',
-                               ],
-                               'işğal ишгъаль işğalcilerine ишгъальджилерине rayon район üst усть'
-                       ],
-                       [ // recent problem words, part 4
-                               [
-                                       'crh'      => 'rayonınıñ районынынъ Noğay Ногъай Yürtü Юрьтю vatandan ватандан',
-                                       'crh-cyrl' => 'районынынъ районынынъ Ногъай Ногъай Юрьтю Юрьтю ватандан ватандан',
-                                       'crh-latn' => 'rayonınıñ rayonınıñ Noğay Noğay Yürtü Yürtü vatandan vatandan',
-                               ],
-                               'rayonınıñ районынынъ Noğay Ногъай Yürtü Юрьтю vatandan ватандан'
-                       ],
-                       [ // recent problem words, part 5
-                               [
-                                       'crh'      => 'ком-кок köm-kök rol роль AQQI АКЪКЪЫ DAĞĞA ДАГЪГЪА 13-ünci 13-юнджи',
-                                       'crh-cyrl' => 'ком-кок ком-кок роль роль АКЪКЪЫ АКЪКЪЫ ДАГЪГЪА ДАГЪГЪА 13-юнджи 13-юнджи',
-                                       'crh-latn' => 'köm-kök köm-kök rol rol AQQI AQQI DAĞĞA DAĞĞA 13-ünci 13-ünci',
-                               ],
-                               'ком-кок köm-kök rol роль AQQI АКЪКЪЫ DAĞĞA ДАГЪГЪА 13-ünci 13-юнджи'
-                       ],
-                       [ // recent problem words, part 6
-                               [
-                                       'crh'      => 'ДЖУРЬМЕК CÜRMEK кетсин ketsin джумлеси cümlesi ильи ilyi Ильи İlyi',
-                                       'crh-cyrl' => 'ДЖУРЬМЕК ДЖУРЬМЕК кетсин кетсин джумлеси джумлеси ильи ильи Ильи Ильи',
-                                       'crh-latn' => 'CÜRMEK CÜRMEK ketsin ketsin cümlesi cümlesi ilyi ilyi İlyi İlyi',
-                               ],
-                               'ДЖУРЬМЕК CÜRMEK кетсин ketsin джумлеси cümlesi ильи ilyi Ильи İlyi'
-                       ],
-                       [ // recent problem words, part 7
-                               [
-                                       'crh'      => 'бруцел brutsel коцюб kotsüb плацен platsen эпицентр epitsentr',
-                                       'crh-cyrl' => 'бруцел бруцел коцюб коцюб плацен плацен эпицентр эпицентр',
-                                       'crh-latn' => 'brutsel brutsel kotsüb kotsüb platsen platsen epitsentr epitsentr',
-                               ],
-                               'бруцел brutsel коцюб kotsüb плацен platsen эпицентр epitsentr'
-                       ],
-                       [ // regex pattern words
-                               [
-                                       'crh'      => 'köyünden коюнден ange аньге',
-                                       'crh-cyrl' => 'коюнден коюнден аньге аньге',
-                                       'crh-latn' => 'köyünden köyünden ange ange',
-                               ],
-                               'köyünden коюнден ange аньге'
-                       ],
-                       [ // multi part words
-                               [
-                                       'crh'      => 'эки юз eki yüz',
-                                       'crh-cyrl' => 'эки юз эки юз',
-                                       'crh-latn' => 'eki yüz eki yüz',
-                               ],
-                               'эки юз eki yüz'
-                       ],
-                       [ // affix patterns
-                               [
-                                       'crh'      => 'köyniñ койнинъ Avcıköyde Авджыкойде ekvatorial экваториаль Canköy Джанкой',
-                                       'crh-cyrl' => 'койнинъ койнинъ Авджыкойде Авджыкойде экваториаль экваториаль Джанкой Джанкой',
-                                       'crh-latn' => 'köyniñ köyniñ Avcıköyde Avcıköyde ekvatorial ekvatorial Canköy Canköy',
-                               ],
-                               'köyniñ койнинъ Avcıköyde Авджыкойде ekvatorial экваториаль Canköy Джанкой'
-                       ],
                        [ // Roman numerals and quotes, esp. single-letter Roman numerals at the end of a string
                                [
                                        'crh'      => 'VI,VII IX “dört” «дёрт» XI XII I V X L C D M',
@@ -144,30 +118,6 @@ class LanguageCrhTest extends LanguageClassesTestCase {
                                ],
                                'VI,VII IX “dört” «дёрт» XI XII I V X L C D M'
                        ],
-                       [ // Roman numerals vs Initials, part 1 - Roman numeral initials without spaces
-                               [
-                                       'crh'      => 'A.B.C.D.M. Qadırova XII, А.Б.Дж.Д.М. Къадырова XII',
-                                       'crh-cyrl' => 'А.Б.Дж.Д.М. Къадырова XII, А.Б.Дж.Д.М. Къадырова XII',
-                                       'crh-latn' => 'A.B.C.D.M. Qadırova XII, A.B.C.D.M. Qadırova XII',
-                               ],
-                               'A.B.C.D.M. Qadırova XII, А.Б.Дж.Д.М. Къадырова XII'
-                       ],
-                       [ // Roman numerals vs Initials, part 2 - Roman numeral initials with spaces
-                               [
-                                       'crh'      => 'G. H. I. V. X. L. Memetov III, Г. Х. Ы. В. X. Л. Меметов III',
-                                       'crh-cyrl' => 'Г. Х. Ы. В. X. Л. Меметов III, Г. Х. Ы. В. X. Л. Меметов III',
-                                       'crh-latn' => 'G. H. I. V. X. L. Memetov III, G. H. I. V. X. L. Memetov III',
-                               ],
-                               'G. H. I. V. X. L. Memetov III, Г. Х. Ы. В. X. Л. Меметов III'
-                       ],
-                       [ // ALL CAPS, made up acronyms
-                               [
-                                       'crh'      => 'ÑAB QIC ĞUK COT НЪАБ КЪЫДЖ ГЪУК ДЖОТ CA ДЖА',
-                                       'crh-cyrl' => 'НЪАБ КЪЫДЖ ГЪУК ДЖОТ НЪАБ КЪЫДЖ ГЪУК ДЖОТ ДЖА ДЖА',
-                                       'crh-latn' => 'ÑAB QIC ĞUK COT ÑAB QIC ĞUK COT CA CA',
-                               ],
-                               'ÑAB QIC ĞUK COT НЪАБ КЪЫДЖ ГЪУК ДЖОТ CA ДЖА'
-                       ],
                        [ // Many-to-one mappings: many Cyrillic to one Latin
                                [
                                        'crh'      => 'шофер шофёр şoför корбекул корьбекул корьбекуль körbekül',
index 143a419..4d35930 100644 (file)
@@ -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/MockSearchEngine.php b/tests/phpunit/mocks/search/MockSearchEngine.php
new file mode 100644 (file)
index 0000000..4d7c78a
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+
+use MediaWiki\MediaWikiServices;
+
+class MockSearchEngine extends SearchEngine {
+       /** @var SearchResult[][] */
+       private static $results = [];
+       /** @var SearchResultSet[][] */
+       private static $interwikiResults = [];
+
+       public static function clearMockResults() {
+               self::$results = [];
+               self::$interwikiResults = [];
+       }
+
+       /**
+        * @param string $query The query searched for *after* initial
+        *  transformations have been applied.
+        * @param SearchResult[] $results The results to return for $query
+        */
+       public static function addMockResults( $query, array $results ) {
+               self::$results[$query] = $results;
+               $lc = MediaWikiServices::getInstance()->getLinkCache();
+               foreach ( $results as $result ) {
+                       // TODO: better page ids?
+                       $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 (file)
index 0000000..d92d39a
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+
+class MockSearchResult extends SearchResult {
+       private $isMissingRevision = false;
+       private $isBrokenTitle = false;
+
+       public function isMissingRevision() {
+               return $this->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 (file)
index 0000000..99f093f
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+
+class MockSearchResultSet extends SearchResultSet {
+       /*
+        * @var SearchResultSet[][] Map from result type to list of results for
+        *  that type.
+        */
+       private $interwikiResults;
+
+       /**
+        * @param SearchResult[] $results
+        * @param SearchResultSet[][] $interwikiResults Map from result type
+        *  to list of results for that type.
+        */
+       public function __construct( array $results, array $interwikiResults = [] ) {
+               $this->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;
+               }
+       }
+}
index 6c2ff02..ea132e9 100644 (file)
@@ -35,6 +35,9 @@ class AvailableRightsTest extends PHPUnit\Framework\TestCase {
                return $rights;
        }
 
+       /**
+        * @coversNothing
+        */
        public function testAvailableRights() {
                $missingRights = array_diff(
                        $this->getAllVisibleRights(),
index c8bcd60..c75a9d0 100644 (file)
@@ -32,6 +32,7 @@ class ContentHandlerSanityTest extends MediaWikiTestCase {
        }
 
        /**
+        * @coversNothing
         * @dataProvider provideHandlers
         * @param ContentHandler $handler
         */
index 60c97cc..dea8f5a 100644 (file)
@@ -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 {
 
index 62ddace..2090e29 100644 (file)
@@ -11,6 +11,7 @@
  * @copyright © 2012, Niklas Laxström
  * @copyright © 2012, Santhosh Thottingal
  * @copyright © 2012, Timo Tijhof
+ * @coversNothing
  */
 class ResourcesTest extends MediaWikiTestCase {
 
index 4df791e..82302b1 100644 (file)
@@ -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() ) {
index 02934fa..7d1d331 100644 (file)
@@ -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 );
        }
index 4a5c254..f6bb944 100755 (executable)
@@ -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
index dfc6fa1..5dbe84b 100644 (file)
@@ -10,8 +10,8 @@ describe( 'Page', function () {
        var content,
                name;
 
-       function getTestString() {
-               return Math.random().toString() + '-öäü-♠♣♥♦';
+       function getTestString( suffix = 'defaultsuffix' ) {
+               return Math.random().toString() + '-öäü-♠♣♥♦-' + 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 () {