Merge "Add flag to HTMLTextField to not persist submitted data"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 1 Apr 2016 14:16:16 +0000 (14:16 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 1 Apr 2016 14:16:16 +0000 (14:16 +0000)
234 files changed:
RELEASE-NOTES-1.27
autoload.php
docs/extension.schema.json
includes/DefaultSettings.php
includes/GitInfo.php
includes/HttpFunctions.php
includes/OutputPage.php
includes/Preferences.php
includes/WatchedItem.php
includes/WatchedItemStore.php
includes/WebRequest.php
includes/api/ApiMain.php
includes/api/ApiQueryExtLinksUsage.php
includes/api/i18n/ba.json
includes/api/i18n/be-tarask.json
includes/api/i18n/de.json
includes/api/i18n/es.json
includes/api/i18n/fr.json
includes/api/i18n/he.json
includes/api/i18n/id.json
includes/api/i18n/it.json
includes/api/i18n/ja.json
includes/api/i18n/mg.json
includes/api/i18n/pl.json
includes/api/i18n/ru.json
includes/cache/LCStoreStaticArray.php [deleted file]
includes/cache/LocalisationCache.php [deleted file]
includes/cache/localisation/LCStore.php [new file with mode: 0644]
includes/cache/localisation/LCStoreCDB.php [new file with mode: 0644]
includes/cache/localisation/LCStoreDB.php [new file with mode: 0644]
includes/cache/localisation/LCStoreNull.php [new file with mode: 0644]
includes/cache/localisation/LCStoreStaticArray.php [new file with mode: 0644]
includes/cache/localisation/LocalisationCache.php [new file with mode: 0644]
includes/cache/localisation/LocalisationCacheBulkLoad.php [new file with mode: 0644]
includes/changes/RecentChange.php
includes/debug/logger/monolog/WikiProcessor.php
includes/exception/MWException.php
includes/exception/MWExceptionHandler.php
includes/filerepo/LocalRepo.php
includes/filerepo/file/LocalFile.php
includes/htmlform/HTMLButtonField.php
includes/htmlform/HTMLForm.php
includes/htmlform/HTMLFormField.php
includes/installer/i18n/ba.json
includes/installer/i18n/be-tarask.json
includes/installer/i18n/es.json
includes/installer/i18n/fi.json
includes/installer/i18n/pl.json
includes/installer/i18n/pt-br.json
includes/libs/objectcache/WANObjectCache.php
includes/logging/LogEventsList.php
includes/logging/PatrolLog.php
includes/logging/PatrolLogFormatter.php
includes/media/DjVu.php
includes/page/Article.php
includes/parser/Preprocessor.php
includes/parser/Preprocessor_DOM.php
includes/parser/Preprocessor_Hash.php
includes/search/SearchSuggestion.php
includes/skins/SkinTemplate.php
includes/specials/SpecialActiveusers.php
includes/specials/SpecialAllMessages.php
includes/specials/SpecialBlockList.php
includes/specials/SpecialCategories.php
includes/specials/SpecialContributions.php
includes/specials/SpecialDeletedContributions.php
includes/specials/SpecialEditWatchlist.php
includes/specials/SpecialListfiles.php
includes/specials/SpecialListusers.php
includes/specials/SpecialLog.php
includes/specials/SpecialMergeHistory.php
includes/specials/SpecialNewimages.php
includes/specials/SpecialNewpages.php
includes/specials/SpecialProtectedtitles.php
includes/specials/SpecialRedirect.php
includes/specials/SpecialUnblock.php
includes/specials/SpecialUndelete.php
includes/specials/SpecialUserrights.php
includes/specials/pagers/ActiveUsersPager.php [new file with mode: 0644]
includes/specials/pagers/AllMessagesTablePager.php [new file with mode: 0644]
includes/specials/pagers/BlockListPager.php [new file with mode: 0644]
includes/specials/pagers/CategoryPager.php [new file with mode: 0644]
includes/specials/pagers/ContribsPager.php [new file with mode: 0644]
includes/specials/pagers/DeletedContribsPager.php [new file with mode: 0644]
includes/specials/pagers/ImageListPager.php [new file with mode: 0644]
includes/specials/pagers/MergeHistoryPager.php [new file with mode: 0644]
includes/specials/pagers/NewFilesPager.php [new file with mode: 0644]
includes/specials/pagers/NewPagesPager.php [new file with mode: 0644]
includes/specials/pagers/ProtectedTitlesPager.php [new file with mode: 0644]
includes/specials/pagers/UsersPager.php [new file with mode: 0644]
includes/upload/UploadBase.php
includes/user/BotPassword.php
includes/user/User.php
includes/utils/MWCryptHash.php
languages/Language.php
languages/i18n/af.json
languages/i18n/an.json
languages/i18n/ar.json
languages/i18n/ba.json
languages/i18n/be-tarask.json
languages/i18n/be.json
languages/i18n/bgn.json
languages/i18n/bs.json
languages/i18n/ca.json
languages/i18n/ce.json
languages/i18n/crh-cyrl.json
languages/i18n/crh-latn.json
languages/i18n/cs.json
languages/i18n/cy.json
languages/i18n/da.json
languages/i18n/de.json
languages/i18n/el.json
languages/i18n/en.json
languages/i18n/eo.json
languages/i18n/es.json
languages/i18n/et.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/frp.json
languages/i18n/frr.json
languages/i18n/ga.json
languages/i18n/gl.json
languages/i18n/gsw.json
languages/i18n/he.json
languages/i18n/hi.json
languages/i18n/hu.json
languages/i18n/ia.json
languages/i18n/id.json
languages/i18n/ilo.json
languages/i18n/inh.json
languages/i18n/is.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/kk-cyrl.json
languages/i18n/ksh.json
languages/i18n/la.json
languages/i18n/lb.json
languages/i18n/lij.json
languages/i18n/lrc.json
languages/i18n/lt.json
languages/i18n/mai.json
languages/i18n/mg.json
languages/i18n/mk.json
languages/i18n/ml.json
languages/i18n/mr.json
languages/i18n/ms.json
languages/i18n/my.json
languages/i18n/nan.json
languages/i18n/nap.json
languages/i18n/nb.json
languages/i18n/nl.json
languages/i18n/nn.json
languages/i18n/or.json
languages/i18n/pl.json
languages/i18n/ps.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/qqq.json
languages/i18n/ro.json
languages/i18n/ru.json
languages/i18n/sa.json
languages/i18n/sah.json
languages/i18n/sh.json
languages/i18n/sk.json
languages/i18n/sl.json
languages/i18n/sv.json
languages/i18n/ta.json
languages/i18n/te.json
languages/i18n/tr.json
languages/i18n/uk.json
languages/i18n/vi.json
languages/i18n/xmf.json
languages/i18n/yi.json
languages/i18n/yue.json
languages/i18n/zh-hans.json
languages/i18n/zh-hant.json
maintenance/dictionary/mediawiki.dic
maintenance/language/digit2html.php
maintenance/language/zhtable/Makefile.py
maintenance/refreshImageMetadata.php
package.json
resources/Resources.php
resources/src/mediawiki.language/specialcharacters.json
resources/src/mediawiki.special/mediawiki.special.apisandbox.js
resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js
resources/src/mediawiki.widgets/mw.widgets.TitleWidget.js
resources/src/mediawiki/api.js
resources/src/mediawiki/mediawiki.requestIdleCallback.js
tests/TestsAutoLoader.php
tests/parser/extraParserTests.txt
tests/parser/parserTest.inc
tests/parser/parserTests.txt
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/includes/HtmlTest.php
tests/phpunit/includes/HttpTest.php
tests/phpunit/includes/LinkerTest.php
tests/phpunit/includes/OutputPageTest.php
tests/phpunit/includes/PathRouterTest.php
tests/phpunit/includes/WatchedItemStoreUnitTest.php
tests/phpunit/includes/WatchedItemUnitTest.php
tests/phpunit/includes/XmlTest.php
tests/phpunit/includes/api/ApiLoginTest.php
tests/phpunit/includes/api/format/ApiFormatPhpTest.php
tests/phpunit/includes/api/format/ApiFormatXmlTest.php
tests/phpunit/includes/content/CssContentHandlerTest.php
tests/phpunit/includes/content/JavaScriptContentHandlerTest.php
tests/phpunit/includes/content/JavaScriptContentTest.php
tests/phpunit/includes/import/ImportTest.php
tests/phpunit/includes/libs/CSSMinTest.php
tests/phpunit/includes/media/GIFTest.php
tests/phpunit/includes/media/PNGTest.php
tests/phpunit/includes/media/WebPTest.php
tests/phpunit/includes/parser/NewParserTest.php
tests/phpunit/includes/parser/PreprocessorTest.php
tests/phpunit/includes/password/BcryptPasswordTest.php
tests/phpunit/includes/password/LayeredParameterizedPasswordTest.php
tests/phpunit/includes/session/BotPasswordSessionProviderTest.php
tests/phpunit/includes/session/ImmutableSessionProviderWithCookieTest.php
tests/phpunit/includes/session/PHPSessionHandlerTest.php
tests/phpunit/includes/session/SessionBackendTest.php
tests/phpunit/includes/session/SessionInfoTest.php
tests/phpunit/includes/session/SessionManagerTest.php
tests/phpunit/includes/session/SessionProviderTest.php
tests/phpunit/includes/session/SessionTest.php
tests/phpunit/includes/session/TestUtils.php
tests/phpunit/includes/session/TokenTest.php
tests/phpunit/includes/specials/SpecialPageExecutor.php [new file with mode: 0644]
tests/phpunit/includes/specials/SpecialPageTestBase.php
tests/phpunit/includes/upload/UploadBaseTest.php
tests/phpunit/includes/user/BotPasswordTest.php
tests/phpunit/includes/utils/MWCryptHKDFTest.php
tests/phpunit/languages/LanguageTest.php
tests/phpunit/phpunit.php

index 2f8f53a..e8924ef 100644 (file)
@@ -104,6 +104,9 @@ HHVM 3.1.
 * $wgPreloadJavaScriptMwUtil was removed (deprecated in 1.26).
   Extensions, skins, gadgets and scripts that use the mediawiki.util module must
   express a dependency on it.
+* $wgIncludeLegacyJavaScript, deprecated in MediaWiki 1.26, now defaults false.
+  Extensions, skins, gadgets and scripts that need the mediawiki.legacy.wikibits
+  module should express a dependency on it.
 
 === New features in 1.27 ===
 * $wgDataCenterUpdateStickTTL was also added. This decides how long a user
@@ -172,6 +175,12 @@ HHVM 3.1.
   be a good idea, but will log out all current sessions.
 * $wgEventRelayerConfig was added, for managing PubSub event relay configuration,
   specifically for reliable CDN url purges.
+* Requests have unique IDs, equal to the UNIQUE_ID environment variable (when
+  MediaWiki is behind Apache+mod_unique_id or something similar) or a randomly-
+  generated 24-character string. This request ID is used to annotate log records
+  and error messages. It is available client-side via mw.config.get( 'wgRequestId' ).
+  The request ID supplants exception IDs. Accordingly, MWExceptionHandler::getLogId()
+  is deprecated.
 
 === External library changes in 1.27 ===
 
@@ -250,6 +259,7 @@ HHVM 3.1.
 * OutputPage::getScript() was removed (deprecated since 1.24).
 * OutputPage::out() was removed (deprecated since 1.22).
 * OutputPage::setAllowedModules() was removed (deprecated since 1.24).
+* UserrightsPage::makeGroupNameListForLog() was removed (deprecated since 1.21).
 
 === Languages updated in 1.27 ===
 
index e74df0a..a4c09e0 100644 (file)
@@ -7,11 +7,11 @@ $wgAutoloadLocalClasses = [
        'APCBagOStuff' => __DIR__ . '/includes/libs/objectcache/APCBagOStuff.php',
        'AbstractContent' => __DIR__ . '/includes/content/AbstractContent.php',
        'Action' => __DIR__ . '/includes/actions/Action.php',
-       'ActiveUsersPager' => __DIR__ . '/includes/specials/SpecialActiveusers.php',
+       'ActiveUsersPager' => __DIR__ . '/includes/specials/pagers/ActiveUsersPager.php',
        'ActivityUpdateJob' => __DIR__ . '/includes/jobqueue/jobs/ActivityUpdateJob.php',
        'AjaxDispatcher' => __DIR__ . '/includes/AjaxDispatcher.php',
        'AjaxResponse' => __DIR__ . '/includes/AjaxResponse.php',
-       'AllMessagesTablePager' => __DIR__ . '/includes/specials/SpecialAllMessages.php',
+       'AllMessagesTablePager' => __DIR__ . '/includes/specials/pagers/AllMessagesTablePager.php',
        'AllTrans' => __DIR__ . '/maintenance/language/alltrans.php',
        'AlphabeticPager' => __DIR__ . '/includes/pager/AlphabeticPager.php',
        'AlterSharedConstraints' => __DIR__ . '/maintenance/oracle/alterSharedConstraints.php',
@@ -180,7 +180,7 @@ $wgAutoloadLocalClasses = [
        'BitmapMetadataHandler' => __DIR__ . '/includes/media/BitmapMetadataHandler.php',
        'Blob' => __DIR__ . '/includes/db/DatabaseUtility.php',
        'Block' => __DIR__ . '/includes/Block.php',
-       'BlockListPager' => __DIR__ . '/includes/specials/SpecialBlockList.php',
+       'BlockListPager' => __DIR__ . '/includes/specials/pagers/BlockListPager.php',
        'BlockLogFormatter' => __DIR__ . '/includes/logging/BlockLogFormatter.php',
        'BmpHandler' => __DIR__ . '/includes/media/BMP.php',
        'BotPassword' => __DIR__ . '/includes/user/BotPassword.php',
@@ -200,7 +200,7 @@ $wgAutoloadLocalClasses = [
        'CategoryMembershipChange' => __DIR__ . '/includes/changes/CategoryMembershipChange.php',
        'CategoryMembershipChangeJob' => __DIR__ . '/includes/jobqueue/jobs/CategoryMembershipChangeJob.php',
        'CategoryPage' => __DIR__ . '/includes/page/CategoryPage.php',
-       'CategoryPager' => __DIR__ . '/includes/specials/SpecialCategories.php',
+       'CategoryPager' => __DIR__ . '/includes/specials/pagers/CategoryPager.php',
        'CategoryViewer' => __DIR__ . '/includes/CategoryViewer.php',
        'CdbException' => __DIR__ . '/includes/compat/CdbCompat.php',
        'CdbReader' => __DIR__ . '/includes/compat/CdbCompat.php',
@@ -263,7 +263,7 @@ $wgAutoloadLocalClasses = [
        'ContentHandler' => __DIR__ . '/includes/content/ContentHandler.php',
        'ContentModelLogFormatter' => __DIR__ . '/includes/logging/ContentModelLogFormatter.php',
        'ContextSource' => __DIR__ . '/includes/context/ContextSource.php',
-       'ContribsPager' => __DIR__ . '/includes/specials/SpecialContributions.php',
+       'ContribsPager' => __DIR__ . '/includes/specials/pagers/ContribsPager.php',
        'ConvertExtensionToRegistration' => __DIR__ . '/maintenance/convertExtensionToRegistration.php',
        'ConvertLinks' => __DIR__ . '/maintenance/convertLinks.php',
        'ConvertUserOptions' => __DIR__ . '/maintenance/convertUserOptions.php',
@@ -332,7 +332,7 @@ $wgAutoloadLocalClasses = [
        'DeleteOrphanedRevisions' => __DIR__ . '/maintenance/deleteOrphanedRevisions.php',
        'DeleteRevision' => __DIR__ . '/maintenance/deleteRevision.php',
        'DeleteSelfExternals' => __DIR__ . '/maintenance/deleteSelfExternals.php',
-       'DeletedContribsPager' => __DIR__ . '/includes/specials/SpecialDeletedContributions.php',
+       'DeletedContribsPager' => __DIR__ . '/includes/specials/pagers/DeletedContribsPager.php',
        'DeletedContributionsPage' => __DIR__ . '/includes/specials/SpecialDeletedContributions.php',
        'DependencyWrapper' => __DIR__ . '/includes/cache/CacheDependency.php',
        'DeprecatedGlobal' => __DIR__ . '/includes/DeprecatedGlobal.php',
@@ -573,7 +573,7 @@ $wgAutoloadLocalClasses = [
        'ImageHandler' => __DIR__ . '/includes/media/ImageHandler.php',
        'ImageHistoryList' => __DIR__ . '/includes/page/ImageHistoryList.php',
        'ImageHistoryPseudoPager' => __DIR__ . '/includes/page/ImageHistoryPseudoPager.php',
-       'ImageListPager' => __DIR__ . '/includes/specials/SpecialListfiles.php',
+       'ImageListPager' => __DIR__ . '/includes/specials/pagers/ImageListPager.php',
        'ImagePage' => __DIR__ . '/includes/page/ImagePage.php',
        'ImageQueryPage' => __DIR__ . '/includes/specialpage/ImageQueryPage.php',
        'ImportLogFormatter' => __DIR__ . '/includes/logging/ImportLogFormatter.php',
@@ -634,11 +634,11 @@ $wgAutoloadLocalClasses = [
        'LBFactoryMulti' => __DIR__ . '/includes/db/loadbalancer/LBFactoryMulti.php',
        'LBFactorySimple' => __DIR__ . '/includes/db/loadbalancer/LBFactorySimple.php',
        'LBFactorySingle' => __DIR__ . '/includes/db/loadbalancer/LBFactorySingle.php',
-       'LCStore' => __DIR__ . '/includes/cache/LocalisationCache.php',
-       'LCStoreCDB' => __DIR__ . '/includes/cache/LocalisationCache.php',
-       'LCStoreDB' => __DIR__ . '/includes/cache/LocalisationCache.php',
-       'LCStoreNull' => __DIR__ . '/includes/cache/LocalisationCache.php',
-       'LCStoreStaticArray' => __DIR__ . '/includes/cache/LCStoreStaticArray.php',
+       'LCStore' => __DIR__ . '/includes/cache/localisation/LCStore.php',
+       'LCStoreCDB' => __DIR__ . '/includes/cache/localisation/LCStoreCDB.php',
+       'LCStoreDB' => __DIR__ . '/includes/cache/localisation/LCStoreDB.php',
+       'LCStoreNull' => __DIR__ . '/includes/cache/localisation/LCStoreNull.php',
+       'LCStoreStaticArray' => __DIR__ . '/includes/cache/localisation/LCStoreStaticArray.php',
        'LangMemUsage' => __DIR__ . '/maintenance/language/langmemusage.php',
        'Language' => __DIR__ . '/languages/Language.php',
        'LanguageAr' => __DIR__ . '/languages/classes/LanguageAr.php',
@@ -718,8 +718,9 @@ $wgAutoloadLocalClasses = [
        'LocalIdLookup' => __DIR__ . '/includes/user/LocalIdLookup.php',
        'LocalRepo' => __DIR__ . '/includes/filerepo/LocalRepo.php',
        'LocalSettingsGenerator' => __DIR__ . '/includes/installer/LocalSettingsGenerator.php',
-       'LocalisationCache' => __DIR__ . '/includes/cache/LocalisationCache.php',
-       'LocalisationCacheBulkLoad' => __DIR__ . '/includes/cache/LocalisationCache.php',
+       'LocalisationCache' => __DIR__ . '/includes/cache/localisation/LocalisationCache.php',
+       'LocalisationCacheBulkLoad' => __DIR__ .
+               '/includes/cache/localisation/LocalisationCacheBulkLoad.php',
        'LockManager' => __DIR__ . '/includes/filebackend/lockmanager/LockManager.php',
        'LockManagerGroup' => __DIR__ . '/includes/filebackend/lockmanager/LockManagerGroup.php',
        'LogEntry' => __DIR__ . '/includes/logging/LogEntry.php',
@@ -833,7 +834,7 @@ $wgAutoloadLocalClasses = [
        'MemoizedCallable' => __DIR__ . '/includes/libs/MemoizedCallable.php',
        'MemoryFileBackend' => __DIR__ . '/includes/filebackend/MemoryFileBackend.php',
        'MergeHistory' => __DIR__ . '/includes/MergeHistory.php',
-       'MergeHistoryPager' => __DIR__ . '/includes/specials/SpecialMergeHistory.php',
+       'MergeHistoryPager' => __DIR__ . '/includes/specials/pagers/MergeHistoryPager.php',
        'MergeLogFormatter' => __DIR__ . '/includes/logging/MergeLogFormatter.php',
        'MergeMessageFileList' => __DIR__ . '/maintenance/mergeMessageFileList.php',
        'MergeableUpdate' => __DIR__ . '/includes/deferred/MergeableUpdate.php',
@@ -880,8 +881,8 @@ $wgAutoloadLocalClasses = [
        'NamespaceAwareForeignTitleFactory' => __DIR__ . '/includes/title/NamespaceAwareForeignTitleFactory.php',
        'NamespaceConflictChecker' => __DIR__ . '/maintenance/namespaceDupes.php',
        'NamespaceImportTitleFactory' => __DIR__ . '/includes/title/NamespaceImportTitleFactory.php',
-       'NewFilesPager' => __DIR__ . '/includes/specials/SpecialNewimages.php',
-       'NewPagesPager' => __DIR__ . '/includes/specials/SpecialNewpages.php',
+       'NewFilesPager' => __DIR__ . '/includes/specials/pagers/NewFilesPager.php',
+       'NewPagesPager' => __DIR__ . '/includes/specials/pagers/NewPagesPager.php',
        'NewUsersLogFormatter' => __DIR__ . '/includes/logging/NewUsersLogFormatter.php',
        'NolinesImageGallery' => __DIR__ . '/includes/gallery/NolinesImageGallery.php',
        'NotRecursiveIterator' => __DIR__ . '/includes/utils/iterators/NotRecursiveIterator.php',
@@ -1006,7 +1007,7 @@ $wgAutoloadLocalClasses = [
        'ProtectAction' => __DIR__ . '/includes/actions/ProtectAction.php',
        'ProtectLogFormatter' => __DIR__ . '/includes/logging/ProtectLogFormatter.php',
        'ProtectedPagesPager' => __DIR__ . '/includes/specials/SpecialProtectedpages.php',
-       'ProtectedTitlesPager' => __DIR__ . '/includes/specials/SpecialProtectedtitles.php',
+       'ProtectedTitlesPager' => __DIR__ . '/includes/specials/pagers/ProtectedTitlesPager.php',
        'ProtectionForm' => __DIR__ . '/includes/ProtectionForm.php',
        'PruneFileCache' => __DIR__ . '/maintenance/pruneFileCache.php',
        'PublishStashedFileJob' => __DIR__ . '/includes/jobqueue/jobs/PublishStashedFileJob.php',
@@ -1387,7 +1388,7 @@ $wgAutoloadLocalClasses = [
        'UsercreateTemplate' => __DIR__ . '/includes/templates/Usercreate.php',
        'UserloginTemplate' => __DIR__ . '/includes/templates/Userlogin.php',
        'UserrightsPage' => __DIR__ . '/includes/specials/SpecialUserrights.php',
-       'UsersPager' => __DIR__ . '/includes/specials/SpecialListusers.php',
+       'UsersPager' => __DIR__ . '/includes/specials/pagers/UsersPager.php',
        'UtfNormal' => __DIR__ . '/includes/compat/normal/UtfNormal.php',
        'UzConverter' => __DIR__ . '/languages/classes/LanguageUz.php',
        'VFormHTMLForm' => __DIR__ . '/includes/htmlform/VFormHTMLForm.php',
index 4218e8a..a743afa 100644 (file)
                                                                        ]
                                                                },
                                                                "templates": {
-                                                                       "type": "object",
+                                                                       "type": ["object", "array"],
                                                                        "description": "Templates to be loaded for client-side usage"
                                                                },
                                                                "targets": {
index 63d04c9..4950359 100644 (file)
@@ -3562,7 +3562,7 @@ $wgResourceLoaderMinifierMaxLineLength = 1000;
  *
  * @deprecated since 1.26: Always declare dependencies.
  */
-$wgIncludeLegacyJavaScript = true;
+$wgIncludeLegacyJavaScript = false;
 
 /**
  * Whether or not to assign configuration variables to the global window object.
@@ -4631,15 +4631,15 @@ $wgAuthenticationTokenVersion = null;
  * @since 1.27
  */
 $wgSessionProviders = [
-       'MediaWiki\\Session\\CookieSessionProvider' => [
-               'class' => 'MediaWiki\\Session\\CookieSessionProvider',
+       MediaWiki\Session\CookieSessionProvider::class => [
+               'class' => MediaWiki\Session\CookieSessionProvider::class,
                'args' => [ [
                        'priority' => 30,
                        'callUserSetCookiesHook' => true,
                ] ],
        ],
-       'MediaWiki\\Session\\BotPasswordSessionProvider' => [
-               'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider',
+       MediaWiki\Session\BotPasswordSessionProvider::class => [
+               'class' => MediaWiki\Session\BotPasswordSessionProvider::class,
                'args' => [ [
                        'priority' => 40,
                ] ],
@@ -6210,14 +6210,15 @@ $wgGitBin = '/usr/bin/git';
  * %h will be replaced by the short SHA-1 (7 first chars) and %H by the
  * full SHA-1 of the HEAD revision.
  * %r will be replaced with a URL-encoded version of $1.
+ * %R will be replaced with $1 and no URL-encoding
  *
  * @since 1.20
  */
 $wgGitRepositoryViewers = [
        'https://(?:[a-z0-9_]+@)?gerrit.wikimedia.org/r/(?:p/)?(.*)' =>
-               'https://git.wikimedia.org/tree/%r/%H',
+               'https://phabricator.wikimedia.org/r/revision/%R;%H',
        'ssh://(?:[a-z0-9_]+@)?gerrit.wikimedia.org:29418/(.*)' =>
-               'https://git.wikimedia.org/tree/%r/%H',
+               'https://phabricator.wikimedia.org/r/revision/%R;%H',
 ];
 
 /** @} */ # End of maintenance }
@@ -7190,6 +7191,7 @@ $wgLogActionsHandlers = [
        'move/move' => 'MoveLogFormatter',
        'move/move_redir' => 'MoveLogFormatter',
        'patrol/patrol' => 'PatrolLogFormatter',
+       'patrol/autopatrol' => 'PatrolLogFormatter',
        'protect/modify' => 'ProtectLogFormatter',
        'protect/move_prot' => 'ProtectLogFormatter',
        'protect/protect' => 'ProtectLogFormatter',
@@ -7207,6 +7209,41 @@ $wgLogActionsHandlers = [
        'upload/upload' => 'UploadLogFormatter',
 ];
 
+/**
+ * List of log types that can be filtered by action types
+ *
+ * To each action is associated the list of log_action
+ * subtypes to search for, usually one, but not necessarily so
+ * Extensions may append to this array
+ * @since 1.27
+ */
+$wgActionFilteredLogs = [
+       'block' => [
+               'block' => [ 'block' ],
+               'reblock' => [ 'reblock' ],
+               'unblock' => [ 'unblock' ],
+       ],
+       'delete' => [
+               'delete' => [ 'delete' ],
+               'restore' => [ 'restore' ],
+               'event' => [ 'event' ],
+               'revision' => [ 'revision' ],
+       ],
+       'patrol' => [
+               'patrol' => [ 'patrol' ],
+               'autopatrol' => [ 'autopatrol' ],
+       ],
+       'protect' => [
+               'protect' => [ 'protect' ],
+               'modify' => [ 'modify' ],
+               'unprotect' => [ 'unprotect' ],
+       ],
+       'upload' => [
+               'upload' => [ 'upload' ],
+               'overwrite' => [ 'overwrite' ],
+       ],
+];
+
 /**
  * Maintain a log of newusers at Log/newusers?
  */
index 29516ab..de7e8c2 100644 (file)
@@ -257,9 +257,6 @@ class GitInfo {
                if ( $url === false ) {
                        return false;
                }
-               if ( substr( $url, -4 ) !== '.git' ) {
-                       $url .= '.git';
-               }
                foreach ( self::getViewers() as $repo => $viewer ) {
                        $pattern = '#^' . $repo . '$#';
                        if ( preg_match( $pattern, $url, $matches ) ) {
@@ -269,6 +266,7 @@ class GitInfo {
                                        '%h' => substr( $headSHA1, 0, 7 ),
                                        '%H' => $headSHA1,
                                        '%r' => urlencode( $matches[1] ),
+                                       '%R' => $matches[1],
                                ];
                                return strtr( $viewerUrl, $replacements );
                        }
index 1a6e382..3f42038 100644 (file)
@@ -192,6 +192,26 @@ class Http {
                        $uri
                );
        }
+
+       /**
+        * Gets the relevant proxy from $wgHTTPProxy/http_proxy (when set).
+        *
+        * @return mixed The proxy address or an empty string if not set.
+        */
+       public static function getProxy() {
+               global $wgHTTPProxy;
+
+               if ( $wgHTTPProxy ) {
+                       return $wgHTTPProxy;
+               }
+
+               $envHttpProxy = getenv( "http_proxy" );
+               if ( $envHttpProxy ) {
+                       return $envHttpProxy;
+               }
+
+               return "";
+       }
 }
 
 /**
@@ -368,8 +388,6 @@ class MWHttpRequest {
         * @return void
         */
        public function proxySetup() {
-               global $wgHTTPProxy;
-
                // If there is an explicit proxy set and proxies are not disabled, then use it
                if ( $this->proxy && !$this->noProxy ) {
                        return;
@@ -379,10 +397,8 @@ class MWHttpRequest {
                // local URL and proxies are not disabled
                if ( Http::isLocalURL( $this->url ) || $this->noProxy ) {
                        $this->proxy = '';
-               } elseif ( $wgHTTPProxy ) {
-                       $this->proxy = $wgHTTPProxy;
-               } elseif ( getenv( "http_proxy" ) ) {
-                       $this->proxy = getenv( "http_proxy" );
+               } else {
+                       $this->proxy = Http::getProxy();
                }
        }
 
index 0c3d609..c724207 100644 (file)
@@ -2315,11 +2315,21 @@ class OutputPage extends ContextSource {
                        // adding of CSS or Javascript by extensions.
                        Hooks::run( 'BeforePageDisplay', [ &$this, &$sk ] );
 
-                       $sk->outputPage();
+                       try {
+                               $sk->outputPage();
+                       } catch ( Exception $e ) {
+                               ob_end_clean(); // bug T129657
+                               throw $e;
+                       }
                }
 
-               // This hook allows last minute changes to final overall output by modifying output buffer
-               Hooks::run( 'AfterFinalPageOutput', [ $this ] );
+               try {
+                       // This hook allows last minute changes to final overall output by modifying output buffer
+                       Hooks::run( 'AfterFinalPageOutput', [ $this ] );
+               } catch ( Exception $e ) {
+                       ob_end_clean(); // bug T129657
+                       throw $e;
+               }
 
                $this->sendCacheControl();
 
@@ -3210,6 +3220,7 @@ class OutputPage extends ContextSource {
                        'wgMonthNamesShort' => $lang->getMonthAbbreviationsArray(),
                        'wgRelevantPageName' => $relevantTitle->getPrefixedDBkey(),
                        'wgRelevantArticleId' => $relevantTitle->getArticleID(),
+                       'wgRequestId' => WebRequest::getRequestId(),
                ];
 
                if ( $user->isLoggedIn() ) {
index 54176a6..66a8152 100644 (file)
@@ -1301,6 +1301,7 @@ class Preferences {
 
                $htmlForm->setModifiedUser( $user );
                $htmlForm->setId( 'mw-prefs-form' );
+               $htmlForm->setAutocomplete( 'off' );
                $htmlForm->setSubmitText( $context->msg( 'saveprefs' )->text() );
                # Used message keys: 'accesskey-preferences-save', 'tooltip-preferences-save'
                $htmlForm->setSubmitTooltip( 'preferences-save' );
index 5b4a4fc..0495536 100644 (file)
@@ -179,23 +179,31 @@ class WatchedItem {
         */
        public static function batchAddWatch( array $items ) {
                // wfDeprecated( __METHOD__, '1.27' );
-               $userTargetCombinations = [];
+               if ( !$items ) {
+                       return false;
+               }
+
+               $targets = [];
+               $users = [];
                /** @var WatchedItem $watchedItem */
                foreach ( $items as $watchedItem ) {
-                       if ( $watchedItem->checkRights && !$watchedItem->getUser()->isAllowed( 'editmywatchlist' ) ) {
+                       $user = $watchedItem->getUser();
+                       if ( $watchedItem->checkRights && !$user->isAllowed( 'editmywatchlist' ) ) {
                                continue;
                        }
-                       $userTargetCombinations[] = [
-                               $watchedItem->getUser(),
-                               $watchedItem->getTitle()->getSubjectPage()
-                       ];
-                       $userTargetCombinations[] = [
-                               $watchedItem->getUser(),
-                               $watchedItem->getTitle()->getTalkPage()
-                       ];
+                       $userId = $user->getId();
+                       $users[$userId] = $user;
+                       $targets[$userId][] = $watchedItem->getTitle()->getSubjectPage();
+                       $targets[$userId][] = $watchedItem->getTitle()->getTalkPage();
                }
+
                $store = WatchedItemStore::getDefaultInstance();
-               return $store->addWatchBatch( $userTargetCombinations );
+               $success = true;
+               foreach ( $users as $userId => $user ) {
+                       $success &= $store->addWatchBatchForUser( $user, $targets[$userId] );
+               }
+
+               return $success;
        }
 
        /**
index 4eea54d..c4340ad 100644 (file)
@@ -615,30 +615,30 @@ class WatchedItemStore {
         * @param LinkTarget $target
         */
        public function addWatch( User $user, LinkTarget $target ) {
-               $this->addWatchBatch( [ [ $user, $target ] ] );
+               $this->addWatchBatchForUser( $user, [ $target ] );
        }
 
        /**
-        * @param array[] $userTargetCombinations array of arrays containing [0] => User [1] => LinkTarget
+        * @param User $user
+        * @param LinkTarget[] $targets
         *
         * @return bool success
         */
-       public function addWatchBatch( array $userTargetCombinations ) {
+       public function addWatchBatchForUser( User $user, array $targets ) {
                if ( $this->loadBalancer->getReadOnlyReason() !== false ) {
                        return false;
                }
+               // Only loggedin user can have a watchlist
+               if ( $user->isAnon() ) {
+                       return false;
+               }
+
+               if ( !$targets ) {
+                       return true;
+               }
 
                $rows = [];
-               foreach ( $userTargetCombinations as list( $user, $target ) ) {
-                       /**
-                        * @var User $user
-                        * @var LinkTarget $target
-                        */
-
-                       // Only loggedin user can have a watchlist
-                       if ( $user->isAnon() ) {
-                               continue;
-                       }
+               foreach ( $targets as $target ) {
                        $rows[] = [
                                'wl_user' => $user->getId(),
                                'wl_namespace' => $target->getNamespace(),
@@ -648,10 +648,6 @@ class WatchedItemStore {
                        $this->uncache( $user, $target );
                }
 
-               if ( !$rows ) {
-                       return false;
-               }
-
                $dbw = $this->getConnection( DB_MASTER );
                foreach ( array_chunk( $rows, 100 ) as $toInsert ) {
                        // Use INSERT IGNORE to avoid overwriting the notification timestamp
index 812a320..f4b4871 100644 (file)
@@ -246,6 +246,25 @@ class WebRequest {
                return microtime( true ) - $this->requestTime;
        }
 
+       /**
+        * Get the unique request ID.
+        * This is either the value of the UNIQUE_ID envvar (if present) or a
+        * randomly-generated 24-character string.
+        *
+        * @return string
+        * @since 1.27
+        */
+       public static function getRequestId() {
+               static $reqId;
+
+               if ( !$reqId ) {
+                       $reqId = isset( $_SERVER['UNIQUE_ID'] )
+                               ? $_SERVER['UNIQUE_ID'] : wfRandomString( 24 );
+               }
+
+               return $reqId;
+       }
+
        /**
         * Get the current URL protocol (http or https)
         * @return string
index 63b79ac..e372511 100644 (file)
@@ -397,7 +397,13 @@ class ApiMain extends ApiBase {
                if ( $this->mInternalMode ) {
                        $this->executeAction();
                } else {
+                       $start = microtime( true );
                        $this->executeActionWithErrorHandling();
+                       if ( $this->isWriteMode() && $this->getRequest()->wasPosted() ) {
+                               $timeMs = 1000 * max( 0, microtime( true ) - $start );
+                               $this->getStats()->timing(
+                                       'api.' . $this->getModuleName() . '.executeTiming', $timeMs );
+                       }
                }
        }
 
@@ -871,7 +877,7 @@ class ApiMain extends ApiBase {
 
                        $errMessage = [
                                'code' => 'internal_api_error_' . get_class( $e ),
-                               'info' => '[' . MWExceptionHandler::getLogId( $e ) . '] ' . $info,
+                               'info' => '[' . WebRequest::getRequestId() . '] ' . $info,
                        ];
                }
                return $errMessage;
@@ -1750,8 +1756,8 @@ class ApiMain extends ApiBase {
                // Use parent to make default message for the main module
                $msg = parent::makeHelpMsg();
 
-               $astriks = str_repeat( '*** ', 14 );
-               $msg .= "\n\n$astriks Modules  $astriks\n\n";
+               $asterisks = str_repeat( '*** ', 14 );
+               $msg .= "\n\n$asterisks Modules  $asterisks\n\n";
 
                foreach ( $this->mModuleMgr->getNames( 'action' ) as $name ) {
                        $module = $this->mModuleMgr->getModule( $name );
@@ -1764,7 +1770,7 @@ class ApiMain extends ApiBase {
                        $msg .= "\n";
                }
 
-               $msg .= "\n$astriks Permissions $astriks\n\n";
+               $msg .= "\n$asterisks Permissions $asterisks\n\n";
                foreach ( self::$mRights as $right => $rightMsg ) {
                        $rightsMsg = $this->msg( $rightMsg['msg'], $rightMsg['params'] )
                                ->useDatabase( false )
@@ -1775,7 +1781,7 @@ class ApiMain extends ApiBase {
                                "\nGranted to:\n  " . str_replace( '*', 'all', implode( ', ', $groups ) ) . "\n\n";
                }
 
-               $msg .= "\n$astriks Formats  $astriks\n\n";
+               $msg .= "\n$asterisks Formats  $asterisks\n\n";
                foreach ( $this->mModuleMgr->getNames( 'format' ) as $name ) {
                        $module = $this->mModuleMgr->getModule( $name );
                        $msg .= self::makeHelpMsgHeader( $module, 'format' );
index 404fc19..9b05537 100644 (file)
@@ -66,6 +66,9 @@ class ApiQueryExtLinksUsage extends ApiQueryGeneratorBase {
                        $this->addWhereFld( 'page_namespace', $params['namespace'] );
                }
 
+               // Normalize query to match the normalization applied for the externallinks table
+               $query = Parser::normalizeLinkUrl( $query );
+
                $whereQuery = $this->prepareUrlQuerySearchString( $query, $protocol );
 
                if ( $whereQuery !== null ) {
index f39998b..0e8b437 100644 (file)
@@ -7,7 +7,12 @@
                        "Айсар",
                        "Янмурза Баки",
                        "Айбикә",
-                       "Лилиә"
+                       "Лилиә",
+                       "Lizalizaufa",
+                       "Гульчатай",
+                       "Ilmira",
+                       "Гизатуллина",
+                       "Танзиля Кутлугильдина"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Документация]]\n* [[mw:API:FAQ|ЧаВО]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Почта таратыу]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce  API яңылыҡтары]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R  Хаталар һәм яуаптар]\n</div>\n<strong>Статус:</strong> Был биттә  күрһәтелгән бар функциялар ҙа эшләргә тейеш,  шулай ҙа  API әүҙем эшкәртеү хәлендә тора һәм теләгән бер ваҡытта үҙгәрергә мөмкин. Яңыртылыуҙарҙы һәр саҡ белеп торор өсөн [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ почта таратыу mediawiki-api-announce], ошоға яҙыл.\n\n<strong>Хаталы һоратыуҙар:</strong> Әгәр API хаталы һоратыу алһа,     HTTP баш һүҙе   «MediaWiki-API-Error» асҡысы менән кире ҡайтарыла,  бынан һуң баш һүҙҙең мәғәнәһе һәм хата  коды кире ебәреләсәк һәм кире шул уҡ мәғәнәлә кире ҡуйыласаҡ. Киңерәк мәғлүмәтте ошонан ҡара  [[mw:API:Errors_and_warnings|API:Хаталар һәм иҫкәртеүҙәр]].\n\n<strong>Тестлау:</strong>   API-һоратыуҙарҙы тестлау уңайлы булһын өсөн ҡара. [[Special:ApiSandbox]]",
@@ -69,7 +74,7 @@
        "apihelp-delete-param-watch": "Ҡулланыусының ағымдағы күҙәтеү исемлегенә бит өҫтәргә.",
        "apihelp-delete-param-watchlist": "Ағымдағы ҡулланыусының теҙмәһенән битте һүҙһеҙ өҫтәргә йәки юйырға, һылтанмаларҙы файҙаланығыҙ йәки сәғәтте алмаштырмаҫҡа.",
        "apihelp-delete-param-unwatch": "Ҡулланыусының ағымдағы күҙәтеү исемлегенән битте юйырға.",
-       "apihelp-delete-param-oldimage": "Имя старого изображения для удаления, как это предусмотрено\n\nБында нисек  ҡаралғанса, юйыу өсөн иҫке һүрәтләмәнең исеме [[Special:ApiHelp/query+imageinfo|action=query&prop=imageinfo&iiprop=archivename]]",
+       "apihelp-delete-param-oldimage": "\nБында нисек  ҡаралғанса, юйыу өсөн иҫке һүрәтләмәнең исеме [[Special:ApiHelp/query+imageinfo|action=query&prop=imageinfo&iiprop=archivename]]",
        "apihelp-delete-example-simple": "Юйырға: <kbd>Main Page</kbd>.",
        "apihelp-delete-example-reason": "Юйырға <kbd>Main Page</kbd> сәбәп <kbd>Preparing for move</kbd>.",
        "apihelp-disabled-description": "Был модуль һүндерелгән.",
@@ -93,7 +98,7 @@
        "apihelp-edit-param-unwatch": "Ҡулланыусының ағымдағы күҙәтеү исемлегенән битте юйырға.",
        "apihelp-edit-param-watchlist": "Ағымдағы ҡулланыусының теҙмәһенән битте һүҙһеҙ өҫтәргә йәки юйырға, һылтанмаларҙы файҙаланығыҙ йәки сәғәтте алмаштырмағыҙ.",
        "apihelp-edit-param-md5": "\n\nMD5-хэш параметрының $1 text, йәки  $1 prepend тексы  һәм $1 appendtext параметрҙары  бәйләнгән. \nҠуйылған булһа, әгәр хэш дөрөҫ булмаһа, мөхәррирләү эшләнмәйәсәк.",
-       "apihelp-edit-param-prependtext": "Был тексты биттең башына өҫтәгеҙ. $ 1text алмаштыра.",
+       "apihelp-edit-param-prependtext": "Был тексты биттең башына өҫтәгеҙ. $1text алмаштыра.",
        "apihelp-edit-param-appendtext": "Был тексты биттең аҙағынаса өҫтәгеҙ.$1text алмаштыра.\n$1section -ды файҙаланығыҙ = яңы, яңы бүлек өҫтәү өсөн, ә был параметрға түгел.",
        "apihelp-edit-param-undo": "Был версияны кире алырға. $1text,$1prependtext,$1appendtext алмаштыра.",
        "apihelp-edit-param-undoafter": "$1undo- нан алып барлыҡ үҙгәртеүҙәрҙе кире алырға. Әгәр ул ҡуйылмаған булһа, бер тикшереүҙе кире алыу ҙа етә.",
        "apihelp-expandtemplates-param-title": "Бит баш һүҙе",
        "apihelp-expandtemplates-param-text": "Конвертлау өсөн викитекст",
        "apihelp-expandtemplates-param-revid": "<nowiki>{{REVISIONID}}</nowiki> һәм шуға оҡшаған  алмаштар өсөн ID-ны яңынан ҡарау",
+       "apihelp-expandtemplates-param-prop": "\nАлыу өсөн, мәғлүмәттең ҡайһы өлөшө\n\nИғтибар итегеҙ, әгәр бер ғәмәл дә һайланмаһа, ул саҡта һөҙөмтә  вики- текстан торасаҡ, тик сығыу элекке форматта.",
        "apihelp-expandtemplates-paramvalue-prop-wikitext": "Киңәйтелгән викитекст",
+       "apihelp-expandtemplates-paramvalue-prop-categories": "Бар категориялар ҙа вики текста  күрһәтелмәй индерелгән мәғлүмәттәрҙе күрһәтә",
+       "apihelp-expandtemplates-paramvalue-prop-properties": "Вики-текстағы  билдәле киңәйтелгән тылсымлы һүҙҙәрҙең биттәре үҙенсәлеге.",
+       "apihelp-expandtemplates-paramvalue-prop-ttl": "Максималь ваҡыт үткәндән һуң һөҙөмтә кэштары яраҡһыҙ тип табылырға тейеш.",
+       "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "Бит өсөн үҙенсәлекле  JavaScript үҙгәреүсән конфигурациялар бирә.",
+       "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "JavaScriptтың JSON юлы һымаҡ үҙенсәлекле биттәренә  алышына торған конфигурация бирә.",
        "apihelp-expandtemplates-paramvalue-prop-parsetree": "XML керетелә торған мәғлүмәт ағасы (шәжәрәһе).",
+       "apihelp-expandtemplates-param-includecomments": "Сыҡҡанда HTML комментарийҙарына  индереү кәрәкме?",
+       "apihelp-expandtemplates-example-simple": "Вики-тексты асығыҙ <kbd><nowiki>{{Project:Sandbox}}</nowiki></kbd>.",
+       "apihelp-feedcontributions-description": "Һеҙҙең исемгә килгән тәҡдимдәргә ҡайтыу",
        "apihelp-feedcontributions-param-feedformat": "Мәғлүмәттәр сығарыу форматы.",
        "apihelp-feedcontributions-param-year": "Йылдан башлап (һәм элегерәк):",
        "apihelp-feedcontributions-param-month": "Айҙан башлап (һәм элегерәк):",
        "apihelp-feedcontributions-param-newonly": "Яңы бит яһаған төҙәтеүҙәрҙе генә күрһәтергә",
        "apihelp-feedcontributions-param-showsizediff": "Өлгәоәр араһыдағы күләм айырмаһын күрһәтергә",
        "apihelp-feedcontributions-example-simple": "Ҡулланыусының өлөшөн күрһәтергә <kbd>Example</kbd>.",
+       "apihelp-feedrecentchanges-description": "Каналдың һуңғы үҙгәрештәрен кире ҡайтарырға.",
        "apihelp-feedrecentchanges-param-feedformat": "Мәғлүмәттәр сығарыу форматы.",
        "apihelp-feedrecentchanges-param-invert": "Һайланғандан башҡа исемдәр арауығы",
        "apihelp-feedrecentchanges-param-limit": "Ҡайтарылған һөҙөмтәләрҙең максималь һаны.",
        "apihelp-feedrecentchanges-param-tagfilter": "Тэг буйынса һөҙгөс",
        "apihelp-feedrecentchanges-param-target": "Был биттән һылтанған биттәрҙә һуңғы үҙгәртеүҙәрҙе күрһәтергә",
        "apihelp-feedrecentchanges-param-showlinkedto": "Киреһенсә, был биткә һылтанма яһаған биттәрҙәге үҙгәртеүҙәрҙе күрһәтергә",
+       "apihelp-feedrecentchanges-param-categories": "Бар категория биттәрендәге үҙгәрештәрҙе генә күрһәтергә",
+       "apihelp-feedrecentchanges-param-categories_any": "Был категориянан башҡа теләһә ҡайһы категориялар биттәрендәге үҙгәрештәрҙе генә күрһәтергә",
        "apihelp-feedrecentchanges-example-simple": "Һуңғы үҙгәртеүҙәрҙе күрһәтергә.",
        "apihelp-feedrecentchanges-example-30days": "30 көн арауығындағы һуңғы үҙгәртеүҙәрҙе күрһәтергә.",
+       "apihelp-feedwatchlist-description": "Күҙәтеү каналын ҡайтара",
        "apihelp-feedwatchlist-param-feedformat": "Мәғлүмәттәр сығарыу форматы.",
+       "apihelp-feedwatchlist-param-hours": "Был моменттан һуң күп сәғәт эсендә биттәр исемлеге үҙгәртелгән.",
        "apihelp-feedwatchlist-param-linktosections": "Мөмкин булһа, үҙгәртеүҙәр булған бүлеккә тура һылтанма.",
        "apihelp-feedwatchlist-example-default": "Күҙәтеү каналын күрһәтергә",
+       "apihelp-feedwatchlist-example-all6hrs": "Күҙәтеү биттәрендәге һуңғы 6 сәғәт эсендәге барлыҡ үҙгәрештәрҙе күрһәтергә.",
+       "apihelp-filerevert-description": "Файлды иҫке версияға ҡайтарырға.",
        "apihelp-filerevert-param-filename": "Префиксһыҙ файл исеме",
        "apihelp-filerevert-param-comment": "Комментарий тейәргә",
        "apihelp-filerevert-example-revert": "Кире <kbd>Wiki.png</kbd> юрауға <kbd>2011-03-05T15:27:40Z</kbd> ҡайтырға.",
        "apihelp-login-param-name": "Ҡатнашыусы исеме.",
        "apihelp-login-param-password": "Серһүҙ.",
        "apihelp-login-param-domain": "Домен (мотлаҡ түгел).",
+       "apihelp-login-param-token": "Беренсе һорау ваҡытынла алынған логин маркер",
+       "apihelp-login-example-gettoken": "Системаға инеү маркерын алыу.",
        "apihelp-login-example-login": "Танылыу.",
        "apihelp-logout-description": "Сығырға һәм сессия мәғлүмәтен юйырға.",
+       "apihelp-logout-example-logout": "Ағымдағы ҡулланыусының киткән саҡта инеүе",
+       "apihelp-managetags-description": "Тегтарҙы үҙгәртеү менән бәйле идара итеү мәсьәләләрен хәл итеү",
+       "apihelp-managetags-param-reason": "\nБилдәне булдырыу, юйҙырыу, активациялау һәм деактивациялау өсөн мотлаҡ булмаған сәбәп",
        "apihelp-mergehistory-description": "Үҙгәртеүҙәр тарихын берләштереү.",
+       "apihelp-mergehistory-param-from": "Тарихты берләштергән бит атамаһы. <var>$1fromid</var> менән бергә ҡуланыуы мөмкин түгел.",
+       "apihelp-mergehistory-param-fromid": "Тарихты берләштергән бит атамаһы. <var>$1fromid</var> менән бергә ҡуланыуы мөмкин түгел.",
+       "apihelp-mergehistory-param-to": "Тарихты берләштергән бит атамаһы. <var>$1fromid</var> менән бергә ҡуланыуы мөмкин түгел.",
+       "apihelp-mergehistory-param-toid": "Тарихты берләштергән бит атамаһы. <var>$1fromid</var> менән бергә ҡуланыуы мөмкин түгел.",
        "apihelp-mergehistory-param-reason": "Тарихты берләштереү сәбәбе",
        "apihelp-move-description": "Биттең исемен үҙгәртергә",
+       "apihelp-move-param-from": "Мөхәриррләү өсөн биттең исеме.<var>$1биттәрҙән</var> бергә файҙаланыу мөмкин түгел.",
+       "apihelp-move-param-fromid": "Бит идентифакторын мөхәррирләү өсөн биттәр.  <var>$1title</var> менән бергә ҡулланыла алмайҙар.",
        "apihelp-move-param-to": "Исемен үҙгәртергә тейешле биттең баш һүҙе",
        "apihelp-move-param-reason": "Үҙгәртеү сәбәбе",
        "apihelp-move-param-movetalk": "Фекер алышыу бите булһа, исемен үҙгәртергә.",
        "apihelp-move-param-noredirect": "Йүнәлтеүҙәр ҡуймаҫҡа",
        "apihelp-move-param-watch": "Ағымдағы ҡулланыусының күҙәтеү битенә бит һәм йүнәлтеү өҫтәргә.",
        "apihelp-move-param-unwatch": "Ағымдағы ҡулланыусының күҙәтеү битендә битте һәм йүнәлтеүҙе юйырға.",
+       "apihelp-move-param-watchlist": "Ағымдағы ҡулланыусының теҙмәһенән битте һүҙһеҙ өҫтәргә йәки юйырға, һылтанмаларҙы файҙаланығыҙ йәки сәғәтте алмаштырмаҫҡа.",
        "apihelp-move-param-ignorewarnings": "Бөтә иҫкәрмәләргә иғтибар итмәҫкә",
        "apihelp-move-example-move": "Исемен үҙгәртергә <kbd>Badtitle</kbd>  <kbd>Goodtitle</kbd> йүнәлтеү ҡуймаҫҡа.",
+       "apihelp-opensearch-description": "OpenSearch протоколын ҡулланып вики эҙләү.",
        "apihelp-opensearch-param-search": "Эҙләү юлы.",
        "apihelp-opensearch-param-limit": "Ҡайтарылған һөҙөмтәләрҙең максималь һаны.",
        "apihelp-opensearch-param-namespace": "Эҙләү өсөн исемдәр арауығы",
        "apihelp-opensearch-param-format": "Мәғлүмәттәр сығарыу форматы.",
+       "apihelp-opensearch-example-te": "<KBD> Te </ KBD> менән башланған биттәрҙе табырға.",
        "apihelp-options-param-reset": "Килешеү буйынса көйләүҙәргә күсергә.",
        "apihelp-options-example-reset": "Бөтә көйләүҙәрҙе ташларға",
        "apihelp-paraminfo-description": "API модуле тураһында мәғлүмәт алырға.",
        "apihelp-paraminfo-param-helpformat": "Белешмә юлы форматы.",
+       "apihelp-parse-param-prop": "Ҡайһы мәғлүмәтте алырға:",
+       "apihelp-parse-paramvalue-prop-langlinks": "Вики-текстың синтаксик анализында тышҡы ссылкалар бирә.",
+       "apihelp-parse-paramvalue-prop-links": "Вики-текстың синтаксик анализында тышҡы ссылкалар бирә.",
+       "apihelp-parse-paramvalue-prop-templates": "Вики-текстың синтаксик анализ ҡалыбын бирә.",
+       "apihelp-parse-paramvalue-prop-images": "Вики-текстың синтаксик анализында һәрәттәр бирә.",
+       "apihelp-parse-paramvalue-prop-externallinks": "Вики-текстың синтаксик анализында тышҡы ссылкалар бирә.",
+       "apihelp-parse-paramvalue-prop-sections": "Вики-текстың синтаксик анализында секциялар бирә.",
+       "apihelp-parse-paramvalue-prop-revid": "Тикшерелгән биттәргә версиялар идентификаторын өҫтәй.",
+       "apihelp-parse-paramvalue-prop-displaytitle": "Вики-текстың синтаксик анализына исем ҡуя.",
+       "apihelp-parse-paramvalue-prop-headitems": "<код> & ЛТ -ҡа һалыу өсөн элементтар бирә; башы & GT; биттең </ код>",
+       "apihelp-parse-paramvalue-prop-headhtml": "Айырылған <код> & лт бирә; & баштары GТ; биттең </ код>.",
+       "apihelp-parse-paramvalue-prop-jsconfigvars": "Бит өсөн үҙенсәлекле  JavaScript үҙгәреүсән конфигурациялар бирә.",
+       "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "JavaScriptтың JSON юлы һымаҡ үҙенсәлекле биттәренә  алышына торған конфигурация бирә.",
+       "apihelp-parse-paramvalue-prop-iwlinks": "Вики-текстың синтаксик анализында интервиктарға һылтанма бирә.",
+       "apihelp-parse-paramvalue-prop-wikitext": "Һығымта яҺау өсөн тәүге вики-тексты күрһәтә",
+       "apihelp-parse-paramvalue-prop-properties": "Вики-текстың синтаксик анализында билдәләнгән төрлө сифаттарҙы бирә.",
+       "apihelp-parse-paramvalue-prop-limitreportdata": "Структура һымаҡ итеп төплө отчет бирә. $1disablelimitreport</ вар> <алышыныусы> ҡуйылған ваҡытта бер ниндәй мәғлүмәт тә бирмәй.",
+       "apihelp-parse-paramvalue-prop-limitreporthtml": "Төплө отчеттың HTML версияһын бирә. <переменная>$1disablelimitreport </ вар> ҡуйылған булһа,бер мәғлүмәт тә бирмәй.",
+       "apihelp-parse-param-disablepp": "Урынына <var>$1disablelimitreport</var> ҡулланырға.",
+       "apihelp-parse-param-preview": "Алдан ҡарау режимында синтаксик анализ",
        "apihelp-parse-example-page": "Битте тикшереү.",
        "apihelp-parse-example-text": "Тикшереү: wikitext.",
+       "apihelp-parse-example-summary": "Һығымтаны тикшереү.",
        "apihelp-patrol-param-rcid": "Яңы ID үҙгәртеүҙәрҙе патрулләү өсөн",
        "apihelp-patrol-param-revid": "ID мөхәррирҙе патулләү",
+       "apihelp-patrol-param-tags": "Юйҙырылғандар журналындағы яҙмаларға  мөрәжәғәт итер өсөн, билдәләрҙе үҙгәртергә.",
+       "apihelp-patrol-example-rcid": "Һуңғы үҙгәрештәрҙе ҡарау.",
+       "apihelp-patrol-example-revid": "Яңынан ҡарау.",
        "apihelp-protect-description": "Битте һаҡлау кимәлен үҙгәртергә",
+       "apihelp-protect-param-title": "Бит атамаһы. $1pageid менән бергә ҡулланылмай.",
+       "apihelp-protect-param-reason": "(ООН) һағы сәбәптәре.",
+       "apihelp-protect-param-tags": "Юйҙырылғандар журналындағы яҙмаларға  мөрәжәғәт итер өсөн, билдәләрҙе үҙгәртергә.",
+       "apihelp-protect-param-watchlist": "Ағымдағы ҡулланыусының теҙмәһенән битте һүҙһеҙ өҫтәргә йәки юйырға, һылтанмаларҙы файҙаланығыҙ йәки сәғәтте алмаштырмаҫҡа.",
        "apihelp-protect-example-protect": "Битте һаҡларға.",
+       "apihelp-protect-example-unprotect": "<kbd>всех</kbd> өсөн сикләүҙәр ҡуйып,биттән һаҡлауҙы алырға.",
+       "apihelp-protect-example-unprotect2": "Бер ниндәй сикләүҙәр ҡуймай биттән һаҡлауҙы алырға.",
        "apihelp-purge-param-forcelinkupdate": "Таблицалар бәйләнешен яңыртыу.",
+       "apihelp-purge-param-forcerecursivelinkupdate": "Һылтанманы һәм таблицаны яңыртығыҙ һәм был битте шаблон итеп ҡулланған башҡа биттәр өсөн һылтанмаларҙы ла яңыртығыҙ.",
        "apihelp-query-param-list": "Ниндәй исемлекте ҡулланырға",
        "apihelp-query-param-meta": "Ниндәй матамәғлүмәт ҡулланырға",
        "apihelp-query+allcategories-description": "Бөтә категорияларҙы иҫәпләргә",
+       "apihelp-query+allcategories-param-from": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+allcategories-param-to": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+allcategories-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+allcategories-param-dir": "Сортлау йүнәлештәре.",
        "apihelp-query+allcategories-param-limit": "Нисә категорияны кире ҡайтарырға",
        "apihelp-query+allcategories-param-prop": "Ниндәй үҙенсәлек алырға:",
-       "apihelp-query+allmessages-param-prop": "Ниндәй үҙенсәлек алырға:"
+       "apihelp-query+allcategories-paramvalue-prop-size": "Категорияларға биттәр һаны өҫтәү",
+       "apihelp-query+allcategories-example-size": "Биттәр һаны буйынса мәғлүмәтле категориялар исемлеге.",
+       "apihelp-query+allcategories-example-generator": "<kbd>исемлек</kbd> категориялар битенән мәғлүмәт алырға.",
+       "apihelp-query+alldeletedrevisions-description": "Бар мөхәррирләү исемлеге ҡулланыусы тарафынан юйылған.",
+       "apihelp-query+alldeletedrevisions-paraminfo-useronly": "<var>$3ҡулланыусының</var> менән генә ҡулланыла ала.",
+       "apihelp-query+alldeletedrevisions-param-end": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+alldeletedrevisions-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+alldeletedrevisions-param-user": "Бары тик был ҡулланыусының үҙгәртеүҙәр исемлеге.",
+       "apihelp-query+alldeletedrevisions-param-namespace": "Бары тик был исемдәр арауығындағы биттәр исемлеге.",
+       "apihelp-query+alldeletedrevisions-example-ns-main": "Төп исемдәр арауығында юйылған тәүге 50 үҙгәртеү исемлеге.",
+       "apihelp-query+allfileusages-description": "Юйылғандар менән бергә барлыҡ файлдар тәртибе исемлеге.",
+       "apihelp-query+allfileusages-param-from": "Һанауҙы башлау өсөн файл атамаһы.",
+       "apihelp-query+allfileusages-param-to": "Һанауҙы туҡтатыу файлы атамаһы.",
+       "apihelp-query+allfileusages-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+allfileusages-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
+       "apihelp-query+allfileusages-paramvalue-prop-title": "Файл атамаһына ҡуша.",
+       "apihelp-query+allfileusages-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+allfileusages-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+allfileusages-example-unique": "Атамаларҙың уҙенсәлекле файлдары исемлеге.",
+       "apihelp-query+allfileusages-example-unique-generator": "Төшөп ҡалғандарҙы айырып, барлыҡ исем-һылтанмаларҙы алырға.",
+       "apihelp-query+allimages-description": "Бер-бер артлы бөтә образдарҙы һанап сығырға.",
+       "apihelp-query+allimages-param-sort": "Сортировкалау үҙенсәлектәре.",
+       "apihelp-query+allimages-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+allimages-param-minsize": "Һүрәттәр лимиты (байттарҙа).",
+       "apihelp-query+allimages-param-maxsize": "Бар һүрәттәр лимиты (байттарҙа).",
+       "apihelp-query+allimages-param-limit": "Кире ҡайтыу өсөн образдар һаны.",
+       "apihelp-query+allimages-example-B": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
+       "apihelp-query+allimages-example-generator": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
+       "apihelp-query+alllinks-description": "Бирелгән исемдәр арауығына йүнәлткән барлыҡ һылтанмаларҙы һанап сығырға.",
+       "apihelp-query+alllinks-param-from": "Һанауҙы башлау өсөн һылтанма атамаһы.",
+       "apihelp-query+alllinks-param-to": "Һанауҙы туҡтатыу һылтанмаһы атамаһы.",
+       "apihelp-query+alllinks-param-prefix": "Был мәғәнәнән башланған бәйләнешле бар атамаларҙы эҙләргә.",
+       "apihelp-query+alllinks-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
+       "apihelp-query+alllinks-paramvalue-prop-title": "Һылтанма атамаһын ҡуша.",
+       "apihelp-query+alllinks-param-namespace": "Һанау өсөн исемдәр арауығы.",
+       "apihelp-query+alllinks-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+alllinks-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+alllinks-example-unique": "Атамаларҙың уҙенсәлекле файлдары исемлеге.",
+       "apihelp-query+alllinks-example-unique-generator": "Төшөп ҡалғандарҙы айырып, барлыҡ исем-һылтанмаларҙы алырға.",
+       "apihelp-query+alllinks-example-generator": "Һылтанмалы биттәр бар.",
+       "apihelp-query+allmessages-description": "Был сайттан хәбәр ҡайтарыу.",
+       "apihelp-query+allmessages-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+allmessages-param-args": "Аргументтар Хәбәрҙәрҙә биреләсәк.",
+       "apihelp-query+allpages-param-from": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+allpages-param-to": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+allpages-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+allpages-param-namespace": "Һанау өсөн исемдәр арауығы.",
+       "apihelp-query+allpages-param-minsize": "Һүрәттәр лимиты (байттарҙа).",
+       "apihelp-query+allpages-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+allpages-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+allpages-example-B": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
+       "apihelp-query+allpages-example-generator": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
+       "apihelp-query+allredirects-param-from": "Һанауҙы туҡтатыу файлы атамаһы.",
+       "apihelp-query+allredirects-param-to": "Һанауҙы туҡтатыу файлы атамаһы.",
+       "apihelp-query+allredirects-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+allredirects-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
+       "apihelp-query+allredirects-param-namespace": "Һанау өсөн исемдәр арауығы.",
+       "apihelp-query+allredirects-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+allredirects-example-generator": "Һылтанмалы биттәр бар.",
+       "apihelp-query+allrevisions-param-start": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+allrevisions-param-end": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+allrevisions-param-user": "Бары тик был ҡулланыусының үҙгәртеүҙәр исемлеге.",
+       "apihelp-query+allrevisions-param-excludeuser": "Бары тик был ҡулланыусының үҙгәртеүҙәр исемлеге.",
+       "apihelp-query+alltransclusions-example-generator": "Һылтанмалы биттәр бар.",
+       "apihelp-query+allusers-param-from": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+allusers-param-to": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+allusers-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+allusers-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
+       "apihelp-query+backlinks-param-title": "Мөхәриррләү өсөн биттең исеме.<var>$1биттәрҙән</var> бергә файҙаланыу  мөмкин түгел.",
+       "apihelp-query+backlinks-param-pageid": "Бит идентифакторын мөхәррирләү өсөн биттәр.  <var>$1title</var> менән бергә ҡулланыла алмайҙар",
+       "apihelp-query+backlinks-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+blocks-param-start": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+blocks-param-end": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+blocks-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+blocks-example-simple": "Берләшмә исемлеге",
+       "apihelp-query+categories-param-limit": "Нисә категорияны кире ҡайтарырға",
+       "apihelp-query+categories-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+categorymembers-param-pageid": "Бит идентифакторы юйылыу өсөн биттәр.  <var>$1title</var> менән бергә ҡулланыла алмайҙар",
+       "apihelp-query+categorymembers-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
+       "apihelp-query+categorymembers-param-limit": "Кире ҡайтарылған белдереүҙәрҙең иң күп һаны",
+       "apihelp-query+categorymembers-param-sort": "Сортҡа бүлеү үҙенсәлеге",
+       "apihelp-query+contributors-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+deletedrevisions-param-user": "Бары тик был ҡулланыусының үҙгәртеүҙәр исемлеге.",
+       "apihelp-query+deletedrevisions-param-excludeuser": "Бары тик был ҡулланыусының үҙгәртеүҙәр исемлеге.",
+       "apihelp-query+deletedrevs-param-start": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+deletedrevs-param-end": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+deletedrevs-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+deletedrevs-param-user": "Бары тик был ҡулланыусының үҙгәртеүҙәр исемлеге.",
+       "apihelp-query+duplicatefiles-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+duplicatefiles-example-generated": "Поиск дубликатов всех файлов.",
+       "apihelp-query+embeddedin-param-title": "Мөхәриррләү өсөн биттең исеме.<var>$1биттәрҙән</var> бергә файҙаланыу  мөмкин түгел.",
+       "apihelp-query+embeddedin-param-pageid": "Бит идентифакторын мөхәррирләү өсөн биттәр.  <var>$1title</var> менән бергә ҡулланыла алмайҙар",
+       "apihelp-query+embeddedin-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+embeddedin-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+exturlusage-param-limit": "Күпме һылтанмаларҙы кире ҡайтарырға.",
+       "apihelp-query+filearchive-param-from": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+filearchive-param-to": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+filearchive-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+filearchive-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+fileusage-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+fileusage-param-limit": "Күпме һылтанмаларҙы кире ҡайтарырға.",
+       "apihelp-query+imageinfo-param-prop": "Ҡайһы мәғлүмәтте алырға:",
+       "apihelp-query+imageinfo-paramvalue-prop-mediatype": "Файл атамаһына ҡуша.",
+       "apihelp-query+images-param-limit": "Күпме һылтанмаларҙы кире ҡайтарырға.",
+       "apihelp-query+images-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+imageusage-param-title": "Мөхәриррләү өсөн биттең исеме.<var>$1биттәрҙән</var> бергә файҙаланыу  мөмкин түгел.",
+       "apihelp-query+imageusage-param-pageid": "Бит идентифакторын мөхәррирләү өсөн биттәр.  <var>$1title</var> менән бергә ҡулланыла алмайҙар",
+       "apihelp-query+imageusage-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+info-paramvalue-prop-protection": "Битте һаҡлау кимәлен үҙгәртергә",
+       "apihelp-query+iwbacklinks-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+iwbacklinks-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Файл атамаһына ҡуша.",
+       "apihelp-query+iwlinks-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+langbacklinks-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+langbacklinks-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+links-param-limit": "Күпме һылтанмаларҙы кире ҡайтарырға.",
+       "apihelp-query+links-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+linkshere-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+logevents-description": "Журналдарҙан ваҡиға алыу.",
+       "apihelp-query+logevents-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+logevents-param-start": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+logevents-param-end": "Иҫәп күсереү тамамланған ваҡыт билдәһе",
+       "apihelp-query+logevents-example-simple": " Һуңғы теркәлгән ваҡиғалар исемлеге.",
+       "apihelp-query+pagepropnames-param-limit": "Кире ҡайтарылған белдереүҙәрҙең иң күп һаны",
+       "apihelp-query+pagepropnames-example-simple": "Тәүге 10 исем сифатын алыу.",
+       "apihelp-query+pageswithprop-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
+       "apihelp-query+pageswithprop-param-limit": "Кире ҡайтарылған белдереүҙәрҙең иң күп һаны",
+       "apihelp-query+pageswithprop-param-dir": "Ниндәй йүнәлешкә айырырға",
+       "apihelp-query+prefixsearch-param-search": "Эҙләү юлы.",
+       "apihelp-query+prefixsearch-param-namespace": "Эҙләү өсөн исемдәр арауығы",
+       "apihelp-query+prefixsearch-param-limit": "Ҡайтарылған һөҙөмтәләрҙең максималь һаны.",
+       "apihelp-query+prefixsearch-param-offset": "Төшөрөп ҡалдырыу өсөн һөҙөмтә иҫәбе",
+       "apihelp-query+protectedtitles-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+protectedtitles-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+querypage-param-limit": "Төшөрөп ҡалдырыу өсөн һөҙөмтә иҫәбе",
+       "apihelp-query+recentchanges-param-start": "Иҫәп күсереү башланған ваҡыт билдәһе",
+       "apihelp-query+recentchanges-param-end": "Иҫәп күсереү тамамланған ваҡыт билдәһе",
+       "apihelp-query+recentchanges-param-user": "Бары тик был ҡулланыусының үҙгәртеүҙәр исемлеге.",
+       "apihelp-query+recentchanges-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+recentchanges-param-type": "Ниндәй төрҙәр үҙгәртеүҙе күрһәтергө",
+       "apihelp-query+recentchanges-example-simple": "Һуңғы үҙгәртеүҙәрҙе күрһәтергә.",
+       "apihelp-query+redirects-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+redirects-param-limit": "Күпме һылтанмаларҙы кире ҡайтарырға.",
+       "apihelp-query+revisions-example-last5": "Һуңғы 5 <kbd>Main Page</kbd> версияны  алырға.",
+       "apihelp-query+revisions-example-first5": "Тәүге 5 <kbd>Main Page</kbd> версияны алырға.",
+       "apihelp-query+search-param-info": "Ниндәй матамәғлүмәт ҡулланырға",
+       "apihelp-query+search-param-prop": "Ниндәй үҙенсәлекте ҡайтарырға",
+       "apihelp-query+search-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+tags-description": "Үҙгәртелгән тамғалар исемлеге.",
+       "apihelp-query+tags-param-limit": "Кире ҡайтарылған белдереүҙәрҙең иң күп һаны",
+       "apihelp-query+tags-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+tags-example-simple": "Аңлайышлы тамғалар бите",
+       "apihelp-query+templates-param-limit": "Күпме һылтанмаларҙы кире ҡайтарырға.",
+       "apihelp-query+templates-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+transcludedin-param-prop": "Ниндәй үҙенсәлек алырға:",
+       "apihelp-query+transcludedin-param-limit": "Күпме һылтанмаларҙы кире ҡайтарырға.",
+       "apihelp-query+usercontribs-description": "Ҡулланыусының бөтә төҙәтеүҙәрен алыу",
+       "apihelp-query+usercontribs-param-limit": "Кире ҡайтарылған белдереүҙәрҙең иң күп һаны"
 }
index 3108e5b..3b5201a 100644 (file)
@@ -1,7 +1,8 @@
 {
        "@metadata": {
                "authors": [
-                       "Red Winged Duck"
+                       "Red Winged Duck",
+                       "Renessaince"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Дакумэнтацыя]]\n* [[mw:API:FAQ|Частыя пытаньні]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Сьпіс рассылкі]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API-аб’явы]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Памылкі і запыты]\n</div>\n<strong>Статус:</strong> усе магчымасьці на гэтай старонцы павінны працаваць, але API знаходзіцца ў актыўнай распрацоўцы і можа зьмяняцца ў любы момант. Падпісвайцеся на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ рассылку mediawiki-api-announce] дзеля паведамленьняў пра абнаўленьні.\n\n<strong>Памылковыя запыты:</strong> калі да API дасылаюцца памылковыя запыты, HTTP-загаловак будзе дасланы з ключом «MediaWiki-API-Error», а потым значэньне загалоўку і код памылкі будуць выстаўленыя на аднолькавае значэньне. Дзеля дадатковай інфармацыі глядзіце [[mw:API:Errors_and_warnings|API: Памылкі і папярэджаньні]].\n\n<strong>Тэставаньне:</strong> для зручнасьці праверкі API-запытаў, глядзіце [[Special:ApiSandbox]].",
@@ -51,5 +52,8 @@
        "apihelp-createaccount-param-reason": "Неабавязковая прычына стварэньня рахунку, якая будзе запісаная ў журнал.",
        "apihelp-createaccount-param-language": "Моўны код, які будзе выстаўлены ўдзельніку па змоўчаньні (неабавязкова, па змоўчаньні мова зьместу).",
        "apihelp-createaccount-example-pass": "Стварэньне ўдзельніка <kbd>testuser</kbd> з паролем <kbd>test123</kbd>.",
-       "apihelp-createaccount-example-mail": "Стварэньне ўдзельніка <kbd>testmailuser</kbd> і адпраўка выпадковага паролю электроннай поштай."
+       "apihelp-createaccount-example-mail": "Стварэньне ўдзельніка <kbd>testmailuser</kbd> і адпраўка выпадковага паролю электроннай поштай.",
+       "apihelp-query+transcludedin-paramvalue-prop-title": "Назва кожнай старонкі.",
+       "apihelp-query+transcludedin-param-limit": "Колькі вяртаць.",
+       "apihelp-query+userinfo-paramvalue-prop-acceptlang": "Дублюе загаловак <code>Accept-Language</code>, адасланы кліентам у структураваным фармаце."
 }
index 5b67c1f..fe4342a 100644 (file)
        "apihelp-purge-example-simple": "Purgt die <kbd>Main Page</kbd> und die <kbd>API</kbd>-Seite.",
        "apihelp-purge-example-generator": "Purgt die ersten 10 Seiten des Hauptnamensraums.",
        "apihelp-query-description": "Bezieht Daten von und über MediaWiki.\n\nAlle Änderungsvorgänge müssen unter Angabe eines Tokens ablaufen, um Missbrauch durch böswillige Anwendungen vorzubeugen.",
-       "apihelp-query-param-prop": "Zurückzuliefernde Eigenschaften der abgefragten Seiten.",
+       "apihelp-query-param-prop": "Zurückzugebende Eigenschaften der abgefragten Seiten.",
        "apihelp-query-param-list": "Welche Listen abgerufen werden sollen.",
        "apihelp-query-param-meta": "Zurückzugebende Metadaten.",
        "apihelp-query-param-indexpageids": "Schließt einen zusätzlichen pageids-Abschnitt mit allen zurückgegebenen Seitenkennungen ein.",
        "apihelp-query+alllinks-example-generator": "Ruft Seiten ab welche die Verknüpfungen beinhalten.",
        "apihelp-query+allmessages-description": "Gibt Nachrichten von dieser Website zurück.",
        "apihelp-query+allmessages-param-messages": "Welche Nachrichten ausgegeben werden sollen. <kbd>*</kbd> (Vorgabe) bedeutet alle Nachrichten.",
-       "apihelp-query+allmessages-param-prop": "Welche Eigenschaften abgerufen werden sollen.",
+       "apihelp-query+allmessages-param-prop": "Zurückzugebende Eigenschaften.",
        "apihelp-query+allmessages-param-enableparser": "Setzen, um den Parser zu aktivieren. Dies wird den Wikitext der Nachricht vorverarbeiten (magische Worte ersetzen, Vorlagen berücksichtigen, usw.).",
        "apihelp-query+allmessages-param-nocontent": "Wenn gesetzt, füge nicht den Inhalt der Nachricht der Ausgabe hinzu.",
        "apihelp-query+allmessages-param-includelocal": "Schließt auch lokale Nachrichten ein. Zum Beispiel Nachrichten die es nicht in der Software gibt, die es aber als MediaWiki: - Seite gibt. Dies listet alle MediaWiki: - Seiten auf. Daher werden auch diejenigen aufgelistet, die eigentlich keine Nachrichten sind, wie [[MediaWiki:Common.js|Common.js]].",
        "apihelp-query+blocks-example-simple": "Sperren auflisten",
        "apihelp-query+blocks-example-users": "Listet Sperren der Benutzer <kbd>Alice</kbd> und <kbd>Bob</kbd> auf.",
        "apihelp-query+categories-description": "Liste alle Kategorien auf, zu denen die Seiten gehören.",
-       "apihelp-query+categories-param-prop": "Welche zusätzlichen Eigenschaften für jede Kategorie abrufen:",
+       "apihelp-query+categories-param-prop": "Zusätzlich zurückzugebende Eigenschaften jeder Kategorie:",
        "apihelp-query+categories-paramvalue-prop-timestamp": "Fügt einen Zeitstempel wann die Kategorie angelegt wurde hinzu.",
        "apihelp-query+categories-param-show": "Welche Art von Kategorien gezeigt werden soll.",
        "apihelp-query+categories-param-limit": "Wie viele Kategorien zurückgegeben werden sollen.",
        "apihelp-query+imageusage-param-redirect": "Falls die verweisende Seite eine Weiterleitung ist, finde alle Seiten, die ebenfalls auf diese Weiterleitung verweisen. Die maximale Grenze wird halbiert.",
        "apihelp-query+imageusage-example-simple": "Zeige Seiten, die [[:File:Albert Einstein Head.jpg]] verwenden.",
        "apihelp-query+info-description": "Ruft Basisinformationen über die Seite ab.",
-       "apihelp-query+info-param-prop": "Welche zusätzlichen Eigenschaften abgerufen werden sollen:",
+       "apihelp-query+info-param-prop": "Zusätzlich zurückzugebende Eigenschaften:",
        "apihelp-query+info-paramvalue-prop-protection": "Liste die Schutzstufe jeder Seite auf.",
        "apihelp-query+info-paramvalue-prop-talkid": "Die Seitenkennung der Diskussionsseite für jede Nicht-Diskussionsseite.",
        "apihelp-query+info-paramvalue-prop-watched": "Liste den Überwachungszustand jeder Seite auf.",
        "apihelp-query+info-paramvalue-prop-displaytitle": "Gibt die Art und Weise an, in der der Seitentitel tatsächlich angezeigt wird.",
        "apihelp-query+info-param-testactions": "Überprüft, ob der aktuelle Benutzer gewisse Aktionen auf der Seite ausführen kann.",
        "apihelp-query+iwbacklinks-param-prefix": "Präfix für das Interwiki.",
+       "apihelp-query+iwbacklinks-param-prop": "Zurückzugebende Eigenschaften:",
        "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "Ergänzt das Präfix des Interwikis.",
        "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Ergänzt den Titel des Interwikis.",
        "apihelp-query+iwbacklinks-param-dir": "Die Auflistungsrichtung.",
+       "apihelp-query+iwlinks-param-prop": "Zusätzlich zurückzugebende Eigenschaften jedes Interlanguage-Links:",
        "apihelp-query+iwlinks-paramvalue-prop-url": "Ergänzt die vollständige URL.",
        "apihelp-query+iwlinks-param-limit": "Wie viele Interwiki-Links zurückgegeben werden sollen.",
        "apihelp-query+iwlinks-param-prefix": "Gibt nur Interwiki-Links mit diesem Präfix zurück.",
        "apihelp-query+iwlinks-param-dir": "Die Auflistungsrichtung.",
        "apihelp-query+langbacklinks-param-limit": "Wie viele Gesamtseiten zurückgegeben werden sollen.",
+       "apihelp-query+langbacklinks-param-prop": "Zurückzugebende Eigenschaften:",
        "apihelp-query+langbacklinks-param-dir": "Die Auflistungsrichtung.",
        "apihelp-query+langbacklinks-example-simple": "Ruft Seiten ab, die auf [[:fr:Test]] verlinken.",
        "apihelp-query+langlinks-param-limit": "Wie viele Sprachlinks zurückgegeben werden sollen.",
+       "apihelp-query+langlinks-param-prop": "Zusätzlich zurückzugebende Eigenschaften jedes Interlanguage-Links:",
        "apihelp-query+langlinks-paramvalue-prop-url": "Ergänzt die vollständige URL.",
        "apihelp-query+langlinks-param-dir": "Die Auflistungsrichtung.",
        "apihelp-query+links-param-limit": "Wie viele Links zurückgegeben werden sollen.",
        "apihelp-query+links-param-dir": "Die Auflistungsrichtung.",
        "apihelp-query+links-example-simple": "Links von der <kbd>Hauptseite</kbd> abrufen",
        "apihelp-query+linkshere-description": "Alle Seiten finden, die auf die angegebenen Seiten verlinken.",
+       "apihelp-query+linkshere-param-prop": "Zurückzugebende Eigenschaften:",
        "apihelp-query+linkshere-paramvalue-prop-pageid": "Die Seitenkennung jeder Seite.",
        "apihelp-query+linkshere-paramvalue-prop-title": "Titel jeder Seite.",
        "apihelp-query+logevents-description": "Ereignisse von den Logbüchern abrufen.",
+       "apihelp-query+logevents-param-prop": "Zurückzugebende Eigenschaften:",
        "apihelp-query+logevents-paramvalue-prop-type": "Ergänzt den Typ des Logbuchereignisses.",
        "apihelp-query+logevents-paramvalue-prop-comment": "Ergänzt den Kommentar des Logbuchereignisses.",
        "apihelp-query+logevents-example-simple": "Listet die letzten Logbuch-Ereignisse auf.",
        "apihelp-query+pageswithprop-param-limit": "Die maximale Anzahl zurückzugebender Seiten.",
        "apihelp-query+prefixsearch-param-search": "Such-Zeichenfolge.",
        "apihelp-query+prefixsearch-param-offset": "Anzahl der zu überspringenden Ergebnisse.",
+       "apihelp-query+protectedtitles-param-prop": "Zurückzugebende Eigenschaften:",
        "apihelp-query+querypage-param-limit": "Anzahl der zurückzugebenden Ergebnisse.",
        "apihelp-query+recentchanges-description": "Listet die letzten Änderungen auf.",
+       "apihelp-query+recentchanges-param-user": "Listet nur Änderungen von diesem Benutzer auf.",
+       "apihelp-query+recentchanges-param-excludeuser": "Listet keine Änderungen von diesem Benutzer auf.",
+       "apihelp-query+recentchanges-param-tag": "Listet nur Änderungen auf, die mit dieser Markierung markiert sind.",
+       "apihelp-query+recentchanges-paramvalue-prop-flags": "Ergänzt Markierungen für die Bearbeitung.",
        "apihelp-query+recentchanges-paramvalue-prop-timestamp": "Ergänzt den Zeitstempel für die Bearbeitung.",
+       "apihelp-query+recentchanges-paramvalue-prop-title": "Ergänzt den Seitentitel der Bearbeitung.",
        "apihelp-query+recentchanges-paramvalue-prop-tags": "Listet Markierungen für den Eintrag auf.",
        "apihelp-query+recentchanges-example-simple": "Listet die letzten Änderungen auf.",
+       "apihelp-query+redirects-param-prop": "Zurückzugebende Eigenschaften:",
        "apihelp-query+redirects-paramvalue-prop-pageid": "Seitenkennung einer jeden Weiterleitung.",
        "apihelp-query+redirects-paramvalue-prop-title": "Titel einer jeden Weiterleitung.",
+       "apihelp-query+redirects-param-limit": "Wie viele Weiterleitungen zurückgegeben werden sollen.",
+       "apihelp-query+revisions-param-tag": "Listet nur Versionen auf, die mit dieser Markierung markiert sind.",
+       "apihelp-query+revisions+base-param-prop": "Zurückzugebende Eigenschaften jeder Version:",
        "apihelp-query+revisions+base-paramvalue-prop-ids": "Die Kennung der Version.",
        "apihelp-query+revisions+base-paramvalue-prop-flags": "Versionsmarkierungen (klein).",
        "apihelp-query+revisions+base-paramvalue-prop-timestamp": "Der Zeitstempel der Version.",
        "apihelp-query+search-example-text": "Texte nach <kbd>meaning</kbd> durchsuchen.",
        "apihelp-query+siteinfo-example-simple": "Websiteinformationen abrufen",
        "apihelp-query+tags-description": "Änderungs-Tags auflisten.",
+       "apihelp-query+tags-param-prop": "Zurückzugebende Eigenschaften:",
        "apihelp-query+tags-example-simple": "Verfügbare Tags auflisten",
        "apihelp-query+templates-param-dir": "Die Auflistungsrichtung.",
+       "apihelp-query+transcludedin-param-prop": "Zurückzugebende Eigenschaften:",
        "apihelp-query+usercontribs-description": "Alle Bearbeitungen von einem Benutzer abrufen.",
        "apihelp-query+usercontribs-param-limit": "Die maximale Anzahl der zurückzugebenden Beiträge.",
        "apihelp-query+usercontribs-param-start": "Der zurückzugebende Start-Zeitstempel.",
        "apihelp-query+users-paramvalue-prop-rights": "Listet alle Rechte auf, die jeder Benutzer hat.",
        "apihelp-query+users-paramvalue-prop-editcount": "Ergänzt den Bearbeitungszähler des Benutzers.",
        "apihelp-query+users-example-simple": "Gibt Informationen für den Benutzer <kbd>Example</kbd> zurück.",
+       "apihelp-query+watchlist-param-prop": "Zusätzlich zurückzugebende Eigenschaften:",
        "apihelp-query+watchlist-paramvalue-prop-user": "Ergänzt den Benutzer, der die Bearbeitung ausgeführt hat.",
        "apihelp-query+watchlist-paramvalue-prop-userid": "Ergänzt die Kennung des Benutzers, der die Bearbeitung ausgeführt hat.",
        "apihelp-query+watchlist-paramvalue-prop-comment": "Ergänzt den Kommentar der Bearbeitung.",
        "apihelp-query+watchlist-paramvalue-prop-sizes": "Ergänzt die alten und neuen Längen der Seite.",
        "apihelp-query+watchlist-paramvalue-type-new": "Seitenerstellungen.",
        "apihelp-query+watchlist-paramvalue-type-log": "Logbucheinträge.",
+       "apihelp-query+watchlistraw-param-prop": "Zusätzlich zurückzugebende Eigenschaften:",
        "apihelp-rsd-description": "Ein RSD-Schema (Really Simple Discovery) exportieren.",
        "apihelp-rsd-example-simple": "Das RSD-Schema exportieren",
        "apihelp-setnotificationtimestamp-param-entirewatchlist": "An allen beobachteten Seiten arbeiten.",
index 2570bc1..49c49f2 100644 (file)
                        "Chris TR",
                        "Ncontinanza",
                        "Poco a poco",
-                       "YoViajo"
+                       "YoViajo",
+                       "Eloy"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentación]]\n* [[mw:API:FAQ|Preguntas frecuentes]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Lista de correos]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce API de anuncios]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Errores y peticiones]\n</div>\n<strong>Estado:</strong> Todas las características que se muestran en esta página debería funcionar, pero la API aún está en desarrollo activo y puede cambiar en cualquier momento. Suscríbete a [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ la lista de correo de mediawiki-api-announce] para estar al día de las actualizaciones.\n\n<strong>Solicitudes erróneas:</strong> Cuando se envían solicitudes erróneas a la API, se envía un encabezado HTTP con la clave \"MediaWiki-API-Error\" y ambos valores, del encabezado y el código de error, se establecerán en el mismo valor. Para más información, véase [[mw:API:Errors_and_warnings|API: Errores y advertencias]].\n\n<strong>Pruebas:</strong> para facilitar las pruebas de solicitudes a la API, consulta [[Special:ApiSandbox]].",
        "apihelp-main-param-action": "Qué acción se realizará.",
        "apihelp-main-param-format": "El formato de la salida.",
-       "apihelp-main-param-smaxage": "Establece el encabezado <code>s-maxage</code> durante estos segundos. Los errores nunca se almacenan en caché.",
-       "apihelp-main-param-maxage": "Establece el encabezado <code>max-age</code> durante estos segundos. Los errores nunca se almacenan en caché.",
+       "apihelp-main-param-smaxage": "Establece el encabezado HTTP <code>s-maxage</code> de control de caché a esta cantidad de segundos. Los errores nunca se almacenan en caché.",
+       "apihelp-main-param-maxage": "Establece el encabezado HTTP <code>max-age</code> de control de caché a esta cantidad de segundos. Los errores nunca se almacenan en caché.",
        "apihelp-main-param-assert": "Comprobar que el usuario haya iniciado sesión si el valor es <kbd>user</kbd> o si tiene el permiso de bot si es <kbd>bot</kbd>.",
        "apihelp-main-param-requestid": "Cualquier valor dado aquí se incluirá en la respuesta. Se puede utilizar para distinguir solicitudes.",
        "apihelp-main-param-servedby": "Incluir el nombre del host que ha servido la solicitud en los resultados.",
        "apihelp-main-param-curtimestamp": "Incluir la marca de tiempo actual en el resultado.",
+       "apihelp-main-param-origin": "Cuando se accede a la API usando una petición AJAX de distinto dominio (CORS), establece este valor al dominio de origen. Debe ser incluido en cualquier petición pre-vuelo, y por lo tanto debe ser parte de la URI de la petición (no del cuerpo POST). Debe coincidir exactamente con uno de los orígenes de la cabecera <code>Origin</code>, por lo que debería ser algo como <kbd>https://en.wikipedia.org</kbd> o <kbd>https://meta.wikimedia.org</kbd>. Si este parámetro no coincide con la cabecera <code>Origin</code>, se devolverá una respuesta 403.\nSi este parámetro coincide con la cabecera <code>Origin</code> y el origen está en lista blanca, se creará una cabecera <code>Access-Control-Allow-Origin</code>.",
        "apihelp-main-param-uselang": "El idioma que se usará para las traducciones de mensajes. <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> con <kbd>siprop=languages</kbd> devuelve una lista de códigos de idiomas, o especifica <kbd>user</kbd> para usar la preferencia de idioma del usuario actual, o especifica <kbd>content</kbd> para usar el idioma de contenido de este wiki.",
        "apihelp-block-description": "Bloquear a un usuario.",
        "apihelp-block-param-user": "El nombre de usuario, dirección IP o intervalo de IP que quieres bloquear.",
-       "apihelp-block-param-expiry": "Fecha de expiración. Puede ser relativa (por ejemplo, <kbd>5 meses</kbd> o <kbd>2 semanas</kbd>) o absoluta (por ejemplo, <kbd>2014-09-18T12:34:56Z</kbd>). Si se establece en <kbd>infinito</kbd>, <kbd>indefinido</kbd>, o <kbd>nunca</kbd>, el bloqueo será permanente.",
+       "apihelp-block-param-expiry": "Fecha de expiración. Puede ser relativa (por ejemplo, <kbd>5 months</kbd> o <kbd>2 weeks</kbd>) o absoluta (por ejemplo, <kbd>2014-09-18T12:34:56Z</kbd>). Si se establece en <kbd>infinite</kbd>, <kbd>indefinite</kbd>, o <kbd>never</kbd>, el bloqueo será permanente.",
        "apihelp-block-param-reason": "Razón para el bloqueo.",
        "apihelp-block-param-anononly": "Bloquear solo usuarios anónimos (es decir, desactivar ediciones anónimas de esta dirección IP).",
        "apihelp-block-param-nocreate": "Prevenir la creación de cuentas.",
@@ -38,7 +40,7 @@
        "apihelp-block-param-allowusertalk": "Permitir que el usuario edite su propia página de discusión (depende de <var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
        "apihelp-block-param-reblock": "Si la cuenta ya está bloqueada, sobrescribir el bloqueo existente.",
        "apihelp-block-param-watchuser": "Vigilar las páginas de usuario y de discusión del usuario o de la dirección IP.",
-       "apihelp-block-example-ip-simple": "Bloquear la dirección IP <kbd>192.0.2.5</kbd> durante 3 días por el motivo: <kbd>Primer ataque</kbd>.",
+       "apihelp-block-example-ip-simple": "Bloquear la dirección IP <kbd>192.0.2.5</kbd> durante 3 días por el motivo <kbd>First strike</kbd>.",
        "apihelp-block-example-user-complex": "Bloquear al usuario <kbd>Vandal</kbd> indefinidamente con el motivo <kbd>Vandalism</kbd> y evitar que se cree nuevas cuentas o envíe correos.",
        "apihelp-checktoken-description": "Comprueba la validez de una ficha desde <kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
        "apihelp-checktoken-param-type": "Tipo de ficha a probar.",
        "apihelp-feedcontributions-param-toponly": "Mostrar solo ediciones que son últimas revisiones.",
        "apihelp-feedcontributions-param-newonly": "Mostrar solo ediciones que son creaciones de páginas.",
        "apihelp-feedcontributions-param-showsizediff": "Mostrar la diferencia de tamaño entre revisiones.",
-       "apihelp-feedcontributions-example-simple": "Devolver las contribuciones del usuario <kbd>Ejemplo</kbd>.",
+       "apihelp-feedcontributions-example-simple": "Devolver las contribuciones del usuario <kbd>Example</kbd>.",
        "apihelp-feedrecentchanges-description": "Devuelve un canal de cambios recientes.",
        "apihelp-feedrecentchanges-param-feedformat": "El formato del canal.",
        "apihelp-feedrecentchanges-param-namespace": "Espacio de nombres al cual limitar los resultados.",
        "apihelp-help-example-query": "Ayuda para dos submódulos de consulta.",
        "apihelp-imagerotate-description": "Girar una o más imágenes.",
        "apihelp-imagerotate-param-rotation": "Grados que rotar una imagen en sentido horario.",
-       "apihelp-imagerotate-example-simple": "Rotar <kbd>File:Ejemplo.png</kbd> <kbd>90</kbd> grados.",
-       "apihelp-imagerotate-example-generator": "Rotar todas las imágenes en la  <kbd>Categoría:Girar</kbd> <kbd>180</kbd> grados.",
+       "apihelp-imagerotate-example-simple": "Rotar <kbd>File:Example.png</kbd> <kbd>90</kbd> grados.",
+       "apihelp-imagerotate-example-generator": "Rotar todas las imágenes en <kbd>Category:Flip</kbd> <kbd>180</kbd> grados.",
        "apihelp-import-param-summary": "Resumen de importación.",
        "apihelp-import-param-xml": "Se cargó el archivo XML.",
        "apihelp-import-param-interwikisource": "Para importaciones interwiki: wiki desde la que importar.",
        "apihelp-managetags-param-tag": "Etiqueta para crear, eliminar, activar o desactivar. Para crear una etiqueta, esta debe no existir. Para eliminarla, debe existir. Para activarla, debe existir y no estar en uso por ninguna extensión. Para desactivarla, debe estar activada y definida manualmente.",
        "apihelp-managetags-param-reason": "Un motivo opcional para crear, eliminar, activar o desactivar la etiqueta.",
        "apihelp-managetags-example-create": "Crear una etiqueta llamada <kbd>spam</kbd> con el motivo <kbd>For use in edit patrolling</kbd>",
-       "apihelp-managetags-example-delete": "Eliminar la etiqueta <kbd>vandlaismo</kbd> con el motivo <kbd>mal deletreado</kbd>",
+       "apihelp-managetags-example-delete": "Eliminar la etiqueta <kbd>vandlaism</kbd> con el motivo <kbd>Misspelt</kbd>",
        "apihelp-managetags-example-activate": "Activar una etiqueta llamada <kbd>spam</kbd> con el motivo <kbd>For use in edit patrolling</kbd>",
        "apihelp-managetags-example-deactivate": "Desactivar una etiqueta llamada <kbd>spam</kbd> con el motivo <kbd>No longer required</kbd>",
        "apihelp-mergehistory-description": "Fusionar historiales de páginas.",
        "apihelp-parse-example-summary": "Analizar un resumen.",
        "apihelp-patrol-description": "Verificar una página o revisión.",
        "apihelp-patrol-param-rcid": "Identificador de cambios recientes que verificar.",
+       "apihelp-patrol-param-revid": "ID de revisión a patrullar.",
        "apihelp-patrol-example-rcid": "Verificar un cambio reciente.",
        "apihelp-patrol-example-revid": "Verificar una revisión.",
        "apihelp-protect-description": "Cambiar el nivel de protección de una página.",
        "apihelp-query+embeddedin-param-limit": "Cuántas páginas se devolverán.",
        "apihelp-query+extlinks-param-limit": "Cuántos enlaces se devolverán.",
        "apihelp-query+extlinks-example-simple": "Obtener una lista de los enlaces externos en <kbd>Main Page</kbd>.",
+       "apihelp-query+exturlusage-description": "Enumera páginas que contienen una URL dada.",
        "apihelp-query+exturlusage-param-prop": "Qué piezas de información incluir:",
        "apihelp-query+exturlusage-paramvalue-prop-ids": "Añade el identificado de la página.",
        "apihelp-query+exturlusage-paramvalue-prop-title": "Agrega el título y el identificador del espacio de nombres de la página.",
        "apihelp-query+redirects-paramvalue-prop-fragment": "Fragmento de cada redirección, si los hubiere.",
        "apihelp-query+redirects-param-limit": "Cuántas redirecciones se devolverán.",
        "apihelp-query+redirects-example-simple": "Mostrar una lista de las redirecciones a la [[Main Page|Portada]]",
-       "apihelp-query+revisions-example-last5": "Mostrar las últimas 5 revisiones de la <kbd>Portada</kbd>.",
+       "apihelp-query+revisions-example-last5": "Mostrar las últimas 5 revisiones de la <kbd>Main Page</kbd>.",
        "apihelp-query+revisions+base-param-prop": "Las propiedades que se obtendrán para cada revisión:",
        "apihelp-query+revisions+base-paramvalue-prop-ids": "El identificador de la revisión.",
        "apihelp-query+revisions+base-paramvalue-prop-flags": "Marcas de revisión (menor).",
        "apihelp-query+usercontribs-paramvalue-prop-patrolled": "Etiqueta ediciones verificadas.",
        "apihelp-query+usercontribs-paramvalue-prop-tags": "Lista las etiquetas para la edición.",
        "apihelp-query+usercontribs-param-show": "Mostrar solo los elementos que coinciden con estos criterios. Por ejemplo, solo ediciones no menores: <kbd>$2show=!minor</kbd>.\n\nSi se establece <kbd>$2show=patrolled</kbd> o <kbd>$2show=!patrolled</kbd>, las revisiones más antiguas que <var>[[mw:Manual:$wgRCMaxAge|$wgRCMaxAge]]</var> ($1 {{PLURAL:$1|segundo|segundos}}) no se mostrarán.",
-       "apihelp-query+usercontribs-example-user": "Mostrar contribuciones del usuario <kbd>Ejemplo</kbd>.",
+       "apihelp-query+usercontribs-example-user": "Mostrar contribuciones del usuario <kbd>Example</kbd>.",
        "apihelp-query+usercontribs-example-ipprefix": "Mostrar las contribuciones de todas las direcciones IP con el prefijo <kbd>192.0.2.</kbd>.",
        "apihelp-query+userinfo-description": "Obtener información sobre el usuario actual.",
        "apihelp-query+userinfo-param-prop": "Qué piezas de información incluir:",
        "apihelp-tag-param-logid": "Uno o más identificadores de entradas del registro a los que agregar o eliminar la etiqueta.",
        "apihelp-tag-param-reason": "Motivo del cambio.",
        "apihelp-tag-example-rev": "Añadir la etiqueta <kbd>vandalism</kbd> al identificador de revisión 123 sin especificar un motivo",
-       "apihelp-tag-example-log": "Eliminar la etiqueta <kbd>spam</kbd> de la entrada del registro con identificador 123 con el motivo <kbd>aplicada incorrectamente</kbd>",
+       "apihelp-tag-example-log": "Eliminar la etiqueta <kbd>spam</kbd> de la entrada del registro con identificador 123 con el motivo <kbd>Wrongly applied</kbd>",
        "apihelp-unblock-description": "Desbloquear un usuario.",
        "apihelp-unblock-param-reason": "Motivo del desbloqueo.",
-       "apihelp-unblock-example-user": "Desbloquear al usuario <kbd>Bob</kbd> con el motivo <kbd>Lo siento, Bob</kbd>",
+       "apihelp-unblock-example-user": "Desbloquear al usuario <kbd>Bob</kbd> con el motivo <kbd>Sorry Bob</kbd>",
        "apihelp-undelete-param-reason": "Motivo de la restauración.",
        "apihelp-undelete-example-revisions": "Restaurar dos revisiones de la página <kbd>Main Page</kbd>.",
        "apihelp-upload-param-tags": "Cambiar etiquetas para aplicar a la entrada del registro de subidas y a la revisión de página de archivo.",
        "apihelp-userrights-param-reason": "Motivo del cambio.",
        "apihelp-userrights-example-user": "Agregar al usuario <kbd>FooBot</kbd> al grupo <kbd>bot</kbd> y eliminarlo de los grupos <kbd>sysop</kbd> y <kbd>bureaucrat</kbd>.",
        "apihelp-watch-example-watch": "Vigilar la página <kbd>Main Page</kbd>.",
-       "apihelp-watch-example-unwatch": "Dejar de vigilar la <kbd>Portada</kbd>.",
+       "apihelp-watch-example-unwatch": "Dejar de vigilar la <kbd>Main Page</kbd>.",
        "apihelp-format-example-generic": "Devolver el resultado de la consulta en formato $1.",
        "api-help-main-header": "Módulo principal",
        "api-help-flag-deprecated": "Este módulo está en desuso.",
index b1089c7..378ffb9 100644 (file)
        "apihelp-purge-param-forcerecursivelinkupdate": "Mettre à jour la table des liens, et mettre à jour les tables de liens pour toute page qui utilise cette page comme modèle",
        "apihelp-purge-example-simple": "Purger les pages <kbd>Main Page</kbd> et <kbd>API</kbd>.",
        "apihelp-purge-example-generator": "Purger les 10 premières pages de l’espace de noms principal",
-       "apihelp-query-description": "Extraire des données de et sur MédiaWiki.\n\nToutes les modifications de données devront d’abord utiliser une requête pour obtenir un jeton, afin d’éviter les abus de la part de sites malveillants.",
+       "apihelp-query-description": "Extraire des données de et sur MediaWiki.\n\nToutes les modifications de données devront d’abord utiliser une requête pour obtenir un jeton, afin d’éviter les abus de la part de sites malveillants.",
        "apihelp-query-param-prop": "Quelles propriétés obtenir des pages demandées.",
        "apihelp-query-param-list": "Quelles listes obtenir.",
        "apihelp-query-param-meta": "Quelles métadonnées obtenir.",
        "apihelp-query+allimages-param-minsize": "Restreindre aux images avec au moins ce nombre d’octets.",
        "apihelp-query+allimages-param-maxsize": "Restreindre aux images avec au plus ce nombre d’octets.",
        "apihelp-query+allimages-param-sha1": "Hachage SHA1 de l’image. Écrase $1sha1base36.",
-       "apihelp-query+allimages-param-sha1base36": "Hachage SHA1 de l’image en base 36 (utilisé dans MédiaWiki).",
+       "apihelp-query+allimages-param-sha1base36": "Hachage SHA1 de l’image en base 36 (utilisé dans MediaWiki).",
        "apihelp-query+allimages-param-user": "Renvoyer seulement les fichiers téléchargés par cet utilisateur. Utilisable uniquement avec $1sort=timestamp. Impossible à utiliser avec $1filterbots.",
        "apihelp-query+allimages-param-filterbots": "Comment filtrer les fichiers téléchargés par des robots. Peut être utilisé uniquement avec $1sort=timestamp. Impossible à utiliser avec $1user.",
        "apihelp-query+allimages-param-mime": "Quels types MIME rechercher, par ex. <kbd>image/jpeg</kbd>.",
        "apihelp-query+pagepropnames-example-simple": "Obtenir les 10 premiers noms de propriété.",
        "apihelp-query+pageprops-description": "Obtenir diverses propriétés de page définies dans le contenu de la page.",
        "apihelp-query+pageprops-param-prop": "Lister uniquement ces propriétés de page (<kbd>[[Special:ApiHelp/query+pagepropnames|action=query&list=pagepropnames]]</kbd> renvoie les noms de propriété de page utilisés). Utile pour vérifier si des pages utilisent une certaine propriété de page.",
-       "apihelp-query+pageprops-example-simple": "Obtenir les propriétés des pages <kbd>Accueil</kbd> et <kbd>MédiaWiki</kbd>.",
+       "apihelp-query+pageprops-example-simple": "Obtenir les propriétés des pages <kbd>Main Page</kbd> et <kbd>MediaWiki</kbd>.",
        "apihelp-query+pageswithprop-description": "Lister toutes les pages utilisant une propriété de page donnée.",
        "apihelp-query+pageswithprop-param-propname": "Propriété de page pour laquelle énumérer les pages (<kbd>[[Special:ApiHelp/query+pagepropnames|action=query&list=pagepropnames]]</kbd> renvoie les noms de propriété de page utilisés).",
        "apihelp-query+pageswithprop-param-prop": "Quelles informations inclure :",
index 618fbc7..a1058b8 100644 (file)
@@ -39,7 +39,7 @@
        "apihelp-block-param-reblock": "אם המשתמש כבר חסום, לדרוס את החסימה הנוכחית.",
        "apihelp-block-param-watchuser": "לעקוב אחרי דף המשתמש ודף השיחה של המשתמש או של כתובת ה־IP.",
        "apihelp-block-example-ip-simple": "חסימת כתובת ה־IP‏ <kbd>192.0.2.5</kbd> לשלושה ימים עם הסיבה <kbd>First strike</kbd>.",
-       "apihelp-block-example-user-complex": "×\97ס×\99×\9eת ×\94×\9eשת×\9eש <kbd>Vandal</kbd> ×\9c×\9c×\90 ×\94×\92×\91×\9cת ×\96×\9e×\9f ×¢×\9d ×\94ס×\99×\91×\94 <kbd>Vandalism</kbd>, ×\95×\9e× ×\99עת ×\99צ×\99רת ×\97ש×\91×\95×\91ות חדשים ושליחת דוא\"ל.",
+       "apihelp-block-example-user-complex": "×\97ס×\99×\9eת ×\94×\9eשת×\9eש <kbd>Vandal</kbd> ×\9c×\9c×\90 ×\94×\92×\91×\9cת ×\96×\9e×\9f ×¢×\9d ×\94ס×\99×\91×\94 <kbd>Vandalism</kbd>, ×\95×\9e× ×\99עת ×\99צ×\99רת ×\97ש×\91×\95× ות חדשים ושליחת דוא\"ל.",
        "apihelp-checktoken-description": "בדיקת התקינות של האסימון מ־<kbd>[[Special:ApiHelp/query+tokens|action=query&meta=tokens]]</kbd>.",
        "apihelp-checktoken-param-type": "סוג האסימון שבבדיקה.",
        "apihelp-checktoken-param-token": "איזה אסימון לבדוק.",
        "apihelp-query+allusers-paramvalue-prop-groups": "הוספת קבוצות שמשתמש חבר בהן. זה משתמש ביותר משאבי דפדפן ויכול להחזיר פחות תוצאות מהמגבלה.",
        "apihelp-query+allusers-paramvalue-prop-implicitgroups": "לרשום את כל הקבוצות שהמשתמש חבר בהן אוטומטית.",
        "apihelp-query+allusers-paramvalue-prop-rights": "רשימת הההרשאות שיש למשתמש.",
-       "apihelp-query+allusers-paramvalue-prop-editcount": "×\94×\95ספת ×\9e× ×\99×\99×\9f ×\94ער×\99×\9b×\95ת ×©×\9c ×\94×\9eשת×\9eש .",
+       "apihelp-query+allusers-paramvalue-prop-editcount": "×\94×\95ספת ×\9e×\95× ×\94 ×\94ער×\99×\9b×\95ת ×©×\9c ×\94×\9eשת×\9eש.",
        "apihelp-query+allusers-paramvalue-prop-registration": "הוספת חותם־הזמן של זמן הרישום של המשתמש (יכול להיות ריק).",
        "apihelp-query+allusers-paramvalue-prop-centralids": "הוספת המזהה המרכזי ומצב השיוך למשתמש.",
        "apihelp-query+allusers-param-limit": "כמה שמות משתמש בסך הכול לשנות.",
index 223e585..480ad24 100644 (file)
@@ -1,8 +1,10 @@
 {
        "@metadata": {
                "authors": [
-                       "WongKentir"
+                       "WongKentir",
+                       "Beeyan"
                ]
        },
-       "apihelp-createaccount-param-name": "Nama pengguna"
+       "apihelp-createaccount-param-name": "Nama pengguna",
+       "apihelp-revisiondelete-param-ids": "Penanda untuk perubahan yang akan dihapus"
 }
index 2825a73..942b4d3 100644 (file)
                        "JackLantern"
                ]
        },
-       "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentazione (in inglese)]]\n* [[mw:API:FAQ|FAQ (in inglese)]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailing list]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Annunci sull'API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bug & richieste]\n</div>\n<strong>Stato:</strong> Tutte le funzioni e caratteristiche mostrate su questa pagina dovrebbero funzionare, ma l'API è ancora in fase d'attivo sviluppo, e potrebbe cambiare in qualsiasi momenento. Iscriviti alla [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce mailing list] per essere informato sugli aggiornamenti.\n\n<strong>Istruzioni sbagliate:</strong> quando vengono impartite all'API delle istruzioni sbagliate, un'intestazione HTTP verrà inviata col messaggio \"MediaWiki-API-Error\" e sia al valore dell'intestazione sia al codice d'errore verrà impostato lo stesso valore. Per maggiori informazioni leggi [[mw:API:Errors_and_warnings|API:Errori ed avvertimenti (in inglese)]].\n\n<strong>Test:</strong> per testare facilmente le richieste API, vedi [[Special:ApiSandbox]].",
+       "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Documentazione]] (in inglese)\n* [[mw:API:FAQ|FAQ]] (in inglese)\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Mailing list]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Annunci sull'API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bug & richieste]\n</div>\n<strong>Stato:</strong> tutte le funzioni e caratteristiche mostrate su questa pagina dovrebbero funzionare, ma le API sono ancora in fase attiva di sviluppo, e potrebbero cambiare in qualsiasi momento. Iscriviti alla [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ la mailing list sugli annunci delle API MediaWiki] per essere informato sugli aggiornamenti.\n\n<strong>Istruzioni sbagliate:</strong> quando vengono impartite alle API delle istruzioni sbagliate, un'intestazione HTTP verrà inviata col messaggio \"MediaWiki-API-Error\" e, sia il valore dell'intestazione, sia il codice d'errore, verranno impostati con lo stesso valore. Per maggiori informazioni leggi [[mw:API:Errors_and_warnings|API:Errori ed avvertimenti]] (in inglese).\n\n<strong>Test:</strong> per testare facilmente le richieste API, vedi [[Special:ApiSandbox]].",
        "apihelp-main-param-action": "Azione da compiere.",
        "apihelp-main-param-format": "Formato dell'output.",
-       "apihelp-main-param-assert": "Verifica che l'utente sia loggato se si è impostato <kbd>utente</kbd>, o che abbia i permessi di bot se si è impostato <kbd>bot</kbd>.",
+       "apihelp-main-param-assert": "Verifica che l'utente abbia effettuato l'accesso se si è impostato <kbd>user</kbd>, o che abbia i permessi di bot se si è impostato <kbd>bot</kbd>.",
        "apihelp-main-param-requestid": "Tutti i valori forniti saranno implementati nella risposta. Potrebbero venir utilizzati per distinguere le richieste.",
        "apihelp-main-param-servedby": "Includi nel risultato il nome dell'host che ha servito la richiesta.",
        "apihelp-main-param-curtimestamp": "Includi nel risultato il timestamp attuale.",
        "apihelp-block-description": "Blocca  un utente.",
        "apihelp-block-param-user": "Nome utente, indirizzo IP o range di IP da bloccare.",
+       "apihelp-block-param-expiry": "Tempo di scadenza. Può essere relativo (ad esempio, <kbd>5 months</kbd> o <kbd>2 weeks</kbd>) o assoluto (ad esempio <kbd>2014-09-18T12:34:56Z</kbd>). Se impostato a <kbd>infinite</kbd>, <kbd>indefinite</kbd> o <kbd>never</kbd>, il blocco non scadrà mai.",
        "apihelp-block-param-reason": "Motivo del blocco.",
        "apihelp-block-param-anononly": "Blocca solo gli utenti non registrati (cioè disattiva i contributi anonimi da questo indirizzo IP).",
        "apihelp-block-param-nocreate": "Impedisci creazione di utenze.",
+       "apihelp-block-param-autoblock": "Blocca automaticamente l'ultimo indirizzo IP usato dall'utente e i successivi con cui viene tentato l'accesso.",
        "apihelp-block-param-hidename": "Nascondi il nome utente dal registro dei blocchi (Richiede i permessi di <code>hideuser</code>).",
        "apihelp-block-param-reblock": "Se l'utente è già bloccato, sovrascrivere il blocco esistente.",
        "apihelp-block-param-watchuser": "Segui la pagina utente e le pagine di discussione utente dell'utente o dell'indirizzo IP.",
        "apihelp-createaccount-example-pass": "Crea l'utente <kbd>testuser</kbd> con password <kbd>test123</kbd>.",
        "apihelp-createaccount-example-mail": "Crea l'utente <kbd>testmailuser</kbd> e mandagli via e-mail una password generata casualmente.",
        "apihelp-delete-description": "Cancella una pagina.",
-       "apihelp-delete-param-title": "Titolo della pagina che si desidera eliminare. Non può essere usato insieme con <var>$1pageid</var>.",
+       "apihelp-delete-param-title": "Titolo della pagina che si desidera eliminare. Non può essere usato insieme a <var>$1pageid</var>.",
        "apihelp-delete-param-pageid": "ID di pagina della pagina da cancellare. Non può essere usato insieme con <var>$1title</var>.",
        "apihelp-delete-param-reason": "Motivo della cancellazione. Se non indicato, verrà usata una motivazione generata automaticamente.",
        "apihelp-delete-param-watch": "Aggiunge la pagina agli osservati speciali dell'utente attuale.",
        "apihelp-delete-param-unwatch": "Rimuove la pagina dagli osservati speciali dell'utente attuale.",
+       "apihelp-delete-param-oldimage": "Il nome della vecchia immagine da cancellare, come fornita da [[Special:ApiHelp/query+imageinfo|action=query&prop=imageinfo&iiprop=archivename]].",
        "apihelp-delete-example-simple": "Cancella <kbd>Main Page</kbd>.",
        "apihelp-delete-example-reason": "Cancella la <kbd>Main Page</kbd> con motivazione <kbd>Preparing for move</kbd>.",
        "apihelp-disabled-description": "Questo modulo è stato disabilitato.",
        "apihelp-edit-description": "Crea e modifica pagine.",
-       "apihelp-edit-param-title": "Titolo della pagina da modificare. Non può essere usato insieme con <var>$1pageid</var>.",
+       "apihelp-edit-param-title": "Titolo della pagina da modificare. Non può essere usato insieme a <var>$1pageid</var>.",
        "apihelp-edit-param-pageid": "ID di pagina della pagina da modificare. Non può essere usato insieme con <var>$1title</var>.",
+       "apihelp-edit-param-section": "Numero di sezione. <kbd>0</kbd> per la sezione iniziale, <kbd>new</kbd> per una nuova sezione.",
        "apihelp-edit-param-sectiontitle": "Il titolo per una nuova sezione.",
        "apihelp-edit-param-text": "Contenuto della pagina.",
        "apihelp-edit-param-summary": "Oggetto della modifica. Anche titolo della sezione se $1sezione=new e $1sectiontitle non è impostato.",
        "apihelp-edit-param-watch": "Aggiunge la pagina agli osservati speciali dell'utente attuale.",
        "apihelp-edit-param-unwatch": "Rimuove la pagina dagli osservati speciali dell'utente attuale.",
        "apihelp-edit-param-redirect": "Risolvi automaticamente redirect.",
+       "apihelp-edit-param-contentmodel": "Modello di contenuto dei nuovi contenuti.",
+       "apihelp-edit-param-token": "Il token deve sempre essere inviato come ultimo parametro, o almeno dopo il parametro $1text.",
        "apihelp-edit-example-edit": "Modifica una pagina.",
+       "apihelp-edit-example-prepend": "Anteponi <kbd>_&#95;NOTOC_&#95;</kbd> a una pagina.",
        "apihelp-emailuser-description": "Manda un'e-mail ad un utente.",
        "apihelp-emailuser-param-target": "Utente a cui inviare l'e-mail.",
        "apihelp-emailuser-param-subject": "Oggetto dell'e-mail.",
        "apihelp-feedcontributions-param-feedformat": "Il formato del feed.",
        "apihelp-feedcontributions-param-year": "Dall'anno (e precedenti).",
        "apihelp-feedcontributions-param-month": "Dal mese (e precedenti).",
+       "apihelp-feedcontributions-param-tagfilter": "Filtra contributi che hanno queste etichette.",
        "apihelp-feedcontributions-param-deletedonly": "Mostra solo i contribuiti cancellati.",
        "apihelp-feedcontributions-param-toponly": "Mostra solo i contributi che sono le ultime versioni per la pagina.",
        "apihelp-feedcontributions-param-newonly": "Visualizza solo le modifiche che sono creazioni di pagina.",
+       "apihelp-feedcontributions-param-showsizediff": "Mostra la differenza di dimensioni tra le versioni.",
+       "apihelp-feedcontributions-example-simple": "Restituisce contributi per l'utente <kbd>Example</kbd>.",
        "apihelp-feedrecentchanges-param-feedformat": "Il formato del feed.",
+       "apihelp-feedrecentchanges-param-namespace": "Namespace a cui limitare i risultati.",
+       "apihelp-feedrecentchanges-param-associated": "Includi namespace associato (discussione o principale)",
        "apihelp-feedrecentchanges-param-limit": "Numero massimo di risultati da restituire.",
        "apihelp-feedrecentchanges-param-hideminor": "Nascondi le modifiche minori.",
        "apihelp-feedrecentchanges-param-hidebots": "Nascondi le modifiche apportate da bot.",
        "apihelp-filerevert-param-comment": "Commento sul caricamento.",
        "apihelp-filerevert-param-archivename": "Nome dell'archivio della versione da ripristinare.",
        "apihelp-filerevert-example-revert": "Ripristina <kbd>Wiki.png</kbd> alla versione del <kbd>2011-03-05T15:27:40Z</kbd>.",
+       "apihelp-help-param-toc": "Includi un indice nell'output HTML.",
+       "apihelp-help-example-main": "Aiuto per il modulo principale.",
        "apihelp-help-example-submodules": "Aiuto per <kbd>action=query</kbd> e tutti i suoi sotto-moduli.",
+       "apihelp-help-example-recursive": "Tutti gli aiuti in una pagina.",
+       "apihelp-help-example-help": "Aiuto per lo stesso modulo di aiuto.",
        "apihelp-imagerotate-description": "Ruota una o più immagini.",
        "apihelp-imagerotate-param-rotation": "Gradi di rotazione dell'immagine in senso orario.",
        "apihelp-imagerotate-example-simple": "Ruota <kbd>File:Example.png</kbd> di <kbd>90</kbd> gradi.",
        "apihelp-import-param-interwikipage": "Per importazioni interwiki: pagina da importare.",
        "apihelp-import-param-fullhistory": "Per importazioni interwiki: importa l'intera cronologia, non solo la versione attuale.",
        "apihelp-import-param-templates": "Per importazioni interwiki: importa anche tutti i template inclusi.",
+       "apihelp-import-param-namespace": "Importa in questo namespace. Non può essere usato insieme a <var>$1rootpage</var>.",
+       "apihelp-import-param-rootpage": "Importa come sottopagina di questa pagina. Non può essere usato insieme a <var>$1namespace</var>.",
        "apihelp-import-example-import": "Importa [[meta:Help:ParserFunctions]] nel namespace 100 con cronologia completa.",
        "apihelp-login-param-name": "Nome utente.",
        "apihelp-login-param-password": "Password.",
        "apihelp-login-param-domain": "Dominio (opzionale).",
+       "apihelp-login-example-gettoken": "Recupera un token di login.",
        "apihelp-login-example-login": "Entra.",
+       "apihelp-logout-description": "Esci e cancella i dati della sessione.",
        "apihelp-mergehistory-description": "Unisce cronologie pagine.",
        "apihelp-mergehistory-param-from": "Il titolo della pagina da cui cronologia sarà unita. Non può essere usato insieme a <var>$1fromid</var>.",
        "apihelp-mergehistory-param-fromid": "L'ID della pagina da cui cronologia sarà unita. Non può essere usato insieme a <var>$1from</var>.",
        "apihelp-mergehistory-example-merge": "Unisci l'intera cronologia di <kbd>Oldpage</kbd> in <kbd>Newpage</kbd>.",
        "apihelp-mergehistory-example-merge-timestamp": "Unisci le versioni della pagina <kbd>Oldpage</kbd> fino a <kbd>2015-12-31T04:37:41Z</kbd> in <kbd>Newpage</kbd>.",
        "apihelp-move-description": "Sposta una pagina.",
+       "apihelp-move-param-to": "Titolo a cui spostare la pagina.",
        "apihelp-move-param-reason": "Motivo della rinomina.",
        "apihelp-move-param-movetalk": "Rinomina la pagina di discussione, se esiste.",
        "apihelp-move-param-movesubpages": "Rinomina sottopagine, se applicabile.",
        "apihelp-move-param-noredirect": "Non creare un rinvio.",
        "apihelp-move-param-watch": "Aggiunge la pagina e il redirect agli osservati speciali dell'utente attuale.",
+       "apihelp-move-param-unwatch": "Rimuovi la pagina e il redirect dagli osservati speciali dell'utente attuale.",
        "apihelp-move-param-ignorewarnings": "Ignora i messaggi di avvertimento del sistema.",
+       "apihelp-move-example-move": "Sposta <kbd>Badtitle</kbd> a <kbd>Goodtitle</kbd> senza lasciare redirect.",
+       "apihelp-opensearch-param-search": "Stringa di ricerca.",
        "apihelp-opensearch-param-limit": "Numero massimo di risultati da restituire.",
+       "apihelp-opensearch-param-suggest": "Non fare nulla se <var>[[mw:Manual:$wgEnableOpenSearchSuggest|$wgEnableOpenSearchSuggest]]</var> è falso.",
        "apihelp-opensearch-param-format": "Il formato dell'output.",
        "apihelp-opensearch-example-te": "Trova le pagine che iniziano con <kbd>Te</kbd>.",
        "apihelp-options-example-reset": "Reimposta tutte le preferenze.",
+       "apihelp-paraminfo-description": "Ottieni informazioni sui moduli API.",
        "apihelp-paraminfo-param-helpformat": "Formato delle stringhe di aiuto.",
        "apihelp-parse-param-summary": "Oggetto da analizzare.",
+       "apihelp-parse-param-prop": "Quali pezzi di informazioni ottenere:",
        "apihelp-parse-example-text": "Analizza wikitext.",
        "apihelp-parse-example-texttitle": "Analizza wikitext, specificando il titolo della pagina.",
        "apihelp-parse-example-summary": "Analizza un oggetto.",
+       "apihelp-patrol-description": "Verifica una pagina o versione.",
+       "apihelp-patrol-param-rcid": "ID della modifica recente da verificare.",
+       "apihelp-patrol-param-revid": "ID versione da verificare.",
        "apihelp-patrol-param-tags": "Modifica etichette da applicare all'elemento del registro delle verifiche.",
+       "apihelp-patrol-example-rcid": "Verifica una modifica recente.",
+       "apihelp-patrol-example-revid": "Verifica una versione.",
        "apihelp-protect-description": "Modifica il livello di protezione di una pagina.",
-       "apihelp-protect-param-title": "Titolo della pagina da (s)proteggere. Non può essere usato insieme con $1pageid.",
+       "apihelp-protect-param-title": "Titolo della pagina da (s)proteggere. Non può essere usato insieme a <var>$1pageid</var>.",
        "apihelp-protect-param-pageid": "ID della pagina da (s)proteggere. Non può essere usato insieme con $1title.",
        "apihelp-protect-param-tags": "Modifica etichette da applicare all'elemento del registro delle protezioni.",
        "apihelp-protect-example-protect": "Proteggi una pagina.",
+       "apihelp-protect-example-unprotect": "Sproteggi una pagina impostando restrizione su <kbd>all</kbd>.",
+       "apihelp-protect-example-unprotect2": "Sproteggi una pagina impostando nessuna restrizione.",
+       "apihelp-purge-param-forcelinkupdate": "Aggiorna la tabella dei collegamenti.",
+       "apihelp-purge-param-forcerecursivelinkupdate": "Aggiorna la tabella dei collegamenti per questa pagina, e per ogni pagina che usa questa pagina come template.",
+       "apihelp-query-param-list": "Quali elenchi ottenere.",
+       "apihelp-query-param-meta": "Quali metadati ottenere.",
        "apihelp-query-param-export": "Esporta la versione attuale di tutte le pagine ottenute o generate.",
+       "apihelp-query+allcategories-description": "Enumera tutte le categorie.",
+       "apihelp-query+allcategories-param-from": "La categoria da cui iniziare l'elenco.",
+       "apihelp-query+allcategories-param-to": "La categoria al quale interrompere l'elenco.",
+       "apihelp-query+allcategories-param-prefix": "Ricerca per tutti i titoli delle categorie che iniziano con questo valore.",
        "apihelp-query+allcategories-param-dir": "Direzione dell'ordinamento.",
        "apihelp-query+allcategories-param-limit": "Quante categorie restituire.",
        "apihelp-query+allcategories-param-prop": "Quali proprietà ottenere:",
        "apihelp-query+allcategories-paramvalue-prop-size": "Aggiungi il numero di pagine nella categoria.",
        "apihelp-query+allcategories-paramvalue-prop-hidden": "Etichetta categorie che sono nascoste con <code>_&#95;HIDDENCAT_&#95;</code>.",
        "apihelp-query+allcategories-example-size": "Elenca categorie con informazioni sul numero di pagine in ognuna.",
+       "apihelp-query+alldeletedrevisions-description": "Elenca tutte le versioni cancellate da un utente o in un namespace.",
        "apihelp-query+alldeletedrevisions-paraminfo-useronly": "Può essere utilizzato solo con <var>$3user</var>.",
        "apihelp-query+alldeletedrevisions-paraminfo-nonuseronly": "Non può essere utilizzato con <var>$3user</var>.",
+       "apihelp-query+alldeletedrevisions-param-start": "Il timestamp da cui iniziare l'elenco.",
+       "apihelp-query+alldeletedrevisions-param-end": "Il timestamp al quale interrompere l'elenco.",
+       "apihelp-query+alldeletedrevisions-param-from": "Inizia elenco a questo titolo.",
+       "apihelp-query+alldeletedrevisions-param-to": "Interrompi elenco a questo titolo.",
+       "apihelp-query+alldeletedrevisions-param-prefix": "Ricerca per tutti i titoli delle pagine che iniziano con questo valore.",
+       "apihelp-query+alldeletedrevisions-param-user": "Elenca solo le versioni di questo utente.",
+       "apihelp-query+alldeletedrevisions-param-excludeuser": "Non elencare le versioni di questo utente.",
+       "apihelp-query+alldeletedrevisions-param-namespace": "Elenca solo le pagine in questo namespace.",
        "apihelp-query+alldeletedrevisions-example-user": "Elenca gli ultimi 50 contributi cancellati dell'utente <kbd>Example</kbd>.",
        "apihelp-query+alldeletedrevisions-example-ns-main": "Elenca le prime 50 versioni cancellate nel namespace principale.",
+       "apihelp-query+allfileusages-param-from": "Il titolo del file da cui iniziare l'elenco.",
+       "apihelp-query+allfileusages-param-to": "Il titolo del file al quale interrompere l'elenco.",
+       "apihelp-query+allfileusages-param-prefix": "Ricerca per tutti i titoli dei file che iniziano con questo valore.",
+       "apihelp-query+allfileusages-param-prop": "Quali pezzi di informazioni includere:",
        "apihelp-query+allfileusages-paramvalue-prop-title": "Aggiunge il titolo del file.",
        "apihelp-query+allfileusages-param-limit": "Quanti elementi totali restituire.",
        "apihelp-query+allfileusages-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+allfileusages-example-generator": "Ottieni le pagine contenenti i file.",
        "apihelp-query+allimages-param-sort": "Proprietà di ordinamento.",
        "apihelp-query+allimages-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+allimages-param-from": "Il titolo dell'immagine da cui iniziare l'elenco. Può essere utilizzato solo con $1sort=name.",
+       "apihelp-query+allimages-param-start": "Il timestamp da cui iniziare l'elenco. Può essere utilizzato solo con $1sort=timestamp.",
+       "apihelp-query+allimages-param-end": "Il timestamp al quale interrompere l'elenco. Può essere utilizzato solo con $1sort=timestamp.",
        "apihelp-query+allimages-param-limit": "Quante immagini in totale restituire.",
        "apihelp-query+allimages-example-B": "Mostra un elenco di file a partire dalla lettera <kbd>B</kbd>.",
+       "apihelp-query+alllinks-description": "Elenca tutti i collegamenti che puntano ad un namespace indicato.",
+       "apihelp-query+alllinks-param-from": "Il titolo del collegamento da cui iniziare l'elenco.",
+       "apihelp-query+alllinks-param-to": "Il titolo del collegamento al quale interrompere l'elenco.",
+       "apihelp-query+alllinks-param-prefix": "Ricerca per tutti i titoli dei collegamenti che iniziano con questo valore.",
+       "apihelp-query+alllinks-param-prop": "Quali pezzi di informazioni includere:",
+       "apihelp-query+alllinks-paramvalue-prop-ids": "Aggiunge l'ID pagina della pagina collegata (non può essere usato con <var>$1unique</var>).",
        "apihelp-query+alllinks-paramvalue-prop-title": "Aggiunge il titolo del collegamento.",
+       "apihelp-query+alllinks-param-namespace": "Il namespace da elencare.",
        "apihelp-query+alllinks-param-limit": "Quanti elementi totali restituire.",
        "apihelp-query+alllinks-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+alllinks-example-generator": "Ottieni le pagine contenenti i collegamenti.",
+       "apihelp-query+allmessages-description": "Restituisce messaggi da questo sito.",
+       "apihelp-query+allmessages-param-prop": "Quali proprietà ottenere.",
        "apihelp-query+allmessages-param-lang": "Restituisci messaggi in questa lingua.",
+       "apihelp-query+allmessages-param-prefix": "Restituisci messaggi con questo prefisso.",
+       "apihelp-query+allpages-param-from": "Il titolo di pagina da cui iniziare l'elenco.",
+       "apihelp-query+allpages-param-to": "Il titolo di pagina al quale interrompere l'elenco.",
+       "apihelp-query+allpages-param-prefix": "Ricerca per tutti i titoli delle pagine che iniziano con questo valore.",
+       "apihelp-query+allpages-param-namespace": "Il namespace da elencare.",
        "apihelp-query+allpages-param-filterredir": "Quali pagine elencare.",
+       "apihelp-query+allpages-param-limit": "Quante pagine totali restituire.",
        "apihelp-query+allpages-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+allredirects-param-from": "Il titolo del reindirizzamento da cui iniziare l'elenco.",
+       "apihelp-query+allredirects-param-prop": "Quali pezzi di informazioni includere:",
        "apihelp-query+allredirects-paramvalue-prop-title": "Aggiunge il titolo del redirect.",
+       "apihelp-query+allredirects-param-namespace": "Il namespace da elencare.",
        "apihelp-query+allredirects-param-limit": "Quanti elementi totali restituire.",
        "apihelp-query+allredirects-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+allredirects-example-generator": "Ottieni le pagine contenenti i reindirizzamenti.",
        "apihelp-query+allrevisions-description": "Elenco di tutte le versioni.",
+       "apihelp-query+allrevisions-param-start": "Il timestamp da cui iniziare l'elenco.",
+       "apihelp-query+allrevisions-param-end": "Il timestamp al quale interrompere l'elenco.",
        "apihelp-query+allrevisions-param-user": "Elenca solo le versioni di questo utente.",
        "apihelp-query+allrevisions-param-excludeuser": "Non elencare le versioni di questo utente.",
        "apihelp-query+allrevisions-param-namespace": "Elenca solo le pagine in questo namespace.",
        "apihelp-query+mystashedfiles-paramvalue-prop-size": "Recupera la dimensione del file e le dimensioni dell'immagine.",
        "apihelp-query+mystashedfiles-paramvalue-prop-type": "Recupera il tipo MIME del file e il tipo media.",
        "apihelp-query+mystashedfiles-param-limit": "Quanti file restituire.",
+       "apihelp-query+alltransclusions-description": "Elenca tutte le inclusioni (pagine incorporate utilizzando &#123;&#123;x&#125;&#125;), comprese le non esistenti.",
+       "apihelp-query+alltransclusions-param-from": "Il titolo dell'inclusione da cui iniziare l'elenco.",
+       "apihelp-query+alltransclusions-param-prop": "Quali pezzi di informazioni includere:",
        "apihelp-query+alltransclusions-paramvalue-prop-title": "Aggiunge il titolo dell'inclusione.",
+       "apihelp-query+alltransclusions-param-namespace": "Il namespace da elencare.",
        "apihelp-query+alltransclusions-param-limit": "Quanti elementi totali restituire.",
        "apihelp-query+alltransclusions-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+alltransclusions-example-generator": "Ottieni pagine contenenti le inclusioni.",
+       "apihelp-query+allusers-param-from": "Il nome utente da cui iniziare l'elenco.",
+       "apihelp-query+allusers-param-to": "Il nome utente al quale interrompere l'elenco.",
+       "apihelp-query+allusers-param-prefix": "Ricerca per tutti gli utenti che iniziano con questo valore.",
        "apihelp-query+allusers-param-dir": "Direzione dell'ordinamento.",
+       "apihelp-query+allusers-param-group": "Includi solo gli utenti nei gruppi indicati.",
+       "apihelp-query+allusers-param-excludegroup": "Escludi gli utenti nei gruppi indicati.",
+       "apihelp-query+allusers-param-prop": "Quali pezzi di informazioni includere:",
        "apihelp-query+allusers-param-limit": "Quanti nomi utente totali restituire.",
        "apihelp-query+backlinks-description": "Trova tutte le pagine che puntano a quella specificata.",
+       "apihelp-query+backlinks-param-namespace": "Il namespace da elencare.",
        "apihelp-query+backlinks-param-dir": "La direzione in cui elencare.",
        "apihelp-query+backlinks-param-redirect": "Se la pagina collegata è un redirect, trova tutte le pagine che puntano al redirect. Il limite massimo è dimezzato.",
+       "apihelp-query+backlinks-example-simple": "Mostra collegamenti a <kbd>Main page</kbd>.",
+       "apihelp-query+blocks-param-start": "Il timestamp da cui iniziare l'elenco.",
+       "apihelp-query+blocks-param-end": "Il timestamp al quale interrompere l'elenco.",
+       "apihelp-query+blocks-param-limit": "Il numero massimo di blocchi da elencare.",
        "apihelp-query+blocks-param-prop": "Quali proprietà ottenere:",
+       "apihelp-query+blocks-paramvalue-prop-id": "Aggiunge l'ID del blocco.",
+       "apihelp-query+blocks-paramvalue-prop-user": "Aggiunge il nome utente dell'utente bloccato.",
        "apihelp-query+blocks-paramvalue-prop-userid": "Aggiunge l'ID utente dell'utente bloccato.",
+       "apihelp-query+blocks-paramvalue-prop-by": "Aggiunge il nome utente dell'utente che ha effettuato il blocco.",
        "apihelp-query+blocks-paramvalue-prop-byid": "Aggiunge l'ID utente dell'utente che ha effettuato il blocco.",
        "apihelp-query+blocks-example-simple": "Elenca i blocchi.",
+       "apihelp-query+categories-param-show": "Quale tipo di categorie mostrare.",
+       "apihelp-query+categories-param-limit": "Quante categorie restituire.",
        "apihelp-query+categories-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+categoryinfo-description": "Restituisce informazioni su una categoria indicata.",
+       "apihelp-query+categoryinfo-example-simple": "Ottieni informazioni su <kbd>Category:Foo</kbd> e <kbd>Category:Bar</kbd>.",
+       "apihelp-query+categorymembers-description": "Elenca tutte le pagine in una categoria indicata.",
+       "apihelp-query+categorymembers-param-prop": "Quali pezzi di informazioni includere:",
+       "apihelp-query+categorymembers-paramvalue-prop-ids": "Aggiunge l'ID pagina.",
        "apihelp-query+categorymembers-paramvalue-prop-title": "Aggiunge il titolo e l'ID namespace della pagina.",
        "apihelp-query+categorymembers-paramvalue-prop-type": "Aggiunge il tipo di come la pagina è stata categorizzata (<samp>page</samp>, <samp>subcat</samp> o <samp>file</samp>).",
        "apihelp-query+categorymembers-param-namespace": "Includi solo le pagine in questi namespace. Nota che può essere usato <kbd>$1type=subcat</kbd> o <kbd>$1type=file</kbd> anziché <kbd>$1namespace=14</kbd> o <kbd>6</kbd>.",
+       "apihelp-query+categorymembers-param-limit": "Il numero massimo di pagine da restituire.",
+       "apihelp-query+categorymembers-param-sort": "Proprietà di ordinamento.",
+       "apihelp-query+categorymembers-param-dir": "In quale direzione ordinare.",
+       "apihelp-query+categorymembers-param-start": "Il timestamp da cui iniziare l'elenco. Può essere utilizzato solo con <kbd>$1sort=timestamp</kbd>.",
+       "apihelp-query+categorymembers-param-end": "Il timestamp al quale interrompere l'elenco. Può essere utilizzato solo con <kbd>$1sort=timestamp</kbd>.",
+       "apihelp-query+categorymembers-param-startsortkey": "Usa $1starthexsortkey invece.",
+       "apihelp-query+categorymembers-param-endsortkey": "Usa $1endhexsortkey invece.",
+       "apihelp-query+categorymembers-example-simple": "Ottieni le prime 10 pagine in <kbd>Category:Physics</kbd>.",
+       "apihelp-query+categorymembers-example-generator": "Ottieni informazioni sulle prime 10 pagine in <kbd>Category:Physics</kbd>.",
+       "apihelp-query+contributors-param-limit": "Quanti contributi restituire.",
+       "apihelp-query+deletedrevisions-param-start": "Il timestamp da cui iniziare l'elenco. Ignorato quando si elabora un elenco di ID versioni.",
+       "apihelp-query+deletedrevisions-param-end": "Il timestamp al quale interrompere l'elenco. Ignorato quando si elabora un elenco di ID versioni.",
+       "apihelp-query+deletedrevisions-param-tag": "Elenca solo le versioni etichettate con questa etichetta.",
+       "apihelp-query+deletedrevisions-param-user": "Elenca solo le versioni di questo utente.",
+       "apihelp-query+deletedrevisions-param-excludeuser": "Non elencare le versioni di questo utente.",
+       "apihelp-query+deletedrevisions-example-titles": "Elenca le versioni cancellate delle pagine <kbd>Main Page</kbd> e <kbd>Talk:Main Page</kbd>, con il contenuto.",
+       "apihelp-query+deletedrevisions-example-revids": "Elenca le informazioni per la versione cancellata <kbd>123456</kbd>.",
+       "apihelp-query+deletedrevs-param-start": "Il timestamp da cui iniziare l'elenco.",
+       "apihelp-query+deletedrevs-param-end": "Il timestamp al quale interrompere l'elenco.",
+       "apihelp-query+deletedrevs-param-from": "Inizia elenco a questo titolo.",
+       "apihelp-query+deletedrevs-param-to": "Interrompi elenco a questo titolo.",
+       "apihelp-query+deletedrevs-param-prefix": "Ricerca per tutti i titoli delle pagine che iniziano con questo valore.",
+       "apihelp-query+deletedrevs-param-unique": "Elenca solo una versione per ogni pagina.",
+       "apihelp-query+deletedrevs-param-tag": "Elenca solo le versioni etichettate con questa etichetta.",
+       "apihelp-query+deletedrevs-param-user": "Elenca solo le versioni di questo utente.",
+       "apihelp-query+deletedrevs-param-excludeuser": "Non elencare le versioni di questo utente.",
+       "apihelp-query+deletedrevs-param-namespace": "Elenca solo le pagine in questo namespace.",
+       "apihelp-query+deletedrevs-param-limit": "Il numero massimo di versioni da elencare.",
+       "apihelp-query+disabled-description": "Questo modulo query è stato disabilitato.",
+       "apihelp-query+duplicatefiles-param-limit": "Quanti file duplicati restituire.",
        "apihelp-query+duplicatefiles-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+duplicatefiles-example-simple": "Cerca i duplicati di [[:File:Albert Einstein Head.jpg]].",
+       "apihelp-query+duplicatefiles-example-generated": "Cerca i duplicati di tutti i file.",
        "apihelp-query+embeddedin-description": "Trova tutte le pagine che incorporano (transclusione) il titolo specificato.",
+       "apihelp-query+embeddedin-param-namespace": "Il namespace da elencare.",
        "apihelp-query+embeddedin-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+embeddedin-param-limit": "Quante pagine totali restituire.",
+       "apihelp-query+extlinks-param-limit": "Quanti collegamenti restituire.",
+       "apihelp-query+exturlusage-param-prop": "Quali pezzi di informazioni includere:",
+       "apihelp-query+exturlusage-paramvalue-prop-ids": "Aggiunge l'ID della pagina.",
        "apihelp-query+exturlusage-paramvalue-prop-title": "Aggiunge il titolo e l'ID namespace della pagina.",
+       "apihelp-query+exturlusage-paramvalue-prop-url": "Aggiunge l'URL utilizzato nella pagina.",
+       "apihelp-query+exturlusage-param-namespace": "I namespace da elencare.",
+       "apihelp-query+exturlusage-param-limit": "Quante pagine restituire.",
+       "apihelp-query+filearchive-param-from": "Il titolo dell'immagine da cui iniziare l'elenco.",
+       "apihelp-query+filearchive-param-limit": "Quante immagini restituire in totale.",
        "apihelp-query+filearchive-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+filearchive-paramvalue-prop-mime": "Aggiunge MIME dell'immagine.",
+       "apihelp-query+filearchive-paramvalue-prop-bitdepth": "Aggiunge la profondità di bit della versione.",
        "apihelp-query+filearchive-example-simple": "Mostra un elenco di tutti i file cancellati.",
        "apihelp-query+fileusage-description": "Trova tutte le pagine che utilizzano il file specificato.",
        "apihelp-query+fileusage-param-prop": "Quali proprietà ottenere:",
        "apihelp-query+fileusage-param-namespace": "Includi solo le pagine in questi namespace.",
        "apihelp-query+fileusage-param-show": "Mostra solo gli elementi che soddisfano questi criteri:\n;redirect:mostra solo i redirect.\n;!redirect:mostra solo i non redirect.",
        "apihelp-query+fileusage-example-simple": "Ottieni un elenco di pagine che usano [[:File:Example.jpg]].",
+       "apihelp-query+imageinfo-paramvalue-prop-mime": "Aggiunge il tipo MIME del file.",
+       "apihelp-query+imageinfo-param-start": "Il timestamp da cui iniziare l'elenco.",
+       "apihelp-query+imageinfo-param-urlheight": "Simile a $1urlwidth.",
+       "apihelp-query+images-param-limit": "Quanti file restituire.",
        "apihelp-query+images-param-dir": "La direzione in cui elencare.",
        "apihelp-query+images-example-simple": "Ottieni un elenco di file usati in [[Main Page]].",
        "apihelp-query+imageusage-description": "Trova tutte le pagine che utilizzano il titolo dell'immagine specificato.",
+       "apihelp-query+imageusage-param-namespace": "Il namespace da elencare.",
        "apihelp-query+imageusage-param-dir": "La direzione in cui elencare.",
        "apihelp-query+imageusage-param-redirect": "Se la pagina collegata è un redirect, trova tutte le pagine che puntano al redirect. Il limite massimo è dimezzato.",
        "apihelp-query+info-paramvalue-prop-visitingwatchers": "Il numero di osservatori di ogni pagina che hanno visitato le ultime modifiche alla pagina, se consentito.",
+       "apihelp-query+iwbacklinks-param-prefix": "Prefisso per l'interwiki.",
+       "apihelp-query+iwbacklinks-param-limit": "Quante pagine totali restituire.",
        "apihelp-query+iwbacklinks-param-prop": "Quali proprietà ottenere:",
+       "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "Aggiunge il prefisso dell'interwiki.",
        "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Aggiunge il titolo dell'interwiki.",
        "apihelp-query+iwbacklinks-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+iwlinks-description": "Restituisce tutti i collegamenti interwiki dalle pagine indicate.",
+       "apihelp-query+iwlinks-paramvalue-prop-url": "Aggiunge l'URL completo.",
+       "apihelp-query+iwlinks-param-limit": "Quanti collegamenti interwiki restituire.",
        "apihelp-query+iwlinks-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+langbacklinks-param-limit": "Quante pagine totali restituire.",
        "apihelp-query+langbacklinks-param-prop": "Quali proprietà ottenere:",
        "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "Aggiunge il titolo del collegamento linguistico.",
        "apihelp-query+langbacklinks-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+langlinks-paramvalue-prop-url": "Aggiunge l'URL completo.",
        "apihelp-query+langlinks-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+links-param-namespace": "Mostra collegamenti solo in questi namespace.",
+       "apihelp-query+links-param-limit": "Quanti collegamenti restituire.",
        "apihelp-query+links-param-dir": "La direzione in cui elencare.",
        "apihelp-query+linkshere-description": "Trova tutte le pagine che puntano a quelle specificate.",
        "apihelp-query+linkshere-param-prop": "Quali proprietà ottenere:",
        "apihelp-query+linkshere-example-simple": "Ottieni un elenco di pagine che puntano a [[Main Page]].",
        "apihelp-query+logevents-param-prop": "Quali proprietà ottenere:",
        "apihelp-query+logevents-paramvalue-prop-title": "Aggiunge il titolo della pagine per l'evento nel registro.",
+       "apihelp-query+logevents-param-start": "Il timestamp da cui iniziare l'elenco.",
+       "apihelp-query+logevents-param-end": "Il timestamp al quale interrompere l'elenco.",
+       "apihelp-query+pageswithprop-param-prop": "Quali pezzi di informazioni includere:",
+       "apihelp-query+pageswithprop-paramvalue-prop-ids": "Aggiunge l'ID pagina.",
        "apihelp-query+pageswithprop-paramvalue-prop-title": "Aggiunge il titolo e l'ID namespace della pagina.",
+       "apihelp-query+pageswithprop-paramvalue-prop-value": "Aggiunge il valore della proprietà di pagina.",
+       "apihelp-query+pageswithprop-param-limit": "Il numero massimo di pagine da restituire.",
+       "apihelp-query+pageswithprop-param-dir": "In quale direzione ordinare.",
+       "apihelp-query+prefixsearch-param-search": "Stringa di ricerca.",
+       "apihelp-query+prefixsearch-param-limit": "Numero massimo di risultati da restituire.",
+       "apihelp-query+prefixsearch-param-offset": "Numero di risultati da saltare",
+       "apihelp-query+protectedtitles-description": "Elenca tutti i titoli protetti dalla creazione.",
+       "apihelp-query+protectedtitles-param-namespace": "Elenca solo i titoli in questi namespace.",
+       "apihelp-query+protectedtitles-param-level": "Elenca solo i titoli con questi livelli di protezione.",
+       "apihelp-query+protectedtitles-param-limit": "Quante pagine totali restituire.",
        "apihelp-query+protectedtitles-param-prop": "Quali proprietà ottenere:",
+       "apihelp-query+protectedtitles-paramvalue-prop-user": "Aggiunge l'utente che ha aggiunto la protezione.",
        "apihelp-query+protectedtitles-paramvalue-prop-userid": "Aggiunge l'ID utente che ha aggiunto la protezione.",
+       "apihelp-query+protectedtitles-paramvalue-prop-comment": "Aggiunge il commento per la protezione.",
        "apihelp-query+protectedtitles-paramvalue-prop-level": "Aggiunge il livello di protezione.",
        "apihelp-query+protectedtitles-example-generator": "Trova collegamenti a titoli protetti nel namespace principale.",
+       "apihelp-query+querypage-param-limit": "Numero di risultati da restituire.",
+       "apihelp-query+querypage-example-ancientpages": "Restituisce risultati da [[Special:Ancientpages|Speciale:PagineMenoRecenti]].",
+       "apihelp-query+random-param-namespace": "Restituisci le pagine solo in questi namespace.",
+       "apihelp-query+random-param-redirect": "Usa <kbd>$1filterredir=redirects</kbd> invece.",
+       "apihelp-query+random-example-simple": "Restituisce due pagine casuali dal namespace principale.",
+       "apihelp-query+recentchanges-description": "Elenca le modifiche recenti.",
+       "apihelp-query+recentchanges-param-start": "Il timestamp da cui iniziare l'elenco.",
+       "apihelp-query+recentchanges-param-end": "Il timestamp al quale interrompere l'elenco.",
        "apihelp-query+recentchanges-example-simple": "Elenco modifiche recenti.",
+       "apihelp-query+redirects-description": "Restituisce tutti i reindirizzamenti alla data indicata.",
        "apihelp-query+redirects-param-prop": "Quali proprietà ottenere:",
        "apihelp-query+redirects-paramvalue-prop-pageid": "ID pagina di ogni redirect.",
        "apihelp-query+redirects-paramvalue-prop-title": "Titolo di ogni redirect.",
        "apihelp-query+redirects-param-namespace": "Includi solo le pagine in questi namespace.",
+       "apihelp-query+redirects-param-limit": "Quanti reindirizzamenti restituire.",
        "apihelp-query+redirects-example-simple": "Ottieni un elenco di redirect a [[Main Page]].",
+       "apihelp-query+revisions-param-startid": "L'ID versione da cui iniziare l'elenco.",
+       "apihelp-query+revisions-param-start": "Il timestamp della versione da cui iniziare l'elenco.",
+       "apihelp-query+revisions-param-tag": "Elenca solo le versioni etichettate con questa etichetta.",
        "apihelp-query+revisions+base-paramvalue-prop-ids": "L'ID della versione.",
+       "apihelp-query+revisions+base-paramvalue-prop-timestamp": "Il timestamp della versione.",
        "apihelp-query+revisions+base-paramvalue-prop-content": "Testo della versione.",
        "apihelp-query+revisions+base-paramvalue-prop-tags": "Etichette della versione.",
+       "apihelp-query+search-param-what": "Quale tipo di ricerca effettuare.",
+       "apihelp-query+search-param-info": "Quali metadati restituire.",
+       "apihelp-query+search-param-prop": "Quali proprietà restituire.",
+       "apihelp-query+search-paramvalue-prop-size": "Aggiungi la dimensione della pagina in byte.",
+       "apihelp-query+search-paramvalue-prop-wordcount": "Aggiungi il conteggio delle parole nella pagina.",
+       "apihelp-query+search-paramvalue-prop-timestamp": "Aggiungi il timestamp di quando la pagina è stata modificata l'ultima volta.",
        "apihelp-query+search-paramvalue-prop-redirecttitle": "Aggiunge il titolo del redirect corrispondente.",
        "apihelp-query+search-paramvalue-prop-sectiontitle": "Aggiunge il titolo della sezione corrispondente.",
+       "apihelp-query+search-param-limit": "Quante pagine totali restituire.",
+       "apihelp-query+siteinfo-param-prop": "Quali informazioni ottenere:",
+       "apihelp-query+siteinfo-paramvalue-prop-libraries": "Restituisci librerie installate sul wiki.",
+       "apihelp-query+siteinfo-paramvalue-prop-extensions": "Restituisci estensioni installate sul wiki.",
        "apihelp-query+siteinfo-paramvalue-prop-restrictions": "Restituisce informazioni sui tipi di restrizione (protezione) disponibili.",
        "apihelp-query+tags-param-prop": "Quali proprietà ottenere:",
+       "apihelp-query+templates-param-limit": "Quanti template restituire.",
        "apihelp-query+templates-param-dir": "La direzione in cui elencare.",
+       "apihelp-query+tokens-param-type": "Tipi di token da richiedere.",
        "apihelp-query+tokens-example-simple": "Recupera un token csrf (il predefinito).",
        "apihelp-query+transcludedin-description": "Trova tutte le pagine che incorporano quella specificata.",
        "apihelp-query+transcludedin-param-prop": "Quali proprietà ottenere:",
        "apihelp-query+transcludedin-param-namespace": "Includi solo le pagine in questi namespace.",
        "apihelp-query+transcludedin-param-show": "Mostra solo gli elementi che soddisfano questi criteri:\n;redirect:mostra solo i redirect.\n;!redirect:mostra solo i non redirect.",
        "apihelp-query+transcludedin-example-simple": "Ottieni un elenco di pagine che includono <kbd>Main Page</kbd>.",
+       "apihelp-query+usercontribs-param-namespace": "Elenca solo i contributi in questi namespace.",
        "apihelp-query+usercontribs-paramvalue-prop-title": "Aggiunge il titolo e l'ID namespace della pagina.",
+       "apihelp-query+usercontribs-paramvalue-prop-patrolled": "Etichetta modifiche verificate",
        "apihelp-query+userinfo-description": "Ottieni informazioni sull'utente attuale.",
        "apihelp-query+userinfo-paramvalue-prop-blockinfo": "Etichetta se l'utente attuale è bloccato, da chi e per quale motivo.",
        "apihelp-query+userinfo-paramvalue-prop-hasmsg": "Aggiunge un'etichetta <samp>messages</samp> se l'utente attuale ha messaggi in attesa.",
        "apihelp-query+userinfo-paramvalue-prop-implicitgroups": "Elenca tutti i gruppi di cui l'utente attuale è automaticamente membro.",
        "apihelp-query+userinfo-paramvalue-prop-changeablegroups": "Elenca tutti i gruppi di cui l'utente attuale può essere aggiunto o rimosso.",
+       "apihelp-query+userinfo-paramvalue-prop-realname": "Aggiungi il nome reale dell'utente.",
+       "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Aggiungi la data di registrazione dell'utente.",
        "apihelp-query+userinfo-example-simple": "Ottieni informazioni sull'utente attuale.",
        "apihelp-query+users-description": "Ottieni informazioni su un elenco di utenti.",
+       "apihelp-query+users-param-prop": "Quali pezzi di informazioni includere:",
        "apihelp-query+users-param-users": "Un elenco di utenti di cui ottenere informazioni.",
        "apihelp-query+watchlist-description": "Ottieni le ultime modifiche alle pagine tra gli osservati speciali dell'utente attuale.",
+       "apihelp-query+watchlist-param-start": "Il timestamp da cui iniziare l'elenco.",
+       "apihelp-query+watchlist-param-end": "Il timestamp al quale interrompere l'elenco.",
+       "apihelp-query+watchlist-param-prop": "Quali proprietà aggiuntive ottenere:",
+       "apihelp-query+watchlist-paramvalue-prop-ids": "Aggiunge l'ID versione e l'ID pagina.",
+       "apihelp-query+watchlist-paramvalue-prop-title": "Aggiungi il titolo della pagina.",
+       "apihelp-query+watchlistraw-param-namespace": "Elenca solo le pagine nei namespace indicati.",
+       "apihelp-query+watchlistraw-param-fromtitle": "Il titolo (con prefisso namespace) da cui iniziare l'elenco.",
+       "apihelp-query+watchlistraw-param-totitle": "Il titolo (con prefisso namespace) al quale interrompere l'elenco.",
        "apihelp-query+watchlistraw-example-simple": "Elenca le pagine fra gli osservati speciali dell'utente attuale.",
        "apihelp-query+watchlistraw-example-generator": "Recupera le informazioni sulle pagine fra gli osservati speciali dell'utente attuale.",
+       "apihelp-stashedit-param-sectiontitle": "Il titolo per una nuova sezione.",
+       "apihelp-stashedit-param-text": "Contenuto della pagina.",
+       "apihelp-stashedit-param-contentmodel": "Modello di contenuto dei nuovi contenuti.",
        "apihelp-tokens-param-type": "Tipi di token da richiedere.",
        "apihelp-tokens-example-edit": "Recupera un token di modifica (il predefinito).",
        "apihelp-unblock-description": "Sblocca un utente",
        "apihelp-unblock-param-tags": "Modifica etichette da applicare all'elemento del registro dei blocchi.",
        "apihelp-undelete-param-title": "Titolo della pagina da ripristinare.",
        "apihelp-undelete-param-tags": "Modifica etichette da applicare all'elemento del registro delle cancellazioni.",
+       "apihelp-upload-param-file": "Contenuto del file.",
        "apihelp-upload-example-url": "Carica da un URL.",
        "apihelp-userrights-param-user": "Nome utente.",
        "apihelp-userrights-param-userid": "ID utente.",
+       "apihelp-userrights-param-add": "Aggiungi l'utente a questi gruppi.",
+       "apihelp-userrights-param-remove": "Rimuovi l'utente da questi gruppi.",
+       "apihelp-userrights-param-reason": "Motivo del cambiamento.",
        "apihelp-watch-description": "Aggiunge o rimuove pagine dagli osservati speciali dell'utente attuale.",
        "apihelp-format-param-wrappedhtml": "Restituisce l'HTML ben formattato e i moduli ResourceLoader associati come un oggetto JSON.",
        "api-pageset-param-titles": "Un elenco di titoli su cui lavorare.",
        "api-pageset-param-pageids": "Un elenco di ID pagina su cui lavorare.",
        "api-pageset-param-revids": "Un elenco di ID versioni su cui lavorare.",
        "api-pageset-param-redirects-generator": "Risolvi automaticamente redirect in <var>$1titles</var>, <var>$1pageids</var>, e <var>$1revids</var>, e nelle pagine restituite da <var>$1generator</var>.",
+       "api-pageset-param-redirects-nogenerator": "Risolve automaticamente i reindirizzamenti in <var>$1titles</var>, <var>$1pageids</var>, e <var>$1revids</var>.",
        "api-pageset-param-converttitles": "Converte i titoli in altre varianti, se necessario. Funziona solo se la lingua del contenuto del wiki supporta la conversione in varianti. Le lingue che supportano la conversione in varianti includono $1",
        "api-help-main-header": "Modulo principale",
+       "api-help-flag-deprecated": "Questo modulo è deprecato.",
+       "api-help-flag-internal": "<strong>Questo modulo è interno o instabile.</strong> Il suo funzionamento potrebbe variare senza preavviso.",
+       "api-help-flag-readrights": "Questo modulo richiede i diritti di lettura.",
+       "api-help-flag-writerights": "Questo modulo richiede i diritti di scrittura.",
+       "api-help-flag-mustbeposted": "Questo modulo accetta solo richieste POST.",
+       "api-help-flag-generator": "Questo modulo può essere utilizzato come generatore.",
+       "api-help-source": "Fonte: $1",
+       "api-help-source-unknown": "Fonte: <span class=\"apihelp-unknown\">sconosciuta</span>",
        "api-help-license": "Licenza: [[$1|$2]]",
+       "api-help-license-noname": "Licenza: [[$1|Vedi collegamento]]",
        "api-help-license-unknown": "Licenza: <span class=\"apihelp-unknown\">sconosciuta</span>",
        "api-help-parameters": "{{PLURAL:$1|Parametro|Parametri}}:",
        "api-help-param-deprecated": "Deprecato.",
        "api-help-param-required": "Questo parametro è obbligatorio.",
+       "api-help-datatypes-header": "Tipi di dato",
+       "api-help-param-type-limit": "Tipo: intero o <kbd>max</kbd>",
+       "api-help-param-type-integer": "Tipo: {{PLURAL:$1|1=intero|2=elenco di interi}}",
+       "api-help-param-type-boolean": "Tipo: booleano ([[Special:ApiHelp/main#main/datatypes|dettagli]])",
+       "api-help-param-type-timestamp": "Tipo: {{PLURAL:$1|1=timestamp|2=elenco di timestamp}} ([[Special:ApiHelp/main#main/datatypes|formati consentiti]])",
        "api-help-param-type-user": "Tipo: {{PLURAL:$1|1=nome utente|2=elenco di nomi utente}}",
        "api-help-param-list": "{{PLURAL:$1|1=Uno dei seguenti valori|2=Valori (separati da <kbd>{{!}}</kbd>)}}: $2",
+       "api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Deve essere vuoto|Può essere vuoto, o $2}}",
+       "api-help-param-limit": "Non più di $1 consentito.",
+       "api-help-param-limit2": "Non più di $1 ($2 per bot) consentito.",
+       "api-help-param-integer-min": "{{PLURAL:$1|1=Il valore non deve essere inferiore|2=I valori non devono essere inferiori}} a $2.",
+       "api-help-param-integer-max": "{{PLURAL:$1|1=Il valore non deve essere superiore|2=I valori non devono essere superiori}} a $3.",
+       "api-help-param-integer-minmax": "{{PLURAL:$1|1=Il valore deve essere compreso|2=I valori devono essere compresi}} tra $2 e $3.",
+       "api-help-param-multi-separate": "Separa i valori con <kbd>|</kbd>.",
        "api-help-param-multi-max": "Il numero massimo di valori è {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} per i bot).",
        "api-help-param-default": "Predefinito: $1",
        "api-help-param-default-empty": "Predefinito: <span class=\"apihelp-empty\">(vuoto)</span>",
index 979f023..d03bc63 100644 (file)
        "apihelp-feedrecentchanges-example-30days": "最近30日間の変更を表示する。",
        "apihelp-feedwatchlist-description": "ウォッチリストのフィードを返します。",
        "apihelp-feedwatchlist-param-feedformat": "フィードの形式。",
+       "apihelp-feedwatchlist-param-linktosections": "可能であれば、変更された節に直接リンクする。",
        "apihelp-feedwatchlist-example-default": "ウォッチリストのフィードを表示する。",
        "apihelp-feedwatchlist-example-all6hrs": "ウォッチ中のページに対する過去6時間の更新をすべて表示する。",
        "apihelp-filerevert-description": "ファイルを古い版に差し戻します。",
        "apihelp-import-param-namespace": "この名前空間に取り込む。<var>$1rootpage</var>パラメータとは同時に使用できません。",
        "apihelp-import-param-rootpage": "このページの下位ページとして取り込む。<var>$1namespace</var> パラメータとは同時に使用できません。",
        "apihelp-import-example-import": "[[meta:Help:ParserFunctions]] をすべての履歴とともに名前空間100に取り込む。",
+       "apihelp-login-description": "ログインして認証クッキーを取得します。\n\nログインが成功した場合、必要なクッキーは HTTP 応答ヘッダに含まれます。ログインに失敗した場合、自動化のパスワード推定攻撃を制限するために、追加の試行は速度制限されることがあります。",
        "apihelp-login-param-name": "利用者名。",
        "apihelp-login-param-password": "パスワード。",
        "apihelp-login-param-domain": "ドメイン (省略可能)",
        "apihelp-managetags-example-activate": "<kbd>spam</kbd> という名前のタグを <kbd>For use in edit patrolling</kbd> という理由で有効化する",
        "apihelp-managetags-example-deactivate": "<kbd>No longer required</kbd> という理由でタグ <kbd>spam</kbd> を無効化する",
        "apihelp-mergehistory-description": "ページの履歴を統合する。",
+       "apihelp-mergehistory-param-from": "履歴統合元のページ名。<var>$1fromid</var> とは同時に使用できません。",
+       "apihelp-mergehistory-param-fromid": "履歴統合元のページ。<var>$1from</var> とは同時に使用できません。",
+       "apihelp-mergehistory-param-to": "履歴統合先のページ名。<var>$1toid</var> とは同時に使用できません。",
+       "apihelp-mergehistory-param-toid": "履歴統合先のページID。<var>$1to</var> とは同時に使用できません。",
        "apihelp-mergehistory-param-reason": "履歴の統合の理由。",
        "apihelp-mergehistory-example-merge": "<kbd>Oldpage</kbd> のすべての履歴を <kbd>Newpage</kbd> に統合する。",
        "apihelp-move-description": "ページを移動します。",
        "apihelp-opensearch-param-format": "出力する形式。",
        "apihelp-opensearch-example-te": "<kbd>Te</kbd> から始まるページを検索する。",
        "apihelp-options-param-reset": "個人設定をサイトの既定値にリセットする。",
+       "apihelp-options-param-resetkinds": "<var>$1reset</var> が設定されている場合、リセットする設定項目の種類のリスト。",
+       "apihelp-options-param-change": "名前=値 の形式 (例えば skin=vector) で整形された変更のリスト。値はパイプ文字を含むことができません。optionname|otheroption|... のように値が与えられない (イコール記号すら無い) 場合、設定は既定値にリセットされます。",
        "apihelp-options-example-reset": "すべて初期設定に戻す。",
        "apihelp-options-example-change": "<kbd>skin</kbd> および <kbd>hideminor</kbd> の個人設定を変更する。",
        "apihelp-options-example-complex": "すべての個人設定を初期化し、<kbd>skin</kbd> および <kbd> nickname </kbd> を設定する。",
        "apihelp-paraminfo-param-helpformat": "ヘルプ文字列の形式。",
        "apihelp-paraminfo-param-querymodules": "クエリモジュール名のリスト (<var>prop</var>, <var>meta</var> or <var>list</var> パラメータの値)。<kbd>$1querymodules=foo</kbd> の代わりに <kbd>$1modules=query+foo</kbd> を使用してください。",
        "apihelp-paraminfo-example-1": "<kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>, <kbd>[[Special:ApiHelp/jsonfm|format=jsonfm]]</kbd>, <kbd>[[Special:ApiHelp/query+allpages|action=query&list=allpages]]</kbd>, and <kbd>[[Special:ApiHelp/query+siteinfo|action=query&meta=siteinfo]]</kbd> に関する情報を表示する。",
+       "apihelp-parse-param-title": "文字列が属するページのページ名。これを省略する場合、必ず <var>$1contentmodel</var> を指定しなければなりません。また、その場合 [[API]] がページ名として使用されます。",
+       "apihelp-parse-param-text": "構文解析する文字列。コンテンツ・モデルを制御するためには<var>$1title</var> または <var>$1contentmodel</var> を使用してください。",
        "apihelp-parse-param-summary": "構文解析のための要約",
        "apihelp-parse-param-page": "このページの内容を構文解析します。<var>$1text</var> および <var>$1title</var> とは同時に使用できません。",
+       "apihelp-parse-param-pageid": "このページの内容を構文解析する。<var>$1page</var> をオーバーライドします。",
        "apihelp-parse-param-redirects": "もし <var>$1page</var> や <var>$1pageid</var> に転送ページが指定された場合、それを解決する。",
+       "apihelp-parse-param-oldid": "この版の内容を構文解析する。<var>$1page</var> および <var>$1pageid</var> をオーバーライドします。",
        "apihelp-parse-param-prop": "どの情報を取得するか:",
        "apihelp-parse-paramvalue-prop-text": "ウィキテキストの解析されたテキストを提供します。",
        "apihelp-parse-paramvalue-prop-langlinks": "解析されたウィキテキストにおける言語リンクを提供します。",
        "apihelp-query+alldeletedrevisions-param-user": "この利用者による版のみを一覧表示する。",
        "apihelp-query+alldeletedrevisions-param-excludeuser": "この利用者による版を一覧表示しない。",
        "apihelp-query+alldeletedrevisions-param-namespace": "この名前空間に含まれるページのみを一覧表示します。",
+       "apihelp-query+alldeletedrevisions-param-miser-user-namespace": "<strong>注意:</strong> [[mw:Manual:$wgMiserMode|miser mode]] により、<var>$1user</var> と <var>$1namespace</var> を同時に使用すると継続する前に <var>$1limit</var> より返される結果が少なくなることがあります; 極端な場合では、ゼロ件の結果が返ることもあります。",
        "apihelp-query+alldeletedrevisions-param-generatetitles": "ジェネレーターとして使用する場合、版IDではなくページ名を生成します。",
        "apihelp-query+alldeletedrevisions-example-user": "利用者 <kbd>Example</kbd> による削除された直近の50版を一覧表示する。",
        "apihelp-query+alldeletedrevisions-example-ns-main": "標準名前空間にある削除された最初の50版を一覧表示する。",
        "apihelp-query+allfileusages-param-limit": "返す項目の総数。",
        "apihelp-query+allfileusages-param-dir": "一覧表示する方向。",
        "apihelp-query+allfileusages-example-unique": "ユニークなファイルを一覧表示する。",
+       "apihelp-query+allfileusages-example-unique-generator": "ファイル名を、存在しないものに印をつけて、すべて取得する。",
        "apihelp-query+allfileusages-example-generator": "ファイルを含むページを取得します。",
        "apihelp-query+allimages-description": "順次すべての画像を列挙します。",
        "apihelp-query+allimages-param-sort": "並べ替えに使用するプロパティ。",
        "apihelp-query+allimages-param-maxsize": "画像の最大バイト数を制限する。",
        "apihelp-query+allimages-param-sha1": "画像の SHA1 ハッシュ値。$1sha1base36 をオーバーライドします。",
        "apihelp-query+allimages-param-user": "この利用者によりアップロードされたファイルのみを返す。$1sort=timestamp を指定した場合のみ使用できます。 $1filterbots とは同時に使用できません。",
+       "apihelp-query+allimages-param-filterbots": "ボットによりアップロードされたファイルを絞り込む方法。$1sort=timestamp を指定した場合のみ使用できます。$1user とは同時に使用できません。",
        "apihelp-query+allimages-param-mime": "検索対象のMIMEタイプ、たとえば <kbd>image/jpeg</kbd>。",
        "apihelp-query+allimages-param-limit": "返す画像の総数。",
        "apihelp-query+allimages-example-B": "<kbd>B</kbd> で始まるファイルの一覧を表示する。",
        "apihelp-query+alllinks-param-dir": "一覧表示する方向。",
        "apihelp-query+alllinks-example-B": "<kbd>B</kbd> で始まるリンクされたページ (存在しないページも含む)を、リンク元のページIDとともに表示する。",
        "apihelp-query+alllinks-example-unique": "ユニークなリンクのタイトルを一覧。",
+       "apihelp-query+alllinks-example-unique-generator": "リンクされているページを、存在しないものに印をつけて、すべて取得する。",
        "apihelp-query+alllinks-example-generator": "リンクを含むページを取得します。",
        "apihelp-query+allmessages-param-messages": "出力のためのメッセージ。 <kbd>*</kbd>(デフォルト)は、すべてのメッセージを意味します。",
        "apihelp-query+allmessages-param-prop": "取得するプロパティ:",
        "apihelp-query+mystashedfiles-paramvalue-prop-size": "ファイルサイズと画像の大きさを取得します。",
        "apihelp-query+mystashedfiles-paramvalue-prop-type": "ファイルの MIME タイプとメディアタイプを取得します。",
        "apihelp-query+mystashedfiles-param-limit": "取得するファイルの数。",
-       "apihelp-query+alltransclusions-param-prefix": "この値で始まるすべてのトランスクルードされているページを検索する。",
+       "apihelp-query+alltransclusions-description": "存在しないものも含めて、すべての参照読み込み (&#123;&#123;x&#125;&#125; で埋め込まれたページ) を一覧表示します。",
+       "apihelp-query+alltransclusions-param-from": "列挙を開始する参照読み込みのページ名。",
+       "apihelp-query+alltransclusions-param-to": "列挙を終了する参照読み込みのページ名。",
+       "apihelp-query+alltransclusions-param-prefix": "この値で始まるすべての参照読み込みされているページを検索する。",
        "apihelp-query+alltransclusions-param-prop": "どの情報を結果に含めるか:",
-       "apihelp-query+alltransclusions-param-namespace": "列挙する前空間。",
+       "apihelp-query+alltransclusions-paramvalue-prop-ids": "参照元のページIDを追加します ($1unique とは同時に使用できません)。",
+       "apihelp-query+alltransclusions-paramvalue-prop-title": "参照読み込みのページ名を追加します。",
+       "apihelp-query+alltransclusions-param-namespace": "列挙する名前空間。",
        "apihelp-query+alltransclusions-param-limit": "返す項目の総数。",
        "apihelp-query+alltransclusions-param-dir": "一覧表示する方向。",
-       "apihelp-query+alltransclusions-example-B": "<kbd>B</kbd> で始まる参照読み込みされているページ (存在しないページも含む)を、参照元のページIDとともに表示する。",
+       "apihelp-query+alltransclusions-example-B": "参照読み込みされているページ (存在しないページも含む) を、参照元のページIDとともに、<kbd>B</kbd> で始まるものから一覧表示する。",
+       "apihelp-query+alltransclusions-example-unique-generator": "参照読み込みされたページを、存在しないものに印をつけて、すべて取得する。",
        "apihelp-query+alltransclusions-example-generator": "参照読み込みを含んでいるページを取得する。",
        "apihelp-query+allusers-description": "すべての登録利用者を一覧表示します。",
        "apihelp-query+allusers-param-from": "列挙を開始する利用者名。",
        "apihelp-query+exturlusage-paramvalue-prop-title": "ページ名と名前空間IDを追加します。",
        "apihelp-query+exturlusage-paramvalue-prop-url": "ページ内で使用されているURLを追加します。",
        "apihelp-query+exturlusage-param-protocol": "URLのプロトコル。このパラメータが空であり、かつ<var>$1query</var> が設定されている場合, protocol は <kbd>http</kbd> となります。すべての外部リンクを一覧表示するためにはこのパラメータと <var>$1query</var> の両方を空にしてください。",
+       "apihelp-query+exturlusage-param-query": "プロトコルを除いた検索文字列。[[Special:LinkSearch]] も参照してください。すべての外部リンクを一覧表示するには空欄にしてください。",
        "apihelp-query+exturlusage-param-namespace": "列挙するページ名前空間。",
        "apihelp-query+exturlusage-example-simple": "<kbd>http://www.mediawiki.org</kbd> にリンクしているページを一覧表示する。",
        "apihelp-query+filearchive-description": "削除されたファイルをすべて順に列挙します。",
        "apihelp-query+pageprops-description": "ページコンテンツで定義されている様々なページのプロパティを取得。",
        "apihelp-query+pageprops-example-simple": "ページ <kbd>Main Page</kbd> および <kbd>MeiaWiki</kbd> のプロパティを取得する。",
        "apihelp-query+pageswithprop-description": "与えられたページプロパティが使用されているすべてのページを一覧表示します。",
+       "apihelp-query+pageswithprop-param-prop": "どの情報を結果に含めるか:",
        "apihelp-query+pageswithprop-paramvalue-prop-ids": "ページIDを追加します。",
        "apihelp-query+pageswithprop-paramvalue-prop-title": "ページ名と名前空間IDを追加します。",
        "apihelp-query+pageswithprop-paramvalue-prop-value": "ページプロパティの値を追加。",
        "apihelp-query+usercontribs-param-tag": "このタグが付与された版のみを一覧表示する。",
        "apihelp-query+usercontribs-param-toponly": "最新の版である変更のみを一覧表示する。",
        "apihelp-query+usercontribs-example-user": "利用者 <kbd>Example</kbd> の投稿記録を表示する。",
+       "apihelp-query+userinfo-param-prop": "どの情報を結果に含めるか:",
        "apihelp-query+userinfo-paramvalue-prop-realname": "利用者の本名を追加します。",
        "apihelp-query+userinfo-example-simple": "現在の利用者に関する情報を取得します。",
        "apihelp-query+userinfo-example-data": "現在の利用者に関する追加情報を取得します。",
        "apihelp-revisiondelete-example-revision": "<kbd>Main Page</kbd> の版 <kbd>12345</kbd> の本文を隠す。",
        "apihelp-rollback-param-title": "巻き戻すページ名です。<var>$1pageid</var> とは同時に使用できません。",
        "apihelp-rollback-param-pageid": "巻き戻すページのページIDです。<var>$1title</var> とは同時に使用できません。",
+       "apihelp-rollback-param-tags": "巻き戻しに適用するタグ。",
        "apihelp-rollback-param-user": "巻き戻し対象の編集を行った利用者名。",
        "apihelp-rollback-param-markbot": "巻き戻された編集と巻き戻しをボットの編集としてマークする。",
        "apihelp-rollback-example-simple": "利用者 <kbd>Example</kbd> による <kbd>Main Page</kbd> への最後の一連の編集を巻き戻す。",
        "apihelp-rollback-example-summary": "IP利用者 <kbd>192.0.2.5</kbd> による <kbd>Main Page</kbd> への最後の一連の編集を <kbd>Reverting vandalism</kbd> という理由で、それらの編集とその差し戻しをボットの編集としてマークして差し戻す。",
        "apihelp-stashedit-param-title": "編集されているページのページ名。",
+       "apihelp-stashedit-param-text": "ページの本文。",
+       "apihelp-stashedit-param-contentmodel": "新しいコンテンツのコンテンツ・モデル。",
+       "apihelp-tag-description": "個々の版または記録項目に対しタグの追加または削除を行います。",
+       "apihelp-tag-param-add": "追加するタグ。手動で定義されたタグのみ追加可能です。",
        "apihelp-tag-param-reason": "変更の理由。",
+       "apihelp-tag-example-rev": "版ID 123に <kbd>vandalism</kbd> タグを理由を指定せずに追加する",
        "apihelp-tag-example-log": "<kbd>Wrongly applied</kbd> という理由で <kbd>spam</kbd> タグを 記録項目ID 123 から取り除く",
        "apihelp-tokens-param-type": "リクエストするトークンの種類。",
        "apihelp-tokens-example-edit": "編集トークンを取得する (既定)。",
        "api-help-param-default": "既定値: $1",
        "api-help-param-default-empty": "既定値: <span class=\"apihelp-empty\">(空)</span>",
        "api-help-param-token": "[[Special:ApiHelp/query+tokens|action=query&meta=tokens]] から取得した「$1」トークン",
+       "api-help-param-token-webui": "互換性のために、ウェブUIで使用されるトークンも受理されます。",
+       "api-help-param-limited-in-miser-mode": "<strong>注意:</strong> [[mw:Manual:$wgMiserMode|miser mode]] により、これを使用すると継続する前に <var>$1limit</var> より返される結果が少なくなることがあります; 極端な場合では、ゼロ件の結果が返ることもあります。",
        "api-help-param-direction": "列挙の方向:\n;newer:古いものを先に表示します。注意: $1start は $1end 以前でなければなりません。\n;older:新しいものを先に表示します (既定)。注意: $1start は $1end 以降でなければなりません。",
        "api-help-param-no-description": "<span class=\"apihelp-empty\">(説明なし)</span>",
        "api-help-examples": "{{PLURAL:$1|例}}:",
index 8e2a8b5..156cf25 100644 (file)
@@ -7,5 +7,30 @@
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [https://www.mediawiki.org/wiki/API:Main_page Torohevitra be kokoa]\n* [https://www.mediawiki.org/wiki/API:FAQ Fanontaniana miverina matetika]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Lisitry ny mailaka manaraka]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Filazana API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Baogy & hataka]\n</div>\n<strong>Status:</strong> \nTokony mandeha avokoa ny fitaovana aseho eto amin'ity pehy ity, na dia izany aza mbola am-panamboarana ny API ary mety hiova na oviana na oviana. Araho amin'ny alalan'ny fisoratana ny mailakao ao amin'ny [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ the mediawiki-api-announce lisitra fampielezana] ny fiovana.\n\n<strong>Hataka diso:</strong> \nRehefa alefa ao amin'i API ny hata, ho alefa miaraka amin'ny lakile \"MediaWiki-API-Error\" ny header HTTP ary samy homen-tsanda mitovy ny header ary ny kaodin-kadisoana. Ho an'ny torohay fanampiny dia jereo https://www.mediawiki.org/wiki/API:Errors_and_warnings.",
        "apihelp-main-param-action": "Inona ny zavatra ho atao.",
        "apihelp-main-param-format": "Format mivoaka",
-       "apihelp-createaccount-param-name": "Anaram-pikambana."
+       "apihelp-block-param-user": "Anaram-pikambana, adiresy IP na valan' IP hosakanana.",
+       "apihelp-block-param-expiry": "Fitaom-pisasarana. Mety miovaova(e.g. <kbd>5 volana</kbd> na <kbd>herinandro 2</kbd>) na voafaritra (e.g. <kbd>2014-09-18T12:34:56Z</kbd>). Raha atao <kbd>tsiefa</kbd>, <kbd>tsy fantatra</kbd>, na <kbd>mandrakizay</kbd>, dia tsy hitsahatra mihitsy ilay sakana.",
+       "apihelp-block-param-reason": "Antom-panakanana",
+       "apihelp-block-param-anononly": "Mpikambana tsy nisoratra anarana ihany no sakanana (izany hoe aza mamela fiovan'olona tsy nisoratra anarana avy amin'ity adiresy IP ity).",
+       "apihelp-block-param-nocreate": "Hanakana famoronan-kaonty.",
+       "apihelp-block-param-autoblock": "Manakana ny adiresy IP farany nampiasaina, ary izay adiresy IP mety hidirany.",
+       "apihelp-block-param-noemail": "Hanakana ny mpikambana tsy handefa mailaka amin'ny alalan'ny wiki (Mila ny zo <code>blockemail</code>).",
+       "apihelp-block-param-hidename": "Hanafina ny anaram-pikambana amin'ny laogim-panakanana (mila ny zo <code>hideuser</code>).",
+       "apihelp-block-param-allowusertalk": "Hamela ny mpikambana hanova ny pejin-dresany (miankina amin'ny <var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>)",
+       "apihelp-block-param-reblock": "Raha efa nosakanana ilay mpikambana, itsahina ilay sakana efa misy.",
+       "apihelp-block-param-watchuser": "Hijery ny adiresy IP ary ny pejin-dresak'ilay mpikambana.",
+       "apihelp-block-example-ip-simple": "Hanakana ny adiresy IP <kbd>192.0.2.5</kbd> mandritry ny telo andro miaraka amin'ny antony <kbd>Filazana voalohany</kbd>.",
+       "apihelp-compare-param-fromtitle": "Lohateny voalohany ampitahaina.",
+       "apihelp-compare-param-fromid": "ID pejy voalohany ampitahaina.",
+       "apihelp-compare-param-fromrev": "Versions voalohany ampitahaina.",
+       "apihelp-compare-param-totitle": "Lohateny faharoa ampitahaina.",
+       "apihelp-compare-param-toid": "ID pejy faharoa ampitahaina.",
+       "apihelp-compare-param-torev": "Versiona faharoa ampitahaina.",
+       "apihelp-compare-example-1": "Hamorona raki-pahasamihafan'ny versiona 1 sy 2.",
+       "apihelp-createaccount-description": "Hamorona kaontim-pikambana vaovao.",
+       "apihelp-createaccount-param-name": "Anaram-pikambana.",
+       "apihelp-createaccount-param-password": "Tenimiafina (tsy raharahiana raha voafaritra i <var>$1mailpassword</var>).",
+       "apihelp-createaccount-param-domain": "Vala ho an'ilay famantarana avy any ivelany (azo tsy fenoina).",
+       "apihelp-createaccount-param-token": "Famantarana famoronan-kaonty azo tamin'ny hataka voalohany.",
+       "apihelp-createaccount-param-email": "Adiresy imailaky ny mpikambana (azo tsy fenoina).",
+       "apihelp-createaccount-param-realname": "Tena anaran'ilay mpikambana (azo tsy fenoina)."
 }
index fcdbb25..7bdb85a 100644 (file)
@@ -11,7 +11,8 @@
                        "Peter Bowman",
                        "Darellur",
                        "The Polish",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Sethakill"
                ]
        },
        "apihelp-main-param-action": "Wybierz akcję do wykonania.",
@@ -25,6 +26,7 @@
        "apihelp-block-param-anononly": "Blokuj tylko anonimowych użytkowników (blokuje anonimowe edycje z tego adresu IP).",
        "apihelp-block-param-nocreate": "Zapobiegnij utworzeniu konta.",
        "apihelp-block-param-autoblock": "Zablokuj ostatni adres IP tego użytkownika i automatycznie wszystkie kolejne, z których będzie się logował.",
+       "apihelp-block-param-hidename": "Ukryj nazwę użytkownika z rejestru blokad. (Wymagane uprawnienia <code>hideuser</code>)",
        "apihelp-block-param-reblock": "Jeżeli ten użytkownik jest już zablokowany, nadpisz blokadę.",
        "apihelp-block-param-watchuser": "Obserwuj stronę użytkownika i jego IP oraz ich strony dyskusji.",
        "apihelp-block-example-ip-simple": "Zablokuj IP <kbd>192.0.2.5</kbd> na 3 dni za <kbd>Pierwszy atak</kbd>.",
        "apihelp-logout-example-logout": "Wyloguj obecnego użytkownika.",
        "apihelp-managetags-param-reason": "Opcjonalny powód utworzenia, usunięcia, włączenia lub wyłączenia znacznika.",
        "apihelp-managetags-param-ignorewarnings": "Czy zignorować ostrzeżenia, które pojawiają się w trakcie operacji.",
+       "apihelp-mergehistory-description": "Łączenie historii edycji.",
        "apihelp-move-description": "Przenieś stronę.",
        "apihelp-move-param-reason": "Powód zmiany nazwy.",
        "apihelp-move-param-movetalk": "Zmień nazwę strony dyskusji, jeśli istnieje.",
index 18dc60c..fd7dd77 100644 (file)
@@ -14,7 +14,8 @@
                        "Macofe",
                        "Краснорядцева Елена",
                        "Iniquity",
-                       "Лилиә"
+                       "Лилиә",
+                       "Айсар"
                ]
        },
        "apihelp-main-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:API:Main_page|Документация]]\n* [[mw:API:FAQ|ЧаВО]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Почтовая рассылка]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Новости API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Ошибки и запросы]\n</div>\n<strong>Статус:</strong> Все отображаемые на этой странице функции должны работать, однако API находится в статусе активной разработки и может измениться в любой момент. Подпишитесь на [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ почтовую рассылку mediawiki-api-announce], чтобы быть в курсе обновлений.\n\n<strong>Ошибочные запросы:</strong> Если API получает запрос с ошибкой, вернётся заголовок HTTP с ключом «MediaWiki-API-Error», после чего значение заголовка и код ошибки будут отправлены обратно и установлены в то же значение. Более подробную информацию см. [[mw:API:Errors_and_warnings|API: Ошибки и предупреждения]].\n\n<strong>Тестирование:</strong> для удобства тестирования API-запросов, см. [[Special:ApiSandbox]].",
@@ -33,7 +34,7 @@
        "apihelp-block-param-anononly": "Блокировать только анонимных пользователей (т. е. запретить анонимные правки для этого IP-адреса).",
        "apihelp-block-param-nocreate": "Запретить создание учётных записей.",
        "apihelp-block-param-autoblock": "Автоматически блокировать последний использованный IP-адрес и все последующие, с которых будут совершаться попытки авторизации.",
-       "apihelp-block-param-noemail": "Ҡулланыусының Вики аша электрон почта ебәреүен тыйыу. (Талап итә <code>blockemail</code> хоҡуғын)",
+       "apihelp-block-param-noemail": "Запретить участнику отправлять электронную почту через интерфейс вики. (Требуется право <code>blockemail</code>).",
        "apihelp-block-param-hidename": "Скрыть имя участника из журнала блокировок. (Требуется право <code>hideuser</code>).",
        "apihelp-block-param-allowusertalk": "Позволяет участникам редактировать их собственные страницы обсуждения (зависит от <var>[[mw:Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
        "apihelp-block-param-reblock": "Если участник уже заблокирован, перезаписать существующую блокировку.",
@@ -96,6 +97,7 @@
        "apihelp-expandtemplates-param-text": "Викитекст для конвертирования",
        "apihelp-expandtemplates-paramvalue-prop-wikitext": "Расширенный викитекст",
        "apihelp-expandtemplates-paramvalue-prop-parsetree": "Дерево разбора XML входных данных.",
+       "apihelp-feedcontributions-param-feedformat": "Биреү форматы",
        "apihelp-feedcontributions-param-year": "От года (и ранее).",
        "apihelp-feedcontributions-param-month": "От месяца (и ранее).",
        "apihelp-feedcontributions-param-deletedonly": "Показать только удалённые правки.",
        "apihelp-feedrecentchanges-param-showlinkedto": "Показать правки на страницах, ссылающихся на данную.",
        "apihelp-feedrecentchanges-example-simple": "Список последних изменений.",
        "apihelp-feedrecentchanges-example-30days": "Показать последние изменения в течение 30 дней.",
+       "apihelp-feedwatchlist-param-feedformat": "Биреү форматы.",
+       "apihelp-feedwatchlist-param-hours": "Был ваҡыттан алып үҙгәртелгән биттәр исемлеге",
        "apihelp-feedwatchlist-param-linktosections": "Ссылаться прямо на разделы с изменениями, если возможно.",
+       "apihelp-feedwatchlist-example-default": "Күҙәтеү каналын күрһәтергә",
+       "apihelp-feedwatchlist-example-all6hrs": "Күҙәтелгән биттәрҙә һуңғы 6 сәғәт эсендәге үҙгәрештәрҙе күрһәтергә.",
+       "apihelp-filerevert-description": "Файлды иҫке версияға ҡайтарырға.",
        "apihelp-filerevert-param-filename": "Целевое имя файла без префикса File:.",
        "apihelp-filerevert-param-comment": "Загрузить комментарий.",
+       "apihelp-help-param-helpformat": "Белешмә яҙыу форматы.",
        "apihelp-help-example-main": "Помощь по главному модулю.",
        "apihelp-help-example-recursive": "Вся справка в одном разделе.",
        "apihelp-imagerotate-description": "Поворот одного или нескольких изображений.",
        "apihelp-options-example-reset": "Сбросить все настройки.",
        "apihelp-paraminfo-description": "Получить информацию о модулях API.",
        "apihelp-paraminfo-param-helpformat": "Формат строк справки.",
+       "apihelp-parse-param-disablepp": "Урынына <var>$1disablelimitreport</var> ҡулланырға.",
+       "apihelp-parse-param-preview": "Алдан ҡарау режимында синтаксик анализ",
        "apihelp-parse-param-disabletoc": "Не включать в вывод таблицу содержания.",
        "apihelp-parse-example-page": "анализ страницы",
        "apihelp-parse-example-text": "Анализ wikitext.",
+       "apihelp-parse-example-summary": "Һығымтаны тикшереү.",
+       "apihelp-patrol-param-rcid": "Яңы үҙгәртеүҙәрҙе ҡарау идентификаторы.",
+       "apihelp-patrol-param-revid": "Ҡарау версияһы идентификаторы.",
+       "apihelp-patrol-example-rcid": "Һуңғы үҙгәрештәрҙе ҡарау.",
+       "apihelp-patrol-example-revid": "Яңынан ҡарау.",
        "apihelp-protect-description": "Изменить уровень защиты страницы.",
+       "apihelp-protect-param-title": "Бит атамаһы. $1pageid менән бергә ҡулланылмай.",
+       "apihelp-protect-param-reason": "(ООН) һағы сәбәптәре.",
        "apihelp-protect-example-protect": "Защитить страницу.",
+       "apihelp-protect-example-unprotect": "<kbd>всех</kbd> өсөн сикләүҙәр ҡуйып,биттән һаҡлауҙы алырға.",
+       "apihelp-protect-example-unprotect2": "Бер ниндәй сикләүҙәр ҡуймай биттән һаҡлауҙы алырға.",
        "apihelp-purge-param-forcelinkupdate": "Обновление связей таблиц.",
+       "apihelp-purge-param-forcerecursivelinkupdate": "Һылтанманы һәм таблицаны яңыртығыҙ һәм был битте шаблон итеп ҡулланған башҡа биттәр өсөн һылтанмаларҙы ла яңыртығыҙ.",
        "apihelp-query-param-list": "Какие списки использовать",
        "apihelp-query-param-meta": "Какие метаданные использовать",
        "apihelp-query+allcategories-description": "Перечислить все категории.",
+       "apihelp-query+allcategories-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+allcategories-param-dir": "Сортлау йүнәлештәре.",
        "apihelp-query+allcategories-param-limit": "Сколько категорий вернуть.",
        "apihelp-query+allcategories-param-prop": "Какие свойства получить:",
+       "apihelp-query+allcategories-paramvalue-prop-size": "Категорияларға биттәр һаны өҫтәү",
+       "apihelp-query+allcategories-example-size": "Биттәр һаны буйынса мәғлүмәтле категориялар исемлеге.",
+       "apihelp-query+allcategories-example-generator": "<kbd>исемлек</kbd> категориялар битенән мәғлүмәт алырға.",
+       "apihelp-query+alldeletedrevisions-description": "Бар мөхәррирләү исемлеге ҡулланыусы тарафынан юйылған.",
+       "apihelp-query+alldeletedrevisions-paraminfo-useronly": "<var>$3ҡулланыусының</var> менән генә ҡулланыла ала.",
+       "apihelp-query+alldeletedrevisions-param-start": "Һанауҙы башлау ваҡытын билдәләү",
+       "apihelp-query+alldeletedrevisions-param-end": "Һанай башлау ваҡытын билдәләү.",
+       "apihelp-query+alldeletedrevisions-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+alldeletedrevisions-param-user": "Бары тик был ҡулланыусының үҙгәртеүҙәр исемлеге.",
+       "apihelp-query+alldeletedrevisions-param-excludeuser": "Был ҡулланыусының үҙгәртеүҙәр исемлеге түгел.",
+       "apihelp-query+alldeletedrevisions-param-namespace": "Бары тик был исемдәр арауығындағы биттәр исемлеге.",
+       "apihelp-query+alldeletedrevisions-example-ns-main": "Төп исемдәр арауығында юйылған тәүге 50 үҙгәртеү исемлеге.",
+       "apihelp-query+allfileusages-description": "Юйылғандар менән бергә барлыҡ файлдар тәртибе исемлеге.",
+       "apihelp-query+allfileusages-param-from": "Һанауҙы башлау өсөн файл атамаһы.",
+       "apihelp-query+allfileusages-param-to": "Һанауҙы туҡтатыу файлы атамаһы.",
+       "apihelp-query+allfileusages-param-prefix": "Был мәғәнәнән башланған бар атамаларҙы категориялар буйынса эҙләргә.",
+       "apihelp-query+allfileusages-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
+       "apihelp-query+allfileusages-paramvalue-prop-title": "Файл атамаһына ҡуша.",
+       "apihelp-query+allfileusages-param-limit": "Нисә битте тергеҙергә?",
+       "apihelp-query+allfileusages-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+allfileusages-example-unique": "Атамаларҙың уҙенсәлекле файлдары исемлеге.",
+       "apihelp-query+allfileusages-example-unique-generator": "Төшөп ҡалғандарҙы айырып, барлыҡ исем-һылтанмаларҙы алырға.",
+       "apihelp-query+allfileusages-example-generator": "Файлдар менән биттәр бар.",
+       "apihelp-query+allimages-description": "Бер-бер артлы бөтә образдарҙы һанап сығырға.",
+       "apihelp-query+allimages-param-sort": "Сортировкалау үҙенсәлектәре.",
+       "apihelp-query+allimages-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+allimages-param-minsize": "Һүрәттәр лимиты (байттарҙа).",
+       "apihelp-query+allimages-param-maxsize": "Бар һүрәттәр лимиты (байттарҙа).",
+       "apihelp-query+allimages-param-limit": "Кире ҡайтыу өсөн образдар һаны.",
+       "apihelp-query+allimages-example-B": "<kbd>Б</kbd> хәрефенән башланған файлдар исемлеген күрһәтергә.",
+       "apihelp-query+allimages-example-recent": "Күптән түгел тейәлгән һәм [[специальные:NewFiles]] оҡшаш файлдар исемлеген күрһәтергә.",
+       "apihelp-query+allimages-example-generator": "<kbd>Т</kbd> хәрефенән башланған 4 файл хаҡында мәғлүмәтте  күрһәтергә.",
+       "apihelp-query+alllinks-description": "Бирелгән исемдәр арауығына йүнәлткән барлыҡ һылтанмаларҙы һанап сығырға.",
+       "apihelp-query+alllinks-param-from": "Һанауҙы башлау өсөн һылтанма атамаһы.",
+       "apihelp-query+alllinks-param-to": "Һанауҙы туҡтатыу һылтанмаһы атамаһы.",
+       "apihelp-query+alllinks-param-prefix": "Был мәғәнәнән башланған бәйләнешле бар атамаларҙы эҙләргә.",
+       "apihelp-query+alllinks-param-prop": "Ҡайһы мәғлүмәтте күрһәтергә:",
+       "apihelp-query+alllinks-paramvalue-prop-title": "Һылтанма атамаһын ҡуша.",
+       "apihelp-query+alllinks-param-namespace": "Һанау өсөн исемдәр арауығы.",
+       "apihelp-query+alllinks-param-limit": "Нисә элементты тергеҙергә?",
+       "apihelp-query+alllinks-param-dir": "Һанау йүнәлеше.",
+       "apihelp-query+alllinks-example-unique": "Атамаларҙың үҙенсәлекле исемдәре бәйләнгән.",
        "apihelp-query+alllinks-example-unique-generator": "Получить все названия-ссылки, выделяя пропущенные.",
+       "apihelp-query+alllinks-example-generator": "Һылтанмалы биттәр бар.",
+       "apihelp-query+allmessages-description": "Был сайттан хәбәр ҡайтарыу.",
+       "apihelp-query+allmessages-param-prop": "Ниндәй үҙенсәлектәрҙе ҡайтарырға.",
+       "apihelp-query+allmessages-param-args": "Аргументтар Хәбәрҙәрҙә биреләсәк.",
        "apihelp-query+blocks-example-simple": "Список блоков.",
        "apihelp-query+categories-param-limit": "Сколько категорий на возврат.",
        "apihelp-query+categorymembers-param-sort": "Свойство для сортировки.",
diff --git a/includes/cache/LCStoreStaticArray.php b/includes/cache/LCStoreStaticArray.php
deleted file mode 100644 (file)
index 1e20082..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-<?php
-/**
- *  Localisation cache storage based on PHP files and static arrays.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * @since 1.26
- */
-class LCStoreStaticArray implements LCStore {
-       /** @var string|null Current language code. */
-       private $currentLang = null;
-
-       /** @var array Localisation data. */
-       private $data = [];
-
-       /** @var string File name. */
-       private $fname = null;
-
-       /** @var string Directory for cache files. */
-       private $directory;
-
-       public function __construct( $conf = [] ) {
-               global $wgCacheDirectory;
-
-               if ( isset( $conf['directory'] ) ) {
-                       $this->directory = $conf['directory'];
-               } else {
-                       $this->directory = $wgCacheDirectory;
-               }
-       }
-
-       public function startWrite( $code ) {
-               $this->currentLang = $code;
-               $this->fname = $this->directory . '/' . $code . '.l10n.php';
-               $this->data[$code] = [];
-               if ( file_exists( $this->fname ) ) {
-                       $this->data[$code] = require $this->fname;
-               }
-       }
-
-       public function set( $key, $value ) {
-               $this->data[$this->currentLang][$key] = self::encode( $value );
-       }
-
-       /**
-        * Encodes a value into an array format
-        *
-        * @param mixed $value
-        * @return array
-        * @throws RuntimeException
-        */
-       public static function encode( $value ) {
-               if ( is_scalar( $value ) || $value === null ) {
-                       // [V]alue
-                       return [ 'v', $value ];
-               }
-               if ( is_object( $value ) ) {
-                       // [S]erialized
-                       return [ 's', serialize( $value ) ];
-               }
-               if ( is_array( $value ) ) {
-                       // [A]rray
-                       return [ 'a', array_map( function ( $v ) {
-                               return LCStoreStaticArray::encode( $v );
-                       }, $value ) ];
-               }
-
-               throw new RuntimeException( 'Cannot encode ' . var_export( $value, true ) );
-       }
-
-       /**
-        * Decode something that was encoded with encode
-        *
-        * @param array $encoded
-        * @return array|mixed
-        * @throws RuntimeException
-        */
-       public static function decode( array $encoded ) {
-               $type = $encoded[0];
-               $data = $encoded[1];
-
-               switch ( $type ) {
-               case 'v':
-                       return $data;
-               case 's':
-                       return unserialize( $data );
-               case 'a':
-                       return array_map( function ( $v ) {
-                               return LCStoreStaticArray::decode( $v );
-                       }, $data );
-               default:
-                       throw new RuntimeException(
-                               'Unable to decode ' . var_export( $encoded, true ) );
-               }
-       }
-
-       public function finishWrite() {
-               file_put_contents(
-                       $this->fname,
-                       "<?php\n" .
-                       "// Generated by LCStoreStaticArray.php -- do not edit!\n" .
-                       "return " .
-                       var_export( $this->data[$this->currentLang], true ) . ';'
-               );
-               $this->currentLang = null;
-               $this->fname = null;
-       }
-
-       public function get( $code, $key ) {
-               if ( !array_key_exists( $code, $this->data ) ) {
-                       $fname = $this->directory . '/' . $code . '.l10n.php';
-                       if ( !file_exists( $fname ) ) {
-                               return null;
-                       }
-                       $this->data[$code] = require $fname;
-               }
-               $data = $this->data[$code];
-               if ( array_key_exists( $key, $data ) ) {
-                       return self::decode( $data[$key] );
-               }
-               return null;
-       }
-}
diff --git a/includes/cache/LocalisationCache.php b/includes/cache/LocalisationCache.php
deleted file mode 100644 (file)
index 6efeabe..0000000
+++ /dev/null
@@ -1,1479 +0,0 @@
-<?php
-/**
- * Cache of the contents of localisation files.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-use Cdb\Exception as CdbException;
-use Cdb\Reader as CdbReader;
-use Cdb\Writer as CdbWriter;
-use CLDRPluralRuleParser\Evaluator;
-
-/**
- * Class for caching the contents of localisation files, Messages*.php
- * and *.i18n.php.
- *
- * An instance of this class is available using Language::getLocalisationCache().
- *
- * The values retrieved from here are merged, containing items from extension
- * files, core messages files and the language fallback sequence (e.g. zh-cn ->
- * zh-hans -> en ). Some common errors are corrected, for example namespace
- * names with spaces instead of underscores, but heavyweight processing, such
- * as grammatical transformation, is done by the caller.
- */
-class LocalisationCache {
-       const VERSION = 4;
-
-       /** Configuration associative array */
-       private $conf;
-
-       /**
-        * True if recaching should only be done on an explicit call to recache().
-        * Setting this reduces the overhead of cache freshness checking, which
-        * requires doing a stat() for every extension i18n file.
-        */
-       private $manualRecache = false;
-
-       /**
-        * True to treat all files as expired until they are regenerated by this object.
-        */
-       private $forceRecache = false;
-
-       /**
-        * The cache data. 3-d array, where the first key is the language code,
-        * the second key is the item key e.g. 'messages', and the third key is
-        * an item specific subkey index. Some items are not arrays and so for those
-        * items, there are no subkeys.
-        */
-       protected $data = [];
-
-       /**
-        * The persistent store object. An instance of LCStore.
-        *
-        * @var LCStore
-        */
-       private $store;
-
-       /**
-        * A 2-d associative array, code/key, where presence indicates that the item
-        * is loaded. Value arbitrary.
-        *
-        * For split items, if set, this indicates that all of the subitems have been
-        * loaded.
-        */
-       private $loadedItems = [];
-
-       /**
-        * A 3-d associative array, code/key/subkey, where presence indicates that
-        * the subitem is loaded. Only used for the split items, i.e. messages.
-        */
-       private $loadedSubitems = [];
-
-       /**
-        * An array where presence of a key indicates that that language has been
-        * initialised. Initialisation includes checking for cache expiry and doing
-        * any necessary updates.
-        */
-       private $initialisedLangs = [];
-
-       /**
-        * An array mapping non-existent pseudo-languages to fallback languages. This
-        * is filled by initShallowFallback() when data is requested from a language
-        * that lacks a Messages*.php file.
-        */
-       private $shallowFallbacks = [];
-
-       /**
-        * An array where the keys are codes that have been recached by this instance.
-        */
-       private $recachedLangs = [];
-
-       /**
-        * All item keys
-        */
-       static public $allKeys = [
-               'fallback', 'namespaceNames', 'bookstoreList',
-               'magicWords', 'messages', 'rtl', 'capitalizeAllNouns', 'digitTransformTable',
-               'separatorTransformTable', 'fallback8bitEncoding', 'linkPrefixExtension',
-               'linkTrail', 'linkPrefixCharset', 'namespaceAliases',
-               'dateFormats', 'datePreferences', 'datePreferenceMigrationMap',
-               'defaultDateFormat', 'extraUserToggles', 'specialPageAliases',
-               'imageFiles', 'preloadedMessages', 'namespaceGenderAliases',
-               'digitGroupingPattern', 'pluralRules', 'pluralRuleTypes', 'compiledPluralRules',
-       ];
-
-       /**
-        * Keys for items which consist of associative arrays, which may be merged
-        * by a fallback sequence.
-        */
-       static public $mergeableMapKeys = [ 'messages', 'namespaceNames',
-               'namespaceAliases', 'dateFormats', 'imageFiles', 'preloadedMessages'
-       ];
-
-       /**
-        * Keys for items which are a numbered array.
-        */
-       static public $mergeableListKeys = [ 'extraUserToggles' ];
-
-       /**
-        * Keys for items which contain an array of arrays of equivalent aliases
-        * for each subitem. The aliases may be merged by a fallback sequence.
-        */
-       static public $mergeableAliasListKeys = [ 'specialPageAliases' ];
-
-       /**
-        * Keys for items which contain an associative array, and may be merged if
-        * the primary value contains the special array key "inherit". That array
-        * key is removed after the first merge.
-        */
-       static public $optionalMergeKeys = [ 'bookstoreList' ];
-
-       /**
-        * Keys for items that are formatted like $magicWords
-        */
-       static public $magicWordKeys = [ 'magicWords' ];
-
-       /**
-        * Keys for items where the subitems are stored in the backend separately.
-        */
-       static public $splitKeys = [ 'messages' ];
-
-       /**
-        * Keys which are loaded automatically by initLanguage()
-        */
-       static public $preloadedKeys = [ 'dateFormats', 'namespaceNames' ];
-
-       /**
-        * Associative array of cached plural rules. The key is the language code,
-        * the value is an array of plural rules for that language.
-        */
-       private $pluralRules = null;
-
-       /**
-        * Associative array of cached plural rule types. The key is the language
-        * code, the value is an array of plural rule types for that language. For
-        * example, $pluralRuleTypes['ar'] = ['zero', 'one', 'two', 'few', 'many'].
-        * The index for each rule type matches the index for the rule in
-        * $pluralRules, thus allowing correlation between the two. The reason we
-        * don't just use the type names as the keys in $pluralRules is because
-        * Language::convertPlural applies the rules based on numeric order (or
-        * explicit numeric parameter), not based on the name of the rule type. For
-        * example, {{plural:count|wordform1|wordform2|wordform3}}, rather than
-        * {{plural:count|one=wordform1|two=wordform2|many=wordform3}}.
-        */
-       private $pluralRuleTypes = null;
-
-       private $mergeableKeys = null;
-
-       /**
-        * Constructor.
-        * For constructor parameters, see the documentation in DefaultSettings.php
-        * for $wgLocalisationCacheConf.
-        *
-        * @param array $conf
-        * @throws MWException
-        */
-       function __construct( $conf ) {
-               global $wgCacheDirectory;
-
-               $this->conf = $conf;
-               $storeConf = [];
-               if ( !empty( $conf['storeClass'] ) ) {
-                       $storeClass = $conf['storeClass'];
-               } else {
-                       switch ( $conf['store'] ) {
-                               case 'files':
-                               case 'file':
-                                       $storeClass = 'LCStoreCDB';
-                                       break;
-                               case 'db':
-                                       $storeClass = 'LCStoreDB';
-                                       break;
-                               case 'array':
-                                       $storeClass = 'LCStoreStaticArray';
-                                       break;
-                               case 'detect':
-                                       if ( !empty( $conf['storeDirectory'] ) ) {
-                                               $storeClass = 'LCStoreCDB';
-                                       } else {
-                                               $cacheDir = $wgCacheDirectory ?: wfTempDir();
-                                               if ( $cacheDir ) {
-                                                       $storeConf['directory'] = $cacheDir;
-                                                       $storeClass = 'LCStoreCDB';
-                                               } else {
-                                                       $storeClass = 'LCStoreDB';
-                                               }
-                                       }
-                                       break;
-                               default:
-                                       throw new MWException(
-                                               'Please set $wgLocalisationCacheConf[\'store\'] to something sensible.' );
-                       }
-               }
-
-               wfDebugLog( 'caches', get_class( $this ) . ": using store $storeClass" );
-               if ( !empty( $conf['storeDirectory'] ) ) {
-                       $storeConf['directory'] = $conf['storeDirectory'];
-               }
-
-               $this->store = new $storeClass( $storeConf );
-               foreach ( [ 'manualRecache', 'forceRecache' ] as $var ) {
-                       if ( isset( $conf[$var] ) ) {
-                               $this->$var = $conf[$var];
-                       }
-               }
-       }
-
-       /**
-        * Returns true if the given key is mergeable, that is, if it is an associative
-        * array which can be merged through a fallback sequence.
-        * @param string $key
-        * @return bool
-        */
-       public function isMergeableKey( $key ) {
-               if ( $this->mergeableKeys === null ) {
-                       $this->mergeableKeys = array_flip( array_merge(
-                               self::$mergeableMapKeys,
-                               self::$mergeableListKeys,
-                               self::$mergeableAliasListKeys,
-                               self::$optionalMergeKeys,
-                               self::$magicWordKeys
-                       ) );
-               }
-
-               return isset( $this->mergeableKeys[$key] );
-       }
-
-       /**
-        * Get a cache item.
-        *
-        * Warning: this may be slow for split items (messages), since it will
-        * need to fetch all of the subitems from the cache individually.
-        * @param string $code
-        * @param string $key
-        * @return mixed
-        */
-       public function getItem( $code, $key ) {
-               if ( !isset( $this->loadedItems[$code][$key] ) ) {
-                       $this->loadItem( $code, $key );
-               }
-
-               if ( $key === 'fallback' && isset( $this->shallowFallbacks[$code] ) ) {
-                       return $this->shallowFallbacks[$code];
-               }
-
-               return $this->data[$code][$key];
-       }
-
-       /**
-        * Get a subitem, for instance a single message for a given language.
-        * @param string $code
-        * @param string $key
-        * @param string $subkey
-        * @return mixed|null
-        */
-       public function getSubitem( $code, $key, $subkey ) {
-               if ( !isset( $this->loadedSubitems[$code][$key][$subkey] ) &&
-                       !isset( $this->loadedItems[$code][$key] )
-               ) {
-                       $this->loadSubitem( $code, $key, $subkey );
-               }
-
-               if ( isset( $this->data[$code][$key][$subkey] ) ) {
-                       return $this->data[$code][$key][$subkey];
-               } else {
-                       return null;
-               }
-       }
-
-       /**
-        * Get the list of subitem keys for a given item.
-        *
-        * This is faster than array_keys($lc->getItem(...)) for the items listed in
-        * self::$splitKeys.
-        *
-        * Will return null if the item is not found, or false if the item is not an
-        * array.
-        * @param string $code
-        * @param string $key
-        * @return bool|null|string
-        */
-       public function getSubitemList( $code, $key ) {
-               if ( in_array( $key, self::$splitKeys ) ) {
-                       return $this->getSubitem( $code, 'list', $key );
-               } else {
-                       $item = $this->getItem( $code, $key );
-                       if ( is_array( $item ) ) {
-                               return array_keys( $item );
-                       } else {
-                               return false;
-                       }
-               }
-       }
-
-       /**
-        * Load an item into the cache.
-        * @param string $code
-        * @param string $key
-        */
-       protected function loadItem( $code, $key ) {
-               if ( !isset( $this->initialisedLangs[$code] ) ) {
-                       $this->initLanguage( $code );
-               }
-
-               // Check to see if initLanguage() loaded it for us
-               if ( isset( $this->loadedItems[$code][$key] ) ) {
-                       return;
-               }
-
-               if ( isset( $this->shallowFallbacks[$code] ) ) {
-                       $this->loadItem( $this->shallowFallbacks[$code], $key );
-
-                       return;
-               }
-
-               if ( in_array( $key, self::$splitKeys ) ) {
-                       $subkeyList = $this->getSubitem( $code, 'list', $key );
-                       foreach ( $subkeyList as $subkey ) {
-                               if ( isset( $this->data[$code][$key][$subkey] ) ) {
-                                       continue;
-                               }
-                               $this->data[$code][$key][$subkey] = $this->getSubitem( $code, $key, $subkey );
-                       }
-               } else {
-                       $this->data[$code][$key] = $this->store->get( $code, $key );
-               }
-
-               $this->loadedItems[$code][$key] = true;
-       }
-
-       /**
-        * Load a subitem into the cache
-        * @param string $code
-        * @param string $key
-        * @param string $subkey
-        */
-       protected function loadSubitem( $code, $key, $subkey ) {
-               if ( !in_array( $key, self::$splitKeys ) ) {
-                       $this->loadItem( $code, $key );
-
-                       return;
-               }
-
-               if ( !isset( $this->initialisedLangs[$code] ) ) {
-                       $this->initLanguage( $code );
-               }
-
-               // Check to see if initLanguage() loaded it for us
-               if ( isset( $this->loadedItems[$code][$key] ) ||
-                       isset( $this->loadedSubitems[$code][$key][$subkey] )
-               ) {
-                       return;
-               }
-
-               if ( isset( $this->shallowFallbacks[$code] ) ) {
-                       $this->loadSubitem( $this->shallowFallbacks[$code], $key, $subkey );
-
-                       return;
-               }
-
-               $value = $this->store->get( $code, "$key:$subkey" );
-               $this->data[$code][$key][$subkey] = $value;
-               $this->loadedSubitems[$code][$key][$subkey] = true;
-       }
-
-       /**
-        * Returns true if the cache identified by $code is missing or expired.
-        *
-        * @param string $code
-        *
-        * @return bool
-        */
-       public function isExpired( $code ) {
-               if ( $this->forceRecache && !isset( $this->recachedLangs[$code] ) ) {
-                       wfDebug( __METHOD__ . "($code): forced reload\n" );
-
-                       return true;
-               }
-
-               $deps = $this->store->get( $code, 'deps' );
-               $keys = $this->store->get( $code, 'list' );
-               $preload = $this->store->get( $code, 'preload' );
-               // Different keys may expire separately for some stores
-               if ( $deps === null || $keys === null || $preload === null ) {
-                       wfDebug( __METHOD__ . "($code): cache missing, need to make one\n" );
-
-                       return true;
-               }
-
-               foreach ( $deps as $dep ) {
-                       // Because we're unserializing stuff from cache, we
-                       // could receive objects of classes that don't exist
-                       // anymore (e.g. uninstalled extensions)
-                       // When this happens, always expire the cache
-                       if ( !$dep instanceof CacheDependency || $dep->isExpired() ) {
-                               wfDebug( __METHOD__ . "($code): cache for $code expired due to " .
-                                       get_class( $dep ) . "\n" );
-
-                               return true;
-                       }
-               }
-
-               return false;
-       }
-
-       /**
-        * Initialise a language in this object. Rebuild the cache if necessary.
-        * @param string $code
-        * @throws MWException
-        */
-       protected function initLanguage( $code ) {
-               if ( isset( $this->initialisedLangs[$code] ) ) {
-                       return;
-               }
-
-               $this->initialisedLangs[$code] = true;
-
-               # If the code is of the wrong form for a Messages*.php file, do a shallow fallback
-               if ( !Language::isValidBuiltInCode( $code ) ) {
-                       $this->initShallowFallback( $code, 'en' );
-
-                       return;
-               }
-
-               # Recache the data if necessary
-               if ( !$this->manualRecache && $this->isExpired( $code ) ) {
-                       if ( Language::isSupportedLanguage( $code ) ) {
-                               $this->recache( $code );
-                       } elseif ( $code === 'en' ) {
-                               throw new MWException( 'MessagesEn.php is missing.' );
-                       } else {
-                               $this->initShallowFallback( $code, 'en' );
-                       }
-
-                       return;
-               }
-
-               # Preload some stuff
-               $preload = $this->getItem( $code, 'preload' );
-               if ( $preload === null ) {
-                       if ( $this->manualRecache ) {
-                               // No Messages*.php file. Do shallow fallback to en.
-                               if ( $code === 'en' ) {
-                                       throw new MWException( 'No localisation cache found for English. ' .
-                                               'Please run maintenance/rebuildLocalisationCache.php.' );
-                               }
-                               $this->initShallowFallback( $code, 'en' );
-
-                               return;
-                       } else {
-                               throw new MWException( 'Invalid or missing localisation cache.' );
-                       }
-               }
-               $this->data[$code] = $preload;
-               foreach ( $preload as $key => $item ) {
-                       if ( in_array( $key, self::$splitKeys ) ) {
-                               foreach ( $item as $subkey => $subitem ) {
-                                       $this->loadedSubitems[$code][$key][$subkey] = true;
-                               }
-                       } else {
-                               $this->loadedItems[$code][$key] = true;
-                       }
-               }
-       }
-
-       /**
-        * Create a fallback from one language to another, without creating a
-        * complete persistent cache.
-        * @param string $primaryCode
-        * @param string $fallbackCode
-        */
-       public function initShallowFallback( $primaryCode, $fallbackCode ) {
-               $this->data[$primaryCode] =& $this->data[$fallbackCode];
-               $this->loadedItems[$primaryCode] =& $this->loadedItems[$fallbackCode];
-               $this->loadedSubitems[$primaryCode] =& $this->loadedSubitems[$fallbackCode];
-               $this->shallowFallbacks[$primaryCode] = $fallbackCode;
-       }
-
-       /**
-        * Read a PHP file containing localisation data.
-        * @param string $_fileName
-        * @param string $_fileType
-        * @throws MWException
-        * @return array
-        */
-       protected function readPHPFile( $_fileName, $_fileType ) {
-               // Disable APC caching
-               MediaWiki\suppressWarnings();
-               $_apcEnabled = ini_set( 'apc.cache_by_default', '0' );
-               MediaWiki\restoreWarnings();
-
-               include $_fileName;
-
-               MediaWiki\suppressWarnings();
-               ini_set( 'apc.cache_by_default', $_apcEnabled );
-               MediaWiki\restoreWarnings();
-
-               if ( $_fileType == 'core' || $_fileType == 'extension' ) {
-                       $data = compact( self::$allKeys );
-               } elseif ( $_fileType == 'aliases' ) {
-                       $data = compact( 'aliases' );
-               } else {
-                       throw new MWException( __METHOD__ . ": Invalid file type: $_fileType" );
-               }
-
-               return $data;
-       }
-
-       /**
-        * Read a JSON file containing localisation messages.
-        * @param string $fileName Name of file to read
-        * @throws MWException If there is a syntax error in the JSON file
-        * @return array Array with a 'messages' key, or empty array if the file doesn't exist
-        */
-       public function readJSONFile( $fileName ) {
-
-               if ( !is_readable( $fileName ) ) {
-                       return [];
-               }
-
-               $json = file_get_contents( $fileName );
-               if ( $json === false ) {
-                       return [];
-               }
-
-               $data = FormatJson::decode( $json, true );
-               if ( $data === null ) {
-
-                       throw new MWException( __METHOD__ . ": Invalid JSON file: $fileName" );
-               }
-
-               // Remove keys starting with '@', they're reserved for metadata and non-message data
-               foreach ( $data as $key => $unused ) {
-                       if ( $key === '' || $key[0] === '@' ) {
-                               unset( $data[$key] );
-                       }
-               }
-
-               // The JSON format only supports messages, none of the other variables, so wrap the data
-               return [ 'messages' => $data ];
-       }
-
-       /**
-        * Get the compiled plural rules for a given language from the XML files.
-        * @since 1.20
-        * @param string $code
-        * @return array|null
-        */
-       public function getCompiledPluralRules( $code ) {
-               $rules = $this->getPluralRules( $code );
-               if ( $rules === null ) {
-                       return null;
-               }
-               try {
-                       $compiledRules = Evaluator::compile( $rules );
-               } catch ( CLDRPluralRuleError $e ) {
-                       wfDebugLog( 'l10n', $e->getMessage() );
-
-                       return [];
-               }
-
-               return $compiledRules;
-       }
-
-       /**
-        * Get the plural rules for a given language from the XML files.
-        * Cached.
-        * @since 1.20
-        * @param string $code
-        * @return array|null
-        */
-       public function getPluralRules( $code ) {
-               if ( $this->pluralRules === null ) {
-                       $this->loadPluralFiles();
-               }
-               if ( !isset( $this->pluralRules[$code] ) ) {
-                       return null;
-               } else {
-                       return $this->pluralRules[$code];
-               }
-       }
-
-       /**
-        * Get the plural rule types for a given language from the XML files.
-        * Cached.
-        * @since 1.22
-        * @param string $code
-        * @return array|null
-        */
-       public function getPluralRuleTypes( $code ) {
-               if ( $this->pluralRuleTypes === null ) {
-                       $this->loadPluralFiles();
-               }
-               if ( !isset( $this->pluralRuleTypes[$code] ) ) {
-                       return null;
-               } else {
-                       return $this->pluralRuleTypes[$code];
-               }
-       }
-
-       /**
-        * Load the plural XML files.
-        */
-       protected function loadPluralFiles() {
-               global $IP;
-               $cldrPlural = "$IP/languages/data/plurals.xml";
-               $mwPlural = "$IP/languages/data/plurals-mediawiki.xml";
-               // Load CLDR plural rules
-               $this->loadPluralFile( $cldrPlural );
-               if ( file_exists( $mwPlural ) ) {
-                       // Override or extend
-                       $this->loadPluralFile( $mwPlural );
-               }
-       }
-
-       /**
-        * Load a plural XML file with the given filename, compile the relevant
-        * rules, and save the compiled rules in a process-local cache.
-        *
-        * @param string $fileName
-        * @throws MWException
-        */
-       protected function loadPluralFile( $fileName ) {
-               // Use file_get_contents instead of DOMDocument::load (T58439)
-               $xml = file_get_contents( $fileName );
-               if ( !$xml ) {
-                       throw new MWException( "Unable to read plurals file $fileName" );
-               }
-               $doc = new DOMDocument;
-               $doc->loadXML( $xml );
-               $rulesets = $doc->getElementsByTagName( "pluralRules" );
-               foreach ( $rulesets as $ruleset ) {
-                       $codes = $ruleset->getAttribute( 'locales' );
-                       $rules = [];
-                       $ruleTypes = [];
-                       $ruleElements = $ruleset->getElementsByTagName( "pluralRule" );
-                       foreach ( $ruleElements as $elt ) {
-                               $ruleType = $elt->getAttribute( 'count' );
-                               if ( $ruleType === 'other' ) {
-                                       // Don't record "other" rules, which have an empty condition
-                                       continue;
-                               }
-                               $rules[] = $elt->nodeValue;
-                               $ruleTypes[] = $ruleType;
-                       }
-                       foreach ( explode( ' ', $codes ) as $code ) {
-                               $this->pluralRules[$code] = $rules;
-                               $this->pluralRuleTypes[$code] = $ruleTypes;
-                       }
-               }
-       }
-
-       /**
-        * Read the data from the source files for a given language, and register
-        * the relevant dependencies in the $deps array. If the localisation
-        * exists, the data array is returned, otherwise false is returned.
-        *
-        * @param string $code
-        * @param array $deps
-        * @return array
-        */
-       protected function readSourceFilesAndRegisterDeps( $code, &$deps ) {
-               global $IP;
-
-               // This reads in the PHP i18n file with non-messages l10n data
-               $fileName = Language::getMessagesFileName( $code );
-               if ( !file_exists( $fileName ) ) {
-                       $data = [];
-               } else {
-                       $deps[] = new FileDependency( $fileName );
-                       $data = $this->readPHPFile( $fileName, 'core' );
-               }
-
-               # Load CLDR plural rules for JavaScript
-               $data['pluralRules'] = $this->getPluralRules( $code );
-               # And for PHP
-               $data['compiledPluralRules'] = $this->getCompiledPluralRules( $code );
-               # Load plural rule types
-               $data['pluralRuleTypes'] = $this->getPluralRuleTypes( $code );
-
-               $deps['plurals'] = new FileDependency( "$IP/languages/data/plurals.xml" );
-               $deps['plurals-mw'] = new FileDependency( "$IP/languages/data/plurals-mediawiki.xml" );
-
-               return $data;
-       }
-
-       /**
-        * Merge two localisation values, a primary and a fallback, overwriting the
-        * primary value in place.
-        * @param string $key
-        * @param mixed $value
-        * @param mixed $fallbackValue
-        */
-       protected function mergeItem( $key, &$value, $fallbackValue ) {
-               if ( !is_null( $value ) ) {
-                       if ( !is_null( $fallbackValue ) ) {
-                               if ( in_array( $key, self::$mergeableMapKeys ) ) {
-                                       $value = $value + $fallbackValue;
-                               } elseif ( in_array( $key, self::$mergeableListKeys ) ) {
-                                       $value = array_unique( array_merge( $fallbackValue, $value ) );
-                               } elseif ( in_array( $key, self::$mergeableAliasListKeys ) ) {
-                                       $value = array_merge_recursive( $value, $fallbackValue );
-                               } elseif ( in_array( $key, self::$optionalMergeKeys ) ) {
-                                       if ( !empty( $value['inherit'] ) ) {
-                                               $value = array_merge( $fallbackValue, $value );
-                                       }
-
-                                       if ( isset( $value['inherit'] ) ) {
-                                               unset( $value['inherit'] );
-                                       }
-                               } elseif ( in_array( $key, self::$magicWordKeys ) ) {
-                                       $this->mergeMagicWords( $value, $fallbackValue );
-                               }
-                       }
-               } else {
-                       $value = $fallbackValue;
-               }
-       }
-
-       /**
-        * @param mixed $value
-        * @param mixed $fallbackValue
-        */
-       protected function mergeMagicWords( &$value, $fallbackValue ) {
-               foreach ( $fallbackValue as $magicName => $fallbackInfo ) {
-                       if ( !isset( $value[$magicName] ) ) {
-                               $value[$magicName] = $fallbackInfo;
-                       } else {
-                               $oldSynonyms = array_slice( $fallbackInfo, 1 );
-                               $newSynonyms = array_slice( $value[$magicName], 1 );
-                               $synonyms = array_values( array_unique( array_merge(
-                                       $newSynonyms, $oldSynonyms ) ) );
-                               $value[$magicName] = array_merge( [ $fallbackInfo[0] ], $synonyms );
-                       }
-               }
-       }
-
-       /**
-        * Given an array mapping language code to localisation value, such as is
-        * found in extension *.i18n.php files, iterate through a fallback sequence
-        * to merge the given data with an existing primary value.
-        *
-        * Returns true if any data from the extension array was used, false
-        * otherwise.
-        * @param array $codeSequence
-        * @param string $key
-        * @param mixed $value
-        * @param mixed $fallbackValue
-        * @return bool
-        */
-       protected function mergeExtensionItem( $codeSequence, $key, &$value, $fallbackValue ) {
-               $used = false;
-               foreach ( $codeSequence as $code ) {
-                       if ( isset( $fallbackValue[$code] ) ) {
-                               $this->mergeItem( $key, $value, $fallbackValue[$code] );
-                               $used = true;
-                       }
-               }
-
-               return $used;
-       }
-
-       /**
-        * Gets the combined list of messages dirs from
-        * core and extensions
-        *
-        * @since 1.25
-        * @return array
-        */
-       public function getMessagesDirs() {
-               global $wgMessagesDirs, $IP;
-               return [
-                       'core' => "$IP/languages/i18n",
-                       'api' => "$IP/includes/api/i18n",
-                       'oojs-ui' => "$IP/resources/lib/oojs-ui/i18n",
-               ] + $wgMessagesDirs;
-       }
-
-       /**
-        * Load localisation data for a given language for both core and extensions
-        * and save it to the persistent cache store and the process cache
-        * @param string $code
-        * @throws MWException
-        */
-       public function recache( $code ) {
-               global $wgExtensionMessagesFiles;
-
-               if ( !$code ) {
-                       throw new MWException( "Invalid language code requested" );
-               }
-               $this->recachedLangs[$code] = true;
-
-               # Initial values
-               $initialData = array_fill_keys( self::$allKeys, null );
-               $coreData = $initialData;
-               $deps = [];
-
-               # Load the primary localisation from the source file
-               $data = $this->readSourceFilesAndRegisterDeps( $code, $deps );
-               if ( $data === false ) {
-                       wfDebug( __METHOD__ . ": no localisation file for $code, using fallback to en\n" );
-                       $coreData['fallback'] = 'en';
-               } else {
-                       wfDebug( __METHOD__ . ": got localisation for $code from source\n" );
-
-                       # Merge primary localisation
-                       foreach ( $data as $key => $value ) {
-                               $this->mergeItem( $key, $coreData[$key], $value );
-                       }
-               }
-
-               # Fill in the fallback if it's not there already
-               if ( is_null( $coreData['fallback'] ) ) {
-                       $coreData['fallback'] = $code === 'en' ? false : 'en';
-               }
-               if ( $coreData['fallback'] === false ) {
-                       $coreData['fallbackSequence'] = [];
-               } else {
-                       $coreData['fallbackSequence'] = array_map( 'trim', explode( ',', $coreData['fallback'] ) );
-                       $len = count( $coreData['fallbackSequence'] );
-
-                       # Ensure that the sequence ends at en
-                       if ( $coreData['fallbackSequence'][$len - 1] !== 'en' ) {
-                               $coreData['fallbackSequence'][] = 'en';
-                       }
-               }
-
-               $codeSequence = array_merge( [ $code ], $coreData['fallbackSequence'] );
-               $messageDirs = $this->getMessagesDirs();
-
-               # Load non-JSON localisation data for extensions
-               $extensionData = array_fill_keys( $codeSequence, $initialData );
-               foreach ( $wgExtensionMessagesFiles as $extension => $fileName ) {
-                       if ( isset( $messageDirs[$extension] ) ) {
-                               # This extension has JSON message data; skip the PHP shim
-                               continue;
-                       }
-
-                       $data = $this->readPHPFile( $fileName, 'extension' );
-                       $used = false;
-
-                       foreach ( $data as $key => $item ) {
-                               foreach ( $codeSequence as $csCode ) {
-                                       if ( isset( $item[$csCode] ) ) {
-                                               $this->mergeItem( $key, $extensionData[$csCode][$key], $item[$csCode] );
-                                               $used = true;
-                                       }
-                               }
-                       }
-
-                       if ( $used ) {
-                               $deps[] = new FileDependency( $fileName );
-                       }
-               }
-
-               # Load the localisation data for each fallback, then merge it into the full array
-               $allData = $initialData;
-               foreach ( $codeSequence as $csCode ) {
-                       $csData = $initialData;
-
-                       # Load core messages and the extension localisations.
-                       foreach ( $messageDirs as $dirs ) {
-                               foreach ( (array)$dirs as $dir ) {
-                                       $fileName = "$dir/$csCode.json";
-                                       $data = $this->readJSONFile( $fileName );
-
-                                       foreach ( $data as $key => $item ) {
-                                               $this->mergeItem( $key, $csData[$key], $item );
-                                       }
-
-                                       $deps[] = new FileDependency( $fileName );
-                               }
-                       }
-
-                       # Merge non-JSON extension data
-                       if ( isset( $extensionData[$csCode] ) ) {
-                               foreach ( $extensionData[$csCode] as $key => $item ) {
-                                       $this->mergeItem( $key, $csData[$key], $item );
-                               }
-                       }
-
-                       if ( $csCode === $code ) {
-                               # Merge core data into extension data
-                               foreach ( $coreData as $key => $item ) {
-                                       $this->mergeItem( $key, $csData[$key], $item );
-                               }
-                       } else {
-                               # Load the secondary localisation from the source file to
-                               # avoid infinite cycles on cyclic fallbacks
-                               $fbData = $this->readSourceFilesAndRegisterDeps( $csCode, $deps );
-                               if ( $fbData !== false ) {
-                                       # Only merge the keys that make sense to merge
-                                       foreach ( self::$allKeys as $key ) {
-                                               if ( !isset( $fbData[$key] ) ) {
-                                                       continue;
-                                               }
-
-                                               if ( is_null( $coreData[$key] ) || $this->isMergeableKey( $key ) ) {
-                                                       $this->mergeItem( $key, $csData[$key], $fbData[$key] );
-                                               }
-                                       }
-                               }
-                       }
-
-                       # Allow extensions an opportunity to adjust the data for this
-                       # fallback
-                       Hooks::run( 'LocalisationCacheRecacheFallback', [ $this, $csCode, &$csData ] );
-
-                       # Merge the data for this fallback into the final array
-                       if ( $csCode === $code ) {
-                               $allData = $csData;
-                       } else {
-                               foreach ( self::$allKeys as $key ) {
-                                       if ( !isset( $csData[$key] ) ) {
-                                               continue;
-                                       }
-
-                                       if ( is_null( $allData[$key] ) || $this->isMergeableKey( $key ) ) {
-                                               $this->mergeItem( $key, $allData[$key], $csData[$key] );
-                                       }
-                               }
-                       }
-               }
-
-               # Add cache dependencies for any referenced globals
-               $deps['wgExtensionMessagesFiles'] = new GlobalDependency( 'wgExtensionMessagesFiles' );
-               // $wgMessagesDirs is used in LocalisationCache::getMessagesDirs()
-               $deps['wgMessagesDirs'] = new GlobalDependency( 'wgMessagesDirs' );
-               $deps['version'] = new ConstantDependency( 'LocalisationCache::VERSION' );
-
-               # Add dependencies to the cache entry
-               $allData['deps'] = $deps;
-
-               # Replace spaces with underscores in namespace names
-               $allData['namespaceNames'] = str_replace( ' ', '_', $allData['namespaceNames'] );
-
-               # And do the same for special page aliases. $page is an array.
-               foreach ( $allData['specialPageAliases'] as &$page ) {
-                       $page = str_replace( ' ', '_', $page );
-               }
-               # Decouple the reference to prevent accidental damage
-               unset( $page );
-
-               # If there were no plural rules, return an empty array
-               if ( $allData['pluralRules'] === null ) {
-                       $allData['pluralRules'] = [];
-               }
-               if ( $allData['compiledPluralRules'] === null ) {
-                       $allData['compiledPluralRules'] = [];
-               }
-               # If there were no plural rule types, return an empty array
-               if ( $allData['pluralRuleTypes'] === null ) {
-                       $allData['pluralRuleTypes'] = [];
-               }
-
-               # Set the list keys
-               $allData['list'] = [];
-               foreach ( self::$splitKeys as $key ) {
-                       $allData['list'][$key] = array_keys( $allData[$key] );
-               }
-               # Run hooks
-               $purgeBlobs = true;
-               Hooks::run( 'LocalisationCacheRecache', [ $this, $code, &$allData, &$purgeBlobs ] );
-
-               if ( is_null( $allData['namespaceNames'] ) ) {
-                       throw new MWException( __METHOD__ . ': Localisation data failed sanity check! ' .
-                               'Check that your languages/messages/MessagesEn.php file is intact.' );
-               }
-
-               # Set the preload key
-               $allData['preload'] = $this->buildPreload( $allData );
-
-               # Save to the process cache and register the items loaded
-               $this->data[$code] = $allData;
-               foreach ( $allData as $key => $item ) {
-                       $this->loadedItems[$code][$key] = true;
-               }
-
-               # Save to the persistent cache
-               $this->store->startWrite( $code );
-               foreach ( $allData as $key => $value ) {
-                       if ( in_array( $key, self::$splitKeys ) ) {
-                               foreach ( $value as $subkey => $subvalue ) {
-                                       $this->store->set( "$key:$subkey", $subvalue );
-                               }
-                       } else {
-                               $this->store->set( $key, $value );
-                       }
-               }
-               $this->store->finishWrite();
-
-               # Clear out the MessageBlobStore
-               # HACK: If using a null (i.e. disabled) storage backend, we
-               # can't write to the MessageBlobStore either
-               if ( $purgeBlobs && !$this->store instanceof LCStoreNull ) {
-                       $blobStore = new MessageBlobStore();
-                       $blobStore->clear();
-               }
-
-       }
-
-       /**
-        * Build the preload item from the given pre-cache data.
-        *
-        * The preload item will be loaded automatically, improving performance
-        * for the commonly-requested items it contains.
-        * @param array $data
-        * @return array
-        */
-       protected function buildPreload( $data ) {
-               $preload = [ 'messages' => [] ];
-               foreach ( self::$preloadedKeys as $key ) {
-                       $preload[$key] = $data[$key];
-               }
-
-               foreach ( $data['preloadedMessages'] as $subkey ) {
-                       if ( isset( $data['messages'][$subkey] ) ) {
-                               $subitem = $data['messages'][$subkey];
-                       } else {
-                               $subitem = null;
-                       }
-                       $preload['messages'][$subkey] = $subitem;
-               }
-
-               return $preload;
-       }
-
-       /**
-        * Unload the data for a given language from the object cache.
-        * Reduces memory usage.
-        * @param string $code
-        */
-       public function unload( $code ) {
-               unset( $this->data[$code] );
-               unset( $this->loadedItems[$code] );
-               unset( $this->loadedSubitems[$code] );
-               unset( $this->initialisedLangs[$code] );
-               unset( $this->shallowFallbacks[$code] );
-
-               foreach ( $this->shallowFallbacks as $shallowCode => $fbCode ) {
-                       if ( $fbCode === $code ) {
-                               $this->unload( $shallowCode );
-                       }
-               }
-       }
-
-       /**
-        * Unload all data
-        */
-       public function unloadAll() {
-               foreach ( $this->initialisedLangs as $lang => $unused ) {
-                       $this->unload( $lang );
-               }
-       }
-
-       /**
-        * Disable the storage backend
-        */
-       public function disableBackend() {
-               $this->store = new LCStoreNull;
-               $this->manualRecache = false;
-       }
-}
-
-/**
- * Interface for the persistence layer of LocalisationCache.
- *
- * The persistence layer is two-level hierarchical cache. The first level
- * is the language, the second level is the item or subitem.
- *
- * Since the data for a whole language is rebuilt in one operation, it needs
- * to have a fast and atomic method for deleting or replacing all of the
- * current data for a given language. The interface reflects this bulk update
- * operation. Callers writing to the cache must first call startWrite(), then
- * will call set() a couple of thousand times, then will call finishWrite()
- * to commit the operation. When finishWrite() is called, the cache is
- * expected to delete all data previously stored for that language.
- *
- * The values stored are PHP variables suitable for serialize(). Implementations
- * of LCStore are responsible for serializing and unserializing.
- */
-interface LCStore {
-       /**
-        * Get a value.
-        * @param string $code Language code
-        * @param string $key Cache key
-        */
-       function get( $code, $key );
-
-       /**
-        * Start a write transaction.
-        * @param string $code Language code
-        */
-       function startWrite( $code );
-
-       /**
-        * Finish a write transaction.
-        */
-       function finishWrite();
-
-       /**
-        * Set a key to a given value. startWrite() must be called before this
-        * is called, and finishWrite() must be called afterwards.
-        * @param string $key
-        * @param mixed $value
-        */
-       function set( $key, $value );
-}
-
-/**
- * LCStore implementation which uses the standard DB functions to store data.
- * This will work on any MediaWiki installation.
- */
-class LCStoreDB implements LCStore {
-       /** @var string */
-       private $currentLang;
-       /** @var bool */
-       private $writesDone = false;
-       /** @var IDatabase */
-       private $dbw;
-       /** @var array */
-       private $batch = [];
-       /** @var bool */
-       private $readOnly = false;
-
-       public function get( $code, $key ) {
-               if ( $this->writesDone && $this->dbw ) {
-                       $db = $this->dbw; // see the changes in finishWrite()
-               } else {
-                       $db = wfGetDB( DB_SLAVE );
-               }
-
-               $value = $db->selectField(
-                       'l10n_cache',
-                       'lc_value',
-                       [ 'lc_lang' => $code, 'lc_key' => $key ],
-                       __METHOD__
-               );
-
-               return ( $value !== false ) ? unserialize( $db->decodeBlob( $value ) ) : null;
-       }
-
-       public function startWrite( $code ) {
-               if ( $this->readOnly ) {
-                       return;
-               } elseif ( !$code ) {
-                       throw new MWException( __METHOD__ . ": Invalid language \"$code\"" );
-               }
-
-               $this->dbw = wfGetDB( DB_MASTER );
-               $this->readOnly = $this->dbw->isReadOnly();
-
-               $this->currentLang = $code;
-               $this->batch = [];
-       }
-
-       public function finishWrite() {
-               if ( $this->readOnly ) {
-                       return;
-               } elseif ( is_null( $this->currentLang ) ) {
-                       throw new MWException( __CLASS__ . ': must call startWrite() before finishWrite()' );
-               }
-
-               $this->dbw->startAtomic( __METHOD__ );
-               try {
-                       $this->dbw->delete(
-                               'l10n_cache',
-                               [ 'lc_lang' => $this->currentLang ],
-                               __METHOD__
-                       );
-                       foreach ( array_chunk( $this->batch, 500 ) as $rows ) {
-                               $this->dbw->insert( 'l10n_cache', $rows, __METHOD__ );
-                       }
-                       $this->writesDone = true;
-               } catch ( DBQueryError $e ) {
-                       if ( $this->dbw->wasReadOnlyError() ) {
-                               $this->readOnly = true; // just avoid site down time
-                       } else {
-                               throw $e;
-                       }
-               }
-               $this->dbw->endAtomic( __METHOD__ );
-
-               $this->currentLang = null;
-               $this->batch = [];
-       }
-
-       public function set( $key, $value ) {
-               if ( $this->readOnly ) {
-                       return;
-               } elseif ( is_null( $this->currentLang ) ) {
-                       throw new MWException( __CLASS__ . ': must call startWrite() before set()' );
-               }
-
-               $this->batch[] = [
-                       'lc_lang' => $this->currentLang,
-                       'lc_key' => $key,
-                       'lc_value' => $this->dbw->encodeBlob( serialize( $value ) )
-               ];
-       }
-}
-
-/**
- * LCStore implementation which stores data as a collection of CDB files in the
- * directory given by $wgCacheDirectory. If $wgCacheDirectory is not set, this
- * will throw an exception.
- *
- * Profiling indicates that on Linux, this implementation outperforms MySQL if
- * the directory is on a local filesystem and there is ample kernel cache
- * space. The performance advantage is greater when the DBA extension is
- * available than it is with the PHP port.
- *
- * See Cdb.php and http://cr.yp.to/cdb.html
- */
-class LCStoreCDB implements LCStore {
-       /** @var CdbReader[] */
-       private $readers;
-
-       /** @var CdbWriter */
-       private $writer;
-
-       /** @var string Current language code */
-       private $currentLang;
-
-       /** @var bool|string Cache directory. False if not set */
-       private $directory;
-
-       function __construct( $conf = [] ) {
-               global $wgCacheDirectory;
-
-               if ( isset( $conf['directory'] ) ) {
-                       $this->directory = $conf['directory'];
-               } else {
-                       $this->directory = $wgCacheDirectory;
-               }
-       }
-
-       public function get( $code, $key ) {
-               if ( !isset( $this->readers[$code] ) ) {
-                       $fileName = $this->getFileName( $code );
-
-                       $this->readers[$code] = false;
-                       if ( file_exists( $fileName ) ) {
-                               try {
-                                       $this->readers[$code] = CdbReader::open( $fileName );
-                               } catch ( CdbException $e ) {
-                                       wfDebug( __METHOD__ . ": unable to open cdb file for reading\n" );
-                               }
-                       }
-               }
-
-               if ( !$this->readers[$code] ) {
-                       return null;
-               } else {
-                       $value = false;
-                       try {
-                               $value = $this->readers[$code]->get( $key );
-                       } catch ( CdbException $e ) {
-                               wfDebug( __METHOD__ . ": CdbException caught, error message was "
-                                       . $e->getMessage() . "\n" );
-                       }
-                       if ( $value === false ) {
-                               return null;
-                       }
-
-                       return unserialize( $value );
-               }
-       }
-
-       public function startWrite( $code ) {
-               if ( !file_exists( $this->directory ) ) {
-                       if ( !wfMkdirParents( $this->directory, null, __METHOD__ ) ) {
-                               throw new MWException( "Unable to create the localisation store " .
-                                       "directory \"{$this->directory}\"" );
-                       }
-               }
-
-               // Close reader to stop permission errors on write
-               if ( !empty( $this->readers[$code] ) ) {
-                       $this->readers[$code]->close();
-               }
-
-               try {
-                       $this->writer = CdbWriter::open( $this->getFileName( $code ) );
-               } catch ( CdbException $e ) {
-                       throw new MWException( $e->getMessage() );
-               }
-               $this->currentLang = $code;
-       }
-
-       public function finishWrite() {
-               // Close the writer
-               try {
-                       $this->writer->close();
-               } catch ( CdbException $e ) {
-                       throw new MWException( $e->getMessage() );
-               }
-               $this->writer = null;
-               unset( $this->readers[$this->currentLang] );
-               $this->currentLang = null;
-       }
-
-       public function set( $key, $value ) {
-               if ( is_null( $this->writer ) ) {
-                       throw new MWException( __CLASS__ . ': must call startWrite() before calling set()' );
-               }
-               try {
-                       $this->writer->set( $key, serialize( $value ) );
-               } catch ( CdbException $e ) {
-                       throw new MWException( $e->getMessage() );
-               }
-       }
-
-       protected function getFileName( $code ) {
-               if ( strval( $code ) === '' || strpos( $code, '/' ) !== false ) {
-                       throw new MWException( __METHOD__ . ": Invalid language \"$code\"" );
-               }
-
-               return "{$this->directory}/l10n_cache-$code.cdb";
-       }
-}
-
-/**
- * Null store backend, used to avoid DB errors during install
- */
-class LCStoreNull implements LCStore {
-       public function get( $code, $key ) {
-               return null;
-       }
-
-       public function startWrite( $code ) {
-       }
-
-       public function finishWrite() {
-       }
-
-       public function set( $key, $value ) {
-       }
-}
-
-/**
- * A localisation cache optimised for loading large amounts of data for many
- * languages. Used by rebuildLocalisationCache.php.
- */
-class LocalisationCacheBulkLoad extends LocalisationCache {
-       /**
-        * A cache of the contents of data files.
-        * Core files are serialized to avoid using ~1GB of RAM during a recache.
-        */
-       private $fileCache = [];
-
-       /**
-        * Most recently used languages. Uses the linked-list aspect of PHP hashtables
-        * to keep the most recently used language codes at the end of the array, and
-        * the language codes that are ready to be deleted at the beginning.
-        */
-       private $mruLangs = [];
-
-       /**
-        * Maximum number of languages that may be loaded into $this->data
-        */
-       private $maxLoadedLangs = 10;
-
-       /**
-        * @param string $fileName
-        * @param string $fileType
-        * @return array|mixed
-        */
-       protected function readPHPFile( $fileName, $fileType ) {
-               $serialize = $fileType === 'core';
-               if ( !isset( $this->fileCache[$fileName][$fileType] ) ) {
-                       $data = parent::readPHPFile( $fileName, $fileType );
-
-                       if ( $serialize ) {
-                               $encData = serialize( $data );
-                       } else {
-                               $encData = $data;
-                       }
-
-                       $this->fileCache[$fileName][$fileType] = $encData;
-
-                       return $data;
-               } elseif ( $serialize ) {
-                       return unserialize( $this->fileCache[$fileName][$fileType] );
-               } else {
-                       return $this->fileCache[$fileName][$fileType];
-               }
-       }
-
-       /**
-        * @param string $code
-        * @param string $key
-        * @return mixed
-        */
-       public function getItem( $code, $key ) {
-               unset( $this->mruLangs[$code] );
-               $this->mruLangs[$code] = true;
-
-               return parent::getItem( $code, $key );
-       }
-
-       /**
-        * @param string $code
-        * @param string $key
-        * @param string $subkey
-        * @return mixed
-        */
-       public function getSubitem( $code, $key, $subkey ) {
-               unset( $this->mruLangs[$code] );
-               $this->mruLangs[$code] = true;
-
-               return parent::getSubitem( $code, $key, $subkey );
-       }
-
-       /**
-        * @param string $code
-        */
-       public function recache( $code ) {
-               parent::recache( $code );
-               unset( $this->mruLangs[$code] );
-               $this->mruLangs[$code] = true;
-               $this->trimCache();
-       }
-
-       /**
-        * @param string $code
-        */
-       public function unload( $code ) {
-               unset( $this->mruLangs[$code] );
-               parent::unload( $code );
-       }
-
-       /**
-        * Unload cached languages until there are less than $this->maxLoadedLangs
-        */
-       protected function trimCache() {
-               while ( count( $this->data ) > $this->maxLoadedLangs && count( $this->mruLangs ) ) {
-                       reset( $this->mruLangs );
-                       $code = key( $this->mruLangs );
-                       wfDebug( __METHOD__ . ": unloading $code\n" );
-                       $this->unload( $code );
-               }
-       }
-}
diff --git a/includes/cache/localisation/LCStore.php b/includes/cache/localisation/LCStore.php
new file mode 100644 (file)
index 0000000..cb1e261
--- /dev/null
@@ -0,0 +1,66 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Interface for the persistence layer of LocalisationCache.
+ *
+ * The persistence layer is two-level hierarchical cache. The first level
+ * is the language, the second level is the item or subitem.
+ *
+ * Since the data for a whole language is rebuilt in one operation, it needs
+ * to have a fast and atomic method for deleting or replacing all of the
+ * current data for a given language. The interface reflects this bulk update
+ * operation. Callers writing to the cache must first call startWrite(), then
+ * will call set() a couple of thousand times, then will call finishWrite()
+ * to commit the operation. When finishWrite() is called, the cache is
+ * expected to delete all data previously stored for that language.
+ *
+ * The values stored are PHP variables suitable for serialize(). Implementations
+ * of LCStore are responsible for serializing and unserializing.
+ */
+interface LCStore {
+
+       /**
+        * Get a value.
+        * @param string $code Language code
+        * @param string $key Cache key
+        */
+       function get( $code, $key );
+
+       /**
+        * Start a write transaction.
+        * @param string $code Language code
+        */
+       function startWrite( $code );
+
+       /**
+        * Finish a write transaction.
+        */
+       function finishWrite();
+
+       /**
+        * Set a key to a given value. startWrite() must be called before this
+        * is called, and finishWrite() must be called afterwards.
+        * @param string $key
+        * @param mixed $value
+        */
+       function set( $key, $value );
+
+}
diff --git a/includes/cache/localisation/LCStoreCDB.php b/includes/cache/localisation/LCStoreCDB.php
new file mode 100644 (file)
index 0000000..386ef8c
--- /dev/null
@@ -0,0 +1,141 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * LCStore implementation which stores data as a collection of CDB files in the
+ * directory given by $wgCacheDirectory. If $wgCacheDirectory is not set, this
+ * will throw an exception.
+ *
+ * Profiling indicates that on Linux, this implementation outperforms MySQL if
+ * the directory is on a local filesystem and there is ample kernel cache
+ * space. The performance advantage is greater when the DBA extension is
+ * available than it is with the PHP port.
+ *
+ * See Cdb.php and http://cr.yp.to/cdb.html
+ */
+class LCStoreCDB implements LCStore {
+
+       /** @var CdbReader[] */
+       private $readers;
+
+       /** @var CdbWriter */
+       private $writer;
+
+       /** @var string Current language code */
+       private $currentLang;
+
+       /** @var bool|string Cache directory. False if not set */
+       private $directory;
+
+       function __construct( $conf = [] ) {
+               global $wgCacheDirectory;
+
+               if ( isset( $conf['directory'] ) ) {
+                       $this->directory = $conf['directory'];
+               } else {
+                       $this->directory = $wgCacheDirectory;
+               }
+       }
+
+       public function get( $code, $key ) {
+               if ( !isset( $this->readers[$code] ) ) {
+                       $fileName = $this->getFileName( $code );
+
+                       $this->readers[$code] = false;
+                       if ( file_exists( $fileName ) ) {
+                               try {
+                                       $this->readers[$code] = CdbReader::open( $fileName );
+                               } catch ( CdbException $e ) {
+                                       wfDebug( __METHOD__ . ": unable to open cdb file for reading\n" );
+                               }
+                       }
+               }
+
+               if ( !$this->readers[$code] ) {
+                       return null;
+               } else {
+                       $value = false;
+                       try {
+                               $value = $this->readers[$code]->get( $key );
+                       } catch ( CdbException $e ) {
+                               wfDebug( __METHOD__ . ": CdbException caught, error message was "
+                                       . $e->getMessage() . "\n" );
+                       }
+                       if ( $value === false ) {
+                               return null;
+                       }
+
+                       return unserialize( $value );
+               }
+       }
+
+       public function startWrite( $code ) {
+               if ( !file_exists( $this->directory ) ) {
+                       if ( !wfMkdirParents( $this->directory, null, __METHOD__ ) ) {
+                               throw new MWException( "Unable to create the localisation store " .
+                                       "directory \"{$this->directory}\"" );
+                       }
+               }
+
+               // Close reader to stop permission errors on write
+               if ( !empty( $this->readers[$code] ) ) {
+                       $this->readers[$code]->close();
+               }
+
+               try {
+                       $this->writer = CdbWriter::open( $this->getFileName( $code ) );
+               } catch ( CdbException $e ) {
+                       throw new MWException( $e->getMessage() );
+               }
+               $this->currentLang = $code;
+       }
+
+       public function finishWrite() {
+               // Close the writer
+               try {
+                       $this->writer->close();
+               } catch ( CdbException $e ) {
+                       throw new MWException( $e->getMessage() );
+               }
+               $this->writer = null;
+               unset( $this->readers[$this->currentLang] );
+               $this->currentLang = null;
+       }
+
+       public function set( $key, $value ) {
+               if ( is_null( $this->writer ) ) {
+                       throw new MWException( __CLASS__ . ': must call startWrite() before calling set()' );
+               }
+               try {
+                       $this->writer->set( $key, serialize( $value ) );
+               } catch ( CdbException $e ) {
+                       throw new MWException( $e->getMessage() );
+               }
+       }
+
+       protected function getFileName( $code ) {
+               if ( strval( $code ) === '' || strpos( $code, '/' ) !== false ) {
+                       throw new MWException( __METHOD__ . ": Invalid language \"$code\"" );
+               }
+
+               return "{$this->directory}/l10n_cache-$code.cdb";
+       }
+
+}
diff --git a/includes/cache/localisation/LCStoreDB.php b/includes/cache/localisation/LCStoreDB.php
new file mode 100644 (file)
index 0000000..c350178
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * LCStore implementation which uses the standard DB functions to store data.
+ * This will work on any MediaWiki installation.
+ */
+class LCStoreDB implements LCStore {
+
+       /** @var string */
+       private $currentLang;
+       /** @var bool */
+       private $writesDone = false;
+       /** @var IDatabase */
+       private $dbw;
+       /** @var array */
+       private $batch = [];
+       /** @var bool */
+       private $readOnly = false;
+
+       public function get( $code, $key ) {
+               if ( $this->writesDone && $this->dbw ) {
+                       $db = $this->dbw; // see the changes in finishWrite()
+               } else {
+                       $db = wfGetDB( DB_SLAVE );
+               }
+
+               $value = $db->selectField(
+                       'l10n_cache',
+                       'lc_value',
+                       [ 'lc_lang' => $code, 'lc_key' => $key ],
+                       __METHOD__
+               );
+
+               return ( $value !== false ) ? unserialize( $db->decodeBlob( $value ) ) : null;
+       }
+
+       public function startWrite( $code ) {
+               if ( $this->readOnly ) {
+                       return;
+               } elseif ( !$code ) {
+                       throw new MWException( __METHOD__ . ": Invalid language \"$code\"" );
+               }
+
+               $this->dbw = wfGetDB( DB_MASTER );
+               $this->readOnly = $this->dbw->isReadOnly();
+
+               $this->currentLang = $code;
+               $this->batch = [];
+       }
+
+       public function finishWrite() {
+               if ( $this->readOnly ) {
+                       return;
+               } elseif ( is_null( $this->currentLang ) ) {
+                       throw new MWException( __CLASS__ . ': must call startWrite() before finishWrite()' );
+               }
+
+               $this->dbw->startAtomic( __METHOD__ );
+               try {
+                       $this->dbw->delete(
+                               'l10n_cache',
+                               [ 'lc_lang' => $this->currentLang ],
+                               __METHOD__
+                       );
+                       foreach ( array_chunk( $this->batch, 500 ) as $rows ) {
+                               $this->dbw->insert( 'l10n_cache', $rows, __METHOD__ );
+                       }
+                       $this->writesDone = true;
+               } catch ( DBQueryError $e ) {
+                       if ( $this->dbw->wasReadOnlyError() ) {
+                               $this->readOnly = true; // just avoid site down time
+                       } else {
+                               throw $e;
+                       }
+               }
+               $this->dbw->endAtomic( __METHOD__ );
+
+               $this->currentLang = null;
+               $this->batch = [];
+       }
+
+       public function set( $key, $value ) {
+               if ( $this->readOnly ) {
+                       return;
+               } elseif ( is_null( $this->currentLang ) ) {
+                       throw new MWException( __CLASS__ . ': must call startWrite() before set()' );
+               }
+
+               $this->batch[] = [
+                       'lc_lang' => $this->currentLang,
+                       'lc_key' => $key,
+                       'lc_value' => $this->dbw->encodeBlob( serialize( $value ) )
+               ];
+       }
+
+}
diff --git a/includes/cache/localisation/LCStoreNull.php b/includes/cache/localisation/LCStoreNull.php
new file mode 100644 (file)
index 0000000..62f88eb
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * Null store backend, used to avoid DB errors during install
+ */
+class LCStoreNull implements LCStore {
+
+       public function get( $code, $key ) {
+               return null;
+       }
+
+       public function startWrite( $code ) {
+       }
+
+       public function finishWrite() {
+       }
+
+       public function set( $key, $value ) {
+       }
+
+}
diff --git a/includes/cache/localisation/LCStoreStaticArray.php b/includes/cache/localisation/LCStoreStaticArray.php
new file mode 100644 (file)
index 0000000..1e20082
--- /dev/null
@@ -0,0 +1,140 @@
+<?php
+/**
+ *  Localisation cache storage based on PHP files and static arrays.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * @since 1.26
+ */
+class LCStoreStaticArray implements LCStore {
+       /** @var string|null Current language code. */
+       private $currentLang = null;
+
+       /** @var array Localisation data. */
+       private $data = [];
+
+       /** @var string File name. */
+       private $fname = null;
+
+       /** @var string Directory for cache files. */
+       private $directory;
+
+       public function __construct( $conf = [] ) {
+               global $wgCacheDirectory;
+
+               if ( isset( $conf['directory'] ) ) {
+                       $this->directory = $conf['directory'];
+               } else {
+                       $this->directory = $wgCacheDirectory;
+               }
+       }
+
+       public function startWrite( $code ) {
+               $this->currentLang = $code;
+               $this->fname = $this->directory . '/' . $code . '.l10n.php';
+               $this->data[$code] = [];
+               if ( file_exists( $this->fname ) ) {
+                       $this->data[$code] = require $this->fname;
+               }
+       }
+
+       public function set( $key, $value ) {
+               $this->data[$this->currentLang][$key] = self::encode( $value );
+       }
+
+       /**
+        * Encodes a value into an array format
+        *
+        * @param mixed $value
+        * @return array
+        * @throws RuntimeException
+        */
+       public static function encode( $value ) {
+               if ( is_scalar( $value ) || $value === null ) {
+                       // [V]alue
+                       return [ 'v', $value ];
+               }
+               if ( is_object( $value ) ) {
+                       // [S]erialized
+                       return [ 's', serialize( $value ) ];
+               }
+               if ( is_array( $value ) ) {
+                       // [A]rray
+                       return [ 'a', array_map( function ( $v ) {
+                               return LCStoreStaticArray::encode( $v );
+                       }, $value ) ];
+               }
+
+               throw new RuntimeException( 'Cannot encode ' . var_export( $value, true ) );
+       }
+
+       /**
+        * Decode something that was encoded with encode
+        *
+        * @param array $encoded
+        * @return array|mixed
+        * @throws RuntimeException
+        */
+       public static function decode( array $encoded ) {
+               $type = $encoded[0];
+               $data = $encoded[1];
+
+               switch ( $type ) {
+               case 'v':
+                       return $data;
+               case 's':
+                       return unserialize( $data );
+               case 'a':
+                       return array_map( function ( $v ) {
+                               return LCStoreStaticArray::decode( $v );
+                       }, $data );
+               default:
+                       throw new RuntimeException(
+                               'Unable to decode ' . var_export( $encoded, true ) );
+               }
+       }
+
+       public function finishWrite() {
+               file_put_contents(
+                       $this->fname,
+                       "<?php\n" .
+                       "// Generated by LCStoreStaticArray.php -- do not edit!\n" .
+                       "return " .
+                       var_export( $this->data[$this->currentLang], true ) . ';'
+               );
+               $this->currentLang = null;
+               $this->fname = null;
+       }
+
+       public function get( $code, $key ) {
+               if ( !array_key_exists( $code, $this->data ) ) {
+                       $fname = $this->directory . '/' . $code . '.l10n.php';
+                       if ( !file_exists( $fname ) ) {
+                               return null;
+                       }
+                       $this->data[$code] = require $fname;
+               }
+               $data = $this->data[$code];
+               if ( array_key_exists( $key, $data ) ) {
+                       return self::decode( $data[$key] );
+               }
+               return null;
+       }
+}
diff --git a/includes/cache/localisation/LocalisationCache.php b/includes/cache/localisation/LocalisationCache.php
new file mode 100644 (file)
index 0000000..dd7d81a
--- /dev/null
@@ -0,0 +1,1098 @@
+<?php
+/**
+ * Cache of the contents of localisation files.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+use Cdb\Reader as CdbReader;
+use Cdb\Writer as CdbWriter;
+use CLDRPluralRuleParser\Evaluator;
+
+/**
+ * Class for caching the contents of localisation files, Messages*.php
+ * and *.i18n.php.
+ *
+ * An instance of this class is available using Language::getLocalisationCache().
+ *
+ * The values retrieved from here are merged, containing items from extension
+ * files, core messages files and the language fallback sequence (e.g. zh-cn ->
+ * zh-hans -> en ). Some common errors are corrected, for example namespace
+ * names with spaces instead of underscores, but heavyweight processing, such
+ * as grammatical transformation, is done by the caller.
+ */
+class LocalisationCache {
+       const VERSION = 4;
+
+       /** Configuration associative array */
+       private $conf;
+
+       /**
+        * True if recaching should only be done on an explicit call to recache().
+        * Setting this reduces the overhead of cache freshness checking, which
+        * requires doing a stat() for every extension i18n file.
+        */
+       private $manualRecache = false;
+
+       /**
+        * True to treat all files as expired until they are regenerated by this object.
+        */
+       private $forceRecache = false;
+
+       /**
+        * The cache data. 3-d array, where the first key is the language code,
+        * the second key is the item key e.g. 'messages', and the third key is
+        * an item specific subkey index. Some items are not arrays and so for those
+        * items, there are no subkeys.
+        */
+       protected $data = [];
+
+       /**
+        * The persistent store object. An instance of LCStore.
+        *
+        * @var LCStore
+        */
+       private $store;
+
+       /**
+        * A 2-d associative array, code/key, where presence indicates that the item
+        * is loaded. Value arbitrary.
+        *
+        * For split items, if set, this indicates that all of the subitems have been
+        * loaded.
+        */
+       private $loadedItems = [];
+
+       /**
+        * A 3-d associative array, code/key/subkey, where presence indicates that
+        * the subitem is loaded. Only used for the split items, i.e. messages.
+        */
+       private $loadedSubitems = [];
+
+       /**
+        * An array where presence of a key indicates that that language has been
+        * initialised. Initialisation includes checking for cache expiry and doing
+        * any necessary updates.
+        */
+       private $initialisedLangs = [];
+
+       /**
+        * An array mapping non-existent pseudo-languages to fallback languages. This
+        * is filled by initShallowFallback() when data is requested from a language
+        * that lacks a Messages*.php file.
+        */
+       private $shallowFallbacks = [];
+
+       /**
+        * An array where the keys are codes that have been recached by this instance.
+        */
+       private $recachedLangs = [];
+
+       /**
+        * All item keys
+        */
+       static public $allKeys = [
+               'fallback', 'namespaceNames', 'bookstoreList',
+               'magicWords', 'messages', 'rtl', 'capitalizeAllNouns', 'digitTransformTable',
+               'separatorTransformTable', 'fallback8bitEncoding', 'linkPrefixExtension',
+               'linkTrail', 'linkPrefixCharset', 'namespaceAliases',
+               'dateFormats', 'datePreferences', 'datePreferenceMigrationMap',
+               'defaultDateFormat', 'extraUserToggles', 'specialPageAliases',
+               'imageFiles', 'preloadedMessages', 'namespaceGenderAliases',
+               'digitGroupingPattern', 'pluralRules', 'pluralRuleTypes', 'compiledPluralRules',
+       ];
+
+       /**
+        * Keys for items which consist of associative arrays, which may be merged
+        * by a fallback sequence.
+        */
+       static public $mergeableMapKeys = [ 'messages', 'namespaceNames',
+               'namespaceAliases', 'dateFormats', 'imageFiles', 'preloadedMessages'
+       ];
+
+       /**
+        * Keys for items which are a numbered array.
+        */
+       static public $mergeableListKeys = [ 'extraUserToggles' ];
+
+       /**
+        * Keys for items which contain an array of arrays of equivalent aliases
+        * for each subitem. The aliases may be merged by a fallback sequence.
+        */
+       static public $mergeableAliasListKeys = [ 'specialPageAliases' ];
+
+       /**
+        * Keys for items which contain an associative array, and may be merged if
+        * the primary value contains the special array key "inherit". That array
+        * key is removed after the first merge.
+        */
+       static public $optionalMergeKeys = [ 'bookstoreList' ];
+
+       /**
+        * Keys for items that are formatted like $magicWords
+        */
+       static public $magicWordKeys = [ 'magicWords' ];
+
+       /**
+        * Keys for items where the subitems are stored in the backend separately.
+        */
+       static public $splitKeys = [ 'messages' ];
+
+       /**
+        * Keys which are loaded automatically by initLanguage()
+        */
+       static public $preloadedKeys = [ 'dateFormats', 'namespaceNames' ];
+
+       /**
+        * Associative array of cached plural rules. The key is the language code,
+        * the value is an array of plural rules for that language.
+        */
+       private $pluralRules = null;
+
+       /**
+        * Associative array of cached plural rule types. The key is the language
+        * code, the value is an array of plural rule types for that language. For
+        * example, $pluralRuleTypes['ar'] = ['zero', 'one', 'two', 'few', 'many'].
+        * The index for each rule type matches the index for the rule in
+        * $pluralRules, thus allowing correlation between the two. The reason we
+        * don't just use the type names as the keys in $pluralRules is because
+        * Language::convertPlural applies the rules based on numeric order (or
+        * explicit numeric parameter), not based on the name of the rule type. For
+        * example, {{plural:count|wordform1|wordform2|wordform3}}, rather than
+        * {{plural:count|one=wordform1|two=wordform2|many=wordform3}}.
+        */
+       private $pluralRuleTypes = null;
+
+       private $mergeableKeys = null;
+
+       /**
+        * Constructor.
+        * For constructor parameters, see the documentation in DefaultSettings.php
+        * for $wgLocalisationCacheConf.
+        *
+        * @param array $conf
+        * @throws MWException
+        */
+       function __construct( $conf ) {
+               global $wgCacheDirectory;
+
+               $this->conf = $conf;
+               $storeConf = [];
+               if ( !empty( $conf['storeClass'] ) ) {
+                       $storeClass = $conf['storeClass'];
+               } else {
+                       switch ( $conf['store'] ) {
+                               case 'files':
+                               case 'file':
+                                       $storeClass = 'LCStoreCDB';
+                                       break;
+                               case 'db':
+                                       $storeClass = 'LCStoreDB';
+                                       break;
+                               case 'array':
+                                       $storeClass = 'LCStoreStaticArray';
+                                       break;
+                               case 'detect':
+                                       if ( !empty( $conf['storeDirectory'] ) ) {
+                                               $storeClass = 'LCStoreCDB';
+                                       } else {
+                                               $cacheDir = $wgCacheDirectory ?: wfTempDir();
+                                               if ( $cacheDir ) {
+                                                       $storeConf['directory'] = $cacheDir;
+                                                       $storeClass = 'LCStoreCDB';
+                                               } else {
+                                                       $storeClass = 'LCStoreDB';
+                                               }
+                                       }
+                                       break;
+                               default:
+                                       throw new MWException(
+                                               'Please set $wgLocalisationCacheConf[\'store\'] to something sensible.' );
+                       }
+               }
+
+               wfDebugLog( 'caches', get_class( $this ) . ": using store $storeClass" );
+               if ( !empty( $conf['storeDirectory'] ) ) {
+                       $storeConf['directory'] = $conf['storeDirectory'];
+               }
+
+               $this->store = new $storeClass( $storeConf );
+               foreach ( [ 'manualRecache', 'forceRecache' ] as $var ) {
+                       if ( isset( $conf[$var] ) ) {
+                               $this->$var = $conf[$var];
+                       }
+               }
+       }
+
+       /**
+        * Returns true if the given key is mergeable, that is, if it is an associative
+        * array which can be merged through a fallback sequence.
+        * @param string $key
+        * @return bool
+        */
+       public function isMergeableKey( $key ) {
+               if ( $this->mergeableKeys === null ) {
+                       $this->mergeableKeys = array_flip( array_merge(
+                               self::$mergeableMapKeys,
+                               self::$mergeableListKeys,
+                               self::$mergeableAliasListKeys,
+                               self::$optionalMergeKeys,
+                               self::$magicWordKeys
+                       ) );
+               }
+
+               return isset( $this->mergeableKeys[$key] );
+       }
+
+       /**
+        * Get a cache item.
+        *
+        * Warning: this may be slow for split items (messages), since it will
+        * need to fetch all of the subitems from the cache individually.
+        * @param string $code
+        * @param string $key
+        * @return mixed
+        */
+       public function getItem( $code, $key ) {
+               if ( !isset( $this->loadedItems[$code][$key] ) ) {
+                       $this->loadItem( $code, $key );
+               }
+
+               if ( $key === 'fallback' && isset( $this->shallowFallbacks[$code] ) ) {
+                       return $this->shallowFallbacks[$code];
+               }
+
+               return $this->data[$code][$key];
+       }
+
+       /**
+        * Get a subitem, for instance a single message for a given language.
+        * @param string $code
+        * @param string $key
+        * @param string $subkey
+        * @return mixed|null
+        */
+       public function getSubitem( $code, $key, $subkey ) {
+               if ( !isset( $this->loadedSubitems[$code][$key][$subkey] ) &&
+                       !isset( $this->loadedItems[$code][$key] )
+               ) {
+                       $this->loadSubitem( $code, $key, $subkey );
+               }
+
+               if ( isset( $this->data[$code][$key][$subkey] ) ) {
+                       return $this->data[$code][$key][$subkey];
+               } else {
+                       return null;
+               }
+       }
+
+       /**
+        * Get the list of subitem keys for a given item.
+        *
+        * This is faster than array_keys($lc->getItem(...)) for the items listed in
+        * self::$splitKeys.
+        *
+        * Will return null if the item is not found, or false if the item is not an
+        * array.
+        * @param string $code
+        * @param string $key
+        * @return bool|null|string
+        */
+       public function getSubitemList( $code, $key ) {
+               if ( in_array( $key, self::$splitKeys ) ) {
+                       return $this->getSubitem( $code, 'list', $key );
+               } else {
+                       $item = $this->getItem( $code, $key );
+                       if ( is_array( $item ) ) {
+                               return array_keys( $item );
+                       } else {
+                               return false;
+                       }
+               }
+       }
+
+       /**
+        * Load an item into the cache.
+        * @param string $code
+        * @param string $key
+        */
+       protected function loadItem( $code, $key ) {
+               if ( !isset( $this->initialisedLangs[$code] ) ) {
+                       $this->initLanguage( $code );
+               }
+
+               // Check to see if initLanguage() loaded it for us
+               if ( isset( $this->loadedItems[$code][$key] ) ) {
+                       return;
+               }
+
+               if ( isset( $this->shallowFallbacks[$code] ) ) {
+                       $this->loadItem( $this->shallowFallbacks[$code], $key );
+
+                       return;
+               }
+
+               if ( in_array( $key, self::$splitKeys ) ) {
+                       $subkeyList = $this->getSubitem( $code, 'list', $key );
+                       foreach ( $subkeyList as $subkey ) {
+                               if ( isset( $this->data[$code][$key][$subkey] ) ) {
+                                       continue;
+                               }
+                               $this->data[$code][$key][$subkey] = $this->getSubitem( $code, $key, $subkey );
+                       }
+               } else {
+                       $this->data[$code][$key] = $this->store->get( $code, $key );
+               }
+
+               $this->loadedItems[$code][$key] = true;
+       }
+
+       /**
+        * Load a subitem into the cache
+        * @param string $code
+        * @param string $key
+        * @param string $subkey
+        */
+       protected function loadSubitem( $code, $key, $subkey ) {
+               if ( !in_array( $key, self::$splitKeys ) ) {
+                       $this->loadItem( $code, $key );
+
+                       return;
+               }
+
+               if ( !isset( $this->initialisedLangs[$code] ) ) {
+                       $this->initLanguage( $code );
+               }
+
+               // Check to see if initLanguage() loaded it for us
+               if ( isset( $this->loadedItems[$code][$key] ) ||
+                       isset( $this->loadedSubitems[$code][$key][$subkey] )
+               ) {
+                       return;
+               }
+
+               if ( isset( $this->shallowFallbacks[$code] ) ) {
+                       $this->loadSubitem( $this->shallowFallbacks[$code], $key, $subkey );
+
+                       return;
+               }
+
+               $value = $this->store->get( $code, "$key:$subkey" );
+               $this->data[$code][$key][$subkey] = $value;
+               $this->loadedSubitems[$code][$key][$subkey] = true;
+       }
+
+       /**
+        * Returns true if the cache identified by $code is missing or expired.
+        *
+        * @param string $code
+        *
+        * @return bool
+        */
+       public function isExpired( $code ) {
+               if ( $this->forceRecache && !isset( $this->recachedLangs[$code] ) ) {
+                       wfDebug( __METHOD__ . "($code): forced reload\n" );
+
+                       return true;
+               }
+
+               $deps = $this->store->get( $code, 'deps' );
+               $keys = $this->store->get( $code, 'list' );
+               $preload = $this->store->get( $code, 'preload' );
+               // Different keys may expire separately for some stores
+               if ( $deps === null || $keys === null || $preload === null ) {
+                       wfDebug( __METHOD__ . "($code): cache missing, need to make one\n" );
+
+                       return true;
+               }
+
+               foreach ( $deps as $dep ) {
+                       // Because we're unserializing stuff from cache, we
+                       // could receive objects of classes that don't exist
+                       // anymore (e.g. uninstalled extensions)
+                       // When this happens, always expire the cache
+                       if ( !$dep instanceof CacheDependency || $dep->isExpired() ) {
+                               wfDebug( __METHOD__ . "($code): cache for $code expired due to " .
+                                       get_class( $dep ) . "\n" );
+
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
+       /**
+        * Initialise a language in this object. Rebuild the cache if necessary.
+        * @param string $code
+        * @throws MWException
+        */
+       protected function initLanguage( $code ) {
+               if ( isset( $this->initialisedLangs[$code] ) ) {
+                       return;
+               }
+
+               $this->initialisedLangs[$code] = true;
+
+               # If the code is of the wrong form for a Messages*.php file, do a shallow fallback
+               if ( !Language::isValidBuiltInCode( $code ) ) {
+                       $this->initShallowFallback( $code, 'en' );
+
+                       return;
+               }
+
+               # Recache the data if necessary
+               if ( !$this->manualRecache && $this->isExpired( $code ) ) {
+                       if ( Language::isSupportedLanguage( $code ) ) {
+                               $this->recache( $code );
+                       } elseif ( $code === 'en' ) {
+                               throw new MWException( 'MessagesEn.php is missing.' );
+                       } else {
+                               $this->initShallowFallback( $code, 'en' );
+                       }
+
+                       return;
+               }
+
+               # Preload some stuff
+               $preload = $this->getItem( $code, 'preload' );
+               if ( $preload === null ) {
+                       if ( $this->manualRecache ) {
+                               // No Messages*.php file. Do shallow fallback to en.
+                               if ( $code === 'en' ) {
+                                       throw new MWException( 'No localisation cache found for English. ' .
+                                               'Please run maintenance/rebuildLocalisationCache.php.' );
+                               }
+                               $this->initShallowFallback( $code, 'en' );
+
+                               return;
+                       } else {
+                               throw new MWException( 'Invalid or missing localisation cache.' );
+                       }
+               }
+               $this->data[$code] = $preload;
+               foreach ( $preload as $key => $item ) {
+                       if ( in_array( $key, self::$splitKeys ) ) {
+                               foreach ( $item as $subkey => $subitem ) {
+                                       $this->loadedSubitems[$code][$key][$subkey] = true;
+                               }
+                       } else {
+                               $this->loadedItems[$code][$key] = true;
+                       }
+               }
+       }
+
+       /**
+        * Create a fallback from one language to another, without creating a
+        * complete persistent cache.
+        * @param string $primaryCode
+        * @param string $fallbackCode
+        */
+       public function initShallowFallback( $primaryCode, $fallbackCode ) {
+               $this->data[$primaryCode] =& $this->data[$fallbackCode];
+               $this->loadedItems[$primaryCode] =& $this->loadedItems[$fallbackCode];
+               $this->loadedSubitems[$primaryCode] =& $this->loadedSubitems[$fallbackCode];
+               $this->shallowFallbacks[$primaryCode] = $fallbackCode;
+       }
+
+       /**
+        * Read a PHP file containing localisation data.
+        * @param string $_fileName
+        * @param string $_fileType
+        * @throws MWException
+        * @return array
+        */
+       protected function readPHPFile( $_fileName, $_fileType ) {
+               // Disable APC caching
+               MediaWiki\suppressWarnings();
+               $_apcEnabled = ini_set( 'apc.cache_by_default', '0' );
+               MediaWiki\restoreWarnings();
+
+               include $_fileName;
+
+               MediaWiki\suppressWarnings();
+               ini_set( 'apc.cache_by_default', $_apcEnabled );
+               MediaWiki\restoreWarnings();
+
+               if ( $_fileType == 'core' || $_fileType == 'extension' ) {
+                       $data = compact( self::$allKeys );
+               } elseif ( $_fileType == 'aliases' ) {
+                       $data = compact( 'aliases' );
+               } else {
+                       throw new MWException( __METHOD__ . ": Invalid file type: $_fileType" );
+               }
+
+               return $data;
+       }
+
+       /**
+        * Read a JSON file containing localisation messages.
+        * @param string $fileName Name of file to read
+        * @throws MWException If there is a syntax error in the JSON file
+        * @return array Array with a 'messages' key, or empty array if the file doesn't exist
+        */
+       public function readJSONFile( $fileName ) {
+
+               if ( !is_readable( $fileName ) ) {
+                       return [];
+               }
+
+               $json = file_get_contents( $fileName );
+               if ( $json === false ) {
+                       return [];
+               }
+
+               $data = FormatJson::decode( $json, true );
+               if ( $data === null ) {
+
+                       throw new MWException( __METHOD__ . ": Invalid JSON file: $fileName" );
+               }
+
+               // Remove keys starting with '@', they're reserved for metadata and non-message data
+               foreach ( $data as $key => $unused ) {
+                       if ( $key === '' || $key[0] === '@' ) {
+                               unset( $data[$key] );
+                       }
+               }
+
+               // The JSON format only supports messages, none of the other variables, so wrap the data
+               return [ 'messages' => $data ];
+       }
+
+       /**
+        * Get the compiled plural rules for a given language from the XML files.
+        * @since 1.20
+        * @param string $code
+        * @return array|null
+        */
+       public function getCompiledPluralRules( $code ) {
+               $rules = $this->getPluralRules( $code );
+               if ( $rules === null ) {
+                       return null;
+               }
+               try {
+                       $compiledRules = Evaluator::compile( $rules );
+               } catch ( CLDRPluralRuleError $e ) {
+                       wfDebugLog( 'l10n', $e->getMessage() );
+
+                       return [];
+               }
+
+               return $compiledRules;
+       }
+
+       /**
+        * Get the plural rules for a given language from the XML files.
+        * Cached.
+        * @since 1.20
+        * @param string $code
+        * @return array|null
+        */
+       public function getPluralRules( $code ) {
+               if ( $this->pluralRules === null ) {
+                       $this->loadPluralFiles();
+               }
+               if ( !isset( $this->pluralRules[$code] ) ) {
+                       return null;
+               } else {
+                       return $this->pluralRules[$code];
+               }
+       }
+
+       /**
+        * Get the plural rule types for a given language from the XML files.
+        * Cached.
+        * @since 1.22
+        * @param string $code
+        * @return array|null
+        */
+       public function getPluralRuleTypes( $code ) {
+               if ( $this->pluralRuleTypes === null ) {
+                       $this->loadPluralFiles();
+               }
+               if ( !isset( $this->pluralRuleTypes[$code] ) ) {
+                       return null;
+               } else {
+                       return $this->pluralRuleTypes[$code];
+               }
+       }
+
+       /**
+        * Load the plural XML files.
+        */
+       protected function loadPluralFiles() {
+               global $IP;
+               $cldrPlural = "$IP/languages/data/plurals.xml";
+               $mwPlural = "$IP/languages/data/plurals-mediawiki.xml";
+               // Load CLDR plural rules
+               $this->loadPluralFile( $cldrPlural );
+               if ( file_exists( $mwPlural ) ) {
+                       // Override or extend
+                       $this->loadPluralFile( $mwPlural );
+               }
+       }
+
+       /**
+        * Load a plural XML file with the given filename, compile the relevant
+        * rules, and save the compiled rules in a process-local cache.
+        *
+        * @param string $fileName
+        * @throws MWException
+        */
+       protected function loadPluralFile( $fileName ) {
+               // Use file_get_contents instead of DOMDocument::load (T58439)
+               $xml = file_get_contents( $fileName );
+               if ( !$xml ) {
+                       throw new MWException( "Unable to read plurals file $fileName" );
+               }
+               $doc = new DOMDocument;
+               $doc->loadXML( $xml );
+               $rulesets = $doc->getElementsByTagName( "pluralRules" );
+               foreach ( $rulesets as $ruleset ) {
+                       $codes = $ruleset->getAttribute( 'locales' );
+                       $rules = [];
+                       $ruleTypes = [];
+                       $ruleElements = $ruleset->getElementsByTagName( "pluralRule" );
+                       foreach ( $ruleElements as $elt ) {
+                               $ruleType = $elt->getAttribute( 'count' );
+                               if ( $ruleType === 'other' ) {
+                                       // Don't record "other" rules, which have an empty condition
+                                       continue;
+                               }
+                               $rules[] = $elt->nodeValue;
+                               $ruleTypes[] = $ruleType;
+                       }
+                       foreach ( explode( ' ', $codes ) as $code ) {
+                               $this->pluralRules[$code] = $rules;
+                               $this->pluralRuleTypes[$code] = $ruleTypes;
+                       }
+               }
+       }
+
+       /**
+        * Read the data from the source files for a given language, and register
+        * the relevant dependencies in the $deps array. If the localisation
+        * exists, the data array is returned, otherwise false is returned.
+        *
+        * @param string $code
+        * @param array $deps
+        * @return array
+        */
+       protected function readSourceFilesAndRegisterDeps( $code, &$deps ) {
+               global $IP;
+
+               // This reads in the PHP i18n file with non-messages l10n data
+               $fileName = Language::getMessagesFileName( $code );
+               if ( !file_exists( $fileName ) ) {
+                       $data = [];
+               } else {
+                       $deps[] = new FileDependency( $fileName );
+                       $data = $this->readPHPFile( $fileName, 'core' );
+               }
+
+               # Load CLDR plural rules for JavaScript
+               $data['pluralRules'] = $this->getPluralRules( $code );
+               # And for PHP
+               $data['compiledPluralRules'] = $this->getCompiledPluralRules( $code );
+               # Load plural rule types
+               $data['pluralRuleTypes'] = $this->getPluralRuleTypes( $code );
+
+               $deps['plurals'] = new FileDependency( "$IP/languages/data/plurals.xml" );
+               $deps['plurals-mw'] = new FileDependency( "$IP/languages/data/plurals-mediawiki.xml" );
+
+               return $data;
+       }
+
+       /**
+        * Merge two localisation values, a primary and a fallback, overwriting the
+        * primary value in place.
+        * @param string $key
+        * @param mixed $value
+        * @param mixed $fallbackValue
+        */
+       protected function mergeItem( $key, &$value, $fallbackValue ) {
+               if ( !is_null( $value ) ) {
+                       if ( !is_null( $fallbackValue ) ) {
+                               if ( in_array( $key, self::$mergeableMapKeys ) ) {
+                                       $value = $value + $fallbackValue;
+                               } elseif ( in_array( $key, self::$mergeableListKeys ) ) {
+                                       $value = array_unique( array_merge( $fallbackValue, $value ) );
+                               } elseif ( in_array( $key, self::$mergeableAliasListKeys ) ) {
+                                       $value = array_merge_recursive( $value, $fallbackValue );
+                               } elseif ( in_array( $key, self::$optionalMergeKeys ) ) {
+                                       if ( !empty( $value['inherit'] ) ) {
+                                               $value = array_merge( $fallbackValue, $value );
+                                       }
+
+                                       if ( isset( $value['inherit'] ) ) {
+                                               unset( $value['inherit'] );
+                                       }
+                               } elseif ( in_array( $key, self::$magicWordKeys ) ) {
+                                       $this->mergeMagicWords( $value, $fallbackValue );
+                               }
+                       }
+               } else {
+                       $value = $fallbackValue;
+               }
+       }
+
+       /**
+        * @param mixed $value
+        * @param mixed $fallbackValue
+        */
+       protected function mergeMagicWords( &$value, $fallbackValue ) {
+               foreach ( $fallbackValue as $magicName => $fallbackInfo ) {
+                       if ( !isset( $value[$magicName] ) ) {
+                               $value[$magicName] = $fallbackInfo;
+                       } else {
+                               $oldSynonyms = array_slice( $fallbackInfo, 1 );
+                               $newSynonyms = array_slice( $value[$magicName], 1 );
+                               $synonyms = array_values( array_unique( array_merge(
+                                       $newSynonyms, $oldSynonyms ) ) );
+                               $value[$magicName] = array_merge( [ $fallbackInfo[0] ], $synonyms );
+                       }
+               }
+       }
+
+       /**
+        * Given an array mapping language code to localisation value, such as is
+        * found in extension *.i18n.php files, iterate through a fallback sequence
+        * to merge the given data with an existing primary value.
+        *
+        * Returns true if any data from the extension array was used, false
+        * otherwise.
+        * @param array $codeSequence
+        * @param string $key
+        * @param mixed $value
+        * @param mixed $fallbackValue
+        * @return bool
+        */
+       protected function mergeExtensionItem( $codeSequence, $key, &$value, $fallbackValue ) {
+               $used = false;
+               foreach ( $codeSequence as $code ) {
+                       if ( isset( $fallbackValue[$code] ) ) {
+                               $this->mergeItem( $key, $value, $fallbackValue[$code] );
+                               $used = true;
+                       }
+               }
+
+               return $used;
+       }
+
+       /**
+        * Gets the combined list of messages dirs from
+        * core and extensions
+        *
+        * @since 1.25
+        * @return array
+        */
+       public function getMessagesDirs() {
+               global $wgMessagesDirs, $IP;
+               return [
+                       'core' => "$IP/languages/i18n",
+                       'api' => "$IP/includes/api/i18n",
+                       'oojs-ui' => "$IP/resources/lib/oojs-ui/i18n",
+               ] + $wgMessagesDirs;
+       }
+
+       /**
+        * Load localisation data for a given language for both core and extensions
+        * and save it to the persistent cache store and the process cache
+        * @param string $code
+        * @throws MWException
+        */
+       public function recache( $code ) {
+               global $wgExtensionMessagesFiles;
+
+               if ( !$code ) {
+                       throw new MWException( "Invalid language code requested" );
+               }
+               $this->recachedLangs[$code] = true;
+
+               # Initial values
+               $initialData = array_fill_keys( self::$allKeys, null );
+               $coreData = $initialData;
+               $deps = [];
+
+               # Load the primary localisation from the source file
+               $data = $this->readSourceFilesAndRegisterDeps( $code, $deps );
+               if ( $data === false ) {
+                       wfDebug( __METHOD__ . ": no localisation file for $code, using fallback to en\n" );
+                       $coreData['fallback'] = 'en';
+               } else {
+                       wfDebug( __METHOD__ . ": got localisation for $code from source\n" );
+
+                       # Merge primary localisation
+                       foreach ( $data as $key => $value ) {
+                               $this->mergeItem( $key, $coreData[$key], $value );
+                       }
+               }
+
+               # Fill in the fallback if it's not there already
+               if ( is_null( $coreData['fallback'] ) ) {
+                       $coreData['fallback'] = $code === 'en' ? false : 'en';
+               }
+               if ( $coreData['fallback'] === false ) {
+                       $coreData['fallbackSequence'] = [];
+               } else {
+                       $coreData['fallbackSequence'] = array_map( 'trim', explode( ',', $coreData['fallback'] ) );
+                       $len = count( $coreData['fallbackSequence'] );
+
+                       # Ensure that the sequence ends at en
+                       if ( $coreData['fallbackSequence'][$len - 1] !== 'en' ) {
+                               $coreData['fallbackSequence'][] = 'en';
+                       }
+               }
+
+               $codeSequence = array_merge( [ $code ], $coreData['fallbackSequence'] );
+               $messageDirs = $this->getMessagesDirs();
+
+               # Load non-JSON localisation data for extensions
+               $extensionData = array_fill_keys( $codeSequence, $initialData );
+               foreach ( $wgExtensionMessagesFiles as $extension => $fileName ) {
+                       if ( isset( $messageDirs[$extension] ) ) {
+                               # This extension has JSON message data; skip the PHP shim
+                               continue;
+                       }
+
+                       $data = $this->readPHPFile( $fileName, 'extension' );
+                       $used = false;
+
+                       foreach ( $data as $key => $item ) {
+                               foreach ( $codeSequence as $csCode ) {
+                                       if ( isset( $item[$csCode] ) ) {
+                                               $this->mergeItem( $key, $extensionData[$csCode][$key], $item[$csCode] );
+                                               $used = true;
+                                       }
+                               }
+                       }
+
+                       if ( $used ) {
+                               $deps[] = new FileDependency( $fileName );
+                       }
+               }
+
+               # Load the localisation data for each fallback, then merge it into the full array
+               $allData = $initialData;
+               foreach ( $codeSequence as $csCode ) {
+                       $csData = $initialData;
+
+                       # Load core messages and the extension localisations.
+                       foreach ( $messageDirs as $dirs ) {
+                               foreach ( (array)$dirs as $dir ) {
+                                       $fileName = "$dir/$csCode.json";
+                                       $data = $this->readJSONFile( $fileName );
+
+                                       foreach ( $data as $key => $item ) {
+                                               $this->mergeItem( $key, $csData[$key], $item );
+                                       }
+
+                                       $deps[] = new FileDependency( $fileName );
+                               }
+                       }
+
+                       # Merge non-JSON extension data
+                       if ( isset( $extensionData[$csCode] ) ) {
+                               foreach ( $extensionData[$csCode] as $key => $item ) {
+                                       $this->mergeItem( $key, $csData[$key], $item );
+                               }
+                       }
+
+                       if ( $csCode === $code ) {
+                               # Merge core data into extension data
+                               foreach ( $coreData as $key => $item ) {
+                                       $this->mergeItem( $key, $csData[$key], $item );
+                               }
+                       } else {
+                               # Load the secondary localisation from the source file to
+                               # avoid infinite cycles on cyclic fallbacks
+                               $fbData = $this->readSourceFilesAndRegisterDeps( $csCode, $deps );
+                               if ( $fbData !== false ) {
+                                       # Only merge the keys that make sense to merge
+                                       foreach ( self::$allKeys as $key ) {
+                                               if ( !isset( $fbData[$key] ) ) {
+                                                       continue;
+                                               }
+
+                                               if ( is_null( $coreData[$key] ) || $this->isMergeableKey( $key ) ) {
+                                                       $this->mergeItem( $key, $csData[$key], $fbData[$key] );
+                                               }
+                                       }
+                               }
+                       }
+
+                       # Allow extensions an opportunity to adjust the data for this
+                       # fallback
+                       Hooks::run( 'LocalisationCacheRecacheFallback', [ $this, $csCode, &$csData ] );
+
+                       # Merge the data for this fallback into the final array
+                       if ( $csCode === $code ) {
+                               $allData = $csData;
+                       } else {
+                               foreach ( self::$allKeys as $key ) {
+                                       if ( !isset( $csData[$key] ) ) {
+                                               continue;
+                                       }
+
+                                       if ( is_null( $allData[$key] ) || $this->isMergeableKey( $key ) ) {
+                                               $this->mergeItem( $key, $allData[$key], $csData[$key] );
+                                       }
+                               }
+                       }
+               }
+
+               # Add cache dependencies for any referenced globals
+               $deps['wgExtensionMessagesFiles'] = new GlobalDependency( 'wgExtensionMessagesFiles' );
+               // $wgMessagesDirs is used in LocalisationCache::getMessagesDirs()
+               $deps['wgMessagesDirs'] = new GlobalDependency( 'wgMessagesDirs' );
+               $deps['version'] = new ConstantDependency( 'LocalisationCache::VERSION' );
+
+               # Add dependencies to the cache entry
+               $allData['deps'] = $deps;
+
+               # Replace spaces with underscores in namespace names
+               $allData['namespaceNames'] = str_replace( ' ', '_', $allData['namespaceNames'] );
+
+               # And do the same for special page aliases. $page is an array.
+               foreach ( $allData['specialPageAliases'] as &$page ) {
+                       $page = str_replace( ' ', '_', $page );
+               }
+               # Decouple the reference to prevent accidental damage
+               unset( $page );
+
+               # If there were no plural rules, return an empty array
+               if ( $allData['pluralRules'] === null ) {
+                       $allData['pluralRules'] = [];
+               }
+               if ( $allData['compiledPluralRules'] === null ) {
+                       $allData['compiledPluralRules'] = [];
+               }
+               # If there were no plural rule types, return an empty array
+               if ( $allData['pluralRuleTypes'] === null ) {
+                       $allData['pluralRuleTypes'] = [];
+               }
+
+               # Set the list keys
+               $allData['list'] = [];
+               foreach ( self::$splitKeys as $key ) {
+                       $allData['list'][$key] = array_keys( $allData[$key] );
+               }
+               # Run hooks
+               $purgeBlobs = true;
+               Hooks::run( 'LocalisationCacheRecache', [ $this, $code, &$allData, &$purgeBlobs ] );
+
+               if ( is_null( $allData['namespaceNames'] ) ) {
+                       throw new MWException( __METHOD__ . ': Localisation data failed sanity check! ' .
+                               'Check that your languages/messages/MessagesEn.php file is intact.' );
+               }
+
+               # Set the preload key
+               $allData['preload'] = $this->buildPreload( $allData );
+
+               # Save to the process cache and register the items loaded
+               $this->data[$code] = $allData;
+               foreach ( $allData as $key => $item ) {
+                       $this->loadedItems[$code][$key] = true;
+               }
+
+               # Save to the persistent cache
+               $this->store->startWrite( $code );
+               foreach ( $allData as $key => $value ) {
+                       if ( in_array( $key, self::$splitKeys ) ) {
+                               foreach ( $value as $subkey => $subvalue ) {
+                                       $this->store->set( "$key:$subkey", $subvalue );
+                               }
+                       } else {
+                               $this->store->set( $key, $value );
+                       }
+               }
+               $this->store->finishWrite();
+
+               # Clear out the MessageBlobStore
+               # HACK: If using a null (i.e. disabled) storage backend, we
+               # can't write to the MessageBlobStore either
+               if ( $purgeBlobs && !$this->store instanceof LCStoreNull ) {
+                       $blobStore = new MessageBlobStore();
+                       $blobStore->clear();
+               }
+
+       }
+
+       /**
+        * Build the preload item from the given pre-cache data.
+        *
+        * The preload item will be loaded automatically, improving performance
+        * for the commonly-requested items it contains.
+        * @param array $data
+        * @return array
+        */
+       protected function buildPreload( $data ) {
+               $preload = [ 'messages' => [] ];
+               foreach ( self::$preloadedKeys as $key ) {
+                       $preload[$key] = $data[$key];
+               }
+
+               foreach ( $data['preloadedMessages'] as $subkey ) {
+                       if ( isset( $data['messages'][$subkey] ) ) {
+                               $subitem = $data['messages'][$subkey];
+                       } else {
+                               $subitem = null;
+                       }
+                       $preload['messages'][$subkey] = $subitem;
+               }
+
+               return $preload;
+       }
+
+       /**
+        * Unload the data for a given language from the object cache.
+        * Reduces memory usage.
+        * @param string $code
+        */
+       public function unload( $code ) {
+               unset( $this->data[$code] );
+               unset( $this->loadedItems[$code] );
+               unset( $this->loadedSubitems[$code] );
+               unset( $this->initialisedLangs[$code] );
+               unset( $this->shallowFallbacks[$code] );
+
+               foreach ( $this->shallowFallbacks as $shallowCode => $fbCode ) {
+                       if ( $fbCode === $code ) {
+                               $this->unload( $shallowCode );
+                       }
+               }
+       }
+
+       /**
+        * Unload all data
+        */
+       public function unloadAll() {
+               foreach ( $this->initialisedLangs as $lang => $unused ) {
+                       $this->unload( $lang );
+               }
+       }
+
+       /**
+        * Disable the storage backend
+        */
+       public function disableBackend() {
+               $this->store = new LCStoreNull;
+               $this->manualRecache = false;
+       }
+
+}
diff --git a/includes/cache/localisation/LocalisationCacheBulkLoad.php b/includes/cache/localisation/LocalisationCacheBulkLoad.php
new file mode 100644 (file)
index 0000000..30c7d37
--- /dev/null
@@ -0,0 +1,126 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * A localisation cache optimised for loading large amounts of data for many
+ * languages. Used by rebuildLocalisationCache.php.
+ */
+class LocalisationCacheBulkLoad extends LocalisationCache {
+
+       /**
+        * A cache of the contents of data files.
+        * Core files are serialized to avoid using ~1GB of RAM during a recache.
+        */
+       private $fileCache = [];
+
+       /**
+        * Most recently used languages. Uses the linked-list aspect of PHP hashtables
+        * to keep the most recently used language codes at the end of the array, and
+        * the language codes that are ready to be deleted at the beginning.
+        */
+       private $mruLangs = [];
+
+       /**
+        * Maximum number of languages that may be loaded into $this->data
+        */
+       private $maxLoadedLangs = 10;
+
+       /**
+        * @param string $fileName
+        * @param string $fileType
+        * @return array|mixed
+        */
+       protected function readPHPFile( $fileName, $fileType ) {
+               $serialize = $fileType === 'core';
+               if ( !isset( $this->fileCache[$fileName][$fileType] ) ) {
+                       $data = parent::readPHPFile( $fileName, $fileType );
+
+                       if ( $serialize ) {
+                               $encData = serialize( $data );
+                       } else {
+                               $encData = $data;
+                       }
+
+                       $this->fileCache[$fileName][$fileType] = $encData;
+
+                       return $data;
+               } elseif ( $serialize ) {
+                       return unserialize( $this->fileCache[$fileName][$fileType] );
+               } else {
+                       return $this->fileCache[$fileName][$fileType];
+               }
+       }
+
+       /**
+        * @param string $code
+        * @param string $key
+        * @return mixed
+        */
+       public function getItem( $code, $key ) {
+               unset( $this->mruLangs[$code] );
+               $this->mruLangs[$code] = true;
+
+               return parent::getItem( $code, $key );
+       }
+
+       /**
+        * @param string $code
+        * @param string $key
+        * @param string $subkey
+        * @return mixed
+        */
+       public function getSubitem( $code, $key, $subkey ) {
+               unset( $this->mruLangs[$code] );
+               $this->mruLangs[$code] = true;
+
+               return parent::getSubitem( $code, $key, $subkey );
+       }
+
+       /**
+        * @param string $code
+        */
+       public function recache( $code ) {
+               parent::recache( $code );
+               unset( $this->mruLangs[$code] );
+               $this->mruLangs[$code] = true;
+               $this->trimCache();
+       }
+
+       /**
+        * @param string $code
+        */
+       public function unload( $code ) {
+               unset( $this->mruLangs[$code] );
+               parent::unload( $code );
+       }
+
+       /**
+        * Unload cached languages until there are less than $this->maxLoadedLangs
+        */
+       protected function trimCache() {
+               while ( count( $this->data ) > $this->maxLoadedLangs && count( $this->mruLangs ) ) {
+                       reset( $this->mruLangs );
+                       $code = key( $this->mruLangs );
+                       wfDebug( __METHOD__ . ": unloading $code\n" );
+                       $this->unload( $code );
+               }
+       }
+
+}
index b6a0868..9f68338 100644 (file)
@@ -461,6 +461,7 @@ class RecentChange {
         */
        public function doMarkPatrolled( User $user, $auto = false, $tags = null ) {
                global $wgUseRCPatrol, $wgUseNPPatrol, $wgUseFilePatrol;
+
                $errors = [];
                // If recentchanges patrol is disabled, only new pages or new file versions
                // can be patrolled, provided the appropriate config variable is set
@@ -497,8 +498,8 @@ class RecentChange {
                PatrolLog::record( $this, $auto, $user, $tags );
 
                Hooks::run(
-                                       'MarkPatrolledComplete',
-                                       [ $this->getAttribute( 'rc_id' ), &$user, false, $auto ]
+                       'MarkPatrolledComplete',
+                       [ $this->getAttribute( 'rc_id' ), &$user, false, $auto ]
                );
 
                return [];
index 7f60f2e..ad939a0 100644 (file)
@@ -21,7 +21,8 @@
 namespace MediaWiki\Logger\Monolog;
 
 /**
- * Injects `wfHostname()`, `wfWikiID()` and `$wgVersion` in all records.
+ * Annotate log records with request-global metadata, such as the hostname,
+ * wiki / request ID, and MediaWiki version.
  *
  * @since 1.25
  * @author Bryan Davis <bd808@wikimedia.org>
@@ -41,6 +42,7 @@ class WikiProcessor {
                                'host' => wfHostname(),
                                'wiki' => wfWikiID(),
                                'mwversion' => $wgVersion,
+                               'reqId' => \WebRequest::getRequestId(),
                        ]
                );
                return $record;
index e1d7e6c..bebd915 100644 (file)
@@ -141,7 +141,7 @@ class MWException extends Exception {
                        nl2br( htmlspecialchars( MWExceptionHandler::getRedactedTraceAsString( $this ) ) ) .
                        "</p>\n";
                } else {
-                       $logId = MWExceptionHandler::getLogId( $this );
+                       $logId = WebRequest::getRequestId();
                        $type = get_class( $this );
                        return "<div class=\"errorbox\">" .
                        '[' . $logId . '] ' .
index b71f92c..63adc29 100644 (file)
@@ -445,14 +445,13 @@ TXT;
         * $wgShowExceptionDetails is set to false), to the entry in the debug log.
         *
         * @since 1.22
+        * @deprecated since 1.27: Exception IDs are synonymous with request IDs.
         * @param Exception|Throwable $e
         * @return string
         */
        public static function getLogId( $e ) {
-               if ( !isset( $e->_mwLogId ) ) {
-                       $e->_mwLogId = wfRandomString( 8 );
-               }
-               return $e->_mwLogId;
+               wfDeprecated( __METHOD__, '1.27' );
+               return WebRequest::getRequestId();
        }
 
        /**
@@ -478,7 +477,7 @@ TXT;
         * @return string
         */
        public static function getLogMessage( $e ) {
-               $id = self::getLogId( $e );
+               $id = WebRequest::getRequestId();
                $type = get_class( $e );
                $file = $e->getFile();
                $line = $e->getLine();
@@ -489,9 +488,9 @@ TXT;
        }
 
        public static function getPublicLogMessage( Exception $e ) {
-               $logId = self::getLogId( $e );
+               $reqId = WebRequest::getRequestId();
                $type = get_class( $e );
-               return '[' . $logId . '] '
+               return '[' . $reqId . '] '
                        . gmdate( 'Y-m-d H:i:s' ) . ': '
                        . 'Fatal exception of type ' . $type;
        }
@@ -509,7 +508,7 @@ TXT;
        public static function getLogContext( $e ) {
                return [
                        'exception' => $e,
-                       'exception_id' => static::getLogId( $e ),
+                       'exception_id' => WebRequest::getRequestId(),
                ];
        }
 
@@ -527,7 +526,7 @@ TXT;
        public static function getStructuredExceptionData( $e ) {
                global $wgLogExceptionBacktrace;
                $data = [
-                       'id' => self::getLogId( $e ),
+                       'id' => WebRequest::getRequestId(),
                        'type' => get_class( $e ),
                        'file' => $e->getFile(),
                        'line' => $e->getLine(),
index d24aa24..8248699 100644 (file)
@@ -226,7 +226,8 @@ class LocalRepo extends FileRepo {
                                return ( $row && $row->rd_namespace == NS_FILE )
                                        ? Title::makeTitle( $row->rd_namespace, $row->rd_title )->getDBkey()
                                        : ''; // negative cache
-                       }
+                       },
+                       [ 'pcTTL' => 30 ]
                );
 
                // @note: also checks " " for b/c
index 609a8fb..3f7eadb 100644 (file)
@@ -242,7 +242,7 @@ class LocalFile extends File {
         * Try to load file metadata from memcached. Returns true on success.
         * @return bool
         */
-       function loadFromCache() {
+       private function loadFromCache() {
                $this->dataLoaded = false;
                $this->extraDataLoaded = false;
                $key = $this->getCacheKey();
@@ -279,7 +279,7 @@ class LocalFile extends File {
        /**
         * Save the file metadata to memcached
         */
-       function saveToCache() {
+       private function saveToCache() {
                $this->load();
 
                $key = $this->getCacheKey();
index 16417fc..1c4daf3 100644 (file)
@@ -79,13 +79,14 @@ class HTMLButtonField extends HTMLFormField {
                        'id' => $this->mID,
                        'type' => $this->buttonType,
                        'name' => $this->mName,
-                       'value' => $value,
+                       'value' => $this->getDefault(),
                ] + $this->getAttributes( [ 'disabled', 'tabindex' ] );
 
                if ( $this->isBadIE() ) {
                        return Html::element( 'input', $attr );
                } else {
-                       return Html::rawElement( 'button', $attr, $this->buttonLabel ?: htmlspecialchars( $value ) );
+                       return Html::rawElement( 'button', $attr,
+                               $this->buttonLabel ?: htmlspecialchars( $this->getDefault() ) );
                }
        }
 
@@ -97,10 +98,10 @@ class HTMLButtonField extends HTMLFormField {
        public function getInputOOUI( $value ) {
                return new OOUI\ButtonInputWidget( [
                        'name' => $this->mName,
-                       'value' => $value,
+                       'value' => $this->getDefault(),
                        'label' => !$this->isBadIE() && $this->buttonLabel
                                ? new OOUI\HtmlSnippet( $this->buttonLabel )
-                               : $value,
+                               : $this->getDefault(),
                        'type' => $this->buttonType,
                        'classes' => [ 'mw-htmlform-submit', $this->mClass ],
                        'id' => $this->mID,
index ba43244..bf46e55 100644 (file)
@@ -198,6 +198,13 @@ class HTMLForm extends ContextSource {
         */
        protected $mAction = false;
 
+       /**
+        * Form attribute autocomplete. false does not set the attribute
+        * @since 1.27
+        * @var bool|string
+        */
+       protected $mAutocomplete = false;
+
        protected $mUseMultipart = false;
        protected $mHiddenFields = [];
        protected $mButtons = [];
@@ -996,6 +1003,9 @@ class HTMLForm extends ContextSource {
                if ( !empty( $this->mId ) ) {
                        $attribs['id'] = $this->mId;
                }
+               if ( !empty( $this->mAutocomplete ) ) {
+                       $attribs['autocomplete'] = $this->mAutocomplete;
+               }
                return $attribs;
        }
 
@@ -1677,4 +1687,20 @@ class HTMLForm extends ContextSource {
 
                return $this->getTitle()->getLocalURL();
        }
+
+       /**
+        * Set the value for the autocomplete attribute of the form.
+        * When set to false (which is the default state), the attribute get not set.
+        *
+        * @since 1.27
+        *
+        * @param string|bool $autocomplete
+        *
+        * @return HTMLForm $this for chaining calls
+        */
+       public function setAutocomplete( $autocomplete ) {
+               $this->mAutocomplete = $autocomplete;
+
+               return $this;
+       }
 }
index a9c7632..4c8ce82 100644 (file)
@@ -179,7 +179,7 @@ abstract class HTMLFormField {
                                        return true;
 
                                case 'OR':
-                                       foreach ( $params as $p ) {
+                                       foreach ( $params as $i => $p ) {
                                                if ( !is_array( $p ) ) {
                                                        throw new MWException(
                                                                "Expected array, found " . gettype( $p ) . " at index $i"
@@ -205,7 +205,7 @@ abstract class HTMLFormField {
                                        return false;
 
                                case 'NOR':
-                                       foreach ( $params as $p ) {
+                                       foreach ( $params as $i => $p ) {
                                                if ( !is_array( $p ) ) {
                                                        throw new MWException(
                                                                "Expected array, found " . gettype( $p ) . " at index $i"
index 6d6b1c6..80105f2 100644 (file)
        "config-admin-error-bademail": "Электрон почта адресы дөрөҫ түгел",
        "config-subscribe": "[https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce MediaWiki яңы версиялары барлыҡҡа килеүен таратыу яңылыҡтарына] яҙылырға.",
        "config-subscribe-help": "Был хәбәрҙәре аҙ булған таратыу исемлеге хәүефһеҙлек проблемалары тураһында хәбәрҙәр һәм яғы сығарылыштар өсөн анонс булараҡ файҙаланыла. \nҺеҙгә уға яҙылырға һәм яңы версиялар сыҡҡан һайын MediaWiki-ҙы яңыртып торорға кәрәк.",
-       "config-subscribe-noemail": "ҺеÒ\99 Ñ\8fÒ£Ñ\8b Ñ\81Ñ\8bÒ\93аÑ\80Ñ\8bлÑ\8bÑ\88Ñ\82аÑ\80 Ñ\82Ñ\83Ñ\80аһÑ\8bнда Ñ\85Ó\99бÓ\99Ñ\80 ÐµÐ±Ó\99Ñ\80еү Ð¸Ñ\81емлегенÓ\99 Ñ\8dлекÑ\82Ñ\80он Ð°Ð´Ñ\80еÑ\81Ñ\8bÒ\93Ñ\8bÒ\99Ò\99Ñ\8b ÐºÒ¯Ñ\80Ò»Ó\99Ñ\82мÓ\99й Ð³ÐµÐ½Ó\99 Ñ\8fÒ\99Ñ\8bлÑ\8bÑ\80Ò\93а Ñ\82Ñ\8bÑ\80Ñ\8bÑ\88Ñ\82Ñ\8bÒ\93Ñ\8bÒ\99.   \nÓ\98гÓ\99Ñ\80 Ñ\85Ó\99бÓ\99Ñ\80 Ð°Ð»Ò\93Ñ\8bÒ\93Ñ\8bÒ\99 ÐºÐ¸Ð»Ò»Ó\99, Ñ\8dлекÑ\82Ñ\80он Ð°Ð´Ñ\80еÑ\81Ñ\8bÒ\93Ñ\8bÒ\99Ò\99Ñ\8b ÐºÒ¯Ñ\80Ò»Ó\99Ñ\82егеÒ\99. \nУкажиÑ\82е Ð°Ð´Ñ\80еÑ\81 Ñ\8dлекÑ\82Ñ\80онной Ð¿Ð¾Ñ\87Ñ\82Ñ\8b, ÐµÑ\81ли Ð²Ñ\8b Ñ\85оÑ\82иÑ\82е Ð¿Ð¾Ð´Ð¿Ð¸Ñ\81аÑ\82Ñ\8cÑ\81Ñ\8f Ð½Ð° Ñ\81пиÑ\81ок Ñ\80аÑ\81Ñ\81Ñ\8bлки.",
+       "config-subscribe-noemail": "ҺеÒ\99 Ñ\8fÒ£Ñ\8b Ñ\81Ñ\8bÒ\93аÑ\80Ñ\8bлÑ\8bÑ\88Ñ\82аÑ\80 Ñ\82Ñ\83Ñ\80аһÑ\8bнда Ñ\85Ó\99бÓ\99Ñ\80 ÐµÐ±Ó\99Ñ\80еү Ð¸Ñ\81емлегенÓ\99 Ñ\8dлекÑ\82Ñ\80он Ð°Ð´Ñ\80еÑ\81Ñ\8bÒ\93Ñ\8bÒ\99Ò\99Ñ\8b ÐºÒ¯Ñ\80Ò»Ó\99Ñ\82мÓ\99й Ð³ÐµÐ½Ó\99 Ñ\8fÒ\99Ñ\8bлÑ\8bÑ\80Ò\93а Ñ\82Ñ\8bÑ\80Ñ\8bÑ\88Ñ\82Ñ\8bÒ\93Ñ\8bÒ\99.   \nÓ\98гÓ\99Ñ\80 Ñ\85Ó\99бÓ\99Ñ\80 ÐµÐ±Ó\99Ñ\80еү Ñ\82еÒ\99мÓ\99һенÓ\99 Ñ\8fÒ\99Ñ\8bлÑ\8bÑ\80Ò\93а Ñ\82елÓ\99Ò»Ó\99геÒ\99\8dлекÑ\82Ñ\80он Ð°Ð´Ñ\80еÑ\81Ñ\8bÒ\93Ñ\8bÒ\99Ò\99Ñ\8b ÐºÒ¯Ñ\80Ò»Ó\99Ñ\82егеÒ\99.",
        "config-almost-done": "Һеҙ маҡсатҡа яҡын!\nҠалған көйләүҙәрҙе төшөрөп ҡалдырып, вики ҡуя алаһығыҙ.",
        "config-optional-continue": "Төплөрәк көйләргә",
        "config-optional-skip": "Етәр, вики ҡуйығыҙ",
index b68e244..9886db4 100644 (file)
        "config-install-mainpage": "Стварэньне галоўнай старонкі са зьместам па змоўчваньні",
        "config-install-extension-tables": "Стварэньне табліцаў для ўключаных пашырэньняў",
        "config-install-mainpage-failed": "Немагчыма ўставіць галоўную старонку: $1",
-       "config-install-done": "'''Віншуем!'''\nВы пасьпяхова ўсталявалі MediaWiki.\n\nПраграма ўсталяваньня стварыла файл <code>LocalSettings.php</code>.\nЁн утрымлівае ўсе Вашыя налады.\n\nВам неабходна загрузіць яго і захаваць у карэнную дырэкторыю Вашай вікі (у тую ж самую дырэкторыю, дзе знаходзіцца index.php). Загрузка павінна пачацца аўтаматычна.\n\nКалі загрузка не пачалася, ці Вы яе адмянілі, Вы можаце перазапусьціць яе націснуўшы на спасылку ніжэй:\n\n$3\n\n'''Заўвага''': калі Вы гэтага ня зробіце зараз, то створаны файл ня будзе даступны Вам потым, калі Вы выйдзеце з праграмы ўсталяваньня  без яго загрузкі.\n\nКалі Вы гэта зробіце, Вы можаце '''[$2 ўвайсьці ў Вашую вікі]'''.",
+       "config-install-done": "<strong>Віншуем!</strong>\nВы ўсталявалі MediaWiki.\n\nПраграма ўсталяваньня стварыла файл <code>LocalSettings.php</code>.\nЁн утрымлівае ўсе Вашыя налады.\n\nВам неабходна загрузіць яго і захаваць у карэнную дырэкторыю Вашай вікі (у тую ж самую дырэкторыю, дзе знаходзіцца index.php). Загрузка павінна пачацца аўтаматычна.\n\nКалі загрузка не пачалася, ці Вы яе адмянілі, Вы можаце перазапусьціць яе націснуўшы на спасылку ніжэй:\n\n$3\n\n<strong>Заўвага</strong>: калі Вы гэтага ня зробіце зараз, то створаны файл ня будзе даступны Вам потым, калі Вы выйдзеце з праграмы ўсталяваньня безь яго загрузкі.\n\nКалі Вы гэта зробіце, Вы можаце <strong>[$2 ўвайсьці ў Вашую вікі]</strong>.",
        "config-download-localsettings": "Загрузіць <code>LocalSettings.php</code>",
        "config-help": "дапамога",
        "config-help-tooltip": "націсьніце, каб разгарнуць",
        "config-nofile": "Файл «$1» ня знойдзены. Ці быў ён выдалены?",
        "config-extension-link": "Ці ведаеце вы, што вашая вікі падтрымлівае [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions пашырэньні]?\n\nВы можаце праглядзець [//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category пашырэньні паводле катэгорыяў].",
-       "mainpagetext": "'''MediaWiki пасьпяхова ўсталяваная.'''",
+       "mainpagetext": "<strong>MediaWiki была ўсталяваная.</strong>",
        "mainpagedocfooter": "Глядзіце [//meta.wikimedia.org/wiki/Help:Contents дапаможнік карыстальніка] для атрыманьня інфармацыі па карыстаньні вікі-праграмамі.\n\n== З чаго пачаць ==\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Сьпіс парамэтраў канфігурацыі]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ Частыя пытаньні MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Рассылка паведамленьняў пра зьяўленьне новых вэрсіяў MediaWiki]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Пераклад MediaWiki на вашую мову]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Даведайцеся, як змагацца з спамам у вашай вікі]"
 }
index 3090edc..003b90a 100644 (file)
        "config-mssql-install-auth": "Selecciona el tipo de autenticación que se utilizará para conectarse a la base de datos durante el proceso de instalación.\nSi seleccionas \"{{int:config-mssql-windowsauth}}\", se usarán las credenciales del usuario con el que se ejecuta el servidor web.",
        "config-mssql-web-auth": "Selecciona el tipo de autenticación que utilizará el servidor web para conectarse al servidor de base de datos, durante el funcionamiento normal de la wiki.\nSi seleccionas \"{{int:config-mssql-windowsauth}}\", se usarán las credenciales del usuario con el cual se ejecuta el servidor web.",
        "config-mssql-sqlauth": "Autenticación de SQL Server",
-       "config-mssql-windowsauth": "Autentificación de Windows",
+       "config-mssql-windowsauth": "Autenticación de Windows",
        "config-site-name": "Nombre del wiki:",
        "config-site-name-help": "Esto aparecerá en la barra de título del navegador y en varios otros lugares.",
        "config-site-name-blank": "Escribe un nombre de sitio.",
        "config-profile-no-anon": "Creación de cuenta requerida",
        "config-profile-fishbowl": "Sólo editores autorizados",
        "config-profile-private": "Wiki privado",
-       "config-profile-help": "Los wikis funcionan mejor cuando dejas que los edite tanta gente como sea posible.\nEn MediaWiki, es fácil revisar los cambios recientes y revertir los daños realizados por usuarios malintencionados o novatos.\nSin embargo, muchos han encontrado que MediaWiki es útil para una amplia variedad de funciones, y a veces no es fácil convencer a todos de los beneficios de la forma wiki.\nPor lo tanto tienes la elección.\n\nEl modelo '''{{int:config-profile-wiki}}''' permite que cualquiera pueda editar, sin siquiera iniciar sesión.\nUn wiki con '''{{int:config-profile-no-anon}}''' ofrece rendición de cuentas adicional, pero puede disuadir a colaboradores.\n\nEl modelo '''{{int:config-profile-fishbowl}}''' permite editar a los usuarios autorizados, pero el público puede ver las páginas, incluyendo el historial.\nUn '''{{int:config-profile-private}}''' sólo permite ver páginas a los usuarios autorizados, el mismo grupo al que le está permitido editar.\n\nConfiguraciones más complejas de derechos de usuario están disponibles después de la instalación, consulte [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights esta entrada en el manual].",
+       "config-profile-help": "Los wikis funcionan mejor cuando dejas que los edite tanta gente como sea posible.\nEn MediaWiki, es fácil revisar los cambios recientes y revertir los daños realizados por usuarios malintencionados o novatos.\nSin embargo, muchos han encontrado que MediaWiki es útil para una amplia variedad de funciones, y a veces no es fácil convencer a todos de los beneficios de la forma wiki.\nPor lo tanto tienes la elección.\n\nEl modelo <strong>{{int:config-profile-wiki}}</strong> permite que cualquiera pueda editar, sin siquiera iniciar sesión.\nUn wiki con <strong>{{int:config-profile-no-anon}}</strong> ofrece rendición de cuentas adicional, pero puede disuadir a colaboradores casuales.\n\nEl modelo <strong>{{int:config-profile-fishbowl}}</strong> permite editar a los usuarios autorizados, pero el público puede ver las páginas, incluyendo el historial.\nUn <strong>{{int:config-profile-private}}</strong> sólo permite ver páginas a los usuarios autorizados, el mismo grupo al que le está permitido editar.\n\nConfiguraciones más complejas de permisos de usuario están disponibles después de la instalación. Consulta [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:User_rights la entrada correspondiente del manual].",
        "config-license": "Derechos de autor y licencia:",
        "config-license-none": "Pie sin licencia",
        "config-license-cc-by-sa": "Creative Commons Atribución-CompartirIgual",
index a083210..f99ca2f 100644 (file)
@@ -18,7 +18,8 @@
                        "SuperPete",
                        "McSalama",
                        "Jaakkoh",
-                       "Mikahama"
+                       "Mikahama",
+                       "Olimar"
                ]
        },
        "config-desc": "MediaWiki-asennin",
        "config-help-tooltip": "Klikkaa laajentaaksesi",
        "config-nofile": "Tiedostoa \"$1\" ei löytynyt. Onko se poistettu?",
        "config-extension-link": "Tiesitkö että wiki tukee [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions laajennuksia]?\n\nLaajennuksia voi hakea myös [//www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category luokittain].",
-       "mainpagetext": "'''MediaWiki on onnistuneesti asennettu.'''",
+       "mainpagetext": "<strong>MediaWiki on onnistuneesti asennettu.</strong>",
        "mainpagedocfooter": "Lisätietoja käytöstä on sivulla [//meta.wikimedia.org/wiki/Help:Contents User's Guide].\n\n=== Lisäohjeita ===\n\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Asetusten teko-ohjeita]\n* [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWikin FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Sähköpostilista, jolla tiedotetaan MediaWikin uusista versioista]\n\n=== Asetukset ===\n\nTarkista, että alla olevat taivutusmuodot ovat oikein. Jos eivät, tee tarvittavat muutokset tiedostoon LocalSettings.php seuraavasti:\n $wgGrammarForms['fi']['genitive']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['partitive']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['elative']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['inessive']['{{SITENAME}}'] = '...';\n $wgGrammarForms['fi']['illative']['{{SITENAME}}'] = '...';\nTaivutusmuodot: {{GRAMMAR:genitive|{{SITENAME}}}} (yön) – {{GRAMMAR:partitive|{{SITENAME}}}} (yötä) – {{GRAMMAR:elative|{{SITENAME}}}} (yöstä) – {{GRAMMAR:inessive|{{SITENAME}}}} (yössä) – {{GRAMMAR:illative|{{SITENAME}}}} (yöhön)."
 }
index 6251c03..0f7748d 100644 (file)
@@ -20,7 +20,8 @@
                        "Pio387",
                        "Darellur",
                        "The Polish",
-                       "Macofe"
+                       "Macofe",
+                       "Sethakill"
                ]
        },
        "config-desc": "Instalator MediaWiki",
        "config-ns-site-name": "Taka sama jak nazwa wiki: $1",
        "config-ns-other": "Inna (należy określić)",
        "config-ns-other-default": "MojaWiki",
-       "config-project-namespace-help": "Według przykładu Wikipedii wiele wiki przechowuje swoje strony zasad oddzielnie od stron z zawartością, w \"'''przestrzeni nazw projektu'''\".\nWszystkie tytuły stron w tej przestrzeni nazw zaczynają się od pewnego przedrostka, który można tutaj określić.\nTradycyjnie ten przedrostek wywodzi się od nazwy wiki, ale nie może zawierać pewnych znaków przestankowych takich jak \"#\" lub \":\".",
+       "config-project-namespace-help": "Według przykładu Wikipedii wiele wiki przechowuje swoje strony zasad oddzielnie od stron z zawartością, w '''przestrzeni nazw projektu'''.\nWszystkie tytuły stron w tej przestrzeni nazw zaczynają się od pewnego przedrostka, który można tutaj określić.\nZazwyczaj ten przedrostek wywodzi się od nazwy wiki, ale nie może zawierać pewnych znaków przestankowych takich jak \"#\" lub \":\".",
        "config-ns-invalid": "Podana przestrzeń nazw „<nowiki>$1</nowiki>” jest nieprawidłowa.\nPodaj inną przestrzeń nazw projektu.",
        "config-ns-conflict": "Określona przestrzeń nazw \"<nowiki>$1</nowiki>\" powoduje konflikt z domyślną przestrzenią nazw MediaWiki.\nWskaż inną przestrzeń nazw projektu.",
        "config-admin-box": "Konto administratora",
        "config-install-mainpage": "Tworzenie strony głównej z domyślną zawartością",
        "config-install-extension-tables": "Tworzenie tabel dla aktywnych rozszerzeń",
        "config-install-mainpage-failed": "Nie udało się wstawić strony głównej: $1",
-       "config-install-done": "'''Gratulacje!'''\nUdało Ci się zainstalować MediaWiki.\n\nInstalator wygenerował plik konfiguracyjny <code>LocalSettings.php</code>.\n\nMusisz go pobrać i umieścić w katalogu głównym Twojej instalacji wiki (tym samym katalogu co index.php). Pobieranie powinno zacząć się automatycznie.\n\nJeżeli pobieranie nie zostało zaproponowane lub jeśli użytkownik je anulował, można ponownie uruchomić pobranie klikając poniższe łącze:\n\n$3\n\n'''Uwaga''': Jeśli nie zrobisz tego teraz, wygenerowany plik konfiguracyjny nie będzie już dostępny po zakończeniu instalacji.\n\nPo załadowaniu pliku konfiguracyjnego możesz '''[$2 wejść na wiki]'''.",
+       "config-install-done": "<strong>'''Gratulacje!</strong>\nUdało Ci się zainstalować MediaWiki.\n\nInstalator wygenerował plik konfiguracyjny <code>LocalSettings.php</code>.\n\nMusisz go pobrać i umieścić w katalogu głównym Twojej instalacji wiki (tym samym katalogu co index.php). Pobieranie powinno zacząć się automatycznie.\n\nJeżeli pobieranie nie zostało zaproponowane lub jeśli użytkownik je anulował, można ponownie uruchomić pobranie klikając poniższe łącze:\n\n$3\n\n<strong>Uwaga</strong>: Jeśli nie zrobisz tego teraz, wygenerowany plik konfiguracyjny nie będzie już dostępny po zakończeniu instalacji.\n\nPo załadowaniu pliku konfiguracyjnego możesz <strong>[$2 wejść na wiki]</strong>.",
        "config-download-localsettings": "Pobierz <code>LocalSettings.php</code>",
        "config-help": "pomoc",
        "config-help-tooltip": "kliknij, aby rozwinąć",
index e41c1f7..677908b 100644 (file)
@@ -18,7 +18,8 @@
                        "TheEduGobi",
                        "Dianakc",
                        "Walesson",
-                       "Almondega"
+                       "Almondega",
+                       "Luk3"
                ]
        },
        "config-desc": "O instalador do MediaWiki",
@@ -27,7 +28,7 @@
        "config-localsettings-upgrade": "Foi detectada a existência do arquivo <code>LocalSettings.php</code>.\nPara atualizar esta instalação, insira na caixa abaixo o valor de <code>$wgUpgradeKey</code>.\nEssa informação pode ser encontrada no arquivo <code>LocalSettings.php</code>",
        "config-localsettings-cli-upgrade": "Foi detectada a existência do arquivo <code><code>LocalSettings.php</code></code>.\nAtualize esta instalação executando o arquivo <code>update.php</code>",
        "config-localsettings-key": "Chave de atualização:",
-       "config-localsettings-badkey": "A chave fornecida está incorreta.",
+       "config-localsettings-badkey": "A chave de atualização que você forneceu está incorreta.",
        "config-upgrade-key-missing": "Foi detectada uma instalação existente do MediaWiki.\nPara atualizar esta instalação, insira a seguinte linha ao final do seu <code>LocalSettings.php</code>:\n\n$1",
        "config-localsettings-incomplete": "O arquivo <code>LocalSettings.php</code> parece incompleto.\nA variável $1 não está definida.\nPor favor, altere seu <code>LocalSettings.php</code> e defina esta variável e clique em \"{{int:Config-continue}}\".",
        "config-localsettings-connection-error": "Ocorreu um erro ao conectar ao banco de dados através das configurações presentes no arquivo <code>LocalSettings.php</code>. Por favor, corrija essas configurações e tente novamente.\n\n$1",
        "config-no-db": "Não foi possível encontrar um driver apropriado para a banco de dados! Você precisa instalar um driver de banco de dados para PHP. {{PLURAL:$2|É aceite o seguinte tipo|São aceites os seguintes tipos}} de banco de dados: $1.\n\nSe compilou o PHP você mesmo, reconfigure-o com um cliente de banco de dados ativado, por exemplo, usando <code>./configure --with-mysqli</code>.\nSe instalou o PHP a partir de um pacote Debian ou Ubuntu, então também precisa instalar, por exemplo, o pacote <code>php5-mysql</code>.",
        "config-outdated-sqlite": "<strong>Aviso:</strong> você tem o SQLite versão $1, que é menor do que a versão mínima necessária $2. O SQLite não estará disponível.",
        "config-no-fts3": "<strong>Aviso</strong> O SQLite foi compilado sem o [//sqlite.org/fts3.html módulo FTS3], as funcionalidades de pesquisa não estarão disponíveis nesta instalação.",
-       "config-register-globals-error": "<strong>Erro: a opção <code>[http://php.net/register_globals register_globals]</code> do PHP está ativada.\nA mesma deve ser desativada para continuar a instalação.</strong>\nVeja [https://www.mediawiki.org/wiki/register_globals https://www.mediawiki.org/wiki/register_globals] para obter ajuda com isto.",
-       "config-magic-quotes-gpc": "<strong>Fatal: [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-gpc magic_quotes_gpc] está ativa!</strong>\nEsta opção corrompe a entrada de dados imprevisivelmente.\nVocê não pode instalar ou usar a MediaWiki a menos que esta opção seja desativada.",
-       "config-magic-quotes-runtime": "<strong>Erro fatal: A opção [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-runtime magic_quotes_runtime] está ativada!</strong>\nEsta opção causa corrupção dos dados de entrada de forma imprevisível.\nVocê não pode instalar ou utilizar o MediaWiki a menos que esta opção seja desativada.",
-       "config-magic-quotes-sybase": "<strong>Erro fatal: A opção [http://www.php.net/manual/en/ref.info.php#ini.magic-quotes-sybase magic_quotes_sybase] está ativada!</strong>\nEsta opção corrompe os dados de entrada de forma imprevisível.\nVocê não pode instalar ou utilizar o MediaWiki a menos que esta opção seja desativada.",
        "config-mbstring": "<strong>Erro fatal: A opção [http://www.php.net/manual/en/ref.mbstring.php#mbstring.overload mbstring.func_overload] está ativada!</strong>\nEsta opção causa erros e pode corromper os dados de forma imprevisível.\nVocê não pode instalar ou utilizar o MediaWiki a menos que esta opção seja desativada.",
-       "config-safe-mode": "<strong>Aviso:</strong> O [http://www.php.net/features.safe-mode safe mode] do PHP está ativado.\nEste modo pode causar problemas, especialmente no upload de arquivos e no suporte a <code>math</code>.",
        "config-xml-bad": "Falta o módulo XML do PHP.\nO MediaWiki necessita de funções deste módulo e não funcionará com esta configuração.\nPode precisar de instalar o pacote RPM chamado php-xml.",
        "config-pcre-old": "<strong>Erro fatal:</strong> É necessário o PCRE $1 ou versão posterior.\nO binário do seu PHP foi vinculado com o PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Mais informações].",
        "config-pcre-no-utf8": "<strong>Erro fatal:</strong> O módulo PCRE do PHP parece ser compilado sem suporte a PCRE_UTF8.\nO MediaWiki requer suporte a UTF-8 para funcionar corretamente.",
@@ -87,7 +83,7 @@
        "config-xcache": "[http://xcache.lighttpd.net/ XCache] está instalado",
        "config-apc": "[http://www.php.net/apc APC] está instalado",
        "config-wincache": "[http://www.iis.net/download/WinCacheForPhp WinCache] está instalado",
-       "config-no-cache": "<strong>Aviso:</strong> Não foi possível encontrar o [http://www.php.net/apc APC], [http://xcache.lighttpd.net/ XCache] ou [http://www.iis.net/download/WinCacheForPhp WinCache].\nO cache de objetos não está habilitado.",
+       "config-no-cache-apcu": "<strong>Aviso:</strong> Não se pode encontrar [http://www.php.net/apcu APCu], [http://xcache.lighttpd.net/ XCache] ou [http://www.iis.net/download/WinCacheForPhp WinCache].\nO caching de objetos não foi ativado.",
        "config-mod-security": "<strong>Aviso:</strong> Seu servidor web tem [http://modsecurity.org/ mod_security] habilitado. Se configurado incorretamente, pode causar problemas para o MediaWiki ou outro software que permite aos usuários postar conteúdo arbitrário.\nConsulte a [http://modsecurity.org/documentation/ documentação do mod_security] ou entre em contato com o suporte do seu host se você encontrar erros aleatórios.",
        "config-diff3-bad": "O GNU diff3 não foi encontrado.",
        "config-git": "Foi encontrado o software de controle de versão Git: <code>$1</code>.",
index e43d37b..b212e97 100644 (file)
@@ -918,6 +918,15 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                $this->lastRelayError = self::ERR_NONE;
        }
 
+       /**
+        * Clear the in-process caches; useful for testing
+        *
+        * @since 1.27
+        */
+       public function clearProcessCache() {
+               $this->procCache->clear();
+       }
+
        /**
         * Do the actual async bus purge of a key
         *
index 039161a..da5527e 100644 (file)
@@ -40,6 +40,11 @@ class LogEventsList extends ContextSource {
         */
        protected $showTagEditUI;
 
+       /**
+        * @var array
+        */
+       protected $allowedActions = null;
+
        /**
         * Constructor.
         * The first two parameters used to be $skin and $out, but now only a context
@@ -74,9 +79,10 @@ class LogEventsList extends ContextSource {
         * @param int $month Month
         * @param array $filter
         * @param string $tagFilter Tag to select by default
+        * @param string $action
         */
        public function showOptions( $types = [], $user = '', $page = '', $pattern = '', $year = 0,
-               $month = 0, $filter = null, $tagFilter = ''
+               $month = 0, $filter = null, $tagFilter = '', $action = null
        ) {
                global $wgScript, $wgMiserMode;
 
@@ -113,6 +119,11 @@ class LogEventsList extends ContextSource {
                        $html .= Xml::tags( 'p', null, $this->getFilterLinks( $filter ) );
                }
 
+               // Action filter
+               if ( $action !== null ) {
+                       $html .= Xml::tags( 'p', null, $this->getActionSelector( $types, $action ) );
+               }
+
                // Submit button
                $html .= Xml::submitButton( $this->msg( 'logeventslist-submit' )->text() );
 
@@ -287,6 +298,41 @@ class LogEventsList extends ContextSource {
                return '';
        }
 
+       /**
+        * Drop down menu for selection of actions that can be used to filter the log
+        * @param array $types
+        * @param string $action
+        * @return string
+        * @since 1.27
+        */
+       private function getActionSelector( $types, $action ) {
+               if ( $this->allowedActions === null || !count( $this->allowedActions ) ) {
+                       return '';
+               }
+               $html = '';
+               $html .= xml::label( wfMessage( 'log-action-filter-' . $types[0] )->text(),
+                       'action-filter-' .$types[0] ) . "\n";
+               $select = new XmlSelect( 'subtype' );
+               $select->addOption( wfMessage( 'log-action-filter-all' )->text(), '' );
+               foreach ( $this->allowedActions as $value ) {
+                       $msgKey = 'log-action-filter-' . $types[0] . '-' . $value;
+                       $select->addOption( wfMessage( $msgKey )->text(), $value );
+               }
+               $select->setDefault( $action );
+               $html .= $select->getHtml();
+               return $html;
+       }
+
+       /**
+        * Sets the action types allowed for log filtering
+        * To one action type may correspond several log_actions
+        * @param array $actions
+        * @since 1.27
+        */
+       public function setAllowedActions( $actions ) {
+               $this->allowedActions = $actions;
+       }
+
        /**
         * @return string
         */
index f6ecc50..d1de2cd 100644 (file)
@@ -58,7 +58,9 @@ class PatrolLog {
                        $user = $wgUser;
                }
 
-               $entry = new ManualLogEntry( 'patrol', 'patrol' );
+               $action = $auto ? 'autopatrol' : 'patrol';
+
+               $entry = new ManualLogEntry( 'patrol', $action );
                $entry->setTarget( $rc->getTitle() );
                $entry->setParameters( self::buildParams( $rc, $auto ) );
                $entry->setPerformer( $user );
index e6f9fb6..5b933ce 100644 (file)
  */
 class PatrolLogFormatter extends LogFormatter {
        protected function getMessageKey() {
-               $key = parent::getMessageKey();
                $params = $this->getMessageParameters();
                if ( isset( $params[5] ) && $params[5] ) {
-                       // Messages: logentry-patrol-patrol-auto
-                       $key .= '-auto';
+                       $key = 'logentry-patrol-patrol-auto';
+               } else {
+                       $key = 'logentry-patrol-patrol';
                }
 
                return $key;
index cd249a8..9add138 100644 (file)
@@ -393,25 +393,24 @@ class DjVuHandler extends ImageHandler {
        }
 
        protected function getDimensionInfo( File $file ) {
-               $that = $this;
-
-               return ObjectCache::getMainWANInstance()->getWithSetCallback(
-                       wfMemcKey( 'file-djvu', 'dimensions', $file->getSha1() ),
-                       WANObjectCache::TTL_INDEFINITE,
-                       function () use ( $that, $file ) {
-                               $tree = $that->getMetaTree( $file );
+               $cache = ObjectCache::getMainWANInstance();
+               return $cache->getWithSetCallback(
+                       $cache->makeKey( 'file-djvu', 'dimensions', $file->getSha1() ),
+                       $cache::TTL_INDEFINITE,
+                       function () use ( $file ) {
+                               $tree = $this->getMetaTree( $file );
                                if ( !$tree ) {
                                        return false;
                                }
 
                                $dimsByPage = [];
                                $count = count( $tree->xpath( '//OBJECT' ) );
-                               for ( $i = 0; $i < $count; ++$i ) {
+                               for ( $i = 0; $i < $count; $i++ ) {
                                        $o = $tree->BODY[0]->OBJECT[$i];
                                        if ( $o ) {
                                                $dimsByPage[$i] = [
                                                        'width' => (int)$o['width'],
-                                                       'height' => (int)$o['height']
+                                                       'height' => (int)$o['height'],
                                                ];
                                        } else {
                                                $dimsByPage[$i] = false;
@@ -420,7 +419,7 @@ class DjVuHandler extends ImageHandler {
 
                                return [ 'pageCount' => $count, 'dimensionsByPage' => $dimsByPage ];
                        },
-                       [ 'pcTTL' => WANObjectCache::TTL_INDEFINITE ]
+                       [ 'pcTTL' => $cache::TTL_INDEFINITE ]
                );
        }
 
index d57d3fd..7592017 100644 (file)
@@ -1644,6 +1644,7 @@ class Article implements Page {
                $title = $this->getTitle();
                $context = $this->getContext();
                $user = $context->getUser();
+               $request = $context->getRequest();
 
                # Check permissions
                $permissionErrors = $title->getUserPermissionsErrors( 'delete', $user );
@@ -1657,7 +1658,9 @@ class Article implements Page {
                }
 
                # Better double-check that it hasn't been deleted yet!
-               $this->mPage->loadPageData( 'fromdbmaster' );
+               $this->mPage->loadPageData(
+                       $request->wasPosted() ? WikiPage::READ_LATEST : WikiPage::READ_NORMAL
+               );
                if ( !$this->mPage->exists() ) {
                        $deleteLogPage = new LogPage( 'delete' );
                        $outputPage = $context->getOutput();
@@ -1677,7 +1680,6 @@ class Article implements Page {
                        return;
                }
 
-               $request = $context->getRequest();
                $deleteReasonList = $request->getText( 'wpDeleteReasonList', 'other' );
                $deleteReason = $request->getText( 'wpReason' );
 
index 368d79e..cc98abd 100644 (file)
@@ -260,8 +260,8 @@ interface PPFrame {
 
        /**
         * Get an argument to this frame by name
-        * @param string $name
-        * @return bool
+        * @param int|string $name
+        * @return string|bool
         */
        public function getArgument( $name );
 
index 79a66e0..4c94b2a 100644 (file)
@@ -1462,6 +1462,10 @@ class PPFrame_DOM implements PPFrame {
                return true;
        }
 
+       /**
+        * @param int|string $name
+        * @return bool Always false in this implementation.
+        */
        public function getArgument( $name ) {
                return false;
        }
@@ -1646,6 +1650,10 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
                return $arguments;
        }
 
+       /**
+        * @param int $index
+        * @return string|bool
+        */
        public function getNumberedArgument( $index ) {
                if ( !isset( $this->numberedArgs[$index] ) ) {
                        return false;
@@ -1660,6 +1668,10 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
                return $this->numberedExpansionCache[$index];
        }
 
+       /**
+        * @param string $name
+        * @return string|bool
+        */
        public function getNamedArgument( $name ) {
                if ( !isset( $this->namedArgs[$name] ) ) {
                        return false;
@@ -1672,6 +1684,10 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
                return $this->namedExpansionCache[$name];
        }
 
+       /**
+        * @param int|string $name
+        * @return string|bool
+        */
        public function getArgument( $name ) {
                $text = $this->getNumberedArgument( $name );
                if ( $text === false ) {
@@ -1738,6 +1754,10 @@ class PPCustomFrame_DOM extends PPFrame_DOM {
                return !count( $this->args );
        }
 
+       /**
+        * @param int|string $index
+        * @return string|bool
+        */
        public function getArgument( $index ) {
                if ( !isset( $this->args[$index] ) ) {
                        return false;
index 24baae4..f030cca 100644 (file)
@@ -1355,8 +1355,8 @@ class PPFrame_Hash implements PPFrame {
        }
 
        /**
-        * @param string $name
-        * @return bool
+        * @param int|string $name
+        * @return bool Always false in this implementation.
         */
        public function getArgument( $name ) {
                return false;
@@ -1549,7 +1549,7 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
 
        /**
         * @param int $index
-        * @return array|bool
+        * @return string|bool
         */
        public function getNumberedArgument( $index ) {
                if ( !isset( $this->numberedArgs[$index] ) ) {
@@ -1567,7 +1567,7 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
 
        /**
         * @param string $name
-        * @return bool
+        * @return string|bool
         */
        public function getNamedArgument( $name ) {
                if ( !isset( $this->namedArgs[$name] ) ) {
@@ -1582,8 +1582,8 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
        }
 
        /**
-        * @param string $name
-        * @return array|bool
+        * @param int|string $name
+        * @return string|bool
         */
        public function getArgument( $name ) {
                $text = $this->getNumberedArgument( $name );
@@ -1652,8 +1652,8 @@ class PPCustomFrame_Hash extends PPFrame_Hash {
        }
 
        /**
-        * @param int $index
-        * @return bool
+        * @param int|string $index
+        * @return string|bool
         */
        public function getArgument( $index ) {
                if ( !isset( $this->args[$index] ) ) {
index cd9062b..80a437b 100644 (file)
@@ -84,7 +84,7 @@ class SearchSuggestion {
         */
        public function setText( $text, $setTitle = true ) {
                $this->text = $text;
-               if ( $setTitle && $text ) {
+               if ( $setTitle && $text !== '' && $text !== null ) {
                        $this->setSuggestedTitle( Title::makeTitle( 0, $text ) );
                }
        }
index 92311b5..2d1679d 100644 (file)
@@ -45,6 +45,14 @@ class SkinTemplate extends Skin {
         */
        public $template = 'QuickTemplate';
 
+       public $thispage;
+       public $titletxt;
+       public $userpage;
+       public $thisquery;
+       public $loggedin;
+       public $username;
+       public $userpageUrlDetails;
+
        /**
         * Add specific styles for this skin
         *
index 9198c1e..d6d4500 100644 (file)
  * @ingroup SpecialPage
  */
 
-/**
- * This class is used to get a list of active users. The ones with specials
- * rights (sysop, bureaucrat, developer) will have them displayed
- * next to their names.
- *
- * @ingroup SpecialPage
- */
-class ActiveUsersPager extends UsersPager {
-       /**
-        * @var FormOptions
-        */
-       protected $opts;
-
-       /**
-        * @var array
-        */
-       protected $hideGroups = [];
-
-       /**
-        * @var array
-        */
-       protected $hideRights = [];
-
-       /**
-        * @var array
-        */
-       private $blockStatusByUid;
-
-       /**
-        * @param IContextSource $context
-        * @param null $group Unused
-        * @param string $par Parameter passed to the page
-        */
-       function __construct( IContextSource $context = null, $group = null, $par = null ) {
-               parent::__construct( $context );
-
-               $this->RCMaxAge = $this->getConfig()->get( 'ActiveUserDays' );
-               $un = $this->getRequest()->getText( 'username', $par );
-               $this->requestedUser = '';
-               if ( $un != '' ) {
-                       $username = Title::makeTitleSafe( NS_USER, $un );
-                       if ( !is_null( $username ) ) {
-                               $this->requestedUser = $username->getText();
-                       }
-               }
-
-               $this->setupOptions();
-       }
-
-       public function setupOptions() {
-               $this->opts = new FormOptions();
-
-               $this->opts->add( 'hidebots', false, FormOptions::BOOL );
-               $this->opts->add( 'hidesysops', false, FormOptions::BOOL );
-
-               $this->opts->fetchValuesFromRequest( $this->getRequest() );
-
-               if ( $this->opts->getValue( 'hidebots' ) == 1 ) {
-                       $this->hideRights[] = 'bot';
-               }
-               if ( $this->opts->getValue( 'hidesysops' ) == 1 ) {
-                       $this->hideGroups[] = 'sysop';
-               }
-       }
-
-       function getIndexField() {
-               return 'qcc_title';
-       }
-
-       function getQueryInfo() {
-               $dbr = $this->getDatabase();
-
-               $activeUserSeconds = $this->getConfig()->get( 'ActiveUserDays' ) * 86400;
-               $timestamp = $dbr->timestamp( wfTimestamp( TS_UNIX ) - $activeUserSeconds );
-               $conds = [
-                       'qcc_type' => 'activeusers',
-                       'qcc_namespace' => NS_USER,
-                       'user_name = qcc_title',
-                       'rc_user_text = qcc_title',
-                       'rc_type != ' . $dbr->addQuotes( RC_EXTERNAL ), // Don't count wikidata.
-                       'rc_type != ' . $dbr->addQuotes( RC_CATEGORIZE ), // Don't count categorization changes.
-                       'rc_log_type IS NULL OR rc_log_type != ' . $dbr->addQuotes( 'newusers' ),
-                       'rc_timestamp >= ' . $dbr->addQuotes( $timestamp ),
-               ];
-               if ( $this->requestedUser != '' ) {
-                       $conds[] = 'qcc_title >= ' . $dbr->addQuotes( $this->requestedUser );
-               }
-               if ( !$this->getUser()->isAllowed( 'hideuser' ) ) {
-                       $conds[] = 'NOT EXISTS (' . $dbr->selectSQLText(
-                               'ipblocks', '1', [ 'ipb_user=user_id', 'ipb_deleted' => 1 ]
-                       ) . ')';
-               }
-
-               if ( $dbr->implicitGroupby() ) {
-                       $options = [ 'GROUP BY' => [ 'qcc_title' ] ];
-               } else {
-                       $options = [ 'GROUP BY' => [ 'user_name', 'user_id', 'qcc_title' ] ];
-               }
-
-               return [
-                       'tables' => [ 'querycachetwo', 'user', 'recentchanges' ],
-                       'fields' => [ 'user_name', 'user_id', 'recentedits' => 'COUNT(*)', 'qcc_title' ],
-                       'options' => $options,
-                       'conds' => $conds
-               ];
-       }
-
-       function doBatchLookups() {
-               parent::doBatchLookups();
-
-               $uids = [];
-               foreach ( $this->mResult as $row ) {
-                       $uids[] = $row->user_id;
-               }
-               // Fetch the block status of the user for showing "(blocked)" text and for
-               // striking out names of suppressed users when privileged user views the list.
-               // Although the first query already hits the block table for un-privileged, this
-               // is done in two queries to avoid huge quicksorts and to make COUNT(*) correct.
-               $dbr = $this->getDatabase();
-               $res = $dbr->select( 'ipblocks',
-                       [ 'ipb_user', 'MAX(ipb_deleted) AS block_status' ],
-                       [ 'ipb_user' => $uids ],
-                       __METHOD__,
-                       [ 'GROUP BY' => [ 'ipb_user' ] ]
-               );
-               $this->blockStatusByUid = [];
-               foreach ( $res as $row ) {
-                       $this->blockStatusByUid[$row->ipb_user] = $row->block_status; // 0 or 1
-               }
-               $this->mResult->seek( 0 );
-       }
-
-       function formatRow( $row ) {
-               $userName = $row->user_name;
-
-               $ulinks = Linker::userLink( $row->user_id, $userName );
-               $ulinks .= Linker::userToolLinks( $row->user_id, $userName );
-
-               $lang = $this->getLanguage();
-
-               $list = [];
-               $user = User::newFromId( $row->user_id );
-
-               // User right filter
-               foreach ( $this->hideRights as $right ) {
-                       // Calling User::getRights() within the loop so that
-                       // if the hideRights() filter is empty, we don't have to
-                       // trigger the lazy-init of the big userrights array in the
-                       // User object
-                       if ( in_array( $right, $user->getRights() ) ) {
-                               return '';
-                       }
-               }
-
-               // User group filter
-               // Note: This is a different loop than for user rights,
-               // because we're reusing it to build the group links
-               // at the same time
-               $groups_list = self::getGroups( intval( $row->user_id ), $this->userGroupCache );
-               foreach ( $groups_list as $group ) {
-                       if ( in_array( $group, $this->hideGroups ) ) {
-                               return '';
-                       }
-                       $list[] = self::buildGroupLink( $group, $userName );
-               }
-
-               $groups = $lang->commaList( $list );
-
-               $item = $lang->specialList( $ulinks, $groups );
-
-               $isBlocked = isset( $this->blockStatusByUid[$row->user_id] );
-               if ( $isBlocked && $this->blockStatusByUid[$row->user_id] == 1 ) {
-                       $item = "<span class=\"deleted\">$item</span>";
-               }
-               $count = $this->msg( 'activeusers-count' )->numParams( $row->recentedits )
-                       ->params( $userName )->numParams( $this->RCMaxAge )->escaped();
-               $blocked = $isBlocked ? ' ' . $this->msg( 'listusers-blocked', $userName )->escaped() : '';
-
-               return Html::rawElement( 'li', [], "{$item} [{$count}]{$blocked}" );
-       }
-
-       function getPageHeader() {
-               $self = $this->getTitle();
-               $limit = $this->mLimit ? Html::hidden( 'limit', $this->mLimit ) : '';
-
-               # Form tag
-               $out = Xml::openElement( 'form', [ 'method' => 'get', 'action' => wfScript() ] );
-               $out .= Xml::fieldset( $this->msg( 'activeusers' )->text() ) . "\n";
-               $out .= Html::hidden( 'title', $self->getPrefixedDBkey() ) . $limit . "\n";
-
-               # Username field (with autocompletion support)
-               $this->getOutput()->addModules( 'mediawiki.userSuggest' );
-               $out .= Xml::inputLabel(
-                       $this->msg( 'activeusers-from' )->text(),
-                       'username',
-                       'offset',
-                       20,
-                       $this->requestedUser,
-                       [
-                               'class' => 'mw-ui-input-inline mw-autocomplete-user',
-                               'tabindex' => 1,
-                       ] + (
-                               // Set autofocus on blank input
-                               $this->requestedUser === '' ? [ 'autofocus' => '' ] : []
-                       )
-               ) . '<br />';
-
-               $out .= Xml::checkLabel( $this->msg( 'activeusers-hidebots' )->text(),
-                       'hidebots', 'hidebots', $this->opts->getValue( 'hidebots' ), [ 'tabindex' => 2 ] );
-
-               $out .= Xml::checkLabel(
-                       $this->msg( 'activeusers-hidesysops' )->text(),
-                       'hidesysops',
-                       'hidesysops',
-                       $this->opts->getValue( 'hidesysops' ),
-                       [ 'tabindex' => 3 ]
-               ) . '<br />';
-
-               # Submit button and form bottom
-               $out .= Xml::submitButton(
-                       $this->msg( 'activeusers-submit' )->text(),
-                       [ 'tabindex' => 4 ]
-               ) . "\n";
-               $out .= Xml::closeElement( 'fieldset' );
-               $out .= Xml::closeElement( 'form' );
-
-               return $out;
-       }
-}
-
 /**
  * @ingroup SpecialPage
  */
index 49d5d6e..49ca9f4 100644 (file)
@@ -77,403 +77,3 @@ class SpecialAllMessages extends SpecialPage {
                return 'wiki';
        }
 }
-
-/**
- * Use TablePager for prettified output. We have to pretend that we're
- * getting data from a table when in fact not all of it comes from the database.
- */
-class AllMessagesTablePager extends TablePager {
-       protected $filter, $prefix, $langcode, $displayPrefix;
-
-       public $mLimitsShown;
-
-       /**
-        * @var Language
-        */
-       public $lang;
-
-       /**
-        * @var null|bool
-        */
-       public $custom;
-
-       function __construct( $page, $conds, $langObj = null ) {
-               parent::__construct( $page->getContext() );
-               $this->mIndexField = 'am_title';
-               $this->mPage = $page;
-               $this->mConds = $conds;
-               // FIXME: Why does this need to be set to DIR_DESCENDING to produce ascending ordering?
-               $this->mDefaultDirection = IndexPager::DIR_DESCENDING;
-               $this->mLimitsShown = [ 20, 50, 100, 250, 500, 5000 ];
-
-               global $wgContLang;
-
-               $this->talk = $this->msg( 'talkpagelinktext' )->escaped();
-
-               $this->lang = ( $langObj ? $langObj : $wgContLang );
-               $this->langcode = $this->lang->getCode();
-               $this->foreign = $this->langcode !== $wgContLang->getCode();
-
-               $request = $this->getRequest();
-
-               $this->filter = $request->getVal( 'filter', 'all' );
-               if ( $this->filter === 'all' ) {
-                       $this->custom = null; // So won't match in either case
-               } else {
-                       $this->custom = ( $this->filter === 'unmodified' );
-               }
-
-               $prefix = $this->getLanguage()->ucfirst( $request->getVal( 'prefix', '' ) );
-               $prefix = $prefix !== '' ?
-                       Title::makeTitleSafe( NS_MEDIAWIKI, $request->getVal( 'prefix', null ) ) :
-                       null;
-
-               if ( $prefix !== null ) {
-                       $this->displayPrefix = $prefix->getDBkey();
-                       $this->prefix = '/^' . preg_quote( $this->displayPrefix, '/' ) . '/i';
-               } else {
-                       $this->displayPrefix = false;
-                       $this->prefix = false;
-               }
-
-               // The suffix that may be needed for message names if we're in a
-               // different language (eg [[MediaWiki:Foo/fr]]: $suffix = '/fr'
-               if ( $this->foreign ) {
-                       $this->suffix = '/' . $this->langcode;
-               } else {
-                       $this->suffix = '';
-               }
-       }
-
-       function buildForm() {
-               $attrs = [ 'id' => 'mw-allmessages-form-lang', 'name' => 'lang' ];
-               $msg = wfMessage( 'allmessages-language' );
-               $langSelect = Xml::languageSelector( $this->langcode, false, null, $attrs, $msg );
-
-               $out = Xml::openElement( 'form', [
-                               'method' => 'get',
-                               'action' => $this->getConfig()->get( 'Script' ),
-                               'id' => 'mw-allmessages-form'
-                       ] ) .
-                       Xml::fieldset( $this->msg( 'allmessages-filter-legend' )->text() ) .
-                       Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
-                       Xml::openElement( 'table', [ 'class' => 'mw-allmessages-table' ] ) . "\n" .
-                       '<tr>
-                               <td class="mw-label">' .
-                       Xml::label( $this->msg( 'allmessages-prefix' )->text(), 'mw-allmessages-form-prefix' ) .
-                       "</td>\n
-                       <td class=\"mw-input\">" .
-                       Xml::input(
-                               'prefix',
-                               20,
-                               str_replace( '_', ' ', $this->displayPrefix ),
-                               [ 'id' => 'mw-allmessages-form-prefix' ]
-                       ) .
-                       "</td>\n
-                       </tr>
-                       <tr>\n
-                       <td class='mw-label'>" .
-                       $this->msg( 'allmessages-filter' )->escaped() .
-                       "</td>\n
-                               <td class='mw-input'>" .
-                       Xml::radioLabel( $this->msg( 'allmessages-filter-unmodified' )->text(),
-                               'filter',
-                               'unmodified',
-                               'mw-allmessages-form-filter-unmodified',
-                               ( $this->filter === 'unmodified' )
-                       ) .
-                       Xml::radioLabel( $this->msg( 'allmessages-filter-all' )->text(),
-                               'filter',
-                               'all',
-                               'mw-allmessages-form-filter-all',
-                               ( $this->filter === 'all' )
-                       ) .
-                       Xml::radioLabel( $this->msg( 'allmessages-filter-modified' )->text(),
-                               'filter',
-                               'modified',
-                               'mw-allmessages-form-filter-modified',
-                               ( $this->filter === 'modified' )
-                       ) .
-                       "</td>\n
-                       </tr>
-                       <tr>\n
-                               <td class=\"mw-label\">" . $langSelect[0] . "</td>\n
-                               <td class=\"mw-input\">" . $langSelect[1] . "</td>\n
-                       </tr>" .
-
-                       '<tr>
-                               <td class="mw-label">' .
-                       Xml::label( $this->msg( 'table_pager_limit_label' )->text(), 'mw-table_pager_limit_label' ) .
-                       '</td>
-                       <td class="mw-input">' .
-                       $this->getLimitSelect( [ 'id' => 'mw-table_pager_limit_label' ] ) .
-                       '</td>
-                       <tr>
-                               <td></td>
-                               <td>' .
-                       Xml::submitButton( $this->msg( 'allmessages-filter-submit' )->text() ) .
-                       "</td>\n
-                       </tr>" .
-
-                       Xml::closeElement( 'table' ) .
-                       $this->getHiddenFields( [ 'title', 'prefix', 'filter', 'lang', 'limit' ] ) .
-                       Xml::closeElement( 'fieldset' ) .
-                       Xml::closeElement( 'form' );
-
-               return $out;
-       }
-
-       function getAllMessages( $descending ) {
-               $messageNames = Language::getLocalisationCache()->getSubitemList( 'en', 'messages' );
-
-               // Normalise message names so they look like page titles and sort correctly - T86139
-               $messageNames = array_map( [ $this->lang, 'ucfirst' ], $messageNames );
-
-               if ( $descending ) {
-                       rsort( $messageNames );
-               } else {
-                       asort( $messageNames );
-               }
-
-               return $messageNames;
-       }
-
-       /**
-        * Determine which of the MediaWiki and MediaWiki_talk namespace pages exist.
-        * Returns array( 'pages' => ..., 'talks' => ... ), where the subarrays have
-        * an entry for each existing page, with the key being the message name and
-        * value arbitrary.
-        *
-        * @param array $messageNames
-        * @param string $langcode What language code
-        * @param bool $foreign Whether the $langcode is not the content language
-        * @return array A 'pages' and 'talks' array with the keys of existing pages
-        */
-       public static function getCustomisedStatuses( $messageNames, $langcode = 'en', $foreign = false ) {
-               // FIXME: This function should be moved to Language:: or something.
-
-               $dbr = wfGetDB( DB_SLAVE );
-               $res = $dbr->select( 'page',
-                       [ 'page_namespace', 'page_title' ],
-                       [ 'page_namespace' => [ NS_MEDIAWIKI, NS_MEDIAWIKI_TALK ] ],
-                       __METHOD__,
-                       [ 'USE INDEX' => 'name_title' ]
-               );
-               $xNames = array_flip( $messageNames );
-
-               $pageFlags = $talkFlags = [];
-
-               foreach ( $res as $s ) {
-                       $exists = false;
-
-                       if ( $foreign ) {
-                               $titleParts = explode( '/', $s->page_title );
-                               if ( count( $titleParts ) === 2 &&
-                                       $langcode === $titleParts[1] &&
-                                       isset( $xNames[$titleParts[0]] )
-                               ) {
-                                       $exists = $titleParts[0];
-                               }
-                       } elseif ( isset( $xNames[$s->page_title] ) ) {
-                               $exists = $s->page_title;
-                       }
-
-                       $title = Title::newFromRow( $s );
-                       if ( $exists && $title->inNamespace( NS_MEDIAWIKI ) ) {
-                               $pageFlags[$exists] = true;
-                       } elseif ( $exists && $title->inNamespace( NS_MEDIAWIKI_TALK ) ) {
-                               $talkFlags[$exists] = true;
-                       }
-               }
-
-               return [ 'pages' => $pageFlags, 'talks' => $talkFlags ];
-       }
-
-       /**
-        *  This function normally does a database query to get the results; we need
-        * to make a pretend result using a FakeResultWrapper.
-        * @param string $offset
-        * @param int $limit
-        * @param bool $descending
-        * @return FakeResultWrapper
-        */
-       function reallyDoQuery( $offset, $limit, $descending ) {
-               $result = new FakeResultWrapper( [] );
-
-               $messageNames = $this->getAllMessages( $descending );
-               $statuses = self::getCustomisedStatuses( $messageNames, $this->langcode, $this->foreign );
-
-               $count = 0;
-               foreach ( $messageNames as $key ) {
-                       $customised = isset( $statuses['pages'][$key] );
-                       if ( $customised !== $this->custom &&
-                               ( $descending && ( $key < $offset || !$offset ) || !$descending && $key > $offset ) &&
-                               ( ( $this->prefix && preg_match( $this->prefix, $key ) ) || $this->prefix === false )
-                       ) {
-                               $actual = wfMessage( $key )->inLanguage( $this->langcode )->plain();
-                               $default = wfMessage( $key )->inLanguage( $this->langcode )->useDatabase( false )->plain();
-                               $result->result[] = [
-                                       'am_title' => $key,
-                                       'am_actual' => $actual,
-                                       'am_default' => $default,
-                                       'am_customised' => $customised,
-                                       'am_talk_exists' => isset( $statuses['talks'][$key] )
-                               ];
-                               $count++;
-                       }
-
-                       if ( $count === $limit ) {
-                               break;
-                       }
-               }
-
-               return $result;
-       }
-
-       function getStartBody() {
-               $tableClass = $this->getTableClass();
-               return Xml::openElement( 'table', [
-                               'class' => "mw-datatable $tableClass",
-                               'id' => 'mw-allmessagestable'
-                       ] ) .
-                       "\n" .
-                       "<thead><tr>
-                               <th rowspan=\"2\">" .
-                       $this->msg( 'allmessagesname' )->escaped() . "
-                               </th>
-                               <th>" .
-                       $this->msg( 'allmessagesdefault' )->escaped() .
-                       "</th>
-                       </tr>\n
-                       <tr>
-                               <th>" .
-                       $this->msg( 'allmessagescurrent' )->escaped() .
-                       "</th>
-                       </tr></thead><tbody>\n";
-       }
-
-       function formatValue( $field, $value ) {
-               switch ( $field ) {
-                       case 'am_title' :
-                               $title = Title::makeTitle( NS_MEDIAWIKI, $value . $this->suffix );
-                               $talk = Title::makeTitle( NS_MEDIAWIKI_TALK, $value . $this->suffix );
-                               $translation = Linker::makeExternalLink(
-                                       'https://translatewiki.net/w/i.php?' . wfArrayToCgi( [
-                                               'title' => 'Special:SearchTranslations',
-                                               'group' => 'mediawiki',
-                                               'grouppath' => 'mediawiki',
-                                               'query' => 'language:' . $this->getLanguage()->getCode() . '^25 ' .
-                                                       'messageid:"MediaWiki:' . $value . '"^10 "' .
-                                                       $this->msg( $value )->inLanguage( 'en' )->plain() . '"'
-                                       ] ),
-                                       $this->msg( 'allmessages-filter-translate' )->text()
-                               );
-
-                               if ( $this->mCurrentRow->am_customised ) {
-                                       $title = Linker::linkKnown( $title, $this->getLanguage()->lcfirst( $value ) );
-                               } else {
-                                       $title = Linker::link(
-                                               $title,
-                                               $this->getLanguage()->lcfirst( $value ),
-                                               [],
-                                               [],
-                                               [ 'broken' ]
-                                       );
-                               }
-                               if ( $this->mCurrentRow->am_talk_exists ) {
-                                       $talk = Linker::linkKnown( $talk, $this->talk );
-                               } else {
-                                       $talk = Linker::link(
-                                               $talk,
-                                               $this->talk,
-                                               [],
-                                               [],
-                                               [ 'broken' ]
-                                       );
-                               }
-
-                               return $title . ' ' .
-                                       $this->msg( 'parentheses' )->rawParams( $talk )->escaped() .
-                                       ' ' .
-                                       $this->msg( 'parentheses' )->rawParams( $translation )->escaped();
-
-                       case 'am_default' :
-                       case 'am_actual' :
-                               return Sanitizer::escapeHtmlAllowEntities( $value );
-               }
-
-               return '';
-       }
-
-       function formatRow( $row ) {
-               // Do all the normal stuff
-               $s = parent::formatRow( $row );
-
-               // But if there's a customised message, add that too.
-               if ( $row->am_customised ) {
-                       $s .= Xml::openElement( 'tr', $this->getRowAttrs( $row, true ) );
-                       $formatted = strval( $this->formatValue( 'am_actual', $row->am_actual ) );
-
-                       if ( $formatted === '' ) {
-                               $formatted = '&#160;';
-                       }
-
-                       $s .= Xml::tags( 'td', $this->getCellAttrs( 'am_actual', $row->am_actual ), $formatted )
-                               . "</tr>\n";
-               }
-
-               return $s;
-       }
-
-       function getRowAttrs( $row, $isSecond = false ) {
-               $arr = [];
-
-               if ( $row->am_customised ) {
-                       $arr['class'] = 'allmessages-customised';
-               }
-
-               if ( !$isSecond ) {
-                       $arr['id'] = Sanitizer::escapeId( 'msg_' . $this->getLanguage()->lcfirst( $row->am_title ) );
-               }
-
-               return $arr;
-       }
-
-       function getCellAttrs( $field, $value ) {
-               if ( $this->mCurrentRow->am_customised && $field === 'am_title' ) {
-                       return [ 'rowspan' => '2', 'class' => $field ];
-               } elseif ( $field === 'am_title' ) {
-                       return [ 'class' => $field ];
-               } else {
-                       return [
-                               'lang' => $this->lang->getHtmlCode(),
-                               'dir' => $this->lang->getDir(),
-                               'class' => $field
-                       ];
-               }
-       }
-
-       // This is not actually used, as getStartBody is overridden above
-       function getFieldNames() {
-               return [
-                       'am_title' => $this->msg( 'allmessagesname' )->text(),
-                       'am_default' => $this->msg( 'allmessagesdefault' )->text()
-               ];
-       }
-
-       function getTitle() {
-               return SpecialPage::getTitleFor( 'Allmessages', false );
-       }
-
-       function isFieldSortable( $x ) {
-               return false;
-       }
-
-       function getDefaultSort() {
-               return '';
-       }
-
-       function getQueryInfo() {
-               return '';
-       }
-}
index e589ecb..dbbee71 100644 (file)
@@ -222,244 +222,3 @@ class SpecialBlockList extends SpecialPage {
                return 'users';
        }
 }
-
-class BlockListPager extends TablePager {
-       protected $conds;
-       protected $page;
-
-       /**
-        * @param SpecialPage $page
-        * @param array $conds
-        */
-       function __construct( $page, $conds ) {
-               $this->page = $page;
-               $this->conds = $conds;
-               $this->mDefaultDirection = IndexPager::DIR_DESCENDING;
-               parent::__construct( $page->getContext() );
-       }
-
-       function getFieldNames() {
-               static $headers = null;
-
-               if ( $headers === null ) {
-                       $headers = [
-                               'ipb_timestamp' => 'blocklist-timestamp',
-                               'ipb_target' => 'blocklist-target',
-                               'ipb_expiry' => 'blocklist-expiry',
-                               'ipb_by' => 'blocklist-by',
-                               'ipb_params' => 'blocklist-params',
-                               'ipb_reason' => 'blocklist-reason',
-                       ];
-                       foreach ( $headers as $key => $val ) {
-                               $headers[$key] = $this->msg( $val )->text();
-                       }
-               }
-
-               return $headers;
-       }
-
-       function formatValue( $name, $value ) {
-               static $msg = null;
-               if ( $msg === null ) {
-                       $keys = [
-                               'anononlyblock',
-                               'createaccountblock',
-                               'noautoblockblock',
-                               'emailblock',
-                               'blocklist-nousertalk',
-                               'unblocklink',
-                               'change-blocklink',
-                       ];
-
-                       foreach ( $keys as $key ) {
-                               $msg[$key] = $this->msg( $key )->escaped();
-                       }
-               }
-
-               /** @var $row object */
-               $row = $this->mCurrentRow;
-
-               $language = $this->getLanguage();
-
-               $formatted = '';
-
-               switch ( $name ) {
-                       case 'ipb_timestamp':
-                               $formatted = htmlspecialchars( $language->userTimeAndDate( $value, $this->getUser() ) );
-                               break;
-
-                       case 'ipb_target':
-                               if ( $row->ipb_auto ) {
-                                       $formatted = $this->msg( 'autoblockid', $row->ipb_id )->parse();
-                               } else {
-                                       list( $target, $type ) = Block::parseTarget( $row->ipb_address );
-                                       switch ( $type ) {
-                                               case Block::TYPE_USER:
-                                               case Block::TYPE_IP:
-                                                       $formatted = Linker::userLink( $target->getId(), $target );
-                                                       $formatted .= Linker::userToolLinks(
-                                                               $target->getId(),
-                                                               $target,
-                                                               false,
-                                                               Linker::TOOL_LINKS_NOBLOCK
-                                                       );
-                                                       break;
-                                               case Block::TYPE_RANGE:
-                                                       $formatted = htmlspecialchars( $target );
-                                       }
-                               }
-                               break;
-
-                       case 'ipb_expiry':
-                               $formatted = htmlspecialchars( $language->formatExpiry(
-                                       $value,
-                                       /* User preference timezone */true
-                               ) );
-                               if ( $this->getUser()->isAllowed( 'block' ) ) {
-                                       if ( $row->ipb_auto ) {
-                                               $links[] = Linker::linkKnown(
-                                                       SpecialPage::getTitleFor( 'Unblock' ),
-                                                       $msg['unblocklink'],
-                                                       [],
-                                                       [ 'wpTarget' => "#{$row->ipb_id}" ]
-                                               );
-                                       } else {
-                                               $links[] = Linker::linkKnown(
-                                                       SpecialPage::getTitleFor( 'Unblock', $row->ipb_address ),
-                                                       $msg['unblocklink']
-                                               );
-                                               $links[] = Linker::linkKnown(
-                                                       SpecialPage::getTitleFor( 'Block', $row->ipb_address ),
-                                                       $msg['change-blocklink']
-                                               );
-                                       }
-                                       $formatted .= ' ' . Html::rawElement(
-                                               'span',
-                                               [ 'class' => 'mw-blocklist-actions' ],
-                                               $this->msg( 'parentheses' )->rawParams(
-                                                       $language->pipeList( $links ) )->escaped()
-                                       );
-                               }
-                               break;
-
-                       case 'ipb_by':
-                               if ( isset( $row->by_user_name ) ) {
-                                       $formatted = Linker::userLink( $value, $row->by_user_name );
-                                       $formatted .= Linker::userToolLinks( $value, $row->by_user_name );
-                               } else {
-                                       $formatted = htmlspecialchars( $row->ipb_by_text ); // foreign user?
-                               }
-                               break;
-
-                       case 'ipb_reason':
-                               $formatted = Linker::formatComment( $value );
-                               break;
-
-                       case 'ipb_params':
-                               $properties = [];
-                               if ( $row->ipb_anon_only ) {
-                                       $properties[] = $msg['anononlyblock'];
-                               }
-                               if ( $row->ipb_create_account ) {
-                                       $properties[] = $msg['createaccountblock'];
-                               }
-                               if ( $row->ipb_user && !$row->ipb_enable_autoblock ) {
-                                       $properties[] = $msg['noautoblockblock'];
-                               }
-
-                               if ( $row->ipb_block_email ) {
-                                       $properties[] = $msg['emailblock'];
-                               }
-
-                               if ( !$row->ipb_allow_usertalk ) {
-                                       $properties[] = $msg['blocklist-nousertalk'];
-                               }
-
-                               $formatted = $language->commaList( $properties );
-                               break;
-
-                       default:
-                               $formatted = "Unable to format $name";
-                               break;
-               }
-
-               return $formatted;
-       }
-
-       function getQueryInfo() {
-               $info = [
-                       'tables' => [ 'ipblocks', 'user' ],
-                       'fields' => [
-                               'ipb_id',
-                               'ipb_address',
-                               'ipb_user',
-                               'ipb_by',
-                               'ipb_by_text',
-                               'by_user_name' => 'user_name',
-                               'ipb_reason',
-                               'ipb_timestamp',
-                               'ipb_auto',
-                               'ipb_anon_only',
-                               'ipb_create_account',
-                               'ipb_enable_autoblock',
-                               'ipb_expiry',
-                               'ipb_range_start',
-                               'ipb_range_end',
-                               'ipb_deleted',
-                               'ipb_block_email',
-                               'ipb_allow_usertalk',
-                       ],
-                       'conds' => $this->conds,
-                       'join_conds' => [ 'user' => [ 'LEFT JOIN', 'user_id = ipb_by' ] ]
-               ];
-
-               # Filter out any expired blocks
-               $db = $this->getDatabase();
-               $info['conds'][] = 'ipb_expiry > ' . $db->addQuotes( $db->timestamp() );
-
-               # Is the user allowed to see hidden blocks?
-               if ( !$this->getUser()->isAllowed( 'hideuser' ) ) {
-                       $info['conds']['ipb_deleted'] = 0;
-               }
-
-               return $info;
-       }
-
-       public function getTableClass() {
-               return parent::getTableClass() . ' mw-blocklist';
-       }
-
-       function getIndexField() {
-               return 'ipb_timestamp';
-       }
-
-       function getDefaultSort() {
-               return 'ipb_timestamp';
-       }
-
-       function isFieldSortable( $name ) {
-               return false;
-       }
-
-       /**
-        * Do a LinkBatch query to minimise database load when generating all these links
-        * @param ResultWrapper $result
-        */
-       function preprocessResults( $result ) {
-               # Do a link batch query
-               $lb = new LinkBatch;
-               $lb->setCaller( __METHOD__ );
-
-               foreach ( $result as $row ) {
-                       $lb->add( NS_USER, $row->ipb_address );
-                       $lb->add( NS_USER_TALK, $row->ipb_address );
-
-                       if ( isset( $row->by_user_name ) ) {
-                               $lb->add( NS_USER, $row->by_user_name );
-                               $lb->add( NS_USER_TALK, $row->by_user_name );
-                       }
-               }
-
-               $lb->execute();
-       }
-}
index 5314f63..d7d338c 100644 (file)
@@ -92,109 +92,3 @@ class SpecialCategories extends SpecialPage {
                return 'pages';
        }
 }
-
-/**
- * TODO: Allow sorting by count.  We need to have a unique index to do this
- * properly.
- *
- * @ingroup SpecialPage Pager
- */
-class CategoryPager extends AlphabeticPager {
-
-       /**
-        * @var PageLinkRenderer
-        */
-       protected $linkRenderer;
-
-       /**
-        * @param IContextSource $context
-        * @param string $from
-        * @param PageLinkRenderer $linkRenderer
-        */
-       public function __construct( IContextSource $context, $from, PageLinkRenderer $linkRenderer
-       ) {
-               parent::__construct( $context );
-               $from = str_replace( ' ', '_', $from );
-               if ( $from !== '' ) {
-                       $from = Title::capitalize( $from, NS_CATEGORY );
-                       $this->setOffset( $from );
-                       $this->setIncludeOffset( true );
-               }
-
-               $this->linkRenderer = $linkRenderer;
-       }
-
-       function getQueryInfo() {
-               return [
-                       'tables' => [ 'category' ],
-                       'fields' => [ 'cat_title', 'cat_pages' ],
-                       'conds' => [ 'cat_pages > 0' ],
-                       'options' => [ 'USE INDEX' => 'cat_title' ],
-               ];
-       }
-
-       function getIndexField() {
-#              return array( 'abc' => 'cat_title', 'count' => 'cat_pages' );
-               return 'cat_title';
-       }
-
-       function getDefaultQuery() {
-               parent::getDefaultQuery();
-               unset( $this->mDefaultQuery['from'] );
-
-               return $this->mDefaultQuery;
-       }
-
-#      protected function getOrderTypeMessages() {
-#              return array( 'abc' => 'special-categories-sort-abc',
-#                      'count' => 'special-categories-sort-count' );
-#      }
-
-       protected function getDefaultDirections() {
-#              return array( 'abc' => false, 'count' => true );
-               return false;
-       }
-
-       /* Override getBody to apply LinksBatch on resultset before actually outputting anything. */
-       public function getBody() {
-               $batch = new LinkBatch;
-
-               $this->mResult->rewind();
-
-               foreach ( $this->mResult as $row ) {
-                       $batch->addObj( Title::makeTitleSafe( NS_CATEGORY, $row->cat_title ) );
-               }
-               $batch->execute();
-               $this->mResult->rewind();
-
-               return parent::getBody();
-       }
-
-       function formatRow( $result ) {
-               $title = new TitleValue( NS_CATEGORY, $result->cat_title );
-               $text = $title->getText();
-               $link = $this->linkRenderer->renderHtmlLink( $title, $text );
-
-               $count = $this->msg( 'nmembers' )->numParams( $result->cat_pages )->escaped();
-               return Html::rawElement( 'li', null, $this->getLanguage()->specialList( $link, $count ) ) . "\n";
-       }
-
-       public function getStartForm( $from ) {
-               return Xml::tags(
-                       'form',
-                       [ 'method' => 'get', 'action' => wfScript() ],
-                       Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
-                               Xml::fieldset(
-                                       $this->msg( 'categories' )->text(),
-                                       Xml::inputLabel(
-                                               $this->msg( 'categoriesfrom' )->text(),
-                                               'from', 'from', 20, $from, [ 'class' => 'mw-ui-input-inline' ] ) .
-                                               ' ' .
-                                               Html::submitButton(
-                                                       $this->msg( 'categories-submit' )->text(),
-                                                       [], [ 'mw-ui-progressive' ]
-                                               )
-                               )
-               );
-       }
-}
index 7b8aa4c..431b556 100644 (file)
@@ -673,508 +673,3 @@ class SpecialContributions extends IncludableSpecialPage {
                return 'users';
        }
 }
-
-/**
- * Pager for Special:Contributions
- * @ingroup SpecialPage Pager
- */
-class ContribsPager extends ReverseChronologicalPager {
-       public $mDefaultDirection = IndexPager::DIR_DESCENDING;
-       public $messages;
-       public $target;
-       public $namespace = '';
-       public $mDb;
-       public $preventClickjacking = false;
-
-       /** @var IDatabase */
-       public $mDbSecondary;
-
-       /**
-        * @var array
-        */
-       protected $mParentLens;
-
-       function __construct( IContextSource $context, array $options ) {
-               parent::__construct( $context );
-
-               $msgs = [
-                       'diff',
-                       'hist',
-                       'pipe-separator',
-                       'uctop'
-               ];
-
-               foreach ( $msgs as $msg ) {
-                       $this->messages[$msg] = $this->msg( $msg )->escaped();
-               }
-
-               $this->target = isset( $options['target'] ) ? $options['target'] : '';
-               $this->contribs = isset( $options['contribs'] ) ? $options['contribs'] : 'users';
-               $this->namespace = isset( $options['namespace'] ) ? $options['namespace'] : '';
-               $this->tagFilter = isset( $options['tagfilter'] ) ? $options['tagfilter'] : false;
-               $this->nsInvert = isset( $options['nsInvert'] ) ? $options['nsInvert'] : false;
-               $this->associated = isset( $options['associated'] ) ? $options['associated'] : false;
-
-               $this->deletedOnly = !empty( $options['deletedOnly'] );
-               $this->topOnly = !empty( $options['topOnly'] );
-               $this->newOnly = !empty( $options['newOnly'] );
-
-               $year = isset( $options['year'] ) ? $options['year'] : false;
-               $month = isset( $options['month'] ) ? $options['month'] : false;
-               $this->getDateCond( $year, $month );
-
-               // Most of this code will use the 'contributions' group DB, which can map to slaves
-               // with extra user based indexes or partioning by user. The additional metadata
-               // queries should use a regular slave since the lookup pattern is not all by user.
-               $this->mDbSecondary = wfGetDB( DB_SLAVE ); // any random slave
-               $this->mDb = wfGetDB( DB_SLAVE, 'contributions' );
-       }
-
-       function getDefaultQuery() {
-               $query = parent::getDefaultQuery();
-               $query['target'] = $this->target;
-
-               return $query;
-       }
-
-       /**
-        * This method basically executes the exact same code as the parent class, though with
-        * a hook added, to allow extensions to add additional queries.
-        *
-        * @param string $offset Index offset, inclusive
-        * @param int $limit Exact query limit
-        * @param bool $descending Query direction, false for ascending, true for descending
-        * @return ResultWrapper
-        */
-       function reallyDoQuery( $offset, $limit, $descending ) {
-               list( $tables, $fields, $conds, $fname, $options, $join_conds ) = $this->buildQueryInfo(
-                       $offset,
-                       $limit,
-                       $descending
-               );
-
-               /*
-                * This hook will allow extensions to add in additional queries, so they can get their data
-                * in My Contributions as well. Extensions should append their results to the $data array.
-                *
-                * Extension queries have to implement the navbar requirement as well. They should
-                * - have a column aliased as $pager->getIndexField()
-                * - have LIMIT set
-                * - have a WHERE-clause that compares the $pager->getIndexField()-equivalent column to the offset
-                * - have the ORDER BY specified based upon the details provided by the navbar
-                *
-                * See includes/Pager.php buildQueryInfo() method on how to build LIMIT, WHERE & ORDER BY
-                *
-                * &$data: an array of results of all contribs queries
-                * $pager: the ContribsPager object hooked into
-                * $offset: see phpdoc above
-                * $limit: see phpdoc above
-                * $descending: see phpdoc above
-                */
-               $data = [ $this->mDb->select(
-                       $tables, $fields, $conds, $fname, $options, $join_conds
-               ) ];
-               Hooks::run(
-                       'ContribsPager::reallyDoQuery',
-                       [ &$data, $this, $offset, $limit, $descending ]
-               );
-
-               $result = [];
-
-               // loop all results and collect them in an array
-               foreach ( $data as $query ) {
-                       foreach ( $query as $i => $row ) {
-                               // use index column as key, allowing us to easily sort in PHP
-                               $result[$row->{$this->getIndexField()} . "-$i"] = $row;
-                       }
-               }
-
-               // sort results
-               if ( $descending ) {
-                       ksort( $result );
-               } else {
-                       krsort( $result );
-               }
-
-               // enforce limit
-               $result = array_slice( $result, 0, $limit );
-
-               // get rid of array keys
-               $result = array_values( $result );
-
-               return new FakeResultWrapper( $result );
-       }
-
-       function getQueryInfo() {
-               list( $tables, $index, $userCond, $join_cond ) = $this->getUserCond();
-
-               $user = $this->getUser();
-               $conds = array_merge( $userCond, $this->getNamespaceCond() );
-
-               // Paranoia: avoid brute force searches (bug 17342)
-               if ( !$user->isAllowed( 'deletedhistory' ) ) {
-                       $conds[] = $this->mDb->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0';
-               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
-                       $conds[] = $this->mDb->bitAnd( 'rev_deleted', Revision::SUPPRESSED_USER ) .
-                               ' != ' . Revision::SUPPRESSED_USER;
-               }
-
-               # Don't include orphaned revisions
-               $join_cond['page'] = Revision::pageJoinCond();
-               # Get the current user name for accounts
-               $join_cond['user'] = Revision::userJoinCond();
-
-               $options = [];
-               if ( $index ) {
-                       $options['USE INDEX'] = [ 'revision' => $index ];
-               }
-
-               $queryInfo = [
-                       'tables' => $tables,
-                       'fields' => array_merge(
-                               Revision::selectFields(),
-                               Revision::selectUserFields(),
-                               [ 'page_namespace', 'page_title', 'page_is_new',
-                                       'page_latest', 'page_is_redirect', 'page_len' ]
-                       ),
-                       'conds' => $conds,
-                       'options' => $options,
-                       'join_conds' => $join_cond
-               ];
-
-               ChangeTags::modifyDisplayQuery(
-                       $queryInfo['tables'],
-                       $queryInfo['fields'],
-                       $queryInfo['conds'],
-                       $queryInfo['join_conds'],
-                       $queryInfo['options'],
-                       $this->tagFilter
-               );
-
-               Hooks::run( 'ContribsPager::getQueryInfo', [ &$this, &$queryInfo ] );
-
-               return $queryInfo;
-       }
-
-       function getUserCond() {
-               $condition = [];
-               $join_conds = [];
-               $tables = [ 'revision', 'page', 'user' ];
-               $index = false;
-               if ( $this->contribs == 'newbie' ) {
-                       $max = $this->mDb->selectField( 'user', 'max(user_id)', false, __METHOD__ );
-                       $condition[] = 'rev_user >' . (int)( $max - $max / 100 );
-                       # ignore local groups with the bot right
-                       # @todo FIXME: Global groups may have 'bot' rights
-                       $groupsWithBotPermission = User::getGroupsWithPermission( 'bot' );
-                       if ( count( $groupsWithBotPermission ) ) {
-                               $tables[] = 'user_groups';
-                               $condition[] = 'ug_group IS NULL';
-                               $join_conds['user_groups'] = [
-                                       'LEFT JOIN', [
-                                               'ug_user = rev_user',
-                                               'ug_group' => $groupsWithBotPermission
-                                       ]
-                               ];
-                       }
-               } else {
-                       $uid = User::idFromName( $this->target );
-                       if ( $uid ) {
-                               $condition['rev_user'] = $uid;
-                               $index = 'user_timestamp';
-                       } else {
-                               $condition['rev_user_text'] = $this->target;
-                               $index = 'usertext_timestamp';
-                       }
-               }
-
-               if ( $this->deletedOnly ) {
-                       $condition[] = 'rev_deleted != 0';
-               }
-
-               if ( $this->topOnly ) {
-                       $condition[] = 'rev_id = page_latest';
-               }
-
-               if ( $this->newOnly ) {
-                       $condition[] = 'rev_parent_id = 0';
-               }
-
-               return [ $tables, $index, $condition, $join_conds ];
-       }
-
-       function getNamespaceCond() {
-               if ( $this->namespace !== '' ) {
-                       $selectedNS = $this->mDb->addQuotes( $this->namespace );
-                       $eq_op = $this->nsInvert ? '!=' : '=';
-                       $bool_op = $this->nsInvert ? 'AND' : 'OR';
-
-                       if ( !$this->associated ) {
-                               return [ "page_namespace $eq_op $selectedNS" ];
-                       }
-
-                       $associatedNS = $this->mDb->addQuotes(
-                               MWNamespace::getAssociated( $this->namespace )
-                       );
-
-                       return [
-                               "page_namespace $eq_op $selectedNS " .
-                                       $bool_op .
-                                       " page_namespace $eq_op $associatedNS"
-                       ];
-               }
-
-               return [];
-       }
-
-       function getIndexField() {
-               return 'rev_timestamp';
-       }
-
-       function doBatchLookups() {
-               # Do a link batch query
-               $this->mResult->seek( 0 );
-               $parentRevIds = [];
-               $this->mParentLens = [];
-               $batch = new LinkBatch();
-               # Give some pointers to make (last) links
-               foreach ( $this->mResult as $row ) {
-                       if ( isset( $row->rev_parent_id ) && $row->rev_parent_id ) {
-                               $parentRevIds[] = $row->rev_parent_id;
-                       }
-                       if ( isset( $row->rev_id ) ) {
-                               $this->mParentLens[$row->rev_id] = $row->rev_len;
-                               if ( $this->contribs === 'newbie' ) { // multiple users
-                                       $batch->add( NS_USER, $row->user_name );
-                                       $batch->add( NS_USER_TALK, $row->user_name );
-                               }
-                               $batch->add( $row->page_namespace, $row->page_title );
-                       }
-               }
-               # Fetch rev_len for revisions not already scanned above
-               $this->mParentLens += Revision::getParentLengths(
-                       $this->mDbSecondary,
-                       array_diff( $parentRevIds, array_keys( $this->mParentLens ) )
-               );
-               $batch->execute();
-               $this->mResult->seek( 0 );
-       }
-
-       /**
-        * @return string
-        */
-       function getStartBody() {
-               return "<ul class=\"mw-contributions-list\">\n";
-       }
-
-       /**
-        * @return string
-        */
-       function getEndBody() {
-               return "</ul>\n";
-       }
-
-       /**
-        * Generates each row in the contributions list.
-        *
-        * Contributions which are marked "top" are currently on top of the history.
-        * For these contributions, a [rollback] link is shown for users with roll-
-        * back privileges. The rollback link restores the most recent version that
-        * was not written by the target user.
-        *
-        * @todo This would probably look a lot nicer in a table.
-        * @param object $row
-        * @return string
-        */
-       function formatRow( $row ) {
-
-               $ret = '';
-               $classes = [];
-
-               /*
-                * There may be more than just revision rows. To make sure that we'll only be processing
-                * revisions here, let's _try_ to build a revision out of our row (without displaying
-                * notices though) and then trying to grab data from the built object. If we succeed,
-                * we're definitely dealing with revision data and we may proceed, if not, we'll leave it
-                * to extensions to subscribe to the hook to parse the row.
-                */
-               MediaWiki\suppressWarnings();
-               try {
-                       $rev = new Revision( $row );
-                       $validRevision = (bool)$rev->getId();
-               } catch ( Exception $e ) {
-                       $validRevision = false;
-               }
-               MediaWiki\restoreWarnings();
-
-               if ( $validRevision ) {
-                       $classes = [];
-
-                       $page = Title::newFromRow( $row );
-                       $link = Linker::link(
-                               $page,
-                               htmlspecialchars( $page->getPrefixedText() ),
-                               [ 'class' => 'mw-contributions-title' ],
-                               $page->isRedirect() ? [ 'redirect' => 'no' ] : []
-                       );
-                       # Mark current revisions
-                       $topmarktext = '';
-                       $user = $this->getUser();
-                       if ( $row->rev_id == $row->page_latest ) {
-                               $topmarktext .= '<span class="mw-uctop">' . $this->messages['uctop'] . '</span>';
-                               # Add rollback link
-                               if ( !$row->page_is_new && $page->quickUserCan( 'rollback', $user )
-                                       && $page->quickUserCan( 'edit', $user )
-                               ) {
-                                       $this->preventClickjacking();
-                                       $topmarktext .= ' ' . Linker::generateRollback( $rev, $this->getContext() );
-                               }
-                       }
-                       # Is there a visible previous revision?
-                       if ( $rev->userCan( Revision::DELETED_TEXT, $user ) && $rev->getParentId() !== 0 ) {
-                               $difftext = Linker::linkKnown(
-                                       $page,
-                                       $this->messages['diff'],
-                                       [],
-                                       [
-                                               'diff' => 'prev',
-                                               'oldid' => $row->rev_id
-                                       ]
-                               );
-                       } else {
-                               $difftext = $this->messages['diff'];
-                       }
-                       $histlink = Linker::linkKnown(
-                               $page,
-                               $this->messages['hist'],
-                               [],
-                               [ 'action' => 'history' ]
-                       );
-
-                       if ( $row->rev_parent_id === null ) {
-                               // For some reason rev_parent_id isn't populated for this row.
-                               // Its rumoured this is true on wikipedia for some revisions (bug 34922).
-                               // Next best thing is to have the total number of bytes.
-                               $chardiff = ' <span class="mw-changeslist-separator">. .</span> ';
-                               $chardiff .= Linker::formatRevisionSize( $row->rev_len );
-                               $chardiff .= ' <span class="mw-changeslist-separator">. .</span> ';
-                       } else {
-                               $parentLen = 0;
-                               if ( isset( $this->mParentLens[$row->rev_parent_id] ) ) {
-                                       $parentLen = $this->mParentLens[$row->rev_parent_id];
-                               }
-
-                               $chardiff = ' <span class="mw-changeslist-separator">. .</span> ';
-                               $chardiff .= ChangesList::showCharacterDifference(
-                                       $parentLen,
-                                       $row->rev_len,
-                                       $this->getContext()
-                               );
-                               $chardiff .= ' <span class="mw-changeslist-separator">. .</span> ';
-                       }
-
-                       $lang = $this->getLanguage();
-                       $comment = $lang->getDirMark() . Linker::revComment( $rev, false, true );
-                       $date = $lang->userTimeAndDate( $row->rev_timestamp, $user );
-                       if ( $rev->userCan( Revision::DELETED_TEXT, $user ) ) {
-                               $d = Linker::linkKnown(
-                                       $page,
-                                       htmlspecialchars( $date ),
-                                       [ 'class' => 'mw-changeslist-date' ],
-                                       [ 'oldid' => intval( $row->rev_id ) ]
-                               );
-                       } else {
-                               $d = htmlspecialchars( $date );
-                       }
-                       if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
-                               $d = '<span class="history-deleted">' . $d . '</span>';
-                       }
-
-                       # Show user names for /newbies as there may be different users.
-                       # Note that we already excluded rows with hidden user names.
-                       if ( $this->contribs == 'newbie' ) {
-                               $userlink = ' . . ' . $lang->getDirMark()
-                                       . Linker::userLink( $rev->getUser(), $rev->getUserText() );
-                               $userlink .= ' ' . $this->msg( 'parentheses' )->rawParams(
-                                       Linker::userTalkLink( $rev->getUser(), $rev->getUserText() ) )->escaped() . ' ';
-                       } else {
-                               $userlink = '';
-                       }
-
-                       if ( $rev->getParentId() === 0 ) {
-                               $nflag = ChangesList::flag( 'newpage' );
-                       } else {
-                               $nflag = '';
-                       }
-
-                       if ( $rev->isMinor() ) {
-                               $mflag = ChangesList::flag( 'minor' );
-                       } else {
-                               $mflag = '';
-                       }
-
-                       $del = Linker::getRevDeleteLink( $user, $rev, $page );
-                       if ( $del !== '' ) {
-                               $del .= ' ';
-                       }
-
-                       $diffHistLinks = $this->msg( 'parentheses' )
-                               ->rawParams( $difftext . $this->messages['pipe-separator'] . $histlink )
-                               ->escaped();
-                       $ret = "{$del}{$d} {$diffHistLinks}{$chardiff}{$nflag}{$mflag} ";
-                       $ret .= "{$link}{$userlink} {$comment} {$topmarktext}";
-
-                       # Denote if username is redacted for this edit
-                       if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
-                               $ret .= " <strong>" .
-                                       $this->msg( 'rev-deleted-user-contribs' )->escaped() .
-                                       "</strong>";
-                       }
-
-                       # Tags, if any.
-                       list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow(
-                               $row->ts_tags,
-                               'contributions',
-                               $this->getContext()
-                       );
-                       $classes = array_merge( $classes, $newClasses );
-                       $ret .= " $tagSummary";
-               }
-
-               // Let extensions add data
-               Hooks::run( 'ContributionsLineEnding', [ $this, &$ret, $row, &$classes ] );
-
-               if ( $classes === [] && $ret === '' ) {
-                       wfDebug( "Dropping Special:Contribution row that could not be formatted\n" );
-                       $ret = "<!-- Could not format Special:Contribution row. -->\n";
-               } else {
-                       $ret = Html::rawElement( 'li', [ 'class' => $classes ], $ret ) . "\n";
-               }
-
-               return $ret;
-       }
-
-       /**
-        * Overwrite Pager function and return a helpful comment
-        * @return string
-        */
-       function getSqlComment() {
-               if ( $this->namespace || $this->deletedOnly ) {
-                       // potentially slow, see CR r58153
-                       return 'contributions page filtered for namespace or RevisionDeleted edits';
-               } else {
-                       return 'contributions page unfiltered';
-               }
-       }
-
-       protected function preventClickjacking() {
-               $this->preventClickjacking = true;
-       }
-
-       /**
-        * @return bool
-        */
-       public function getPreventClickjacking() {
-               return $this->preventClickjacking;
-       }
-}
index 6256bbf..190bf9f 100644 (file)
  * Implements Special:DeletedContributions to display archived revisions
  * @ingroup SpecialPage
  */
-class DeletedContribsPager extends IndexPager {
-       public $mDefaultDirection = IndexPager::DIR_DESCENDING;
-       public $messages;
-       public $target;
-       public $namespace = '';
-       public $mDb;
-
-       /**
-        * @var string Navigation bar with paging links.
-        */
-       protected $mNavigationBar;
-
-       function __construct( IContextSource $context, $target, $namespace = false ) {
-               parent::__construct( $context );
-               $msgs = [ 'deletionlog', 'undeleteviewlink', 'diff' ];
-               foreach ( $msgs as $msg ) {
-                       $this->messages[$msg] = $this->msg( $msg )->escaped();
-               }
-               $this->target = $target;
-               $this->namespace = $namespace;
-               $this->mDb = wfGetDB( DB_SLAVE, 'contributions' );
-       }
-
-       function getDefaultQuery() {
-               $query = parent::getDefaultQuery();
-               $query['target'] = $this->target;
-
-               return $query;
-       }
-
-       function getQueryInfo() {
-               list( $index, $userCond ) = $this->getUserCond();
-               $conds = array_merge( $userCond, $this->getNamespaceCond() );
-               $user = $this->getUser();
-               // Paranoia: avoid brute force searches (bug 17792)
-               if ( !$user->isAllowed( 'deletedhistory' ) ) {
-                       $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::DELETED_USER ) . ' = 0';
-               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
-                       $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::SUPPRESSED_USER ) .
-                               ' != ' . Revision::SUPPRESSED_USER;
-               }
-
-               return [
-                       'tables' => [ 'archive' ],
-                       'fields' => [
-                               'ar_rev_id', 'ar_namespace', 'ar_title', 'ar_timestamp', 'ar_comment',
-                               'ar_minor_edit', 'ar_user', 'ar_user_text', 'ar_deleted'
-                       ],
-                       'conds' => $conds,
-                       'options' => [ 'USE INDEX' => $index ]
-               ];
-       }
-
-       /**
-        * This method basically executes the exact same code as the parent class, though with
-        * a hook added, to allow extensions to add additional queries.
-        *
-        * @param string $offset Index offset, inclusive
-        * @param int $limit Exact query limit
-        * @param bool $descending Query direction, false for ascending, true for descending
-        * @return ResultWrapper
-        */
-       function reallyDoQuery( $offset, $limit, $descending ) {
-               $data = [ parent::reallyDoQuery( $offset, $limit, $descending ) ];
-
-               // This hook will allow extensions to add in additional queries, nearly
-               // identical to ContribsPager::reallyDoQuery.
-               Hooks::run(
-                       'DeletedContribsPager::reallyDoQuery',
-                       [ &$data, $this, $offset, $limit, $descending ]
-               );
-
-               $result = [];
-
-               // loop all results and collect them in an array
-               foreach ( $data as $query ) {
-                       foreach ( $query as $i => $row ) {
-                               // use index column as key, allowing us to easily sort in PHP
-                               $result[$row->{$this->getIndexField()} . "-$i"] = $row;
-                       }
-               }
-
-               // sort results
-               if ( $descending ) {
-                       ksort( $result );
-               } else {
-                       krsort( $result );
-               }
-
-               // enforce limit
-               $result = array_slice( $result, 0, $limit );
-
-               // get rid of array keys
-               $result = array_values( $result );
-
-               return new FakeResultWrapper( $result );
-       }
-
-       function getUserCond() {
-               $condition = [];
-
-               $condition['ar_user_text'] = $this->target;
-               $index = 'usertext_timestamp';
-
-               return [ $index, $condition ];
-       }
-
-       function getIndexField() {
-               return 'ar_timestamp';
-       }
-
-       function getStartBody() {
-               return "<ul>\n";
-       }
-
-       function getEndBody() {
-               return "</ul>\n";
-       }
-
-       function getNavigationBar() {
-               if ( isset( $this->mNavigationBar ) ) {
-                       return $this->mNavigationBar;
-               }
-
-               $linkTexts = [
-                       'prev' => $this->msg( 'pager-newer-n' )->numParams( $this->mLimit )->escaped(),
-                       'next' => $this->msg( 'pager-older-n' )->numParams( $this->mLimit )->escaped(),
-                       'first' => $this->msg( 'histlast' )->escaped(),
-                       'last' => $this->msg( 'histfirst' )->escaped()
-               ];
-
-               $pagingLinks = $this->getPagingLinks( $linkTexts );
-               $limitLinks = $this->getLimitLinks();
-               $lang = $this->getLanguage();
-               $limits = $lang->pipeList( $limitLinks );
-
-               $firstLast = $lang->pipeList( [ $pagingLinks['first'], $pagingLinks['last'] ] );
-               $firstLast = $this->msg( 'parentheses' )->rawParams( $firstLast )->escaped();
-               $prevNext = $this->msg( 'viewprevnext' )
-                       ->rawParams(
-                               $pagingLinks['prev'],
-                               $pagingLinks['next'],
-                               $limits
-                       )->escaped();
-               $separator = $this->msg( 'word-separator' )->escaped();
-               $this->mNavigationBar = $firstLast . $separator . $prevNext;
-
-               return $this->mNavigationBar;
-       }
-
-       function getNamespaceCond() {
-               if ( $this->namespace !== '' ) {
-                       return [ 'ar_namespace' => (int)$this->namespace ];
-               } else {
-                       return [];
-               }
-       }
-
-       /**
-        * Generates each row in the contributions list.
-        *
-        * @todo This would probably look a lot nicer in a table.
-        * @param stdClass $row
-        * @return string
-        */
-       function formatRow( $row ) {
-               $ret = '';
-               $classes = [];
-
-               /*
-                * There may be more than just revision rows. To make sure that we'll only be processing
-                * revisions here, let's _try_ to build a revision out of our row (without displaying
-                * notices though) and then trying to grab data from the built object. If we succeed,
-                * we're definitely dealing with revision data and we may proceed, if not, we'll leave it
-                * to extensions to subscribe to the hook to parse the row.
-                */
-               MediaWiki\suppressWarnings();
-               try {
-                       $rev = Revision::newFromArchiveRow( $row );
-                       $validRevision = (bool)$rev->getId();
-               } catch ( Exception $e ) {
-                       $validRevision = false;
-               }
-               MediaWiki\restoreWarnings();
-
-               if ( $validRevision ) {
-                       $ret = $this->formatRevisionRow( $row );
-               }
-
-               // Let extensions add data
-               Hooks::run( 'DeletedContributionsLineEnding', [ $this, &$ret, $row, &$classes ] );
-
-               if ( $classes === [] && $ret === '' ) {
-                       wfDebug( "Dropping Special:DeletedContribution row that could not be formatted\n" );
-                       $ret = "<!-- Could not format Special:DeletedContribution row. -->\n";
-               } else {
-                       $ret = Html::rawElement( 'li', [ 'class' => $classes ], $ret ) . "\n";
-               }
-
-               return $ret;
-       }
-
-       /**
-        * Generates each row in the contributions list for archive entries.
-        *
-        * Contributions which are marked "top" are currently on top of the history.
-        * For these contributions, a [rollback] link is shown for users with sysop
-        * privileges. The rollback link restores the most recent version that was not
-        * written by the target user.
-        *
-        * @todo This would probably look a lot nicer in a table.
-        * @param stdClass $row
-        * @return string
-        */
-       function formatRevisionRow( $row ) {
-               $page = Title::makeTitle( $row->ar_namespace, $row->ar_title );
-
-               $rev = new Revision( [
-                       'title' => $page,
-                       'id' => $row->ar_rev_id,
-                       'comment' => $row->ar_comment,
-                       'user' => $row->ar_user,
-                       'user_text' => $row->ar_user_text,
-                       'timestamp' => $row->ar_timestamp,
-                       'minor_edit' => $row->ar_minor_edit,
-                       'deleted' => $row->ar_deleted,
-               ] );
-
-               $undelete = SpecialPage::getTitleFor( 'Undelete' );
-
-               $logs = SpecialPage::getTitleFor( 'Log' );
-               $dellog = Linker::linkKnown(
-                       $logs,
-                       $this->messages['deletionlog'],
-                       [],
-                       [
-                               'type' => 'delete',
-                               'page' => $page->getPrefixedText()
-                       ]
-               );
-
-               $reviewlink = Linker::linkKnown(
-                       SpecialPage::getTitleFor( 'Undelete', $page->getPrefixedDBkey() ),
-                       $this->messages['undeleteviewlink']
-               );
-
-               $user = $this->getUser();
-
-               if ( $user->isAllowed( 'deletedtext' ) ) {
-                       $last = Linker::linkKnown(
-                               $undelete,
-                               $this->messages['diff'],
-                               [],
-                               [
-                                       'target' => $page->getPrefixedText(),
-                                       'timestamp' => $rev->getTimestamp(),
-                                       'diff' => 'prev'
-                               ]
-                       );
-               } else {
-                       $last = $this->messages['diff'];
-               }
-
-               $comment = Linker::revComment( $rev );
-               $date = $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $user );
-               $date = htmlspecialchars( $date );
-
-               if ( !$user->isAllowed( 'undelete' ) || !$rev->userCan( Revision::DELETED_TEXT, $user ) ) {
-                       $link = $date; // unusable link
-               } else {
-                       $link = Linker::linkKnown(
-                               $undelete,
-                               $date,
-                               [ 'class' => 'mw-changeslist-date' ],
-                               [
-                                       'target' => $page->getPrefixedText(),
-                                       'timestamp' => $rev->getTimestamp()
-                               ]
-                       );
-               }
-               // Style deleted items
-               if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
-                       $link = '<span class="history-deleted">' . $link . '</span>';
-               }
-
-               $pagelink = Linker::link(
-                       $page,
-                       null,
-                       [ 'class' => 'mw-changeslist-title' ]
-               );
-
-               if ( $rev->isMinor() ) {
-                       $mflag = ChangesList::flag( 'minor' );
-               } else {
-                       $mflag = '';
-               }
-
-               // Revision delete link
-               $del = Linker::getRevDeleteLink( $user, $rev, $page );
-               if ( $del ) {
-                       $del .= ' ';
-               }
-
-               $tools = Html::rawElement(
-                       'span',
-                       [ 'class' => 'mw-deletedcontribs-tools' ],
-                       $this->msg( 'parentheses' )->rawParams( $this->getLanguage()->pipeList(
-                               [ $last, $dellog, $reviewlink ] ) )->escaped()
-               );
-
-               $separator = '<span class="mw-changeslist-separator">. .</span>';
-               $ret = "{$del}{$link} {$tools} {$separator} {$mflag} {$pagelink} {$comment}";
-
-               # Denote if username is redacted for this edit
-               if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
-                       $ret .= " <strong>" . $this->msg( 'rev-deleted-user-contribs' )->escaped() . "</strong>";
-               }
-
-               return $ret;
-       }
-
-       /**
-        * Get the Database object in use
-        *
-        * @return IDatabase
-        */
-       public function getDatabase() {
-               return $this->mDb;
-       }
-}
-
 class DeletedContributionsPage extends SpecialPage {
        function __construct() {
                parent::__construct( 'DeletedContributions', 'deletedhistory',
index a9753ae..c1abd6e 100644 (file)
@@ -49,10 +49,26 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
 
        private $badItems = [];
 
+       /**
+        * @var TitleParser
+        */
+       private $titleParser;
+
        public function __construct() {
                parent::__construct( 'EditWatchlist', 'editmywatchlist' );
        }
 
+       /**
+        * Initialize any services we'll need (unless it has already been provided via a setter).
+        * This allows for dependency injection even though we don't control object creation.
+        */
+       private function initServices() {
+               if ( !$this->titleParser ) {
+                       $lang = $this->getContext()->getLanguage();
+                       $this->titleParser = new MediaWikiTitleCodec( $lang, GenderCache::singleton() );
+               }
+       }
+
        public function doesWrites() {
                return true;
        }
@@ -63,6 +79,7 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         * @param int $mode
         */
        public function execute( $mode ) {
+               $this->initServices();
                $this->setHeaders();
 
                # Anons don't get a watchlist
@@ -432,39 +449,32 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
        }
 
        /**
-        * Add a list of titles to a user's watchlist
-        *
-        * $titles can be an array of strings or Title objects; the former
-        * is preferred, since Titles are very memory-heavy
+        * Add a list of targets to a user's watchlist
         *
-        * @param array $titles Array of strings, or Title objects
+        * @param string[]|LinkTarget[] $targets
         */
-       private function watchTitles( $titles ) {
-               $dbw = wfGetDB( DB_MASTER );
-               $rows = [];
-
-               foreach ( $titles as $title ) {
-                       if ( !$title instanceof Title ) {
-                               $title = Title::newFromText( $title );
+       private function watchTitles( $targets ) {
+               $expandedTargets = [];
+               foreach ( $targets as $target ) {
+                       if ( !$target instanceof LinkTarget ) {
+                               try {
+                                       $target = $this->titleParser->parseTitle( $target, NS_MAIN );
+                               }
+                               catch ( MalformedTitleException $e ) {
+                                       continue;
+                               }
                        }
 
-                       if ( $title instanceof Title ) {
-                               $rows[] = [
-                                       'wl_user' => $this->getUser()->getId(),
-                                       'wl_namespace' => MWNamespace::getSubject( $title->getNamespace() ),
-                                       'wl_title' => $title->getDBkey(),
-                                       'wl_notificationtimestamp' => null,
-                               ];
-                               $rows[] = [
-                                       'wl_user' => $this->getUser()->getId(),
-                                       'wl_namespace' => MWNamespace::getTalk( $title->getNamespace() ),
-                                       'wl_title' => $title->getDBkey(),
-                                       'wl_notificationtimestamp' => null,
-                               ];
-                       }
+                       $ns = $target->getNamespace();
+                       $dbKey = $target->getDBkey();
+                       $expandedTargets[] = new TitleValue( MWNamespace::getSubject( $ns ), $dbKey );
+                       $expandedTargets[] = new TitleValue( MWNamespace::getTalk( $ns ), $dbKey );
                }
 
-               $dbw->insert( 'watchlist', $rows, __METHOD__, 'IGNORE' );
+               WatchedItemStore::getDefaultInstance()->addWatchBatchForUser(
+                       $this->getUser(),
+                       $expandedTargets
+               );
        }
 
        /**
index 6c856e9..e6e1048 100644 (file)
@@ -81,584 +81,3 @@ class SpecialListFiles extends IncludableSpecialPage {
                return 'media';
        }
 }
-
-/**
- * @ingroup SpecialPage Pager
- */
-class ImageListPager extends TablePager {
-       protected $mFieldNames = null;
-
-       // Subclasses should override buildQueryConds instead of using $mQueryConds variable.
-       protected $mQueryConds = [];
-
-       protected $mUserName = null;
-
-       /**
-        * The relevant user
-        *
-        * @var User|null
-        */
-       protected $mUser = null;
-
-       protected $mSearch = '';
-
-       protected $mIncluding = false;
-
-       protected $mShowAll = false;
-
-       protected $mTableName = 'image';
-
-       function __construct( IContextSource $context, $userName = null, $search = '',
-               $including = false, $showAll = false
-       ) {
-               $this->setContext( $context );
-               $this->mIncluding = $including;
-               $this->mShowAll = $showAll;
-
-               if ( $userName !== null && $userName !== '' ) {
-                       $nt = Title::newFromText( $userName, NS_USER );
-                       if ( is_null( $nt ) ) {
-                               $this->outputUserDoesNotExist( $userName );
-                       } else {
-                               $this->mUserName = $nt->getText();
-                               $user = User::newFromName( $this->mUserName, false );
-                               if ( $user ) {
-                                       $this->mUser = $user;
-                               }
-                               if ( !$user || ( $user->isAnon() && !User::isIP( $user->getName() ) ) ) {
-                                       $this->outputUserDoesNotExist( $userName );
-                               }
-                       }
-               }
-
-               if ( $search !== '' && !$this->getConfig()->get( 'MiserMode' ) ) {
-                       $this->mSearch = $search;
-                       $nt = Title::newFromText( $this->mSearch );
-
-                       if ( $nt ) {
-                               $dbr = wfGetDB( DB_SLAVE );
-                               $this->mQueryConds[] = 'LOWER(img_name)' .
-                                       $dbr->buildLike( $dbr->anyString(),
-                                               strtolower( $nt->getDBkey() ), $dbr->anyString() );
-                       }
-               }
-
-               if ( !$including ) {
-                       if ( $this->getRequest()->getText( 'sort', 'img_date' ) == 'img_date' ) {
-                               $this->mDefaultDirection = IndexPager::DIR_DESCENDING;
-                       } else {
-                               $this->mDefaultDirection = IndexPager::DIR_ASCENDING;
-                       }
-               } else {
-                       $this->mDefaultDirection = IndexPager::DIR_DESCENDING;
-               }
-
-               parent::__construct( $context );
-       }
-
-       /**
-        * Get the user relevant to the ImageList
-        *
-        * @return User|null
-        */
-       function getRelevantUser() {
-               return $this->mUser;
-       }
-
-       /**
-        * Add a message to the output stating that the user doesn't exist
-        *
-        * @param string $userName Unescaped user name
-        */
-       protected function outputUserDoesNotExist( $userName ) {
-               $this->getOutput()->wrapWikiMsg(
-                       "<div class=\"mw-userpage-userdoesnotexist error\">\n$1\n</div>",
-                       [
-                               'listfiles-userdoesnotexist',
-                               wfEscapeWikiText( $userName ),
-                       ]
-               );
-       }
-
-       /**
-        * Build the where clause of the query.
-        *
-        * Replaces the older mQueryConds member variable.
-        * @param string $table Either "image" or "oldimage"
-        * @return array The query conditions.
-        */
-       protected function buildQueryConds( $table ) {
-               $prefix = $table === 'image' ? 'img' : 'oi';
-               $conds = [];
-
-               if ( !is_null( $this->mUserName ) ) {
-                       $conds[$prefix . '_user_text'] = $this->mUserName;
-               }
-
-               if ( $this->mSearch !== '' ) {
-                       $nt = Title::newFromText( $this->mSearch );
-                       if ( $nt ) {
-                               $dbr = wfGetDB( DB_SLAVE );
-                               $conds[] = 'LOWER(' . $prefix . '_name)' .
-                                       $dbr->buildLike( $dbr->anyString(),
-                                               strtolower( $nt->getDBkey() ), $dbr->anyString() );
-                       }
-               }
-
-               if ( $table === 'oldimage' ) {
-                       // Don't want to deal with revdel.
-                       // Future fixme: Show partial information as appropriate.
-                       // Would have to be careful about filtering by username when username is deleted.
-                       $conds['oi_deleted'] = 0;
-               }
-
-               // Add mQueryConds in case anyone was subclassing and using the old variable.
-               return $conds + $this->mQueryConds;
-       }
-
-       /**
-        * @return array
-        */
-       function getFieldNames() {
-               if ( !$this->mFieldNames ) {
-                       $this->mFieldNames = [
-                               'img_timestamp' => $this->msg( 'listfiles_date' )->text(),
-                               'img_name' => $this->msg( 'listfiles_name' )->text(),
-                               'thumb' => $this->msg( 'listfiles_thumb' )->text(),
-                               'img_size' => $this->msg( 'listfiles_size' )->text(),
-                       ];
-                       if ( is_null( $this->mUserName ) ) {
-                               // Do not show username if filtering by username
-                               $this->mFieldNames['img_user_text'] = $this->msg( 'listfiles_user' )->text();
-                       }
-                       // img_description down here, in order so that its still after the username field.
-                       $this->mFieldNames['img_description'] = $this->msg( 'listfiles_description' )->text();
-
-                       if ( !$this->getConfig()->get( 'MiserMode' ) && !$this->mShowAll ) {
-                               $this->mFieldNames['count'] = $this->msg( 'listfiles_count' )->text();
-                       }
-                       if ( $this->mShowAll ) {
-                               $this->mFieldNames['top'] = $this->msg( 'listfiles-latestversion' )->text();
-                       }
-               }
-
-               return $this->mFieldNames;
-       }
-
-       function isFieldSortable( $field ) {
-               if ( $this->mIncluding ) {
-                       return false;
-               }
-               $sortable = [ 'img_timestamp', 'img_name', 'img_size' ];
-               /* For reference, the indicies we can use for sorting are:
-                * On the image table: img_usertext_timestamp, img_size, img_timestamp
-                * On oldimage: oi_usertext_timestamp, oi_name_timestamp
-                *
-                * In particular that means we cannot sort by timestamp when not filtering
-                * by user and including old images in the results. Which is sad.
-                */
-               if ( $this->getConfig()->get( 'MiserMode' ) && !is_null( $this->mUserName ) ) {
-                       // If we're sorting by user, the index only supports sorting by time.
-                       if ( $field === 'img_timestamp' ) {
-                               return true;
-                       } else {
-                               return false;
-                       }
-               } elseif ( $this->getConfig()->get( 'MiserMode' )
-                       && $this->mShowAll /* && mUserName === null */
-               ) {
-                       // no oi_timestamp index, so only alphabetical sorting in this case.
-                       if ( $field === 'img_name' ) {
-                               return true;
-                       } else {
-                               return false;
-                       }
-               }
-
-               return in_array( $field, $sortable );
-       }
-
-       function getQueryInfo() {
-               // Hacky Hacky Hacky - I want to get query info
-               // for two different tables, without reimplementing
-               // the pager class.
-               $qi = $this->getQueryInfoReal( $this->mTableName );
-
-               return $qi;
-       }
-
-       /**
-        * Actually get the query info.
-        *
-        * This is to allow displaying both stuff from image and oldimage table.
-        *
-        * This is a bit hacky.
-        *
-        * @param string $table Either 'image' or 'oldimage'
-        * @return array Query info
-        */
-       protected function getQueryInfoReal( $table ) {
-               $prefix = $table === 'oldimage' ? 'oi' : 'img';
-
-               $tables = [ $table ];
-               $fields = array_keys( $this->getFieldNames() );
-
-               if ( $table === 'oldimage' ) {
-                       foreach ( $fields as $id => &$field ) {
-                               if ( substr( $field, 0, 4 ) !== 'img_' ) {
-                                       continue;
-                               }
-                               $field = $prefix . substr( $field, 3 ) . ' AS ' . $field;
-                       }
-                       $fields[array_search( 'top', $fields )] = "'no' AS top";
-               } else {
-                       if ( $this->mShowAll ) {
-                               $fields[array_search( 'top', $fields )] = "'yes' AS top";
-                       }
-               }
-               $fields[] = $prefix . '_user AS img_user';
-               $fields[array_search( 'thumb', $fields )] = $prefix . '_name AS thumb';
-
-               $options = $join_conds = [];
-
-               # Depends on $wgMiserMode
-               # Will also not happen if mShowAll is true.
-               if ( isset( $this->mFieldNames['count'] ) ) {
-                       $tables[] = 'oldimage';
-
-                       # Need to rewrite this one
-                       foreach ( $fields as &$field ) {
-                               if ( $field == 'count' ) {
-                                       $field = 'COUNT(oi_archive_name) AS count';
-                               }
-                       }
-                       unset( $field );
-
-                       $dbr = wfGetDB( DB_SLAVE );
-                       if ( $dbr->implicitGroupby() ) {
-                               $options = [ 'GROUP BY' => 'img_name' ];
-                       } else {
-                               $columnlist = preg_grep( '/^img/', array_keys( $this->getFieldNames() ) );
-                               $options = [ 'GROUP BY' => array_merge( [ 'img_user' ], $columnlist ) ];
-                       }
-                       $join_conds = [ 'oldimage' => [ 'LEFT JOIN', 'oi_name = img_name' ] ];
-               }
-
-               return [
-                       'tables' => $tables,
-                       'fields' => $fields,
-                       'conds' => $this->buildQueryConds( $table ),
-                       'options' => $options,
-                       'join_conds' => $join_conds
-               ];
-       }
-
-       /**
-        * Override reallyDoQuery to mix together two queries.
-        *
-        * @note $asc is named $descending in IndexPager base class. However
-        *   it is true when the order is ascending, and false when the order
-        *   is descending, so I renamed it to $asc here.
-        * @param int $offset
-        * @param int $limit
-        * @param bool $asc
-        * @return array
-        * @throws MWException
-        */
-       function reallyDoQuery( $offset, $limit, $asc ) {
-               $prevTableName = $this->mTableName;
-               $this->mTableName = 'image';
-               list( $tables, $fields, $conds, $fname, $options, $join_conds ) =
-                       $this->buildQueryInfo( $offset, $limit, $asc );
-               $imageRes = $this->mDb->select( $tables, $fields, $conds, $fname, $options, $join_conds );
-               $this->mTableName = $prevTableName;
-
-               if ( !$this->mShowAll ) {
-                       return $imageRes;
-               }
-
-               $this->mTableName = 'oldimage';
-
-               # Hacky...
-               $oldIndex = $this->mIndexField;
-               if ( substr( $this->mIndexField, 0, 4 ) !== 'img_' ) {
-                       throw new MWException( "Expected to be sorting on an image table field" );
-               }
-               $this->mIndexField = 'oi_' . substr( $this->mIndexField, 4 );
-
-               list( $tables, $fields, $conds, $fname, $options, $join_conds ) =
-                       $this->buildQueryInfo( $offset, $limit, $asc );
-               $oldimageRes = $this->mDb->select( $tables, $fields, $conds, $fname, $options, $join_conds );
-
-               $this->mTableName = $prevTableName;
-               $this->mIndexField = $oldIndex;
-
-               return $this->combineResult( $imageRes, $oldimageRes, $limit, $asc );
-       }
-
-       /**
-        * Combine results from 2 tables.
-        *
-        * Note: This will throw away some results
-        *
-        * @param ResultWrapper $res1
-        * @param ResultWrapper $res2
-        * @param int $limit
-        * @param bool $ascending See note about $asc in $this->reallyDoQuery
-        * @return FakeResultWrapper $res1 and $res2 combined
-        */
-       protected function combineResult( $res1, $res2, $limit, $ascending ) {
-               $res1->rewind();
-               $res2->rewind();
-               $topRes1 = $res1->next();
-               $topRes2 = $res2->next();
-               $resultArray = [];
-               for ( $i = 0; $i < $limit && $topRes1 && $topRes2; $i++ ) {
-                       if ( strcmp( $topRes1->{$this->mIndexField}, $topRes2->{$this->mIndexField} ) > 0 ) {
-                               if ( !$ascending ) {
-                                       $resultArray[] = $topRes1;
-                                       $topRes1 = $res1->next();
-                               } else {
-                                       $resultArray[] = $topRes2;
-                                       $topRes2 = $res2->next();
-                               }
-                       } else {
-                               if ( !$ascending ) {
-                                       $resultArray[] = $topRes2;
-                                       $topRes2 = $res2->next();
-                               } else {
-                                       $resultArray[] = $topRes1;
-                                       $topRes1 = $res1->next();
-                               }
-                       }
-               }
-
-               // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
-               for ( ; $i < $limit && $topRes1; $i++ ) {
-                       // @codingStandardsIgnoreEnd
-                       $resultArray[] = $topRes1;
-                       $topRes1 = $res1->next();
-               }
-
-               // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
-               for ( ; $i < $limit && $topRes2; $i++ ) {
-                       // @codingStandardsIgnoreEnd
-                       $resultArray[] = $topRes2;
-                       $topRes2 = $res2->next();
-               }
-
-               return new FakeResultWrapper( $resultArray );
-       }
-
-       function getDefaultSort() {
-               if ( $this->mShowAll && $this->getConfig()->get( 'MiserMode' ) && is_null( $this->mUserName ) ) {
-                       // Unfortunately no index on oi_timestamp.
-                       return 'img_name';
-               } else {
-                       return 'img_timestamp';
-               }
-       }
-
-       function doBatchLookups() {
-               $userIds = [];
-               $this->mResult->seek( 0 );
-               foreach ( $this->mResult as $row ) {
-                       $userIds[] = $row->img_user;
-               }
-               # Do a link batch query for names and userpages
-               UserCache::singleton()->doQuery( $userIds, [ 'userpage' ], __METHOD__ );
-       }
-
-       /**
-        * @param string $field
-        * @param string $value
-        * @return Message|string|int The return type depends on the value of $field:
-        *   - thumb: string
-        *   - img_timestamp: string
-        *   - img_name: string
-        *   - img_user_text: string
-        *   - img_size: string
-        *   - img_description: string
-        *   - count: int
-        *   - top: Message
-        * @throws MWException
-        */
-       function formatValue( $field, $value ) {
-               switch ( $field ) {
-                       case 'thumb':
-                               $opt = [ 'time' => wfTimestamp( TS_MW, $this->mCurrentRow->img_timestamp ) ];
-                               $file = RepoGroup::singleton()->getLocalRepo()->findFile( $value, $opt );
-                               // If statement for paranoia
-                               if ( $file ) {
-                                       $thumb = $file->transform( [ 'width' => 180, 'height' => 360 ] );
-
-                                       return $thumb->toHtml( [ 'desc-link' => true ] );
-                               } else {
-                                       return htmlspecialchars( $value );
-                               }
-                       case 'img_timestamp':
-                               // We may want to make this a link to the "old" version when displaying old files
-                               return htmlspecialchars( $this->getLanguage()->userTimeAndDate( $value, $this->getUser() ) );
-                       case 'img_name':
-                               static $imgfile = null;
-                               if ( $imgfile === null ) {
-                                       $imgfile = $this->msg( 'imgfile' )->text();
-                               }
-
-                               // Weird files can maybe exist? Bug 22227
-                               $filePage = Title::makeTitleSafe( NS_FILE, $value );
-                               if ( $filePage ) {
-                                       $link = Linker::linkKnown(
-                                               $filePage,
-                                               htmlspecialchars( $filePage->getText() )
-                                       );
-                                       $download = Xml::element( 'a',
-                                               [ 'href' => wfLocalFile( $filePage )->getUrl() ],
-                                               $imgfile
-                                       );
-                                       $download = $this->msg( 'parentheses' )->rawParams( $download )->escaped();
-
-                                       // Add delete links if allowed
-                                       // From https://github.com/Wikia/app/pull/3859
-                                       if ( $filePage->userCan( 'delete', $this->getUser() ) ) {
-                                               $deleteMsg = $this->msg( 'listfiles-delete' )->escaped();
-
-                                               $delete = Linker::linkKnown(
-                                                       $filePage, $deleteMsg, [], [ 'action' => 'delete' ]
-                                               );
-                                               $delete = $this->msg( 'parentheses' )->rawParams( $delete )->escaped();
-
-                                               return "$link $download $delete";
-                                       }
-
-                                       return "$link $download";
-                               } else {
-                                       return htmlspecialchars( $value );
-                               }
-                       case 'img_user_text':
-                               if ( $this->mCurrentRow->img_user ) {
-                                       $name = User::whoIs( $this->mCurrentRow->img_user );
-                                       $link = Linker::link(
-                                               Title::makeTitle( NS_USER, $name ),
-                                               htmlspecialchars( $name )
-                                       );
-                               } else {
-                                       $link = htmlspecialchars( $value );
-                               }
-
-                               return $link;
-                       case 'img_size':
-                               return htmlspecialchars( $this->getLanguage()->formatSize( $value ) );
-                       case 'img_description':
-                               return Linker::formatComment( $value );
-                       case 'count':
-                               return intval( $value ) + 1;
-                       case 'top':
-                               // Messages: listfiles-latestversion-yes, listfiles-latestversion-no
-                               return $this->msg( 'listfiles-latestversion-' . $value );
-                       default:
-                               throw new MWException( "Unknown field '$field'" );
-               }
-       }
-
-       function getForm() {
-               $fields = [];
-               $fields['limit'] = [
-                       'type' => 'select',
-                       'name' => 'limit',
-                       'label-message' => 'table_pager_limit_label',
-                       'options' => $this->getLimitSelectList(),
-                       'default' => $this->mLimit,
-               ];
-
-               if ( !$this->getConfig()->get( 'MiserMode' ) ) {
-                       $fields['ilsearch'] = [
-                               'type' => 'text',
-                               'name' => 'ilsearch',
-                               'id' => 'mw-ilsearch',
-                               'label-message' => 'listfiles_search_for',
-                               'default' => $this->mSearch,
-                               'size' => '40',
-                               'maxlength' => '255',
-                       ];
-               }
-
-               $this->getOutput()->addModules( 'mediawiki.userSuggest' );
-               $fields['user'] = [
-                       'type' => 'text',
-                       'name' => 'user',
-                       'id' => 'mw-listfiles-user',
-                       'label-message' => 'username',
-                       'default' => $this->mUserName,
-                       'size' => '40',
-                       'maxlength' => '255',
-                       'cssclass' => 'mw-autocomplete-user', // used by mediawiki.userSuggest
-               ];
-
-               $fields['ilshowall'] = [
-                       'type' => 'check',
-                       'name' => 'ilshowall',
-                       'id' => 'mw-listfiles-show-all',
-                       'label-message' => 'listfiles-show-all',
-                       'default' => $this->mShowAll,
-               ];
-
-               $query = $this->getRequest()->getQueryValues();
-               unset( $query['title'] );
-               unset( $query['limit'] );
-               unset( $query['ilsearch'] );
-               unset( $query['ilshowall'] );
-               unset( $query['user'] );
-
-               $form = new HTMLForm( $fields, $this->getContext() );
-
-               $form->setMethod( 'get' );
-               $form->setTitle( $this->getTitle() );
-               $form->setId( 'mw-listfiles-form' );
-               $form->setWrapperLegendMsg( 'listfiles' );
-               $form->setSubmitTextMsg( 'table_pager_limit_submit' );
-               $form->addHiddenFields( $query );
-
-               $form->prepareForm();
-               $form->displayForm( '' );
-       }
-
-       function getTableClass() {
-               return parent::getTableClass() . ' listfiles';
-       }
-
-       function getNavClass() {
-               return parent::getNavClass() . ' listfiles_nav';
-       }
-
-       function getSortHeaderClass() {
-               return parent::getSortHeaderClass() . ' listfiles_sort';
-       }
-
-       function getPagingQueries() {
-               $queries = parent::getPagingQueries();
-               if ( !is_null( $this->mUserName ) ) {
-                       # Append the username to the query string
-                       foreach ( $queries as &$query ) {
-                               if ( $query !== false ) {
-                                       $query['user'] = $this->mUserName;
-                               }
-                       }
-               }
-
-               return $queries;
-       }
-
-       function getDefaultQuery() {
-               $queries = parent::getDefaultQuery();
-               if ( !isset( $queries['user'] ) && !is_null( $this->mUserName ) ) {
-                       $queries['user'] = $this->mUserName;
-               }
-
-               return $queries;
-       }
-
-       function getTitle() {
-               return SpecialPage::getTitleFor( 'Listfiles' );
-       }
-}
index 7eb3757..1a8dccf 100644 (file)
  * @ingroup SpecialPage
  */
 
-/**
- * This class is used to get a list of user. The ones with specials
- * rights (sysop, bureaucrat, developer) will have them displayed
- * next to their names.
- *
- * @ingroup SpecialPage
- */
-class UsersPager extends AlphabeticPager {
-
-       /**
-        * @var array A array with user ids as key and a array of groups as value
-        */
-       protected $userGroupCache;
-
-       /**
-        * @param IContextSource $context
-        * @param array $par (Default null)
-        * @param bool $including Whether this page is being transcluded in
-        * another page
-        */
-       function __construct( IContextSource $context = null, $par = null, $including = null ) {
-               if ( $context ) {
-                       $this->setContext( $context );
-               }
-
-               $request = $this->getRequest();
-               $par = ( $par !== null ) ? $par : '';
-               $parms = explode( '/', $par );
-               $symsForAll = [ '*', 'user' ];
-
-               if ( $parms[0] != '' &&
-                       ( in_array( $par, User::getAllGroups() ) || in_array( $par, $symsForAll ) )
-               ) {
-                       $this->requestedGroup = $par;
-                       $un = $request->getText( 'username' );
-               } elseif ( count( $parms ) == 2 ) {
-                       $this->requestedGroup = $parms[0];
-                       $un = $parms[1];
-               } else {
-                       $this->requestedGroup = $request->getVal( 'group' );
-                       $un = ( $par != '' ) ? $par : $request->getText( 'username' );
-               }
-
-               if ( in_array( $this->requestedGroup, $symsForAll ) ) {
-                       $this->requestedGroup = '';
-               }
-               $this->editsOnly = $request->getBool( 'editsOnly' );
-               $this->creationSort = $request->getBool( 'creationSort' );
-               $this->including = $including;
-               $this->mDefaultDirection = $request->getBool( 'desc' )
-                       ? IndexPager::DIR_DESCENDING
-                       : IndexPager::DIR_ASCENDING;
-
-               $this->requestedUser = '';
-
-               if ( $un != '' ) {
-                       $username = Title::makeTitleSafe( NS_USER, $un );
-
-                       if ( !is_null( $username ) ) {
-                               $this->requestedUser = $username->getText();
-                       }
-               }
-
-               parent::__construct();
-       }
-
-       /**
-        * @return string
-        */
-       function getIndexField() {
-               return $this->creationSort ? 'user_id' : 'user_name';
-       }
-
-       /**
-        * @return array
-        */
-       function getQueryInfo() {
-               $dbr = wfGetDB( DB_SLAVE );
-               $conds = [];
-
-               // Don't show hidden names
-               if ( !$this->getUser()->isAllowed( 'hideuser' ) ) {
-                       $conds[] = 'ipb_deleted IS NULL OR ipb_deleted = 0';
-               }
-
-               $options = [];
-
-               if ( $this->requestedGroup != '' ) {
-                       $conds['ug_group'] = $this->requestedGroup;
-               }
-
-               if ( $this->requestedUser != '' ) {
-                       # Sorted either by account creation or name
-                       if ( $this->creationSort ) {
-                               $conds[] = 'user_id >= ' . intval( User::idFromName( $this->requestedUser ) );
-                       } else {
-                               $conds[] = 'user_name >= ' . $dbr->addQuotes( $this->requestedUser );
-                       }
-               }
-
-               if ( $this->editsOnly ) {
-                       $conds[] = 'user_editcount > 0';
-               }
-
-               $options['GROUP BY'] = $this->creationSort ? 'user_id' : 'user_name';
-
-               $query = [
-                       'tables' => [ 'user', 'user_groups', 'ipblocks' ],
-                       'fields' => [
-                               'user_name' => $this->creationSort ? 'MAX(user_name)' : 'user_name',
-                               'user_id' => $this->creationSort ? 'user_id' : 'MAX(user_id)',
-                               'edits' => 'MAX(user_editcount)',
-                               'creation' => 'MIN(user_registration)',
-                               'ipb_deleted' => 'MAX(ipb_deleted)' // block/hide status
-                       ],
-                       'options' => $options,
-                       'join_conds' => [
-                               'user_groups' => [ 'LEFT JOIN', 'user_id=ug_user' ],
-                               'ipblocks' => [
-                                       'LEFT JOIN', [
-                                               'user_id=ipb_user',
-                                               'ipb_auto' => 0
-                                       ]
-                               ],
-                       ],
-                       'conds' => $conds
-               ];
-
-               Hooks::run( 'SpecialListusersQueryInfo', [ $this, &$query ] );
-
-               return $query;
-       }
-
-       /**
-        * @param stdClass $row
-        * @return string
-        */
-       function formatRow( $row ) {
-               if ( $row->user_id == 0 ) { # Bug 16487
-                       return '';
-               }
-
-               $userName = $row->user_name;
-
-               $ulinks = Linker::userLink( $row->user_id, $userName );
-               $ulinks .= Linker::userToolLinksRedContribs(
-                       $row->user_id,
-                       $userName,
-                       (int)$row->edits
-               );
-
-               $lang = $this->getLanguage();
-
-               $groups = '';
-               $groups_list = self::getGroups( intval( $row->user_id ), $this->userGroupCache );
-
-               if ( !$this->including && count( $groups_list ) > 0 ) {
-                       $list = [];
-                       foreach ( $groups_list as $group ) {
-                               $list[] = self::buildGroupLink( $group, $userName );
-                       }
-                       $groups = $lang->commaList( $list );
-               }
-
-               $item = $lang->specialList( $ulinks, $groups );
-
-               if ( $row->ipb_deleted ) {
-                       $item = "<span class=\"deleted\">$item</span>";
-               }
-
-               $edits = '';
-               if ( !$this->including && $this->getConfig()->get( 'Edititis' ) ) {
-                       $count = $this->msg( 'usereditcount' )->numParams( $row->edits )->escaped();
-                       $edits = $this->msg( 'word-separator' )->escaped() . $this->msg( 'brackets', $count )->escaped();
-               }
-
-               $created = '';
-               # Some rows may be null
-               if ( !$this->including && $row->creation ) {
-                       $user = $this->getUser();
-                       $d = $lang->userDate( $row->creation, $user );
-                       $t = $lang->userTime( $row->creation, $user );
-                       $created = $this->msg( 'usercreated', $d, $t, $row->user_name )->escaped();
-                       $created = ' ' . $this->msg( 'parentheses' )->rawParams( $created )->escaped();
-               }
-               $blocked = !is_null( $row->ipb_deleted ) ?
-                       ' ' . $this->msg( 'listusers-blocked', $userName )->escaped() :
-                       '';
-
-               Hooks::run( 'SpecialListusersFormatRow', [ &$item, $row ] );
-
-               return Html::rawElement( 'li', [], "{$item}{$edits}{$created}{$blocked}" );
-       }
-
-       function doBatchLookups() {
-               $batch = new LinkBatch();
-               $userIds = [];
-               # Give some pointers to make user links
-               foreach ( $this->mResult as $row ) {
-                       $batch->add( NS_USER, $row->user_name );
-                       $batch->add( NS_USER_TALK, $row->user_name );
-                       $userIds[] = $row->user_id;
-               }
-
-               // Lookup groups for all the users
-               $dbr = wfGetDB( DB_SLAVE );
-               $groupRes = $dbr->select(
-                       'user_groups',
-                       [ 'ug_user', 'ug_group' ],
-                       [ 'ug_user' => $userIds ],
-                       __METHOD__
-               );
-               $cache = [];
-               $groups = [];
-               foreach ( $groupRes as $row ) {
-                       $cache[intval( $row->ug_user )][] = $row->ug_group;
-                       $groups[$row->ug_group] = true;
-               }
-               $this->userGroupCache = $cache;
-
-               // Add page of groups to link batch
-               foreach ( $groups as $group => $unused ) {
-                       $groupPage = User::getGroupPage( $group );
-                       if ( $groupPage ) {
-                               $batch->addObj( $groupPage );
-                       }
-               }
-
-               $batch->execute();
-               $this->mResult->rewind();
-       }
-
-       /**
-        * @return string
-        */
-       function getPageHeader() {
-               list( $self ) = explode( '/', $this->getTitle()->getPrefixedDBkey() );
-
-               $this->getOutput()->addModules( 'mediawiki.userSuggest' );
-
-               # Form tag
-               $out = Xml::openElement(
-                       'form',
-                       [ 'method' => 'get', 'action' => wfScript(), 'id' => 'mw-listusers-form' ]
-               ) .
-                       Xml::fieldset( $this->msg( 'listusers' )->text() ) .
-                       Html::hidden( 'title', $self );
-
-               # Username field (with autocompletion support)
-               $out .= Xml::label( $this->msg( 'listusersfrom' )->text(), 'offset' ) . ' ' .
-                       Html::input(
-                               'username',
-                               $this->requestedUser,
-                               'text',
-                               [
-                                       'class' => 'mw-autocomplete-user',
-                                       'id' => 'offset',
-                                       'size' => 20,
-                                       'autofocus' => $this->requestedUser === ''
-                               ]
-                       ) . ' ';
-
-               # Group drop-down list
-               $sel = new XmlSelect( 'group', 'group', $this->requestedGroup );
-               $sel->addOption( $this->msg( 'group-all' )->text(), '' );
-               foreach ( $this->getAllGroups() as $group => $groupText ) {
-                       $sel->addOption( $groupText, $group );
-               }
-
-               $out .= Xml::label( $this->msg( 'group' )->text(), 'group' ) . ' ';
-               $out .= $sel->getHTML() . '<br />';
-               $out .= Xml::checkLabel(
-                       $this->msg( 'listusers-editsonly' )->text(),
-                       'editsOnly',
-                       'editsOnly',
-                       $this->editsOnly
-               );
-               $out .= '&#160;';
-               $out .= Xml::checkLabel(
-                       $this->msg( 'listusers-creationsort' )->text(),
-                       'creationSort',
-                       'creationSort',
-                       $this->creationSort
-               );
-               $out .= '&#160;';
-               $out .= Xml::checkLabel(
-                       $this->msg( 'listusers-desc' )->text(),
-                       'desc',
-                       'desc',
-                       $this->mDefaultDirection
-               );
-               $out .= '<br />';
-
-               Hooks::run( 'SpecialListusersHeaderForm', [ $this, &$out ] );
-
-               # Submit button and form bottom
-               $out .= Html::hidden( 'limit', $this->mLimit );
-               $out .= Xml::submitButton( $this->msg( 'listusers-submit' )->text() );
-               Hooks::run( 'SpecialListusersHeader', [ $this, &$out ] );
-               $out .= Xml::closeElement( 'fieldset' ) .
-                       Xml::closeElement( 'form' );
-
-               return $out;
-       }
-
-       /**
-        * Get a list of all explicit groups
-        * @return array
-        */
-       function getAllGroups() {
-               $result = [];
-               foreach ( User::getAllGroups() as $group ) {
-                       $result[$group] = User::getGroupName( $group );
-               }
-               asort( $result );
-
-               return $result;
-       }
-
-       /**
-        * Preserve group and username offset parameters when paging
-        * @return array
-        */
-       function getDefaultQuery() {
-               $query = parent::getDefaultQuery();
-               if ( $this->requestedGroup != '' ) {
-                       $query['group'] = $this->requestedGroup;
-               }
-               if ( $this->requestedUser != '' ) {
-                       $query['username'] = $this->requestedUser;
-               }
-               Hooks::run( 'SpecialListusersDefaultQuery', [ $this, &$query ] );
-
-               return $query;
-       }
-
-       /**
-        * Get a list of groups the specified user belongs to
-        *
-        * @param int $uid User id
-        * @param array|null $cache
-        * @return array
-        */
-       protected static function getGroups( $uid, $cache = null ) {
-               if ( $cache === null ) {
-                       $user = User::newFromId( $uid );
-                       $effectiveGroups = $user->getEffectiveGroups();
-               } else {
-                       $effectiveGroups = isset( $cache[$uid] ) ? $cache[$uid] : [];
-               }
-               $groups = array_diff( $effectiveGroups, User::getImplicitGroups() );
-
-               return $groups;
-       }
-
-       /**
-        * Format a link to a group description page
-        *
-        * @param string $group Group name
-        * @param string $username Username
-        * @return string
-        */
-       protected static function buildGroupLink( $group, $username ) {
-               return User::makeGroupLinkHTML(
-                       $group,
-                       User::getGroupMember( $group, $username )
-               );
-       }
-}
-
 /**
  * @ingroup SpecialPage
  */
index d4c7c6a..7132207 100644 (file)
@@ -49,6 +49,7 @@ class SpecialLog extends SpecialPage {
                $opts->add( 'offset', '' );
                $opts->add( 'dir', '' );
                $opts->add( 'offender', '' );
+               $opts->add( 'subtype', '' );
 
                // Set values
                $opts->fetchValuesFromRequest( $this->getRequest() );
@@ -167,6 +168,26 @@ class SpecialLog extends SpecialPage {
                        null,
                        LogEventsList::USE_CHECKBOXES
                );
+
+               $action = '';
+               // Allow to filter the log by actions
+               $type = $opts->getValue( 'type' );
+               if ( $type !== '' ) {
+                       $actions = $this->getConfig()->get( 'ActionFilteredLogs' );
+                       if ( isset( $actions[$type] ) ) {
+                               // log type can be filtered by actions
+                               $loglist->setAllowedActions( array_keys( $actions[$type] ) );
+                               $action = $opts->getValue( 'subtype' );
+                               if ( $action !== '' && isset( $actions[$type][$action] ) ) {
+                                       // add condition to query
+                                       $extraConds['log_action'] = $actions[$type][$action];
+                               } else {
+                                       // no action or invalid action
+                                       $action = '';
+                               }
+                       }
+               }
+
                $pager = new LogPager(
                        $loglist,
                        $opts->getValue( 'type' ),
@@ -195,7 +216,8 @@ class SpecialLog extends SpecialPage {
                        $pager->getYear(),
                        $pager->getMonth(),
                        $pager->getFilterParams(),
-                       $opts->getValue( 'tagfilter' )
+                       $opts->getValue( 'tagfilter' ),
+                       $action
                );
 
                # Insert list
index 3310538..b916c1f 100644 (file)
@@ -379,78 +379,3 @@ class SpecialMergeHistory extends SpecialPage {
                return 'pagetools';
        }
 }
-
-class MergeHistoryPager extends ReverseChronologicalPager {
-       /** @var SpecialMergeHistory */
-       public $mForm;
-
-       /** @var array */
-       public $mConds;
-
-       function __construct( SpecialMergeHistory $form, $conds, Title $source, Title $dest ) {
-               $this->mForm = $form;
-               $this->mConds = $conds;
-               $this->title = $source;
-               $this->articleID = $source->getArticleID();
-
-               $dbr = wfGetDB( DB_SLAVE );
-               $maxtimestamp = $dbr->selectField(
-                       'revision',
-                       'MIN(rev_timestamp)',
-                       [ 'rev_page' => $dest->getArticleID() ],
-                       __METHOD__
-               );
-               $this->maxTimestamp = $maxtimestamp;
-
-               parent::__construct( $form->getContext() );
-       }
-
-       function getStartBody() {
-               # Do a link batch query
-               $this->mResult->seek( 0 );
-               $batch = new LinkBatch();
-               # Give some pointers to make (last) links
-               $this->mForm->prevId = [];
-               foreach ( $this->mResult as $row ) {
-                       $batch->addObj( Title::makeTitleSafe( NS_USER, $row->user_name ) );
-                       $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->user_name ) );
-
-                       $rev_id = isset( $rev_id ) ? $rev_id : $row->rev_id;
-                       if ( $rev_id > $row->rev_id ) {
-                               $this->mForm->prevId[$rev_id] = $row->rev_id;
-                       } elseif ( $rev_id < $row->rev_id ) {
-                               $this->mForm->prevId[$row->rev_id] = $rev_id;
-                       }
-
-                       $rev_id = $row->rev_id;
-               }
-
-               $batch->execute();
-               $this->mResult->seek( 0 );
-
-               return '';
-       }
-
-       function formatRow( $row ) {
-               return $this->mForm->formatRevisionRow( $row );
-       }
-
-       function getQueryInfo() {
-               $conds = $this->mConds;
-               $conds['rev_page'] = $this->articleID;
-               $conds[] = "rev_timestamp < " . $this->mDb->addQuotes( $this->maxTimestamp );
-
-               return [
-                       'tables' => [ 'revision', 'page', 'user' ],
-                       'fields' => array_merge( Revision::selectFields(), Revision::selectUserFields() ),
-                       'conds' => $conds,
-                       'join_conds' => [
-                               'page' => Revision::pageJoinCond(),
-                               'user' => Revision::userJoinCond() ]
-               ];
-       }
-
-       function getIndexField() {
-               return 'rev_timestamp';
-       }
-}
index 629a508..14391d2 100644 (file)
@@ -71,189 +71,3 @@ class SpecialNewFiles extends IncludableSpecialPage {
                }
        }
 }
-
-/**
- * @ingroup SpecialPage Pager
- */
-class NewFilesPager extends ReverseChronologicalPager {
-       /**
-        * @var ImageGallery
-        */
-       protected $gallery;
-
-       /**
-        * @var bool
-        */
-       protected $showBots;
-
-       /**
-        * @var bool
-        */
-       protected $hidePatrolled;
-
-       function __construct( IContextSource $context, $par = null ) {
-               $this->like = $context->getRequest()->getText( 'like' );
-               $this->showBots = $context->getRequest()->getBool( 'showbots', 0 );
-               $this->hidePatrolled = $context->getRequest()->getBool( 'hidepatrolled', 0 );
-               if ( is_numeric( $par ) ) {
-                       $this->setLimit( $par );
-               }
-
-               parent::__construct( $context );
-       }
-
-       function getQueryInfo() {
-               $conds = $jconds = [];
-               $tables = [ 'image' ];
-               $fields = [ 'img_name', 'img_user', 'img_timestamp' ];
-               $options = [];
-
-               if ( !$this->showBots ) {
-                       $groupsWithBotPermission = User::getGroupsWithPermission( 'bot' );
-
-                       if ( count( $groupsWithBotPermission ) ) {
-                               $tables[] = 'user_groups';
-                               $conds[] = 'ug_group IS NULL';
-                               $jconds['user_groups'] = [
-                                       'LEFT JOIN',
-                                       [
-                                               'ug_group' => $groupsWithBotPermission,
-                                               'ug_user = img_user'
-                                       ]
-                               ];
-                       }
-               }
-
-               if ( $this->hidePatrolled ) {
-                       $tables[] = 'recentchanges';
-                       $conds['rc_type'] = RC_LOG;
-                       $conds['rc_log_type'] = 'upload';
-                       $conds['rc_patrolled'] = 0;
-                       $conds['rc_namespace'] = NS_FILE;
-                       $jconds['recentchanges'] = [
-                               'INNER JOIN',
-                               [
-                                       'rc_title = img_name',
-                                       'rc_user = img_user',
-                                       'rc_timestamp = img_timestamp'
-                               ]
-                       ];
-                       // We're ordering by img_timestamp, so we have to make sure MariaDB queries `image` first.
-                       // It sometimes decides to query `recentchanges` first and filesort the result set later
-                       // to get the right ordering. T124205 / https://mariadb.atlassian.net/browse/MDEV-8880
-                       $options[] = 'STRAIGHT_JOIN';
-               }
-
-               if ( !$this->getConfig()->get( 'MiserMode' ) && $this->like !== null ) {
-                       $dbr = wfGetDB( DB_SLAVE );
-                       $likeObj = Title::newFromText( $this->like );
-                       if ( $likeObj instanceof Title ) {
-                               $like = $dbr->buildLike(
-                                       $dbr->anyString(),
-                                       strtolower( $likeObj->getDBkey() ),
-                                       $dbr->anyString()
-                               );
-                               $conds[] = "LOWER(img_name) $like";
-                       }
-               }
-
-               $query = [
-                       'tables' => $tables,
-                       'fields' => $fields,
-                       'join_conds' => $jconds,
-                       'conds' => $conds,
-                       'options' => $options,
-               ];
-
-               return $query;
-       }
-
-       function getIndexField() {
-               return 'img_timestamp';
-       }
-
-       function getStartBody() {
-               if ( !$this->gallery ) {
-                       // Note that null for mode is taken to mean use default.
-                       $mode = $this->getRequest()->getVal( 'gallerymode', null );
-                       try {
-                               $this->gallery = ImageGalleryBase::factory( $mode, $this->getContext() );
-                       } catch ( Exception $e ) {
-                               // User specified something invalid, fallback to default.
-                               $this->gallery = ImageGalleryBase::factory( false, $this->getContext() );
-                       }
-               }
-
-               return '';
-       }
-
-       function getEndBody() {
-               return $this->gallery->toHTML();
-       }
-
-       function formatRow( $row ) {
-               $name = $row->img_name;
-               $user = User::newFromId( $row->img_user );
-
-               $title = Title::makeTitle( NS_FILE, $name );
-               $ul = Linker::link( $user->getUserPage(), $user->getName() );
-               $time = $this->getLanguage()->userTimeAndDate( $row->img_timestamp, $this->getUser() );
-
-               $this->gallery->add(
-                       $title,
-                       "$ul<br />\n<i>"
-                               . htmlspecialchars( $time )
-                               . "</i><br />\n"
-               );
-       }
-
-       function getForm() {
-               $fields = [
-                       'like' => [
-                               'type' => 'text',
-                               'label-message' => 'newimages-label',
-                               'name' => 'like',
-                       ],
-                       'showbots' => [
-                               'type' => 'check',
-                               'label-message' => 'newimages-showbots',
-                               'name' => 'showbots',
-                       ],
-                       'hidepatrolled' => [
-                               'type' => 'check',
-                               'label-message' => 'newimages-hidepatrolled',
-                               'name' => 'hidepatrolled',
-                       ],
-                       'limit' => [
-                               'type' => 'hidden',
-                               'default' => $this->mLimit,
-                               'name' => 'limit',
-                       ],
-                       'offset' => [
-                               'type' => 'hidden',
-                               'default' => $this->getRequest()->getText( 'offset' ),
-                               'name' => 'offset',
-                       ],
-               ];
-
-               if ( $this->getConfig()->get( 'MiserMode' ) ) {
-                       unset( $fields['like'] );
-               }
-
-               if ( !$this->getUser()->useFilePatrol() ) {
-                       unset( $fields['hidepatrolled'] );
-               }
-
-               $context = new DerivativeContext( $this->getContext() );
-               $context->setTitle( $this->getTitle() ); // Remove subpage
-               $form = new HTMLForm( $fields, $context );
-
-               $form->setSubmitTextMsg( 'ilsubmit' );
-               $form->setSubmitProgressive();
-
-               $form->setMethod( 'get' );
-               $form->setWrapperLegendMsg( 'newimages-legend' );
-
-               return $form;
-       }
-}
index ab29d13..c24b054 100644 (file)
@@ -479,130 +479,3 @@ class SpecialNewpages extends IncludableSpecialPage {
                return 'changes';
        }
 }
-
-/**
- * @ingroup SpecialPage Pager
- */
-class NewPagesPager extends ReverseChronologicalPager {
-       // Stored opts
-       protected $opts;
-
-       /**
-        * @var HtmlForm
-        */
-       protected $mForm;
-
-       function __construct( $form, FormOptions $opts ) {
-               parent::__construct( $form->getContext() );
-               $this->mForm = $form;
-               $this->opts = $opts;
-       }
-
-       function getQueryInfo() {
-               $conds = [];
-               $conds['rc_new'] = 1;
-
-               $namespace = $this->opts->getValue( 'namespace' );
-               $namespace = ( $namespace === 'all' ) ? false : intval( $namespace );
-
-               $username = $this->opts->getValue( 'username' );
-               $user = Title::makeTitleSafe( NS_USER, $username );
-
-               $rcIndexes = [];
-
-               if ( $namespace !== false ) {
-                       if ( $this->opts->getValue( 'invert' ) ) {
-                               $conds[] = 'rc_namespace != ' . $this->mDb->addQuotes( $namespace );
-                       } else {
-                               $conds['rc_namespace'] = $namespace;
-                       }
-               }
-
-               if ( $user ) {
-                       $conds['rc_user_text'] = $user->getText();
-                       $rcIndexes = 'rc_user_text';
-               } elseif ( User::groupHasPermission( '*', 'createpage' ) &&
-                       $this->opts->getValue( 'hideliu' )
-               ) {
-                       # If anons cannot make new pages, don't "exclude logged in users"!
-                       $conds['rc_user'] = 0;
-               }
-
-               # If this user cannot see patrolled edits or they are off, don't do dumb queries!
-               if ( $this->opts->getValue( 'hidepatrolled' ) && $this->getUser()->useNPPatrol() ) {
-                       $conds['rc_patrolled'] = 0;
-               }
-
-               if ( $this->opts->getValue( 'hidebots' ) ) {
-                       $conds['rc_bot'] = 0;
-               }
-
-               if ( $this->opts->getValue( 'hideredirs' ) ) {
-                       $conds['page_is_redirect'] = 0;
-               }
-
-               // Allow changes to the New Pages query
-               $tables = [ 'recentchanges', 'page' ];
-               $fields = [
-                       'rc_namespace', 'rc_title', 'rc_cur_id', 'rc_user', 'rc_user_text',
-                       'rc_comment', 'rc_timestamp', 'rc_patrolled', 'rc_id', 'rc_deleted',
-                       'length' => 'page_len', 'rev_id' => 'page_latest', 'rc_this_oldid',
-                       'page_namespace', 'page_title'
-               ];
-               $join_conds = [ 'page' => [ 'INNER JOIN', 'page_id=rc_cur_id' ] ];
-
-               Hooks::run( 'SpecialNewpagesConditions',
-                       [ &$this, $this->opts, &$conds, &$tables, &$fields, &$join_conds ] );
-
-               $options = [];
-
-               if ( $rcIndexes ) {
-                       $options = [ 'USE INDEX' => [ 'recentchanges' => $rcIndexes ] ];
-               }
-
-               $info = [
-                       'tables' => $tables,
-                       'fields' => $fields,
-                       'conds' => $conds,
-                       'options' => $options,
-                       'join_conds' => $join_conds
-               ];
-
-               // Modify query for tags
-               ChangeTags::modifyDisplayQuery(
-                       $info['tables'],
-                       $info['fields'],
-                       $info['conds'],
-                       $info['join_conds'],
-                       $info['options'],
-                       $this->opts['tagfilter']
-               );
-
-               return $info;
-       }
-
-       function getIndexField() {
-               return 'rc_timestamp';
-       }
-
-       function formatRow( $row ) {
-               return $this->mForm->formatRow( $row );
-       }
-
-       function getStartBody() {
-               # Do a batch existence check on pages
-               $linkBatch = new LinkBatch();
-               foreach ( $this->mResult as $row ) {
-                       $linkBatch->add( NS_USER, $row->rc_user_text );
-                       $linkBatch->add( NS_USER_TALK, $row->rc_user_text );
-                       $linkBatch->add( $row->page_namespace, $row->page_title );
-               }
-               $linkBatch->execute();
-
-               return '<ul>';
-       }
-
-       function getEndBody() {
-               return '</ul>';
-       }
-}
index 5df425a..c800d96 100644 (file)
@@ -190,74 +190,3 @@ class SpecialProtectedtitles extends SpecialPage {
                return 'maintenance';
        }
 }
-
-/**
- * @todo document
- * @ingroup Pager
- */
-class ProtectedTitlesPager extends AlphabeticPager {
-       public $mForm, $mConds;
-
-       function __construct( $form, $conds = [], $type, $level, $namespace,
-               $sizetype = '', $size = 0
-       ) {
-               $this->mForm = $form;
-               $this->mConds = $conds;
-               $this->level = $level;
-               $this->namespace = $namespace;
-               $this->size = intval( $size );
-               parent::__construct( $form->getContext() );
-       }
-
-       function getStartBody() {
-               # Do a link batch query
-               $this->mResult->seek( 0 );
-               $lb = new LinkBatch;
-
-               foreach ( $this->mResult as $row ) {
-                       $lb->add( $row->pt_namespace, $row->pt_title );
-               }
-
-               $lb->execute();
-
-               return '';
-       }
-
-       /**
-        * @return Title
-        */
-       function getTitle() {
-               return $this->mForm->getTitle();
-       }
-
-       function formatRow( $row ) {
-               return $this->mForm->formatRow( $row );
-       }
-
-       /**
-        * @return array
-        */
-       function getQueryInfo() {
-               $conds = $this->mConds;
-               $conds[] = 'pt_expiry > ' . $this->mDb->addQuotes( $this->mDb->timestamp() ) .
-                       ' OR pt_expiry IS NULL';
-               if ( $this->level ) {
-                       $conds['pt_create_perm'] = $this->level;
-               }
-
-               if ( !is_null( $this->namespace ) ) {
-                       $conds[] = 'pt_namespace=' . $this->mDb->addQuotes( $this->namespace );
-               }
-
-               return [
-                       'tables' => 'protected_titles',
-                       'fields' => [ 'pt_namespace', 'pt_title', 'pt_create_perm',
-                               'pt_expiry', 'pt_timestamp' ],
-                       'conds' => $conds
-               ];
-       }
-
-       function getIndexField() {
-               return 'pt_timestamp';
-       }
-}
index c0ed4c9..12959a3 100644 (file)
@@ -272,7 +272,6 @@ class SpecialRedirect extends FormSpecialPage {
                                $url = $this->dispatchLog();
                                break;
                        default:
-                               $this->getOutput()->setStatusCode( 404 );
                                $url = null;
                                break;
                }
index cc7a091..cff8bf4 100644 (file)
@@ -238,7 +238,9 @@ class SpecialUnblock extends SpecialPage {
                $logEntry->setTarget( $page );
                $logEntry->setComment( $data['Reason'] );
                $logEntry->setPerformer( $performer );
-               $logEntry->setTags( $data['Tags'] );
+               if ( isset( $data['Tags'] ) ) {
+                       $logEntry->setTags( $data['Tags'] );
+               }
                $logId = $logEntry->insert();
                $logEntry->publish( $logId );
 
index 52a3d17..c6d3f6e 100644 (file)
@@ -698,6 +698,10 @@ class SpecialUndelete extends SpecialPage {
                parent::__construct( 'Undelete', 'deletedhistory' );
        }
 
+       public function doesWrites() {
+               return true;
+       }
+
        function loadRequest( $par ) {
                $request = $this->getRequest();
                $user = $this->getUser();
index 740f2f7..be110aa 100644 (file)
@@ -417,28 +417,18 @@ class UserrightsPage extends SpecialPage {
                return Status::newGood( $user );
        }
 
-       function makeGroupNameList( $ids ) {
-               if ( empty( $ids ) ) {
-                       return $this->msg( 'rightsnone' )->inContentLanguage()->text();
-               } else {
-                       return implode( ', ', $ids );
-               }
-       }
-
        /**
-        * Make a list of group names to be stored as parameter for log entries
+        * @since 1.15
         *
-        * @deprecated since 1.21; use LogFormatter instead.
         * @param array $ids
+        *
         * @return string
         */
-       function makeGroupNameListForLog( $ids ) {
-               wfDeprecated( __METHOD__, '1.21' );
-
+       public function makeGroupNameList( $ids ) {
                if ( empty( $ids ) ) {
-                       return '';
+                       return $this->msg( 'rightsnone' )->inContentLanguage()->text();
                } else {
-                       return $this->makeGroupNameList( $ids );
+                       return implode( ', ', $ids );
                }
        }
 
diff --git a/includes/specials/pagers/ActiveUsersPager.php b/includes/specials/pagers/ActiveUsersPager.php
new file mode 100644 (file)
index 0000000..0d3bc9a
--- /dev/null
@@ -0,0 +1,254 @@
+<?php
+/**
+ * Copyright © 2008 Aaron Schulz
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * This class is used to get a list of active users. The ones with specials
+ * rights (sysop, bureaucrat, developer) will have them displayed
+ * next to their names.
+ *
+ * @ingroup Pager
+ */
+class ActiveUsersPager extends UsersPager {
+
+       /**
+        * @var FormOptions
+        */
+       protected $opts;
+
+       /**
+        * @var array
+        */
+       protected $hideGroups = [];
+
+       /**
+        * @var array
+        */
+       protected $hideRights = [];
+
+       /**
+        * @var array
+        */
+       private $blockStatusByUid;
+
+       /**
+        * @param IContextSource $context
+        * @param null $group Unused
+        * @param string $par Parameter passed to the page
+        */
+       function __construct( IContextSource $context = null, $group = null, $par = null ) {
+               parent::__construct( $context );
+
+               $this->RCMaxAge = $this->getConfig()->get( 'ActiveUserDays' );
+               $un = $this->getRequest()->getText( 'username', $par );
+               $this->requestedUser = '';
+               if ( $un != '' ) {
+                       $username = Title::makeTitleSafe( NS_USER, $un );
+                       if ( !is_null( $username ) ) {
+                               $this->requestedUser = $username->getText();
+                       }
+               }
+
+               $this->setupOptions();
+       }
+
+       public function setupOptions() {
+               $this->opts = new FormOptions();
+
+               $this->opts->add( 'hidebots', false, FormOptions::BOOL );
+               $this->opts->add( 'hidesysops', false, FormOptions::BOOL );
+
+               $this->opts->fetchValuesFromRequest( $this->getRequest() );
+
+               if ( $this->opts->getValue( 'hidebots' ) == 1 ) {
+                       $this->hideRights[] = 'bot';
+               }
+               if ( $this->opts->getValue( 'hidesysops' ) == 1 ) {
+                       $this->hideGroups[] = 'sysop';
+               }
+       }
+
+       function getIndexField() {
+               return 'qcc_title';
+       }
+
+       function getQueryInfo() {
+               $dbr = $this->getDatabase();
+
+               $activeUserSeconds = $this->getConfig()->get( 'ActiveUserDays' ) * 86400;
+               $timestamp = $dbr->timestamp( wfTimestamp( TS_UNIX ) - $activeUserSeconds );
+               $conds = [
+                       'qcc_type' => 'activeusers',
+                       'qcc_namespace' => NS_USER,
+                       'user_name = qcc_title',
+                       'rc_user_text = qcc_title',
+                       'rc_type != ' . $dbr->addQuotes( RC_EXTERNAL ), // Don't count wikidata.
+                       'rc_type != ' . $dbr->addQuotes( RC_CATEGORIZE ), // Don't count categorization changes.
+                       'rc_log_type IS NULL OR rc_log_type != ' . $dbr->addQuotes( 'newusers' ),
+                       'rc_timestamp >= ' . $dbr->addQuotes( $timestamp ),
+               ];
+               if ( $this->requestedUser != '' ) {
+                       $conds[] = 'qcc_title >= ' . $dbr->addQuotes( $this->requestedUser );
+               }
+               if ( !$this->getUser()->isAllowed( 'hideuser' ) ) {
+                       $conds[] = 'NOT EXISTS (' . $dbr->selectSQLText(
+                                       'ipblocks', '1', [ 'ipb_user=user_id', 'ipb_deleted' => 1 ]
+                               ) . ')';
+               }
+
+               if ( $dbr->implicitGroupby() ) {
+                       $options = [ 'GROUP BY' => [ 'qcc_title' ] ];
+               } else {
+                       $options = [ 'GROUP BY' => [ 'user_name', 'user_id', 'qcc_title' ] ];
+               }
+
+               return [
+                       'tables' => [ 'querycachetwo', 'user', 'recentchanges' ],
+                       'fields' => [ 'user_name', 'user_id', 'recentedits' => 'COUNT(*)', 'qcc_title' ],
+                       'options' => $options,
+                       'conds' => $conds
+               ];
+       }
+
+       function doBatchLookups() {
+               parent::doBatchLookups();
+
+               $uids = [];
+               foreach ( $this->mResult as $row ) {
+                       $uids[] = $row->user_id;
+               }
+               // Fetch the block status of the user for showing "(blocked)" text and for
+               // striking out names of suppressed users when privileged user views the list.
+               // Although the first query already hits the block table for un-privileged, this
+               // is done in two queries to avoid huge quicksorts and to make COUNT(*) correct.
+               $dbr = $this->getDatabase();
+               $res = $dbr->select( 'ipblocks',
+                       [ 'ipb_user', 'MAX(ipb_deleted) AS block_status' ],
+                       [ 'ipb_user' => $uids ],
+                       __METHOD__,
+                       [ 'GROUP BY' => [ 'ipb_user' ] ]
+               );
+               $this->blockStatusByUid = [];
+               foreach ( $res as $row ) {
+                       $this->blockStatusByUid[$row->ipb_user] = $row->block_status; // 0 or 1
+               }
+               $this->mResult->seek( 0 );
+       }
+
+       function formatRow( $row ) {
+               $userName = $row->user_name;
+
+               $ulinks = Linker::userLink( $row->user_id, $userName );
+               $ulinks .= Linker::userToolLinks( $row->user_id, $userName );
+
+               $lang = $this->getLanguage();
+
+               $list = [];
+               $user = User::newFromId( $row->user_id );
+
+               // User right filter
+               foreach ( $this->hideRights as $right ) {
+                       // Calling User::getRights() within the loop so that
+                       // if the hideRights() filter is empty, we don't have to
+                       // trigger the lazy-init of the big userrights array in the
+                       // User object
+                       if ( in_array( $right, $user->getRights() ) ) {
+                               return '';
+                       }
+               }
+
+               // User group filter
+               // Note: This is a different loop than for user rights,
+               // because we're reusing it to build the group links
+               // at the same time
+               $groups_list = self::getGroups( intval( $row->user_id ), $this->userGroupCache );
+               foreach ( $groups_list as $group ) {
+                       if ( in_array( $group, $this->hideGroups ) ) {
+                               return '';
+                       }
+                       $list[] = self::buildGroupLink( $group, $userName );
+               }
+
+               $groups = $lang->commaList( $list );
+
+               $item = $lang->specialList( $ulinks, $groups );
+
+               $isBlocked = isset( $this->blockStatusByUid[$row->user_id] );
+               if ( $isBlocked && $this->blockStatusByUid[$row->user_id] == 1 ) {
+                       $item = "<span class=\"deleted\">$item</span>";
+               }
+               $count = $this->msg( 'activeusers-count' )->numParams( $row->recentedits )
+                       ->params( $userName )->numParams( $this->RCMaxAge )->escaped();
+               $blocked = $isBlocked ? ' ' . $this->msg( 'listusers-blocked', $userName )->escaped() : '';
+
+               return Html::rawElement( 'li', [], "{$item} [{$count}]{$blocked}" );
+       }
+
+       function getPageHeader() {
+               $self = $this->getTitle();
+               $limit = $this->mLimit ? Html::hidden( 'limit', $this->mLimit ) : '';
+
+               # Form tag
+               $out = Xml::openElement( 'form', [ 'method' => 'get', 'action' => wfScript() ] );
+               $out .= Xml::fieldset( $this->msg( 'activeusers' )->text() ) . "\n";
+               $out .= Html::hidden( 'title', $self->getPrefixedDBkey() ) . $limit . "\n";
+
+               # Username field (with autocompletion support)
+               $this->getOutput()->addModules( 'mediawiki.userSuggest' );
+               $out .= Xml::inputLabel(
+                               $this->msg( 'activeusers-from' )->text(),
+                               'username',
+                               'offset',
+                               20,
+                               $this->requestedUser,
+                               [
+                                       'class' => 'mw-ui-input-inline mw-autocomplete-user',
+                                       'tabindex' => 1,
+                               ] + (
+                                       // Set autofocus on blank input
+                               $this->requestedUser === '' ? [ 'autofocus' => '' ] : []
+                               )
+                       ) . '<br />';
+
+               $out .= Xml::checkLabel( $this->msg( 'activeusers-hidebots' )->text(),
+                       'hidebots', 'hidebots', $this->opts->getValue( 'hidebots' ), [ 'tabindex' => 2 ] );
+
+               $out .= Xml::checkLabel(
+                               $this->msg( 'activeusers-hidesysops' )->text(),
+                               'hidesysops',
+                               'hidesysops',
+                               $this->opts->getValue( 'hidesysops' ),
+                               [ 'tabindex' => 3 ]
+                       ) . '<br />';
+
+               # Submit button and form bottom
+               $out .= Xml::submitButton(
+                               $this->msg( 'activeusers-submit' )->text(),
+                               [ 'tabindex' => 4 ]
+                       ) . "\n";
+               $out .= Xml::closeElement( 'fieldset' );
+               $out .= Xml::closeElement( 'form' );
+
+               return $out;
+       }
+
+}
diff --git a/includes/specials/pagers/AllMessagesTablePager.php b/includes/specials/pagers/AllMessagesTablePager.php
new file mode 100644 (file)
index 0000000..2f2cbc2
--- /dev/null
@@ -0,0 +1,424 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * Use TablePager for prettified output. We have to pretend that we're
+ * getting data from a table when in fact not all of it comes from the database.
+ *
+ * @ingroup Pager
+ */
+class AllMessagesTablePager extends TablePager {
+
+       protected $filter, $prefix, $langcode, $displayPrefix;
+
+       public $mLimitsShown;
+
+       /**
+        * @var Language
+        */
+       public $lang;
+
+       /**
+        * @var null|bool
+        */
+       public $custom;
+
+       function __construct( $page, $conds, $langObj = null ) {
+               parent::__construct( $page->getContext() );
+               $this->mIndexField = 'am_title';
+               $this->mPage = $page;
+               $this->mConds = $conds;
+               // FIXME: Why does this need to be set to DIR_DESCENDING to produce ascending ordering?
+               $this->mDefaultDirection = IndexPager::DIR_DESCENDING;
+               $this->mLimitsShown = [ 20, 50, 100, 250, 500, 5000 ];
+
+               global $wgContLang;
+
+               $this->talk = $this->msg( 'talkpagelinktext' )->escaped();
+
+               $this->lang = ( $langObj ? $langObj : $wgContLang );
+               $this->langcode = $this->lang->getCode();
+               $this->foreign = $this->langcode !== $wgContLang->getCode();
+
+               $request = $this->getRequest();
+
+               $this->filter = $request->getVal( 'filter', 'all' );
+               if ( $this->filter === 'all' ) {
+                       $this->custom = null; // So won't match in either case
+               } else {
+                       $this->custom = ( $this->filter === 'unmodified' );
+               }
+
+               $prefix = $this->getLanguage()->ucfirst( $request->getVal( 'prefix', '' ) );
+               $prefix = $prefix !== '' ?
+                       Title::makeTitleSafe( NS_MEDIAWIKI, $request->getVal( 'prefix', null ) ) :
+                       null;
+
+               if ( $prefix !== null ) {
+                       $this->displayPrefix = $prefix->getDBkey();
+                       $this->prefix = '/^' . preg_quote( $this->displayPrefix, '/' ) . '/i';
+               } else {
+                       $this->displayPrefix = false;
+                       $this->prefix = false;
+               }
+
+               // The suffix that may be needed for message names if we're in a
+               // different language (eg [[MediaWiki:Foo/fr]]: $suffix = '/fr'
+               if ( $this->foreign ) {
+                       $this->suffix = '/' . $this->langcode;
+               } else {
+                       $this->suffix = '';
+               }
+       }
+
+       function buildForm() {
+               $attrs = [ 'id' => 'mw-allmessages-form-lang', 'name' => 'lang' ];
+               $msg = wfMessage( 'allmessages-language' );
+               $langSelect = Xml::languageSelector( $this->langcode, false, null, $attrs, $msg );
+
+               $out = Xml::openElement( 'form', [
+                               'method' => 'get',
+                               'action' => $this->getConfig()->get( 'Script' ),
+                               'id' => 'mw-allmessages-form'
+                       ] ) .
+                       Xml::fieldset( $this->msg( 'allmessages-filter-legend' )->text() ) .
+                       Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
+                       Xml::openElement( 'table', [ 'class' => 'mw-allmessages-table' ] ) . "\n" .
+                       '<tr>
+                               <td class="mw-label">' .
+                       Xml::label( $this->msg( 'allmessages-prefix' )->text(), 'mw-allmessages-form-prefix' ) .
+                       "</td>\n
+                       <td class=\"mw-input\">" .
+                       Xml::input(
+                               'prefix',
+                               20,
+                               str_replace( '_', ' ', $this->displayPrefix ),
+                               [ 'id' => 'mw-allmessages-form-prefix' ]
+                       ) .
+                       "</td>\n
+                       </tr>
+                       <tr>\n
+                       <td class='mw-label'>" .
+                       $this->msg( 'allmessages-filter' )->escaped() .
+                       "</td>\n
+                               <td class='mw-input'>" .
+                       Xml::radioLabel( $this->msg( 'allmessages-filter-unmodified' )->text(),
+                               'filter',
+                               'unmodified',
+                               'mw-allmessages-form-filter-unmodified',
+                               ( $this->filter === 'unmodified' )
+                       ) .
+                       Xml::radioLabel( $this->msg( 'allmessages-filter-all' )->text(),
+                               'filter',
+                               'all',
+                               'mw-allmessages-form-filter-all',
+                               ( $this->filter === 'all' )
+                       ) .
+                       Xml::radioLabel( $this->msg( 'allmessages-filter-modified' )->text(),
+                               'filter',
+                               'modified',
+                               'mw-allmessages-form-filter-modified',
+                               ( $this->filter === 'modified' )
+                       ) .
+                       "</td>\n
+                       </tr>
+                       <tr>\n
+                               <td class=\"mw-label\">" . $langSelect[0] . "</td>\n
+                               <td class=\"mw-input\">" . $langSelect[1] . "</td>\n
+                       </tr>" .
+
+                       '<tr>
+                               <td class="mw-label">' .
+                       Xml::label( $this->msg( 'table_pager_limit_label' )->text(), 'mw-table_pager_limit_label' ) .
+                       '</td>
+                       <td class="mw-input">' .
+                       $this->getLimitSelect( [ 'id' => 'mw-table_pager_limit_label' ] ) .
+                       '</td>
+                       <tr>
+                               <td></td>
+                               <td>' .
+                       Xml::submitButton( $this->msg( 'allmessages-filter-submit' )->text() ) .
+                       "</td>\n
+                       </tr>" .
+
+                       Xml::closeElement( 'table' ) .
+                       $this->getHiddenFields( [ 'title', 'prefix', 'filter', 'lang', 'limit' ] ) .
+                       Xml::closeElement( 'fieldset' ) .
+                       Xml::closeElement( 'form' );
+
+               return $out;
+       }
+
+       function getAllMessages( $descending ) {
+               $messageNames = Language::getLocalisationCache()->getSubitemList( 'en', 'messages' );
+
+               // Normalise message names so they look like page titles and sort correctly - T86139
+               $messageNames = array_map( [ $this->lang, 'ucfirst' ], $messageNames );
+
+               if ( $descending ) {
+                       rsort( $messageNames );
+               } else {
+                       asort( $messageNames );
+               }
+
+               return $messageNames;
+       }
+
+       /**
+        * Determine which of the MediaWiki and MediaWiki_talk namespace pages exist.
+        * Returns array( 'pages' => ..., 'talks' => ... ), where the subarrays have
+        * an entry for each existing page, with the key being the message name and
+        * value arbitrary.
+        *
+        * @param array $messageNames
+        * @param string $langcode What language code
+        * @param bool $foreign Whether the $langcode is not the content language
+        * @return array A 'pages' and 'talks' array with the keys of existing pages
+        */
+       public static function getCustomisedStatuses( $messageNames, $langcode = 'en', $foreign = false ) {
+               // FIXME: This function should be moved to Language:: or something.
+
+               $dbr = wfGetDB( DB_SLAVE );
+               $res = $dbr->select( 'page',
+                       [ 'page_namespace', 'page_title' ],
+                       [ 'page_namespace' => [ NS_MEDIAWIKI, NS_MEDIAWIKI_TALK ] ],
+                       __METHOD__,
+                       [ 'USE INDEX' => 'name_title' ]
+               );
+               $xNames = array_flip( $messageNames );
+
+               $pageFlags = $talkFlags = [];
+
+               foreach ( $res as $s ) {
+                       $exists = false;
+
+                       if ( $foreign ) {
+                               $titleParts = explode( '/', $s->page_title );
+                               if ( count( $titleParts ) === 2 &&
+                                       $langcode === $titleParts[1] &&
+                                       isset( $xNames[$titleParts[0]] )
+                               ) {
+                                       $exists = $titleParts[0];
+                               }
+                       } elseif ( isset( $xNames[$s->page_title] ) ) {
+                               $exists = $s->page_title;
+                       }
+
+                       $title = Title::newFromRow( $s );
+                       if ( $exists && $title->inNamespace( NS_MEDIAWIKI ) ) {
+                               $pageFlags[$exists] = true;
+                       } elseif ( $exists && $title->inNamespace( NS_MEDIAWIKI_TALK ) ) {
+                               $talkFlags[$exists] = true;
+                       }
+               }
+
+               return [ 'pages' => $pageFlags, 'talks' => $talkFlags ];
+       }
+
+       /**
+        *  This function normally does a database query to get the results; we need
+        * to make a pretend result using a FakeResultWrapper.
+        * @param string $offset
+        * @param int $limit
+        * @param bool $descending
+        * @return FakeResultWrapper
+        */
+       function reallyDoQuery( $offset, $limit, $descending ) {
+               $result = new FakeResultWrapper( [] );
+
+               $messageNames = $this->getAllMessages( $descending );
+               $statuses = self::getCustomisedStatuses( $messageNames, $this->langcode, $this->foreign );
+
+               $count = 0;
+               foreach ( $messageNames as $key ) {
+                       $customised = isset( $statuses['pages'][$key] );
+                       if ( $customised !== $this->custom &&
+                               ( $descending && ( $key < $offset || !$offset ) || !$descending && $key > $offset ) &&
+                               ( ( $this->prefix && preg_match( $this->prefix, $key ) ) || $this->prefix === false )
+                       ) {
+                               $actual = wfMessage( $key )->inLanguage( $this->langcode )->plain();
+                               $default = wfMessage( $key )->inLanguage( $this->langcode )->useDatabase( false )->plain();
+                               $result->result[] = [
+                                       'am_title' => $key,
+                                       'am_actual' => $actual,
+                                       'am_default' => $default,
+                                       'am_customised' => $customised,
+                                       'am_talk_exists' => isset( $statuses['talks'][$key] )
+                               ];
+                               $count++;
+                       }
+
+                       if ( $count === $limit ) {
+                               break;
+                       }
+               }
+
+               return $result;
+       }
+
+       function getStartBody() {
+               $tableClass = $this->getTableClass();
+               return Xml::openElement( 'table', [
+                       'class' => "mw-datatable $tableClass",
+                       'id' => 'mw-allmessagestable'
+               ] ) .
+               "\n" .
+               "<thead><tr>
+                               <th rowspan=\"2\">" .
+               $this->msg( 'allmessagesname' )->escaped() . "
+                               </th>
+                               <th>" .
+               $this->msg( 'allmessagesdefault' )->escaped() .
+               "</th>
+                       </tr>\n
+                       <tr>
+                               <th>" .
+               $this->msg( 'allmessagescurrent' )->escaped() .
+               "</th>
+                       </tr></thead><tbody>\n";
+       }
+
+       function formatValue( $field, $value ) {
+               switch ( $field ) {
+                       case 'am_title' :
+                               $title = Title::makeTitle( NS_MEDIAWIKI, $value . $this->suffix );
+                               $talk = Title::makeTitle( NS_MEDIAWIKI_TALK, $value . $this->suffix );
+                               $translation = Linker::makeExternalLink(
+                                       'https://translatewiki.net/w/i.php?' . wfArrayToCgi( [
+                                               'title' => 'Special:SearchTranslations',
+                                               'group' => 'mediawiki',
+                                               'grouppath' => 'mediawiki',
+                                               'query' => 'language:' . $this->getLanguage()->getCode() . '^25 ' .
+                                                       'messageid:"MediaWiki:' . $value . '"^10 "' .
+                                                       $this->msg( $value )->inLanguage( 'en' )->plain() . '"'
+                                       ] ),
+                                       $this->msg( 'allmessages-filter-translate' )->text()
+                               );
+
+                               if ( $this->mCurrentRow->am_customised ) {
+                                       $title = Linker::linkKnown( $title, $this->getLanguage()->lcfirst( $value ) );
+                               } else {
+                                       $title = Linker::link(
+                                               $title,
+                                               $this->getLanguage()->lcfirst( $value ),
+                                               [],
+                                               [],
+                                               [ 'broken' ]
+                                       );
+                               }
+                               if ( $this->mCurrentRow->am_talk_exists ) {
+                                       $talk = Linker::linkKnown( $talk, $this->talk );
+                               } else {
+                                       $talk = Linker::link(
+                                               $talk,
+                                               $this->talk,
+                                               [],
+                                               [],
+                                               [ 'broken' ]
+                                       );
+                               }
+
+                               return $title . ' ' .
+                               $this->msg( 'parentheses' )->rawParams( $talk )->escaped() .
+                               ' ' .
+                               $this->msg( 'parentheses' )->rawParams( $translation )->escaped();
+
+                       case 'am_default' :
+                       case 'am_actual' :
+                               return Sanitizer::escapeHtmlAllowEntities( $value );
+               }
+
+               return '';
+       }
+
+       function formatRow( $row ) {
+               // Do all the normal stuff
+               $s = parent::formatRow( $row );
+
+               // But if there's a customised message, add that too.
+               if ( $row->am_customised ) {
+                       $s .= Xml::openElement( 'tr', $this->getRowAttrs( $row, true ) );
+                       $formatted = strval( $this->formatValue( 'am_actual', $row->am_actual ) );
+
+                       if ( $formatted === '' ) {
+                               $formatted = '&#160;';
+                       }
+
+                       $s .= Xml::tags( 'td', $this->getCellAttrs( 'am_actual', $row->am_actual ), $formatted )
+                               . "</tr>\n";
+               }
+
+               return $s;
+       }
+
+       function getRowAttrs( $row, $isSecond = false ) {
+               $arr = [];
+
+               if ( $row->am_customised ) {
+                       $arr['class'] = 'allmessages-customised';
+               }
+
+               if ( !$isSecond ) {
+                       $arr['id'] = Sanitizer::escapeId( 'msg_' . $this->getLanguage()->lcfirst( $row->am_title ) );
+               }
+
+               return $arr;
+       }
+
+       function getCellAttrs( $field, $value ) {
+               if ( $this->mCurrentRow->am_customised && $field === 'am_title' ) {
+                       return [ 'rowspan' => '2', 'class' => $field ];
+               } elseif ( $field === 'am_title' ) {
+                       return [ 'class' => $field ];
+               } else {
+                       return [
+                               'lang' => $this->lang->getHtmlCode(),
+                               'dir' => $this->lang->getDir(),
+                               'class' => $field
+                       ];
+               }
+       }
+
+       // This is not actually used, as getStartBody is overridden above
+       function getFieldNames() {
+               return [
+                       'am_title' => $this->msg( 'allmessagesname' )->text(),
+                       'am_default' => $this->msg( 'allmessagesdefault' )->text()
+               ];
+       }
+
+       function getTitle() {
+               return SpecialPage::getTitleFor( 'Allmessages', false );
+       }
+
+       function isFieldSortable( $x ) {
+               return false;
+       }
+
+       function getDefaultSort() {
+               return '';
+       }
+
+       function getQueryInfo() {
+               return '';
+       }
+
+}
diff --git a/includes/specials/pagers/BlockListPager.php b/includes/specials/pagers/BlockListPager.php
new file mode 100644 (file)
index 0000000..8857907
--- /dev/null
@@ -0,0 +1,266 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * @ingroup Pager
+ */
+class BlockListPager extends TablePager {
+
+       protected $conds;
+       protected $page;
+
+       /**
+        * @param SpecialPage $page
+        * @param array $conds
+        */
+       function __construct( $page, $conds ) {
+               $this->page = $page;
+               $this->conds = $conds;
+               $this->mDefaultDirection = IndexPager::DIR_DESCENDING;
+               parent::__construct( $page->getContext() );
+       }
+
+       function getFieldNames() {
+               static $headers = null;
+
+               if ( $headers === null ) {
+                       $headers = [
+                               'ipb_timestamp' => 'blocklist-timestamp',
+                               'ipb_target' => 'blocklist-target',
+                               'ipb_expiry' => 'blocklist-expiry',
+                               'ipb_by' => 'blocklist-by',
+                               'ipb_params' => 'blocklist-params',
+                               'ipb_reason' => 'blocklist-reason',
+                       ];
+                       foreach ( $headers as $key => $val ) {
+                               $headers[$key] = $this->msg( $val )->text();
+                       }
+               }
+
+               return $headers;
+       }
+
+       function formatValue( $name, $value ) {
+               static $msg = null;
+               if ( $msg === null ) {
+                       $keys = [
+                               'anononlyblock',
+                               'createaccountblock',
+                               'noautoblockblock',
+                               'emailblock',
+                               'blocklist-nousertalk',
+                               'unblocklink',
+                               'change-blocklink',
+                       ];
+
+                       foreach ( $keys as $key ) {
+                               $msg[$key] = $this->msg( $key )->escaped();
+                       }
+               }
+
+               /** @var $row object */
+               $row = $this->mCurrentRow;
+
+               $language = $this->getLanguage();
+
+               $formatted = '';
+
+               switch ( $name ) {
+                       case 'ipb_timestamp':
+                               $formatted = htmlspecialchars( $language->userTimeAndDate( $value, $this->getUser() ) );
+                               break;
+
+                       case 'ipb_target':
+                               if ( $row->ipb_auto ) {
+                                       $formatted = $this->msg( 'autoblockid', $row->ipb_id )->parse();
+                               } else {
+                                       list( $target, $type ) = Block::parseTarget( $row->ipb_address );
+                                       switch ( $type ) {
+                                               case Block::TYPE_USER:
+                                               case Block::TYPE_IP:
+                                                       $formatted = Linker::userLink( $target->getId(), $target );
+                                                       $formatted .= Linker::userToolLinks(
+                                                               $target->getId(),
+                                                               $target,
+                                                               false,
+                                                               Linker::TOOL_LINKS_NOBLOCK
+                                                       );
+                                                       break;
+                                               case Block::TYPE_RANGE:
+                                                       $formatted = htmlspecialchars( $target );
+                                       }
+                               }
+                               break;
+
+                       case 'ipb_expiry':
+                               $formatted = htmlspecialchars( $language->formatExpiry(
+                                       $value,
+                                       /* User preference timezone */true
+                               ) );
+                               if ( $this->getUser()->isAllowed( 'block' ) ) {
+                                       if ( $row->ipb_auto ) {
+                                               $links[] = Linker::linkKnown(
+                                                       SpecialPage::getTitleFor( 'Unblock' ),
+                                                       $msg['unblocklink'],
+                                                       [],
+                                                       [ 'wpTarget' => "#{$row->ipb_id}" ]
+                                               );
+                                       } else {
+                                               $links[] = Linker::linkKnown(
+                                                       SpecialPage::getTitleFor( 'Unblock', $row->ipb_address ),
+                                                       $msg['unblocklink']
+                                               );
+                                               $links[] = Linker::linkKnown(
+                                                       SpecialPage::getTitleFor( 'Block', $row->ipb_address ),
+                                                       $msg['change-blocklink']
+                                               );
+                                       }
+                                       $formatted .= ' ' . Html::rawElement(
+                                                       'span',
+                                                       [ 'class' => 'mw-blocklist-actions' ],
+                                                       $this->msg( 'parentheses' )->rawParams(
+                                                               $language->pipeList( $links ) )->escaped()
+                                               );
+                               }
+                               break;
+
+                       case 'ipb_by':
+                               if ( isset( $row->by_user_name ) ) {
+                                       $formatted = Linker::userLink( $value, $row->by_user_name );
+                                       $formatted .= Linker::userToolLinks( $value, $row->by_user_name );
+                               } else {
+                                       $formatted = htmlspecialchars( $row->ipb_by_text ); // foreign user?
+                               }
+                               break;
+
+                       case 'ipb_reason':
+                               $formatted = Linker::formatComment( $value );
+                               break;
+
+                       case 'ipb_params':
+                               $properties = [];
+                               if ( $row->ipb_anon_only ) {
+                                       $properties[] = $msg['anononlyblock'];
+                               }
+                               if ( $row->ipb_create_account ) {
+                                       $properties[] = $msg['createaccountblock'];
+                               }
+                               if ( $row->ipb_user && !$row->ipb_enable_autoblock ) {
+                                       $properties[] = $msg['noautoblockblock'];
+                               }
+
+                               if ( $row->ipb_block_email ) {
+                                       $properties[] = $msg['emailblock'];
+                               }
+
+                               if ( !$row->ipb_allow_usertalk ) {
+                                       $properties[] = $msg['blocklist-nousertalk'];
+                               }
+
+                               $formatted = $language->commaList( $properties );
+                               break;
+
+                       default:
+                               $formatted = "Unable to format $name";
+                               break;
+               }
+
+               return $formatted;
+       }
+
+       function getQueryInfo() {
+               $info = [
+                       'tables' => [ 'ipblocks', 'user' ],
+                       'fields' => [
+                               'ipb_id',
+                               'ipb_address',
+                               'ipb_user',
+                               'ipb_by',
+                               'ipb_by_text',
+                               'by_user_name' => 'user_name',
+                               'ipb_reason',
+                               'ipb_timestamp',
+                               'ipb_auto',
+                               'ipb_anon_only',
+                               'ipb_create_account',
+                               'ipb_enable_autoblock',
+                               'ipb_expiry',
+                               'ipb_range_start',
+                               'ipb_range_end',
+                               'ipb_deleted',
+                               'ipb_block_email',
+                               'ipb_allow_usertalk',
+                       ],
+                       'conds' => $this->conds,
+                       'join_conds' => [ 'user' => [ 'LEFT JOIN', 'user_id = ipb_by' ] ]
+               ];
+
+               # Filter out any expired blocks
+               $db = $this->getDatabase();
+               $info['conds'][] = 'ipb_expiry > ' . $db->addQuotes( $db->timestamp() );
+
+               # Is the user allowed to see hidden blocks?
+               if ( !$this->getUser()->isAllowed( 'hideuser' ) ) {
+                       $info['conds']['ipb_deleted'] = 0;
+               }
+
+               return $info;
+       }
+
+       public function getTableClass() {
+               return parent::getTableClass() . ' mw-blocklist';
+       }
+
+       function getIndexField() {
+               return 'ipb_timestamp';
+       }
+
+       function getDefaultSort() {
+               return 'ipb_timestamp';
+       }
+
+       function isFieldSortable( $name ) {
+               return false;
+       }
+
+       /**
+        * Do a LinkBatch query to minimise database load when generating all these links
+        * @param ResultWrapper $result
+        */
+       function preprocessResults( $result ) {
+               # Do a link batch query
+               $lb = new LinkBatch;
+               $lb->setCaller( __METHOD__ );
+
+               foreach ( $result as $row ) {
+                       $lb->add( NS_USER, $row->ipb_address );
+                       $lb->add( NS_USER_TALK, $row->ipb_address );
+
+                       if ( isset( $row->by_user_name ) ) {
+                               $lb->add( NS_USER, $row->by_user_name );
+                               $lb->add( NS_USER_TALK, $row->by_user_name );
+                       }
+               }
+
+               $lb->execute();
+       }
+
+}
diff --git a/includes/specials/pagers/CategoryPager.php b/includes/specials/pagers/CategoryPager.php
new file mode 100644 (file)
index 0000000..fd2ac1f
--- /dev/null
@@ -0,0 +1,126 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * TODO: Allow sorting by count.  We need to have a unique index to do this
+ * properly.
+ *
+ * @ingroup Pager
+ */
+class CategoryPager extends AlphabeticPager {
+
+       /**
+        * @var PageLinkRenderer
+        */
+       protected $linkRenderer;
+
+       /**
+        * @param IContextSource $context
+        * @param string $from
+        * @param PageLinkRenderer $linkRenderer
+        */
+       public function __construct( IContextSource $context, $from, PageLinkRenderer $linkRenderer
+       ) {
+               parent::__construct( $context );
+               $from = str_replace( ' ', '_', $from );
+               if ( $from !== '' ) {
+                       $from = Title::capitalize( $from, NS_CATEGORY );
+                       $this->setOffset( $from );
+                       $this->setIncludeOffset( true );
+               }
+
+               $this->linkRenderer = $linkRenderer;
+       }
+
+       function getQueryInfo() {
+               return [
+                       'tables' => [ 'category' ],
+                       'fields' => [ 'cat_title', 'cat_pages' ],
+                       'conds' => [ 'cat_pages > 0' ],
+                       'options' => [ 'USE INDEX' => 'cat_title' ],
+               ];
+       }
+
+       function getIndexField() {
+#              return array( 'abc' => 'cat_title', 'count' => 'cat_pages' );
+               return 'cat_title';
+       }
+
+       function getDefaultQuery() {
+               parent::getDefaultQuery();
+               unset( $this->mDefaultQuery['from'] );
+
+               return $this->mDefaultQuery;
+       }
+
+#      protected function getOrderTypeMessages() {
+#              return array( 'abc' => 'special-categories-sort-abc',
+#                      'count' => 'special-categories-sort-count' );
+#      }
+
+       protected function getDefaultDirections() {
+#              return array( 'abc' => false, 'count' => true );
+               return false;
+       }
+
+       /* Override getBody to apply LinksBatch on resultset before actually outputting anything. */
+       public function getBody() {
+               $batch = new LinkBatch;
+
+               $this->mResult->rewind();
+
+               foreach ( $this->mResult as $row ) {
+                       $batch->addObj( Title::makeTitleSafe( NS_CATEGORY, $row->cat_title ) );
+               }
+               $batch->execute();
+               $this->mResult->rewind();
+
+               return parent::getBody();
+       }
+
+       function formatRow( $result ) {
+               $title = new TitleValue( NS_CATEGORY, $result->cat_title );
+               $text = $title->getText();
+               $link = $this->linkRenderer->renderHtmlLink( $title, $text );
+
+               $count = $this->msg( 'nmembers' )->numParams( $result->cat_pages )->escaped();
+               return Html::rawElement( 'li', null, $this->getLanguage()->specialList( $link, $count ) ) . "\n";
+       }
+
+       public function getStartForm( $from ) {
+               return Xml::tags(
+                       'form',
+                       [ 'method' => 'get', 'action' => wfScript() ],
+                       Html::hidden( 'title', $this->getTitle()->getPrefixedText() ) .
+                       Xml::fieldset(
+                               $this->msg( 'categories' )->text(),
+                               Xml::inputLabel(
+                                       $this->msg( 'categoriesfrom' )->text(),
+                                       'from', 'from', 20, $from, [ 'class' => 'mw-ui-input-inline' ] ) .
+                               ' ' .
+                               Html::submitButton(
+                                       $this->msg( 'categories-submit' )->text(),
+                                       [], [ 'mw-ui-progressive' ]
+                               )
+                       )
+               );
+       }
+}
diff --git a/includes/specials/pagers/ContribsPager.php b/includes/specials/pagers/ContribsPager.php
new file mode 100644 (file)
index 0000000..d90c37b
--- /dev/null
@@ -0,0 +1,526 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * Pager for Special:Contributions
+ * @ingroup Pager
+ */
+class ContribsPager extends ReverseChronologicalPager {
+
+       public $mDefaultDirection = IndexPager::DIR_DESCENDING;
+       public $messages;
+       public $target;
+       public $namespace = '';
+       public $mDb;
+       public $preventClickjacking = false;
+
+       /** @var IDatabase */
+       public $mDbSecondary;
+
+       /**
+        * @var array
+        */
+       protected $mParentLens;
+
+       function __construct( IContextSource $context, array $options ) {
+               parent::__construct( $context );
+
+               $msgs = [
+                       'diff',
+                       'hist',
+                       'pipe-separator',
+                       'uctop'
+               ];
+
+               foreach ( $msgs as $msg ) {
+                       $this->messages[$msg] = $this->msg( $msg )->escaped();
+               }
+
+               $this->target = isset( $options['target'] ) ? $options['target'] : '';
+               $this->contribs = isset( $options['contribs'] ) ? $options['contribs'] : 'users';
+               $this->namespace = isset( $options['namespace'] ) ? $options['namespace'] : '';
+               $this->tagFilter = isset( $options['tagfilter'] ) ? $options['tagfilter'] : false;
+               $this->nsInvert = isset( $options['nsInvert'] ) ? $options['nsInvert'] : false;
+               $this->associated = isset( $options['associated'] ) ? $options['associated'] : false;
+
+               $this->deletedOnly = !empty( $options['deletedOnly'] );
+               $this->topOnly = !empty( $options['topOnly'] );
+               $this->newOnly = !empty( $options['newOnly'] );
+
+               $year = isset( $options['year'] ) ? $options['year'] : false;
+               $month = isset( $options['month'] ) ? $options['month'] : false;
+               $this->getDateCond( $year, $month );
+
+               // Most of this code will use the 'contributions' group DB, which can map to slaves
+               // with extra user based indexes or partioning by user. The additional metadata
+               // queries should use a regular slave since the lookup pattern is not all by user.
+               $this->mDbSecondary = wfGetDB( DB_SLAVE ); // any random slave
+               $this->mDb = wfGetDB( DB_SLAVE, 'contributions' );
+       }
+
+       function getDefaultQuery() {
+               $query = parent::getDefaultQuery();
+               $query['target'] = $this->target;
+
+               return $query;
+       }
+
+       /**
+        * This method basically executes the exact same code as the parent class, though with
+        * a hook added, to allow extensions to add additional queries.
+        *
+        * @param string $offset Index offset, inclusive
+        * @param int $limit Exact query limit
+        * @param bool $descending Query direction, false for ascending, true for descending
+        * @return ResultWrapper
+        */
+       function reallyDoQuery( $offset, $limit, $descending ) {
+               list( $tables, $fields, $conds, $fname, $options, $join_conds ) = $this->buildQueryInfo(
+                       $offset,
+                       $limit,
+                       $descending
+               );
+
+               /*
+                * This hook will allow extensions to add in additional queries, so they can get their data
+                * in My Contributions as well. Extensions should append their results to the $data array.
+                *
+                * Extension queries have to implement the navbar requirement as well. They should
+                * - have a column aliased as $pager->getIndexField()
+                * - have LIMIT set
+                * - have a WHERE-clause that compares the $pager->getIndexField()-equivalent column to the offset
+                * - have the ORDER BY specified based upon the details provided by the navbar
+                *
+                * See includes/Pager.php buildQueryInfo() method on how to build LIMIT, WHERE & ORDER BY
+                *
+                * &$data: an array of results of all contribs queries
+                * $pager: the ContribsPager object hooked into
+                * $offset: see phpdoc above
+                * $limit: see phpdoc above
+                * $descending: see phpdoc above
+                */
+               $data = [ $this->mDb->select(
+                       $tables, $fields, $conds, $fname, $options, $join_conds
+               ) ];
+               Hooks::run(
+                       'ContribsPager::reallyDoQuery',
+                       [ &$data, $this, $offset, $limit, $descending ]
+               );
+
+               $result = [];
+
+               // loop all results and collect them in an array
+               foreach ( $data as $query ) {
+                       foreach ( $query as $i => $row ) {
+                               // use index column as key, allowing us to easily sort in PHP
+                               $result[$row->{$this->getIndexField()} . "-$i"] = $row;
+                       }
+               }
+
+               // sort results
+               if ( $descending ) {
+                       ksort( $result );
+               } else {
+                       krsort( $result );
+               }
+
+               // enforce limit
+               $result = array_slice( $result, 0, $limit );
+
+               // get rid of array keys
+               $result = array_values( $result );
+
+               return new FakeResultWrapper( $result );
+       }
+
+       function getQueryInfo() {
+               list( $tables, $index, $userCond, $join_cond ) = $this->getUserCond();
+
+               $user = $this->getUser();
+               $conds = array_merge( $userCond, $this->getNamespaceCond() );
+
+               // Paranoia: avoid brute force searches (bug 17342)
+               if ( !$user->isAllowed( 'deletedhistory' ) ) {
+                       $conds[] = $this->mDb->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0';
+               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
+                       $conds[] = $this->mDb->bitAnd( 'rev_deleted', Revision::SUPPRESSED_USER ) .
+                               ' != ' . Revision::SUPPRESSED_USER;
+               }
+
+               # Don't include orphaned revisions
+               $join_cond['page'] = Revision::pageJoinCond();
+               # Get the current user name for accounts
+               $join_cond['user'] = Revision::userJoinCond();
+
+               $options = [];
+               if ( $index ) {
+                       $options['USE INDEX'] = [ 'revision' => $index ];
+               }
+
+               $queryInfo = [
+                       'tables' => $tables,
+                       'fields' => array_merge(
+                               Revision::selectFields(),
+                               Revision::selectUserFields(),
+                               [ 'page_namespace', 'page_title', 'page_is_new',
+                                       'page_latest', 'page_is_redirect', 'page_len' ]
+                       ),
+                       'conds' => $conds,
+                       'options' => $options,
+                       'join_conds' => $join_cond
+               ];
+
+               ChangeTags::modifyDisplayQuery(
+                       $queryInfo['tables'],
+                       $queryInfo['fields'],
+                       $queryInfo['conds'],
+                       $queryInfo['join_conds'],
+                       $queryInfo['options'],
+                       $this->tagFilter
+               );
+
+               Hooks::run( 'ContribsPager::getQueryInfo', [ &$this, &$queryInfo ] );
+
+               return $queryInfo;
+       }
+
+       function getUserCond() {
+               $condition = [];
+               $join_conds = [];
+               $tables = [ 'revision', 'page', 'user' ];
+               $index = false;
+               if ( $this->contribs == 'newbie' ) {
+                       $max = $this->mDb->selectField( 'user', 'max(user_id)', false, __METHOD__ );
+                       $condition[] = 'rev_user >' . (int)( $max - $max / 100 );
+                       # ignore local groups with the bot right
+                       # @todo FIXME: Global groups may have 'bot' rights
+                       $groupsWithBotPermission = User::getGroupsWithPermission( 'bot' );
+                       if ( count( $groupsWithBotPermission ) ) {
+                               $tables[] = 'user_groups';
+                               $condition[] = 'ug_group IS NULL';
+                               $join_conds['user_groups'] = [
+                                       'LEFT JOIN', [
+                                               'ug_user = rev_user',
+                                               'ug_group' => $groupsWithBotPermission
+                                       ]
+                               ];
+                       }
+               } else {
+                       $uid = User::idFromName( $this->target );
+                       if ( $uid ) {
+                               $condition['rev_user'] = $uid;
+                               $index = 'user_timestamp';
+                       } else {
+                               $condition['rev_user_text'] = $this->target;
+                               $index = 'usertext_timestamp';
+                       }
+               }
+
+               if ( $this->deletedOnly ) {
+                       $condition[] = 'rev_deleted != 0';
+               }
+
+               if ( $this->topOnly ) {
+                       $condition[] = 'rev_id = page_latest';
+               }
+
+               if ( $this->newOnly ) {
+                       $condition[] = 'rev_parent_id = 0';
+               }
+
+               return [ $tables, $index, $condition, $join_conds ];
+       }
+
+       function getNamespaceCond() {
+               if ( $this->namespace !== '' ) {
+                       $selectedNS = $this->mDb->addQuotes( $this->namespace );
+                       $eq_op = $this->nsInvert ? '!=' : '=';
+                       $bool_op = $this->nsInvert ? 'AND' : 'OR';
+
+                       if ( !$this->associated ) {
+                               return [ "page_namespace $eq_op $selectedNS" ];
+                       }
+
+                       $associatedNS = $this->mDb->addQuotes(
+                               MWNamespace::getAssociated( $this->namespace )
+                       );
+
+                       return [
+                               "page_namespace $eq_op $selectedNS " .
+                               $bool_op .
+                               " page_namespace $eq_op $associatedNS"
+                       ];
+               }
+
+               return [];
+       }
+
+       function getIndexField() {
+               return 'rev_timestamp';
+       }
+
+       function doBatchLookups() {
+               # Do a link batch query
+               $this->mResult->seek( 0 );
+               $parentRevIds = [];
+               $this->mParentLens = [];
+               $batch = new LinkBatch();
+               # Give some pointers to make (last) links
+               foreach ( $this->mResult as $row ) {
+                       if ( isset( $row->rev_parent_id ) && $row->rev_parent_id ) {
+                               $parentRevIds[] = $row->rev_parent_id;
+                       }
+                       if ( isset( $row->rev_id ) ) {
+                               $this->mParentLens[$row->rev_id] = $row->rev_len;
+                               if ( $this->contribs === 'newbie' ) { // multiple users
+                                       $batch->add( NS_USER, $row->user_name );
+                                       $batch->add( NS_USER_TALK, $row->user_name );
+                               }
+                               $batch->add( $row->page_namespace, $row->page_title );
+                       }
+               }
+               # Fetch rev_len for revisions not already scanned above
+               $this->mParentLens += Revision::getParentLengths(
+                       $this->mDbSecondary,
+                       array_diff( $parentRevIds, array_keys( $this->mParentLens ) )
+               );
+               $batch->execute();
+               $this->mResult->seek( 0 );
+       }
+
+       /**
+        * @return string
+        */
+       function getStartBody() {
+               return "<ul class=\"mw-contributions-list\">\n";
+       }
+
+       /**
+        * @return string
+        */
+       function getEndBody() {
+               return "</ul>\n";
+       }
+
+       /**
+        * Generates each row in the contributions list.
+        *
+        * Contributions which are marked "top" are currently on top of the history.
+        * For these contributions, a [rollback] link is shown for users with roll-
+        * back privileges. The rollback link restores the most recent version that
+        * was not written by the target user.
+        *
+        * @todo This would probably look a lot nicer in a table.
+        * @param object $row
+        * @return string
+        */
+       function formatRow( $row ) {
+
+               $ret = '';
+               $classes = [];
+
+               /*
+                * There may be more than just revision rows. To make sure that we'll only be processing
+                * revisions here, let's _try_ to build a revision out of our row (without displaying
+                * notices though) and then trying to grab data from the built object. If we succeed,
+                * we're definitely dealing with revision data and we may proceed, if not, we'll leave it
+                * to extensions to subscribe to the hook to parse the row.
+                */
+               MediaWiki\suppressWarnings();
+               try {
+                       $rev = new Revision( $row );
+                       $validRevision = (bool)$rev->getId();
+               } catch ( Exception $e ) {
+                       $validRevision = false;
+               }
+               MediaWiki\restoreWarnings();
+
+               if ( $validRevision ) {
+                       $classes = [];
+
+                       $page = Title::newFromRow( $row );
+                       $link = Linker::link(
+                               $page,
+                               htmlspecialchars( $page->getPrefixedText() ),
+                               [ 'class' => 'mw-contributions-title' ],
+                               $page->isRedirect() ? [ 'redirect' => 'no' ] : []
+                       );
+                       # Mark current revisions
+                       $topmarktext = '';
+                       $user = $this->getUser();
+                       if ( $row->rev_id == $row->page_latest ) {
+                               $topmarktext .= '<span class="mw-uctop">' . $this->messages['uctop'] . '</span>';
+                               # Add rollback link
+                               if ( !$row->page_is_new && $page->quickUserCan( 'rollback', $user )
+                                       && $page->quickUserCan( 'edit', $user )
+                               ) {
+                                       $this->preventClickjacking();
+                                       $topmarktext .= ' ' . Linker::generateRollback( $rev, $this->getContext() );
+                               }
+                       }
+                       # Is there a visible previous revision?
+                       if ( $rev->userCan( Revision::DELETED_TEXT, $user ) && $rev->getParentId() !== 0 ) {
+                               $difftext = Linker::linkKnown(
+                                       $page,
+                                       $this->messages['diff'],
+                                       [],
+                                       [
+                                               'diff' => 'prev',
+                                               'oldid' => $row->rev_id
+                                       ]
+                               );
+                       } else {
+                               $difftext = $this->messages['diff'];
+                       }
+                       $histlink = Linker::linkKnown(
+                               $page,
+                               $this->messages['hist'],
+                               [],
+                               [ 'action' => 'history' ]
+                       );
+
+                       if ( $row->rev_parent_id === null ) {
+                               // For some reason rev_parent_id isn't populated for this row.
+                               // Its rumoured this is true on wikipedia for some revisions (bug 34922).
+                               // Next best thing is to have the total number of bytes.
+                               $chardiff = ' <span class="mw-changeslist-separator">. .</span> ';
+                               $chardiff .= Linker::formatRevisionSize( $row->rev_len );
+                               $chardiff .= ' <span class="mw-changeslist-separator">. .</span> ';
+                       } else {
+                               $parentLen = 0;
+                               if ( isset( $this->mParentLens[$row->rev_parent_id] ) ) {
+                                       $parentLen = $this->mParentLens[$row->rev_parent_id];
+                               }
+
+                               $chardiff = ' <span class="mw-changeslist-separator">. .</span> ';
+                               $chardiff .= ChangesList::showCharacterDifference(
+                                       $parentLen,
+                                       $row->rev_len,
+                                       $this->getContext()
+                               );
+                               $chardiff .= ' <span class="mw-changeslist-separator">. .</span> ';
+                       }
+
+                       $lang = $this->getLanguage();
+                       $comment = $lang->getDirMark() . Linker::revComment( $rev, false, true );
+                       $date = $lang->userTimeAndDate( $row->rev_timestamp, $user );
+                       if ( $rev->userCan( Revision::DELETED_TEXT, $user ) ) {
+                               $d = Linker::linkKnown(
+                                       $page,
+                                       htmlspecialchars( $date ),
+                                       [ 'class' => 'mw-changeslist-date' ],
+                                       [ 'oldid' => intval( $row->rev_id ) ]
+                               );
+                       } else {
+                               $d = htmlspecialchars( $date );
+                       }
+                       if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+                               $d = '<span class="history-deleted">' . $d . '</span>';
+                       }
+
+                       # Show user names for /newbies as there may be different users.
+                       # Note that we already excluded rows with hidden user names.
+                       if ( $this->contribs == 'newbie' ) {
+                               $userlink = ' . . ' . $lang->getDirMark()
+                                       . Linker::userLink( $rev->getUser(), $rev->getUserText() );
+                               $userlink .= ' ' . $this->msg( 'parentheses' )->rawParams(
+                                               Linker::userTalkLink( $rev->getUser(), $rev->getUserText() ) )->escaped() . ' ';
+                       } else {
+                               $userlink = '';
+                       }
+
+                       if ( $rev->getParentId() === 0 ) {
+                               $nflag = ChangesList::flag( 'newpage' );
+                       } else {
+                               $nflag = '';
+                       }
+
+                       if ( $rev->isMinor() ) {
+                               $mflag = ChangesList::flag( 'minor' );
+                       } else {
+                               $mflag = '';
+                       }
+
+                       $del = Linker::getRevDeleteLink( $user, $rev, $page );
+                       if ( $del !== '' ) {
+                               $del .= ' ';
+                       }
+
+                       $diffHistLinks = $this->msg( 'parentheses' )
+                               ->rawParams( $difftext . $this->messages['pipe-separator'] . $histlink )
+                               ->escaped();
+                       $ret = "{$del}{$d} {$diffHistLinks}{$chardiff}{$nflag}{$mflag} ";
+                       $ret .= "{$link}{$userlink} {$comment} {$topmarktext}";
+
+                       # Denote if username is redacted for this edit
+                       if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
+                               $ret .= " <strong>" .
+                                       $this->msg( 'rev-deleted-user-contribs' )->escaped() .
+                                       "</strong>";
+                       }
+
+                       # Tags, if any.
+                       list( $tagSummary, $newClasses ) = ChangeTags::formatSummaryRow(
+                               $row->ts_tags,
+                               'contributions',
+                               $this->getContext()
+                       );
+                       $classes = array_merge( $classes, $newClasses );
+                       $ret .= " $tagSummary";
+               }
+
+               // Let extensions add data
+               Hooks::run( 'ContributionsLineEnding', [ $this, &$ret, $row, &$classes ] );
+
+               if ( $classes === [] && $ret === '' ) {
+                       wfDebug( "Dropping Special:Contribution row that could not be formatted\n" );
+                       $ret = "<!-- Could not format Special:Contribution row. -->\n";
+               } else {
+                       $ret = Html::rawElement( 'li', [ 'class' => $classes ], $ret ) . "\n";
+               }
+
+               return $ret;
+       }
+
+       /**
+        * Overwrite Pager function and return a helpful comment
+        * @return string
+        */
+       function getSqlComment() {
+               if ( $this->namespace || $this->deletedOnly ) {
+                       // potentially slow, see CR r58153
+                       return 'contributions page filtered for namespace or RevisionDeleted edits';
+               } else {
+                       return 'contributions page unfiltered';
+               }
+       }
+
+       protected function preventClickjacking() {
+               $this->preventClickjacking = true;
+       }
+
+       /**
+        * @return bool
+        */
+       public function getPreventClickjacking() {
+               return $this->preventClickjacking;
+       }
+}
diff --git a/includes/specials/pagers/DeletedContribsPager.php b/includes/specials/pagers/DeletedContribsPager.php
new file mode 100644 (file)
index 0000000..f2421f8
--- /dev/null
@@ -0,0 +1,355 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * @ingroup Pager
+ */
+class DeletedContribsPager extends IndexPager {
+
+       public $mDefaultDirection = IndexPager::DIR_DESCENDING;
+       public $messages;
+       public $target;
+       public $namespace = '';
+       public $mDb;
+
+       /**
+        * @var string Navigation bar with paging links.
+        */
+       protected $mNavigationBar;
+
+       function __construct( IContextSource $context, $target, $namespace = false ) {
+               parent::__construct( $context );
+               $msgs = [ 'deletionlog', 'undeleteviewlink', 'diff' ];
+               foreach ( $msgs as $msg ) {
+                       $this->messages[$msg] = $this->msg( $msg )->escaped();
+               }
+               $this->target = $target;
+               $this->namespace = $namespace;
+               $this->mDb = wfGetDB( DB_SLAVE, 'contributions' );
+       }
+
+       function getDefaultQuery() {
+               $query = parent::getDefaultQuery();
+               $query['target'] = $this->target;
+
+               return $query;
+       }
+
+       function getQueryInfo() {
+               list( $index, $userCond ) = $this->getUserCond();
+               $conds = array_merge( $userCond, $this->getNamespaceCond() );
+               $user = $this->getUser();
+               // Paranoia: avoid brute force searches (bug 17792)
+               if ( !$user->isAllowed( 'deletedhistory' ) ) {
+                       $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::DELETED_USER ) . ' = 0';
+               } elseif ( !$user->isAllowedAny( 'suppressrevision', 'viewsuppressed' ) ) {
+                       $conds[] = $this->mDb->bitAnd( 'ar_deleted', Revision::SUPPRESSED_USER ) .
+                               ' != ' . Revision::SUPPRESSED_USER;
+               }
+
+               return [
+                       'tables' => [ 'archive' ],
+                       'fields' => [
+                               'ar_rev_id', 'ar_namespace', 'ar_title', 'ar_timestamp', 'ar_comment',
+                               'ar_minor_edit', 'ar_user', 'ar_user_text', 'ar_deleted'
+                       ],
+                       'conds' => $conds,
+                       'options' => [ 'USE INDEX' => $index ]
+               ];
+       }
+
+       /**
+        * This method basically executes the exact same code as the parent class, though with
+        * a hook added, to allow extensions to add additional queries.
+        *
+        * @param string $offset Index offset, inclusive
+        * @param int $limit Exact query limit
+        * @param bool $descending Query direction, false for ascending, true for descending
+        * @return ResultWrapper
+        */
+       function reallyDoQuery( $offset, $limit, $descending ) {
+               $data = [ parent::reallyDoQuery( $offset, $limit, $descending ) ];
+
+               // This hook will allow extensions to add in additional queries, nearly
+               // identical to ContribsPager::reallyDoQuery.
+               Hooks::run(
+                       'DeletedContribsPager::reallyDoQuery',
+                       [ &$data, $this, $offset, $limit, $descending ]
+               );
+
+               $result = [];
+
+               // loop all results and collect them in an array
+               foreach ( $data as $query ) {
+                       foreach ( $query as $i => $row ) {
+                               // use index column as key, allowing us to easily sort in PHP
+                               $result[$row->{$this->getIndexField()} . "-$i"] = $row;
+                       }
+               }
+
+               // sort results
+               if ( $descending ) {
+                       ksort( $result );
+               } else {
+                       krsort( $result );
+               }
+
+               // enforce limit
+               $result = array_slice( $result, 0, $limit );
+
+               // get rid of array keys
+               $result = array_values( $result );
+
+               return new FakeResultWrapper( $result );
+       }
+
+       function getUserCond() {
+               $condition = [];
+
+               $condition['ar_user_text'] = $this->target;
+               $index = 'usertext_timestamp';
+
+               return [ $index, $condition ];
+       }
+
+       function getIndexField() {
+               return 'ar_timestamp';
+       }
+
+       function getStartBody() {
+               return "<ul>\n";
+       }
+
+       function getEndBody() {
+               return "</ul>\n";
+       }
+
+       function getNavigationBar() {
+               if ( isset( $this->mNavigationBar ) ) {
+                       return $this->mNavigationBar;
+               }
+
+               $linkTexts = [
+                       'prev' => $this->msg( 'pager-newer-n' )->numParams( $this->mLimit )->escaped(),
+                       'next' => $this->msg( 'pager-older-n' )->numParams( $this->mLimit )->escaped(),
+                       'first' => $this->msg( 'histlast' )->escaped(),
+                       'last' => $this->msg( 'histfirst' )->escaped()
+               ];
+
+               $pagingLinks = $this->getPagingLinks( $linkTexts );
+               $limitLinks = $this->getLimitLinks();
+               $lang = $this->getLanguage();
+               $limits = $lang->pipeList( $limitLinks );
+
+               $firstLast = $lang->pipeList( [ $pagingLinks['first'], $pagingLinks['last'] ] );
+               $firstLast = $this->msg( 'parentheses' )->rawParams( $firstLast )->escaped();
+               $prevNext = $this->msg( 'viewprevnext' )
+                       ->rawParams(
+                               $pagingLinks['prev'],
+                               $pagingLinks['next'],
+                               $limits
+                       )->escaped();
+               $separator = $this->msg( 'word-separator' )->escaped();
+               $this->mNavigationBar = $firstLast . $separator . $prevNext;
+
+               return $this->mNavigationBar;
+       }
+
+       function getNamespaceCond() {
+               if ( $this->namespace !== '' ) {
+                       return [ 'ar_namespace' => (int)$this->namespace ];
+               } else {
+                       return [];
+               }
+       }
+
+       /**
+        * Generates each row in the contributions list.
+        *
+        * @todo This would probably look a lot nicer in a table.
+        * @param stdClass $row
+        * @return string
+        */
+       function formatRow( $row ) {
+               $ret = '';
+               $classes = [];
+
+               /*
+                * There may be more than just revision rows. To make sure that we'll only be processing
+                * revisions here, let's _try_ to build a revision out of our row (without displaying
+                * notices though) and then trying to grab data from the built object. If we succeed,
+                * we're definitely dealing with revision data and we may proceed, if not, we'll leave it
+                * to extensions to subscribe to the hook to parse the row.
+                */
+               MediaWiki\suppressWarnings();
+               try {
+                       $rev = Revision::newFromArchiveRow( $row );
+                       $validRevision = (bool)$rev->getId();
+               } catch ( Exception $e ) {
+                       $validRevision = false;
+               }
+               MediaWiki\restoreWarnings();
+
+               if ( $validRevision ) {
+                       $ret = $this->formatRevisionRow( $row );
+               }
+
+               // Let extensions add data
+               Hooks::run( 'DeletedContributionsLineEnding', [ $this, &$ret, $row, &$classes ] );
+
+               if ( $classes === [] && $ret === '' ) {
+                       wfDebug( "Dropping Special:DeletedContribution row that could not be formatted\n" );
+                       $ret = "<!-- Could not format Special:DeletedContribution row. -->\n";
+               } else {
+                       $ret = Html::rawElement( 'li', [ 'class' => $classes ], $ret ) . "\n";
+               }
+
+               return $ret;
+       }
+
+       /**
+        * Generates each row in the contributions list for archive entries.
+        *
+        * Contributions which are marked "top" are currently on top of the history.
+        * For these contributions, a [rollback] link is shown for users with sysop
+        * privileges. The rollback link restores the most recent version that was not
+        * written by the target user.
+        *
+        * @todo This would probably look a lot nicer in a table.
+        * @param stdClass $row
+        * @return string
+        */
+       function formatRevisionRow( $row ) {
+               $page = Title::makeTitle( $row->ar_namespace, $row->ar_title );
+
+               $rev = new Revision( [
+                       'title' => $page,
+                       'id' => $row->ar_rev_id,
+                       'comment' => $row->ar_comment,
+                       'user' => $row->ar_user,
+                       'user_text' => $row->ar_user_text,
+                       'timestamp' => $row->ar_timestamp,
+                       'minor_edit' => $row->ar_minor_edit,
+                       'deleted' => $row->ar_deleted,
+               ] );
+
+               $undelete = SpecialPage::getTitleFor( 'Undelete' );
+
+               $logs = SpecialPage::getTitleFor( 'Log' );
+               $dellog = Linker::linkKnown(
+                       $logs,
+                       $this->messages['deletionlog'],
+                       [],
+                       [
+                               'type' => 'delete',
+                               'page' => $page->getPrefixedText()
+                       ]
+               );
+
+               $reviewlink = Linker::linkKnown(
+                       SpecialPage::getTitleFor( 'Undelete', $page->getPrefixedDBkey() ),
+                       $this->messages['undeleteviewlink']
+               );
+
+               $user = $this->getUser();
+
+               if ( $user->isAllowed( 'deletedtext' ) ) {
+                       $last = Linker::linkKnown(
+                               $undelete,
+                               $this->messages['diff'],
+                               [],
+                               [
+                                       'target' => $page->getPrefixedText(),
+                                       'timestamp' => $rev->getTimestamp(),
+                                       'diff' => 'prev'
+                               ]
+                       );
+               } else {
+                       $last = $this->messages['diff'];
+               }
+
+               $comment = Linker::revComment( $rev );
+               $date = $this->getLanguage()->userTimeAndDate( $rev->getTimestamp(), $user );
+               $date = htmlspecialchars( $date );
+
+               if ( !$user->isAllowed( 'undelete' ) || !$rev->userCan( Revision::DELETED_TEXT, $user ) ) {
+                       $link = $date; // unusable link
+               } else {
+                       $link = Linker::linkKnown(
+                               $undelete,
+                               $date,
+                               [ 'class' => 'mw-changeslist-date' ],
+                               [
+                                       'target' => $page->getPrefixedText(),
+                                       'timestamp' => $rev->getTimestamp()
+                               ]
+                       );
+               }
+               // Style deleted items
+               if ( $rev->isDeleted( Revision::DELETED_TEXT ) ) {
+                       $link = '<span class="history-deleted">' . $link . '</span>';
+               }
+
+               $pagelink = Linker::link(
+                       $page,
+                       null,
+                       [ 'class' => 'mw-changeslist-title' ]
+               );
+
+               if ( $rev->isMinor() ) {
+                       $mflag = ChangesList::flag( 'minor' );
+               } else {
+                       $mflag = '';
+               }
+
+               // Revision delete link
+               $del = Linker::getRevDeleteLink( $user, $rev, $page );
+               if ( $del ) {
+                       $del .= ' ';
+               }
+
+               $tools = Html::rawElement(
+                       'span',
+                       [ 'class' => 'mw-deletedcontribs-tools' ],
+                       $this->msg( 'parentheses' )->rawParams( $this->getLanguage()->pipeList(
+                               [ $last, $dellog, $reviewlink ] ) )->escaped()
+               );
+
+               $separator = '<span class="mw-changeslist-separator">. .</span>';
+               $ret = "{$del}{$link} {$tools} {$separator} {$mflag} {$pagelink} {$comment}";
+
+               # Denote if username is redacted for this edit
+               if ( $rev->isDeleted( Revision::DELETED_USER ) ) {
+                       $ret .= " <strong>" . $this->msg( 'rev-deleted-user-contribs' )->escaped() . "</strong>";
+               }
+
+               return $ret;
+       }
+
+       /**
+        * Get the Database object in use
+        *
+        * @return IDatabase
+        */
+       public function getDatabase() {
+               return $this->mDb;
+       }
+}
diff --git a/includes/specials/pagers/ImageListPager.php b/includes/specials/pagers/ImageListPager.php
new file mode 100644 (file)
index 0000000..48f60ca
--- /dev/null
@@ -0,0 +1,602 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * @ingroup Pager
+ */
+class ImageListPager extends TablePager {
+
+       protected $mFieldNames = null;
+
+       // Subclasses should override buildQueryConds instead of using $mQueryConds variable.
+       protected $mQueryConds = [];
+
+       protected $mUserName = null;
+
+       /**
+        * The relevant user
+        *
+        * @var User|null
+        */
+       protected $mUser = null;
+
+       protected $mSearch = '';
+
+       protected $mIncluding = false;
+
+       protected $mShowAll = false;
+
+       protected $mTableName = 'image';
+
+       function __construct( IContextSource $context, $userName = null, $search = '',
+               $including = false, $showAll = false
+       ) {
+               $this->setContext( $context );
+               $this->mIncluding = $including;
+               $this->mShowAll = $showAll;
+
+               if ( $userName !== null && $userName !== '' ) {
+                       $nt = Title::newFromText( $userName, NS_USER );
+                       if ( is_null( $nt ) ) {
+                               $this->outputUserDoesNotExist( $userName );
+                       } else {
+                               $this->mUserName = $nt->getText();
+                               $user = User::newFromName( $this->mUserName, false );
+                               if ( $user ) {
+                                       $this->mUser = $user;
+                               }
+                               if ( !$user || ( $user->isAnon() && !User::isIP( $user->getName() ) ) ) {
+                                       $this->outputUserDoesNotExist( $userName );
+                               }
+                       }
+               }
+
+               if ( $search !== '' && !$this->getConfig()->get( 'MiserMode' ) ) {
+                       $this->mSearch = $search;
+                       $nt = Title::newFromText( $this->mSearch );
+
+                       if ( $nt ) {
+                               $dbr = wfGetDB( DB_SLAVE );
+                               $this->mQueryConds[] = 'LOWER(img_name)' .
+                                       $dbr->buildLike( $dbr->anyString(),
+                                               strtolower( $nt->getDBkey() ), $dbr->anyString() );
+                       }
+               }
+
+               if ( !$including ) {
+                       if ( $this->getRequest()->getText( 'sort', 'img_date' ) == 'img_date' ) {
+                               $this->mDefaultDirection = IndexPager::DIR_DESCENDING;
+                       } else {
+                               $this->mDefaultDirection = IndexPager::DIR_ASCENDING;
+                       }
+               } else {
+                       $this->mDefaultDirection = IndexPager::DIR_DESCENDING;
+               }
+
+               parent::__construct( $context );
+       }
+
+       /**
+        * Get the user relevant to the ImageList
+        *
+        * @return User|null
+        */
+       function getRelevantUser() {
+               return $this->mUser;
+       }
+
+       /**
+        * Add a message to the output stating that the user doesn't exist
+        *
+        * @param string $userName Unescaped user name
+        */
+       protected function outputUserDoesNotExist( $userName ) {
+               $this->getOutput()->wrapWikiMsg(
+                       "<div class=\"mw-userpage-userdoesnotexist error\">\n$1\n</div>",
+                       [
+                               'listfiles-userdoesnotexist',
+                               wfEscapeWikiText( $userName ),
+                       ]
+               );
+       }
+
+       /**
+        * Build the where clause of the query.
+        *
+        * Replaces the older mQueryConds member variable.
+        * @param string $table Either "image" or "oldimage"
+        * @return array The query conditions.
+        */
+       protected function buildQueryConds( $table ) {
+               $prefix = $table === 'image' ? 'img' : 'oi';
+               $conds = [];
+
+               if ( !is_null( $this->mUserName ) ) {
+                       $conds[$prefix . '_user_text'] = $this->mUserName;
+               }
+
+               if ( $this->mSearch !== '' ) {
+                       $nt = Title::newFromText( $this->mSearch );
+                       if ( $nt ) {
+                               $dbr = wfGetDB( DB_SLAVE );
+                               $conds[] = 'LOWER(' . $prefix . '_name)' .
+                                       $dbr->buildLike( $dbr->anyString(),
+                                               strtolower( $nt->getDBkey() ), $dbr->anyString() );
+                       }
+               }
+
+               if ( $table === 'oldimage' ) {
+                       // Don't want to deal with revdel.
+                       // Future fixme: Show partial information as appropriate.
+                       // Would have to be careful about filtering by username when username is deleted.
+                       $conds['oi_deleted'] = 0;
+               }
+
+               // Add mQueryConds in case anyone was subclassing and using the old variable.
+               return $conds + $this->mQueryConds;
+       }
+
+       /**
+        * @return array
+        */
+       function getFieldNames() {
+               if ( !$this->mFieldNames ) {
+                       $this->mFieldNames = [
+                               'img_timestamp' => $this->msg( 'listfiles_date' )->text(),
+                               'img_name' => $this->msg( 'listfiles_name' )->text(),
+                               'thumb' => $this->msg( 'listfiles_thumb' )->text(),
+                               'img_size' => $this->msg( 'listfiles_size' )->text(),
+                       ];
+                       if ( is_null( $this->mUserName ) ) {
+                               // Do not show username if filtering by username
+                               $this->mFieldNames['img_user_text'] = $this->msg( 'listfiles_user' )->text();
+                       }
+                       // img_description down here, in order so that its still after the username field.
+                       $this->mFieldNames['img_description'] = $this->msg( 'listfiles_description' )->text();
+
+                       if ( !$this->getConfig()->get( 'MiserMode' ) && !$this->mShowAll ) {
+                               $this->mFieldNames['count'] = $this->msg( 'listfiles_count' )->text();
+                       }
+                       if ( $this->mShowAll ) {
+                               $this->mFieldNames['top'] = $this->msg( 'listfiles-latestversion' )->text();
+                       }
+               }
+
+               return $this->mFieldNames;
+       }
+
+       function isFieldSortable( $field ) {
+               if ( $this->mIncluding ) {
+                       return false;
+               }
+               $sortable = [ 'img_timestamp', 'img_name', 'img_size' ];
+               /* For reference, the indicies we can use for sorting are:
+                * On the image table: img_usertext_timestamp, img_size, img_timestamp
+                * On oldimage: oi_usertext_timestamp, oi_name_timestamp
+                *
+                * In particular that means we cannot sort by timestamp when not filtering
+                * by user and including old images in the results. Which is sad.
+                */
+               if ( $this->getConfig()->get( 'MiserMode' ) && !is_null( $this->mUserName ) ) {
+                       // If we're sorting by user, the index only supports sorting by time.
+                       if ( $field === 'img_timestamp' ) {
+                               return true;
+                       } else {
+                               return false;
+                       }
+               } elseif ( $this->getConfig()->get( 'MiserMode' )
+                       && $this->mShowAll /* && mUserName === null */
+               ) {
+                       // no oi_timestamp index, so only alphabetical sorting in this case.
+                       if ( $field === 'img_name' ) {
+                               return true;
+                       } else {
+                               return false;
+                       }
+               }
+
+               return in_array( $field, $sortable );
+       }
+
+       function getQueryInfo() {
+               // Hacky Hacky Hacky - I want to get query info
+               // for two different tables, without reimplementing
+               // the pager class.
+               $qi = $this->getQueryInfoReal( $this->mTableName );
+
+               return $qi;
+       }
+
+       /**
+        * Actually get the query info.
+        *
+        * This is to allow displaying both stuff from image and oldimage table.
+        *
+        * This is a bit hacky.
+        *
+        * @param string $table Either 'image' or 'oldimage'
+        * @return array Query info
+        */
+       protected function getQueryInfoReal( $table ) {
+               $prefix = $table === 'oldimage' ? 'oi' : 'img';
+
+               $tables = [ $table ];
+               $fields = array_keys( $this->getFieldNames() );
+
+               if ( $table === 'oldimage' ) {
+                       foreach ( $fields as $id => &$field ) {
+                               if ( substr( $field, 0, 4 ) !== 'img_' ) {
+                                       continue;
+                               }
+                               $field = $prefix . substr( $field, 3 ) . ' AS ' . $field;
+                       }
+                       $fields[array_search( 'top', $fields )] = "'no' AS top";
+               } else {
+                       if ( $this->mShowAll ) {
+                               $fields[array_search( 'top', $fields )] = "'yes' AS top";
+                       }
+               }
+               $fields[] = $prefix . '_user AS img_user';
+               $fields[array_search( 'thumb', $fields )] = $prefix . '_name AS thumb';
+
+               $options = $join_conds = [];
+
+               # Depends on $wgMiserMode
+               # Will also not happen if mShowAll is true.
+               if ( isset( $this->mFieldNames['count'] ) ) {
+                       $tables[] = 'oldimage';
+
+                       # Need to rewrite this one
+                       foreach ( $fields as &$field ) {
+                               if ( $field == 'count' ) {
+                                       $field = 'COUNT(oi_archive_name) AS count';
+                               }
+                       }
+                       unset( $field );
+
+                       $dbr = wfGetDB( DB_SLAVE );
+                       if ( $dbr->implicitGroupby() ) {
+                               $options = [ 'GROUP BY' => 'img_name' ];
+                       } else {
+                               $columnlist = preg_grep( '/^img/', array_keys( $this->getFieldNames() ) );
+                               $options = [ 'GROUP BY' => array_merge( [ 'img_user' ], $columnlist ) ];
+                       }
+                       $join_conds = [ 'oldimage' => [ 'LEFT JOIN', 'oi_name = img_name' ] ];
+               }
+
+               return [
+                       'tables' => $tables,
+                       'fields' => $fields,
+                       'conds' => $this->buildQueryConds( $table ),
+                       'options' => $options,
+                       'join_conds' => $join_conds
+               ];
+       }
+
+       /**
+        * Override reallyDoQuery to mix together two queries.
+        *
+        * @note $asc is named $descending in IndexPager base class. However
+        *   it is true when the order is ascending, and false when the order
+        *   is descending, so I renamed it to $asc here.
+        * @param int $offset
+        * @param int $limit
+        * @param bool $asc
+        * @return array
+        * @throws MWException
+        */
+       function reallyDoQuery( $offset, $limit, $asc ) {
+               $prevTableName = $this->mTableName;
+               $this->mTableName = 'image';
+               list( $tables, $fields, $conds, $fname, $options, $join_conds ) =
+                       $this->buildQueryInfo( $offset, $limit, $asc );
+               $imageRes = $this->mDb->select( $tables, $fields, $conds, $fname, $options, $join_conds );
+               $this->mTableName = $prevTableName;
+
+               if ( !$this->mShowAll ) {
+                       return $imageRes;
+               }
+
+               $this->mTableName = 'oldimage';
+
+               # Hacky...
+               $oldIndex = $this->mIndexField;
+               if ( substr( $this->mIndexField, 0, 4 ) !== 'img_' ) {
+                       throw new MWException( "Expected to be sorting on an image table field" );
+               }
+               $this->mIndexField = 'oi_' . substr( $this->mIndexField, 4 );
+
+               list( $tables, $fields, $conds, $fname, $options, $join_conds ) =
+                       $this->buildQueryInfo( $offset, $limit, $asc );
+               $oldimageRes = $this->mDb->select( $tables, $fields, $conds, $fname, $options, $join_conds );
+
+               $this->mTableName = $prevTableName;
+               $this->mIndexField = $oldIndex;
+
+               return $this->combineResult( $imageRes, $oldimageRes, $limit, $asc );
+       }
+
+       /**
+        * Combine results from 2 tables.
+        *
+        * Note: This will throw away some results
+        *
+        * @param ResultWrapper $res1
+        * @param ResultWrapper $res2
+        * @param int $limit
+        * @param bool $ascending See note about $asc in $this->reallyDoQuery
+        * @return FakeResultWrapper $res1 and $res2 combined
+        */
+       protected function combineResult( $res1, $res2, $limit, $ascending ) {
+               $res1->rewind();
+               $res2->rewind();
+               $topRes1 = $res1->next();
+               $topRes2 = $res2->next();
+               $resultArray = [];
+               for ( $i = 0; $i < $limit && $topRes1 && $topRes2; $i++ ) {
+                       if ( strcmp( $topRes1->{$this->mIndexField}, $topRes2->{$this->mIndexField} ) > 0 ) {
+                               if ( !$ascending ) {
+                                       $resultArray[] = $topRes1;
+                                       $topRes1 = $res1->next();
+                               } else {
+                                       $resultArray[] = $topRes2;
+                                       $topRes2 = $res2->next();
+                               }
+                       } else {
+                               if ( !$ascending ) {
+                                       $resultArray[] = $topRes2;
+                                       $topRes2 = $res2->next();
+                               } else {
+                                       $resultArray[] = $topRes1;
+                                       $topRes1 = $res1->next();
+                               }
+                       }
+               }
+
+               // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
+               for ( ; $i < $limit && $topRes1; $i++ ) {
+                       // @codingStandardsIgnoreEnd
+                       $resultArray[] = $topRes1;
+                       $topRes1 = $res1->next();
+               }
+
+               // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
+               for ( ; $i < $limit && $topRes2; $i++ ) {
+                       // @codingStandardsIgnoreEnd
+                       $resultArray[] = $topRes2;
+                       $topRes2 = $res2->next();
+               }
+
+               return new FakeResultWrapper( $resultArray );
+       }
+
+       function getDefaultSort() {
+               if ( $this->mShowAll && $this->getConfig()->get( 'MiserMode' ) && is_null( $this->mUserName ) ) {
+                       // Unfortunately no index on oi_timestamp.
+                       return 'img_name';
+               } else {
+                       return 'img_timestamp';
+               }
+       }
+
+       function doBatchLookups() {
+               $userIds = [];
+               $this->mResult->seek( 0 );
+               foreach ( $this->mResult as $row ) {
+                       $userIds[] = $row->img_user;
+               }
+               # Do a link batch query for names and userpages
+               UserCache::singleton()->doQuery( $userIds, [ 'userpage' ], __METHOD__ );
+       }
+
+       /**
+        * @param string $field
+        * @param string $value
+        * @return Message|string|int The return type depends on the value of $field:
+        *   - thumb: string
+        *   - img_timestamp: string
+        *   - img_name: string
+        *   - img_user_text: string
+        *   - img_size: string
+        *   - img_description: string
+        *   - count: int
+        *   - top: Message
+        * @throws MWException
+        */
+       function formatValue( $field, $value ) {
+               switch ( $field ) {
+                       case 'thumb':
+                               $opt = [ 'time' => wfTimestamp( TS_MW, $this->mCurrentRow->img_timestamp ) ];
+                               $file = RepoGroup::singleton()->getLocalRepo()->findFile( $value, $opt );
+                               // If statement for paranoia
+                               if ( $file ) {
+                                       $thumb = $file->transform( [ 'width' => 180, 'height' => 360 ] );
+
+                                       return $thumb->toHtml( [ 'desc-link' => true ] );
+                               } else {
+                                       return htmlspecialchars( $value );
+                               }
+                       case 'img_timestamp':
+                               // We may want to make this a link to the "old" version when displaying old files
+                               return htmlspecialchars( $this->getLanguage()->userTimeAndDate( $value, $this->getUser() ) );
+                       case 'img_name':
+                               static $imgfile = null;
+                               if ( $imgfile === null ) {
+                                       $imgfile = $this->msg( 'imgfile' )->text();
+                               }
+
+                               // Weird files can maybe exist? Bug 22227
+                               $filePage = Title::makeTitleSafe( NS_FILE, $value );
+                               if ( $filePage ) {
+                                       $link = Linker::linkKnown(
+                                               $filePage,
+                                               htmlspecialchars( $filePage->getText() )
+                                       );
+                                       $download = Xml::element( 'a',
+                                               [ 'href' => wfLocalFile( $filePage )->getUrl() ],
+                                               $imgfile
+                                       );
+                                       $download = $this->msg( 'parentheses' )->rawParams( $download )->escaped();
+
+                                       // Add delete links if allowed
+                                       // From https://github.com/Wikia/app/pull/3859
+                                       if ( $filePage->userCan( 'delete', $this->getUser() ) ) {
+                                               $deleteMsg = $this->msg( 'listfiles-delete' )->escaped();
+
+                                               $delete = Linker::linkKnown(
+                                                       $filePage, $deleteMsg, [], [ 'action' => 'delete' ]
+                                               );
+                                               $delete = $this->msg( 'parentheses' )->rawParams( $delete )->escaped();
+
+                                               return "$link $download $delete";
+                                       }
+
+                                       return "$link $download";
+                               } else {
+                                       return htmlspecialchars( $value );
+                               }
+                       case 'img_user_text':
+                               if ( $this->mCurrentRow->img_user ) {
+                                       $name = User::whoIs( $this->mCurrentRow->img_user );
+                                       $link = Linker::link(
+                                               Title::makeTitle( NS_USER, $name ),
+                                               htmlspecialchars( $name )
+                                       );
+                               } else {
+                                       $link = htmlspecialchars( $value );
+                               }
+
+                               return $link;
+                       case 'img_size':
+                               return htmlspecialchars( $this->getLanguage()->formatSize( $value ) );
+                       case 'img_description':
+                               return Linker::formatComment( $value );
+                       case 'count':
+                               return intval( $value ) + 1;
+                       case 'top':
+                               // Messages: listfiles-latestversion-yes, listfiles-latestversion-no
+                               return $this->msg( 'listfiles-latestversion-' . $value );
+                       default:
+                               throw new MWException( "Unknown field '$field'" );
+               }
+       }
+
+       function getForm() {
+               $fields = [];
+               $fields['limit'] = [
+                       'type' => 'select',
+                       'name' => 'limit',
+                       'label-message' => 'table_pager_limit_label',
+                       'options' => $this->getLimitSelectList(),
+                       'default' => $this->mLimit,
+               ];
+
+               if ( !$this->getConfig()->get( 'MiserMode' ) ) {
+                       $fields['ilsearch'] = [
+                               'type' => 'text',
+                               'name' => 'ilsearch',
+                               'id' => 'mw-ilsearch',
+                               'label-message' => 'listfiles_search_for',
+                               'default' => $this->mSearch,
+                               'size' => '40',
+                               'maxlength' => '255',
+                       ];
+               }
+
+               $this->getOutput()->addModules( 'mediawiki.userSuggest' );
+               $fields['user'] = [
+                       'type' => 'text',
+                       'name' => 'user',
+                       'id' => 'mw-listfiles-user',
+                       'label-message' => 'username',
+                       'default' => $this->mUserName,
+                       'size' => '40',
+                       'maxlength' => '255',
+                       'cssclass' => 'mw-autocomplete-user', // used by mediawiki.userSuggest
+               ];
+
+               $fields['ilshowall'] = [
+                       'type' => 'check',
+                       'name' => 'ilshowall',
+                       'id' => 'mw-listfiles-show-all',
+                       'label-message' => 'listfiles-show-all',
+                       'default' => $this->mShowAll,
+               ];
+
+               $query = $this->getRequest()->getQueryValues();
+               unset( $query['title'] );
+               unset( $query['limit'] );
+               unset( $query['ilsearch'] );
+               unset( $query['ilshowall'] );
+               unset( $query['user'] );
+
+               $form = new HTMLForm( $fields, $this->getContext() );
+
+               $form->setMethod( 'get' );
+               $form->setTitle( $this->getTitle() );
+               $form->setId( 'mw-listfiles-form' );
+               $form->setWrapperLegendMsg( 'listfiles' );
+               $form->setSubmitTextMsg( 'table_pager_limit_submit' );
+               $form->addHiddenFields( $query );
+
+               $form->prepareForm();
+               $form->displayForm( '' );
+       }
+
+       function getTableClass() {
+               return parent::getTableClass() . ' listfiles';
+       }
+
+       function getNavClass() {
+               return parent::getNavClass() . ' listfiles_nav';
+       }
+
+       function getSortHeaderClass() {
+               return parent::getSortHeaderClass() . ' listfiles_sort';
+       }
+
+       function getPagingQueries() {
+               $queries = parent::getPagingQueries();
+               if ( !is_null( $this->mUserName ) ) {
+                       # Append the username to the query string
+                       foreach ( $queries as &$query ) {
+                               if ( $query !== false ) {
+                                       $query['user'] = $this->mUserName;
+                               }
+                       }
+               }
+
+               return $queries;
+       }
+
+       function getDefaultQuery() {
+               $queries = parent::getDefaultQuery();
+               if ( !isset( $queries['user'] ) && !is_null( $this->mUserName ) ) {
+                       $queries['user'] = $this->mUserName;
+               }
+
+               return $queries;
+       }
+
+       function getTitle() {
+               return SpecialPage::getTitleFor( 'Listfiles' );
+       }
+}
diff --git a/includes/specials/pagers/MergeHistoryPager.php b/includes/specials/pagers/MergeHistoryPager.php
new file mode 100644 (file)
index 0000000..0b9587c
--- /dev/null
@@ -0,0 +1,99 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * @ingroup Pager
+ */
+class MergeHistoryPager extends ReverseChronologicalPager {
+
+       /** @var SpecialMergeHistory */
+       public $mForm;
+
+       /** @var array */
+       public $mConds;
+
+       function __construct( SpecialMergeHistory $form, $conds, Title $source, Title $dest ) {
+               $this->mForm = $form;
+               $this->mConds = $conds;
+               $this->title = $source;
+               $this->articleID = $source->getArticleID();
+
+               $dbr = wfGetDB( DB_SLAVE );
+               $maxtimestamp = $dbr->selectField(
+                       'revision',
+                       'MIN(rev_timestamp)',
+                       [ 'rev_page' => $dest->getArticleID() ],
+                       __METHOD__
+               );
+               $this->maxTimestamp = $maxtimestamp;
+
+               parent::__construct( $form->getContext() );
+       }
+
+       function getStartBody() {
+               # Do a link batch query
+               $this->mResult->seek( 0 );
+               $batch = new LinkBatch();
+               # Give some pointers to make (last) links
+               $this->mForm->prevId = [];
+               foreach ( $this->mResult as $row ) {
+                       $batch->addObj( Title::makeTitleSafe( NS_USER, $row->user_name ) );
+                       $batch->addObj( Title::makeTitleSafe( NS_USER_TALK, $row->user_name ) );
+
+                       $rev_id = isset( $rev_id ) ? $rev_id : $row->rev_id;
+                       if ( $rev_id > $row->rev_id ) {
+                               $this->mForm->prevId[$rev_id] = $row->rev_id;
+                       } elseif ( $rev_id < $row->rev_id ) {
+                               $this->mForm->prevId[$row->rev_id] = $rev_id;
+                       }
+
+                       $rev_id = $row->rev_id;
+               }
+
+               $batch->execute();
+               $this->mResult->seek( 0 );
+
+               return '';
+       }
+
+       function formatRow( $row ) {
+               return $this->mForm->formatRevisionRow( $row );
+       }
+
+       function getQueryInfo() {
+               $conds = $this->mConds;
+               $conds['rev_page'] = $this->articleID;
+               $conds[] = "rev_timestamp < " . $this->mDb->addQuotes( $this->maxTimestamp );
+
+               return [
+                       'tables' => [ 'revision', 'page', 'user' ],
+                       'fields' => array_merge( Revision::selectFields(), Revision::selectUserFields() ),
+                       'conds' => $conds,
+                       'join_conds' => [
+                               'page' => Revision::pageJoinCond(),
+                               'user' => Revision::userJoinCond() ]
+               ];
+       }
+
+       function getIndexField() {
+               return 'rev_timestamp';
+       }
+}
diff --git a/includes/specials/pagers/NewFilesPager.php b/includes/specials/pagers/NewFilesPager.php
new file mode 100644 (file)
index 0000000..ae57736
--- /dev/null
@@ -0,0 +1,207 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * @ingroup Pager
+ */
+class NewFilesPager extends ReverseChronologicalPager {
+
+       /**
+        * @var ImageGallery
+        */
+       protected $gallery;
+
+       /**
+        * @var bool
+        */
+       protected $showBots;
+
+       /**
+        * @var bool
+        */
+       protected $hidePatrolled;
+
+       function __construct( IContextSource $context, $par = null ) {
+               $this->like = $context->getRequest()->getText( 'like' );
+               $this->showBots = $context->getRequest()->getBool( 'showbots', 0 );
+               $this->hidePatrolled = $context->getRequest()->getBool( 'hidepatrolled', 0 );
+               if ( is_numeric( $par ) ) {
+                       $this->setLimit( $par );
+               }
+
+               parent::__construct( $context );
+       }
+
+       function getQueryInfo() {
+               $conds = $jconds = [];
+               $tables = [ 'image' ];
+               $fields = [ 'img_name', 'img_user', 'img_timestamp' ];
+               $options = [];
+
+               if ( !$this->showBots ) {
+                       $groupsWithBotPermission = User::getGroupsWithPermission( 'bot' );
+
+                       if ( count( $groupsWithBotPermission ) ) {
+                               $tables[] = 'user_groups';
+                               $conds[] = 'ug_group IS NULL';
+                               $jconds['user_groups'] = [
+                                       'LEFT JOIN',
+                                       [
+                                               'ug_group' => $groupsWithBotPermission,
+                                               'ug_user = img_user'
+                                       ]
+                               ];
+                       }
+               }
+
+               if ( $this->hidePatrolled ) {
+                       $tables[] = 'recentchanges';
+                       $conds['rc_type'] = RC_LOG;
+                       $conds['rc_log_type'] = 'upload';
+                       $conds['rc_patrolled'] = 0;
+                       $conds['rc_namespace'] = NS_FILE;
+                       $jconds['recentchanges'] = [
+                               'INNER JOIN',
+                               [
+                                       'rc_title = img_name',
+                                       'rc_user = img_user',
+                                       'rc_timestamp = img_timestamp'
+                               ]
+                       ];
+                       // We're ordering by img_timestamp, so we have to make sure MariaDB queries `image` first.
+                       // It sometimes decides to query `recentchanges` first and filesort the result set later
+                       // to get the right ordering. T124205 / https://mariadb.atlassian.net/browse/MDEV-8880
+                       $options[] = 'STRAIGHT_JOIN';
+               }
+
+               if ( !$this->getConfig()->get( 'MiserMode' ) && $this->like !== null ) {
+                       $dbr = wfGetDB( DB_SLAVE );
+                       $likeObj = Title::newFromText( $this->like );
+                       if ( $likeObj instanceof Title ) {
+                               $like = $dbr->buildLike(
+                                       $dbr->anyString(),
+                                       strtolower( $likeObj->getDBkey() ),
+                                       $dbr->anyString()
+                               );
+                               $conds[] = "LOWER(img_name) $like";
+                       }
+               }
+
+               $query = [
+                       'tables' => $tables,
+                       'fields' => $fields,
+                       'join_conds' => $jconds,
+                       'conds' => $conds,
+                       'options' => $options,
+               ];
+
+               return $query;
+       }
+
+       function getIndexField() {
+               return 'img_timestamp';
+       }
+
+       function getStartBody() {
+               if ( !$this->gallery ) {
+                       // Note that null for mode is taken to mean use default.
+                       $mode = $this->getRequest()->getVal( 'gallerymode', null );
+                       try {
+                               $this->gallery = ImageGalleryBase::factory( $mode, $this->getContext() );
+                       } catch ( Exception $e ) {
+                               // User specified something invalid, fallback to default.
+                               $this->gallery = ImageGalleryBase::factory( false, $this->getContext() );
+                       }
+               }
+
+               return '';
+       }
+
+       function getEndBody() {
+               return $this->gallery->toHTML();
+       }
+
+       function formatRow( $row ) {
+               $name = $row->img_name;
+               $user = User::newFromId( $row->img_user );
+
+               $title = Title::makeTitle( NS_FILE, $name );
+               $ul = Linker::link( $user->getUserPage(), $user->getName() );
+               $time = $this->getLanguage()->userTimeAndDate( $row->img_timestamp, $this->getUser() );
+
+               $this->gallery->add(
+                       $title,
+                       "$ul<br />\n<i>"
+                       . htmlspecialchars( $time )
+                       . "</i><br />\n"
+               );
+       }
+
+       function getForm() {
+               $fields = [
+                       'like' => [
+                               'type' => 'text',
+                               'label-message' => 'newimages-label',
+                               'name' => 'like',
+                       ],
+                       'showbots' => [
+                               'type' => 'check',
+                               'label-message' => 'newimages-showbots',
+                               'name' => 'showbots',
+                       ],
+                       'hidepatrolled' => [
+                               'type' => 'check',
+                               'label-message' => 'newimages-hidepatrolled',
+                               'name' => 'hidepatrolled',
+                       ],
+                       'limit' => [
+                               'type' => 'hidden',
+                               'default' => $this->mLimit,
+                               'name' => 'limit',
+                       ],
+                       'offset' => [
+                               'type' => 'hidden',
+                               'default' => $this->getRequest()->getText( 'offset' ),
+                               'name' => 'offset',
+                       ],
+               ];
+
+               if ( $this->getConfig()->get( 'MiserMode' ) ) {
+                       unset( $fields['like'] );
+               }
+
+               if ( !$this->getUser()->useFilePatrol() ) {
+                       unset( $fields['hidepatrolled'] );
+               }
+
+               $context = new DerivativeContext( $this->getContext() );
+               $context->setTitle( $this->getTitle() ); // Remove subpage
+               $form = new HTMLForm( $fields, $context );
+
+               $form->setSubmitTextMsg( 'ilsubmit' );
+               $form->setSubmitProgressive();
+
+               $form->setMethod( 'get' );
+               $form->setWrapperLegendMsg( 'newimages-legend' );
+
+               return $form;
+       }
+}
diff --git a/includes/specials/pagers/NewPagesPager.php b/includes/specials/pagers/NewPagesPager.php
new file mode 100644 (file)
index 0000000..2d39f99
--- /dev/null
@@ -0,0 +1,148 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * @ingroup Pager
+ */
+class NewPagesPager extends ReverseChronologicalPager {
+
+       // Stored opts
+       protected $opts;
+
+       /**
+        * @var HtmlForm
+        */
+       protected $mForm;
+
+       function __construct( $form, FormOptions $opts ) {
+               parent::__construct( $form->getContext() );
+               $this->mForm = $form;
+               $this->opts = $opts;
+       }
+
+       function getQueryInfo() {
+               $conds = [];
+               $conds['rc_new'] = 1;
+
+               $namespace = $this->opts->getValue( 'namespace' );
+               $namespace = ( $namespace === 'all' ) ? false : intval( $namespace );
+
+               $username = $this->opts->getValue( 'username' );
+               $user = Title::makeTitleSafe( NS_USER, $username );
+
+               $rcIndexes = [];
+
+               if ( $namespace !== false ) {
+                       if ( $this->opts->getValue( 'invert' ) ) {
+                               $conds[] = 'rc_namespace != ' . $this->mDb->addQuotes( $namespace );
+                       } else {
+                               $conds['rc_namespace'] = $namespace;
+                       }
+               }
+
+               if ( $user ) {
+                       $conds['rc_user_text'] = $user->getText();
+                       $rcIndexes = 'rc_user_text';
+               } elseif ( User::groupHasPermission( '*', 'createpage' ) &&
+                       $this->opts->getValue( 'hideliu' )
+               ) {
+                       # If anons cannot make new pages, don't "exclude logged in users"!
+                       $conds['rc_user'] = 0;
+               }
+
+               # If this user cannot see patrolled edits or they are off, don't do dumb queries!
+               if ( $this->opts->getValue( 'hidepatrolled' ) && $this->getUser()->useNPPatrol() ) {
+                       $conds['rc_patrolled'] = 0;
+               }
+
+               if ( $this->opts->getValue( 'hidebots' ) ) {
+                       $conds['rc_bot'] = 0;
+               }
+
+               if ( $this->opts->getValue( 'hideredirs' ) ) {
+                       $conds['page_is_redirect'] = 0;
+               }
+
+               // Allow changes to the New Pages query
+               $tables = [ 'recentchanges', 'page' ];
+               $fields = [
+                       'rc_namespace', 'rc_title', 'rc_cur_id', 'rc_user', 'rc_user_text',
+                       'rc_comment', 'rc_timestamp', 'rc_patrolled', 'rc_id', 'rc_deleted',
+                       'length' => 'page_len', 'rev_id' => 'page_latest', 'rc_this_oldid',
+                       'page_namespace', 'page_title'
+               ];
+               $join_conds = [ 'page' => [ 'INNER JOIN', 'page_id=rc_cur_id' ] ];
+
+               Hooks::run( 'SpecialNewpagesConditions',
+                       [ &$this, $this->opts, &$conds, &$tables, &$fields, &$join_conds ] );
+
+               $options = [];
+
+               if ( $rcIndexes ) {
+                       $options = [ 'USE INDEX' => [ 'recentchanges' => $rcIndexes ] ];
+               }
+
+               $info = [
+                       'tables' => $tables,
+                       'fields' => $fields,
+                       'conds' => $conds,
+                       'options' => $options,
+                       'join_conds' => $join_conds
+               ];
+
+               // Modify query for tags
+               ChangeTags::modifyDisplayQuery(
+                       $info['tables'],
+                       $info['fields'],
+                       $info['conds'],
+                       $info['join_conds'],
+                       $info['options'],
+                       $this->opts['tagfilter']
+               );
+
+               return $info;
+       }
+
+       function getIndexField() {
+               return 'rc_timestamp';
+       }
+
+       function formatRow( $row ) {
+               return $this->mForm->formatRow( $row );
+       }
+
+       function getStartBody() {
+               # Do a batch existence check on pages
+               $linkBatch = new LinkBatch();
+               foreach ( $this->mResult as $row ) {
+                       $linkBatch->add( NS_USER, $row->rc_user_text );
+                       $linkBatch->add( NS_USER_TALK, $row->rc_user_text );
+                       $linkBatch->add( $row->page_namespace, $row->page_title );
+               }
+               $linkBatch->execute();
+
+               return '<ul>';
+       }
+
+       function getEndBody() {
+               return '</ul>';
+       }
+}
diff --git a/includes/specials/pagers/ProtectedTitlesPager.php b/includes/specials/pagers/ProtectedTitlesPager.php
new file mode 100644 (file)
index 0000000..8f172f8
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * @ingroup Pager
+ */
+class ProtectedTitlesPager extends AlphabeticPager {
+
+       public $mForm, $mConds;
+
+       function __construct( $form, $conds = [], $type, $level, $namespace,
+               $sizetype = '', $size = 0
+       ) {
+               $this->mForm = $form;
+               $this->mConds = $conds;
+               $this->level = $level;
+               $this->namespace = $namespace;
+               $this->size = intval( $size );
+               parent::__construct( $form->getContext() );
+       }
+
+       function getStartBody() {
+               # Do a link batch query
+               $this->mResult->seek( 0 );
+               $lb = new LinkBatch;
+
+               foreach ( $this->mResult as $row ) {
+                       $lb->add( $row->pt_namespace, $row->pt_title );
+               }
+
+               $lb->execute();
+
+               return '';
+       }
+
+       /**
+        * @return Title
+        */
+       function getTitle() {
+               return $this->mForm->getTitle();
+       }
+
+       function formatRow( $row ) {
+               return $this->mForm->formatRow( $row );
+       }
+
+       /**
+        * @return array
+        */
+       function getQueryInfo() {
+               $conds = $this->mConds;
+               $conds[] = 'pt_expiry > ' . $this->mDb->addQuotes( $this->mDb->timestamp() ) .
+                       ' OR pt_expiry IS NULL';
+               if ( $this->level ) {
+                       $conds['pt_create_perm'] = $this->level;
+               }
+
+               if ( !is_null( $this->namespace ) ) {
+                       $conds[] = 'pt_namespace=' . $this->mDb->addQuotes( $this->namespace );
+               }
+
+               return [
+                       'tables' => 'protected_titles',
+                       'fields' => [ 'pt_namespace', 'pt_title', 'pt_create_perm',
+                               'pt_expiry', 'pt_timestamp' ],
+                       'conds' => $conds
+               ];
+       }
+
+       function getIndexField() {
+               return 'pt_timestamp';
+       }
+}
diff --git a/includes/specials/pagers/UsersPager.php b/includes/specials/pagers/UsersPager.php
new file mode 100644 (file)
index 0000000..7b058c1
--- /dev/null
@@ -0,0 +1,395 @@
+<?php
+/**
+ * Copyright © 2004 Brion Vibber, lcrocker, Tim Starling,
+ * Domas Mituzas, Antoine Musso, Jens Frank, Zhengzhu,
+ * 2006 Rob Church <robchur@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Pager
+ */
+
+/**
+ * This class is used to get a list of user. The ones with specials
+ * rights (sysop, bureaucrat, developer) will have them displayed
+ * next to their names.
+ *
+ * @ingroup Pager
+ */
+class UsersPager extends AlphabeticPager {
+
+       /**
+        * @var array A array with user ids as key and a array of groups as value
+        */
+       protected $userGroupCache;
+
+       /**
+        * @param IContextSource $context
+        * @param array $par (Default null)
+        * @param bool $including Whether this page is being transcluded in
+        * another page
+        */
+       function __construct( IContextSource $context = null, $par = null, $including = null ) {
+               if ( $context ) {
+                       $this->setContext( $context );
+               }
+
+               $request = $this->getRequest();
+               $par = ( $par !== null ) ? $par : '';
+               $parms = explode( '/', $par );
+               $symsForAll = [ '*', 'user' ];
+
+               if ( $parms[0] != '' &&
+                       ( in_array( $par, User::getAllGroups() ) || in_array( $par, $symsForAll ) )
+               ) {
+                       $this->requestedGroup = $par;
+                       $un = $request->getText( 'username' );
+               } elseif ( count( $parms ) == 2 ) {
+                       $this->requestedGroup = $parms[0];
+                       $un = $parms[1];
+               } else {
+                       $this->requestedGroup = $request->getVal( 'group' );
+                       $un = ( $par != '' ) ? $par : $request->getText( 'username' );
+               }
+
+               if ( in_array( $this->requestedGroup, $symsForAll ) ) {
+                       $this->requestedGroup = '';
+               }
+               $this->editsOnly = $request->getBool( 'editsOnly' );
+               $this->creationSort = $request->getBool( 'creationSort' );
+               $this->including = $including;
+               $this->mDefaultDirection = $request->getBool( 'desc' )
+                       ? IndexPager::DIR_DESCENDING
+                       : IndexPager::DIR_ASCENDING;
+
+               $this->requestedUser = '';
+
+               if ( $un != '' ) {
+                       $username = Title::makeTitleSafe( NS_USER, $un );
+
+                       if ( !is_null( $username ) ) {
+                               $this->requestedUser = $username->getText();
+                       }
+               }
+
+               parent::__construct();
+       }
+
+       /**
+        * @return string
+        */
+       function getIndexField() {
+               return $this->creationSort ? 'user_id' : 'user_name';
+       }
+
+       /**
+        * @return array
+        */
+       function getQueryInfo() {
+               $dbr = wfGetDB( DB_SLAVE );
+               $conds = [];
+
+               // Don't show hidden names
+               if ( !$this->getUser()->isAllowed( 'hideuser' ) ) {
+                       $conds[] = 'ipb_deleted IS NULL OR ipb_deleted = 0';
+               }
+
+               $options = [];
+
+               if ( $this->requestedGroup != '' ) {
+                       $conds['ug_group'] = $this->requestedGroup;
+               }
+
+               if ( $this->requestedUser != '' ) {
+                       # Sorted either by account creation or name
+                       if ( $this->creationSort ) {
+                               $conds[] = 'user_id >= ' . intval( User::idFromName( $this->requestedUser ) );
+                       } else {
+                               $conds[] = 'user_name >= ' . $dbr->addQuotes( $this->requestedUser );
+                       }
+               }
+
+               if ( $this->editsOnly ) {
+                       $conds[] = 'user_editcount > 0';
+               }
+
+               $options['GROUP BY'] = $this->creationSort ? 'user_id' : 'user_name';
+
+               $query = [
+                       'tables' => [ 'user', 'user_groups', 'ipblocks' ],
+                       'fields' => [
+                               'user_name' => $this->creationSort ? 'MAX(user_name)' : 'user_name',
+                               'user_id' => $this->creationSort ? 'user_id' : 'MAX(user_id)',
+                               'edits' => 'MAX(user_editcount)',
+                               'creation' => 'MIN(user_registration)',
+                               'ipb_deleted' => 'MAX(ipb_deleted)' // block/hide status
+                       ],
+                       'options' => $options,
+                       'join_conds' => [
+                               'user_groups' => [ 'LEFT JOIN', 'user_id=ug_user' ],
+                               'ipblocks' => [
+                                       'LEFT JOIN', [
+                                               'user_id=ipb_user',
+                                               'ipb_auto' => 0
+                                       ]
+                               ],
+                       ],
+                       'conds' => $conds
+               ];
+
+               Hooks::run( 'SpecialListusersQueryInfo', [ $this, &$query ] );
+
+               return $query;
+       }
+
+       /**
+        * @param stdClass $row
+        * @return string
+        */
+       function formatRow( $row ) {
+               if ( $row->user_id == 0 ) { # Bug 16487
+                       return '';
+               }
+
+               $userName = $row->user_name;
+
+               $ulinks = Linker::userLink( $row->user_id, $userName );
+               $ulinks .= Linker::userToolLinksRedContribs(
+                       $row->user_id,
+                       $userName,
+                       (int)$row->edits
+               );
+
+               $lang = $this->getLanguage();
+
+               $groups = '';
+               $groups_list = self::getGroups( intval( $row->user_id ), $this->userGroupCache );
+
+               if ( !$this->including && count( $groups_list ) > 0 ) {
+                       $list = [];
+                       foreach ( $groups_list as $group ) {
+                               $list[] = self::buildGroupLink( $group, $userName );
+                       }
+                       $groups = $lang->commaList( $list );
+               }
+
+               $item = $lang->specialList( $ulinks, $groups );
+
+               if ( $row->ipb_deleted ) {
+                       $item = "<span class=\"deleted\">$item</span>";
+               }
+
+               $edits = '';
+               if ( !$this->including && $this->getConfig()->get( 'Edititis' ) ) {
+                       $count = $this->msg( 'usereditcount' )->numParams( $row->edits )->escaped();
+                       $edits = $this->msg( 'word-separator' )->escaped() . $this->msg( 'brackets', $count )->escaped();
+               }
+
+               $created = '';
+               # Some rows may be null
+               if ( !$this->including && $row->creation ) {
+                       $user = $this->getUser();
+                       $d = $lang->userDate( $row->creation, $user );
+                       $t = $lang->userTime( $row->creation, $user );
+                       $created = $this->msg( 'usercreated', $d, $t, $row->user_name )->escaped();
+                       $created = ' ' . $this->msg( 'parentheses' )->rawParams( $created )->escaped();
+               }
+               $blocked = !is_null( $row->ipb_deleted ) ?
+                       ' ' . $this->msg( 'listusers-blocked', $userName )->escaped() :
+                       '';
+
+               Hooks::run( 'SpecialListusersFormatRow', [ &$item, $row ] );
+
+               return Html::rawElement( 'li', [], "{$item}{$edits}{$created}{$blocked}" );
+       }
+
+       function doBatchLookups() {
+               $batch = new LinkBatch();
+               $userIds = [];
+               # Give some pointers to make user links
+               foreach ( $this->mResult as $row ) {
+                       $batch->add( NS_USER, $row->user_name );
+                       $batch->add( NS_USER_TALK, $row->user_name );
+                       $userIds[] = $row->user_id;
+               }
+
+               // Lookup groups for all the users
+               $dbr = wfGetDB( DB_SLAVE );
+               $groupRes = $dbr->select(
+                       'user_groups',
+                       [ 'ug_user', 'ug_group' ],
+                       [ 'ug_user' => $userIds ],
+                       __METHOD__
+               );
+               $cache = [];
+               $groups = [];
+               foreach ( $groupRes as $row ) {
+                       $cache[intval( $row->ug_user )][] = $row->ug_group;
+                       $groups[$row->ug_group] = true;
+               }
+               $this->userGroupCache = $cache;
+
+               // Add page of groups to link batch
+               foreach ( $groups as $group => $unused ) {
+                       $groupPage = User::getGroupPage( $group );
+                       if ( $groupPage ) {
+                               $batch->addObj( $groupPage );
+                       }
+               }
+
+               $batch->execute();
+               $this->mResult->rewind();
+       }
+
+       /**
+        * @return string
+        */
+       function getPageHeader() {
+               list( $self ) = explode( '/', $this->getTitle()->getPrefixedDBkey() );
+
+               $this->getOutput()->addModules( 'mediawiki.userSuggest' );
+
+               # Form tag
+               $out = Xml::openElement(
+                               'form',
+                               [ 'method' => 'get', 'action' => wfScript(), 'id' => 'mw-listusers-form' ]
+                       ) .
+                       Xml::fieldset( $this->msg( 'listusers' )->text() ) .
+                       Html::hidden( 'title', $self );
+
+               # Username field (with autocompletion support)
+               $out .= Xml::label( $this->msg( 'listusersfrom' )->text(), 'offset' ) . ' ' .
+                       Html::input(
+                               'username',
+                               $this->requestedUser,
+                               'text',
+                               [
+                                       'class' => 'mw-autocomplete-user',
+                                       'id' => 'offset',
+                                       'size' => 20,
+                                       'autofocus' => $this->requestedUser === ''
+                               ]
+                       ) . ' ';
+
+               # Group drop-down list
+               $sel = new XmlSelect( 'group', 'group', $this->requestedGroup );
+               $sel->addOption( $this->msg( 'group-all' )->text(), '' );
+               foreach ( $this->getAllGroups() as $group => $groupText ) {
+                       $sel->addOption( $groupText, $group );
+               }
+
+               $out .= Xml::label( $this->msg( 'group' )->text(), 'group' ) . ' ';
+               $out .= $sel->getHTML() . '<br />';
+               $out .= Xml::checkLabel(
+                       $this->msg( 'listusers-editsonly' )->text(),
+                       'editsOnly',
+                       'editsOnly',
+                       $this->editsOnly
+               );
+               $out .= '&#160;';
+               $out .= Xml::checkLabel(
+                       $this->msg( 'listusers-creationsort' )->text(),
+                       'creationSort',
+                       'creationSort',
+                       $this->creationSort
+               );
+               $out .= '&#160;';
+               $out .= Xml::checkLabel(
+                       $this->msg( 'listusers-desc' )->text(),
+                       'desc',
+                       'desc',
+                       $this->mDefaultDirection
+               );
+               $out .= '<br />';
+
+               Hooks::run( 'SpecialListusersHeaderForm', [ $this, &$out ] );
+
+               # Submit button and form bottom
+               $out .= Html::hidden( 'limit', $this->mLimit );
+               $out .= Xml::submitButton( $this->msg( 'listusers-submit' )->text() );
+               Hooks::run( 'SpecialListusersHeader', [ $this, &$out ] );
+               $out .= Xml::closeElement( 'fieldset' ) .
+                       Xml::closeElement( 'form' );
+
+               return $out;
+       }
+
+       /**
+        * Get a list of all explicit groups
+        * @return array
+        */
+       function getAllGroups() {
+               $result = [];
+               foreach ( User::getAllGroups() as $group ) {
+                       $result[$group] = User::getGroupName( $group );
+               }
+               asort( $result );
+
+               return $result;
+       }
+
+       /**
+        * Preserve group and username offset parameters when paging
+        * @return array
+        */
+       function getDefaultQuery() {
+               $query = parent::getDefaultQuery();
+               if ( $this->requestedGroup != '' ) {
+                       $query['group'] = $this->requestedGroup;
+               }
+               if ( $this->requestedUser != '' ) {
+                       $query['username'] = $this->requestedUser;
+               }
+               Hooks::run( 'SpecialListusersDefaultQuery', [ $this, &$query ] );
+
+               return $query;
+       }
+
+       /**
+        * Get a list of groups the specified user belongs to
+        *
+        * @param int $uid User id
+        * @param array|null $cache
+        * @return array
+        */
+       protected static function getGroups( $uid, $cache = null ) {
+               if ( $cache === null ) {
+                       $user = User::newFromId( $uid );
+                       $effectiveGroups = $user->getEffectiveGroups();
+               } else {
+                       $effectiveGroups = isset( $cache[$uid] ) ? $cache[$uid] : [];
+               }
+               $groups = array_diff( $effectiveGroups, User::getImplicitGroups() );
+
+               return $groups;
+       }
+
+       /**
+        * Format a link to a group description page
+        *
+        * @param string $group Group name
+        * @param string $username Username
+        * @return string
+        */
+       protected static function buildGroupLink( $group, $username ) {
+               return User::makeGroupLinkHTML(
+                       $group,
+                       User::getGroupMember( $group, $username )
+               );
+       }
+
+}
index 9d7b294..1185c4d 100644 (file)
@@ -645,9 +645,6 @@ abstract class UploadBase {
 
                if ( $this->mDesiredDestName != $filename && $comparableName != $filename ) {
                        $warnings['badfilename'] = $filename;
-                       // Debugging for bug 62241
-                       wfDebugLog( 'upload', "Filename: '$filename', mDesiredDestName: "
-                               . "'$this->mDesiredDestName', comparableName: '$comparableName'" );
                }
 
                // Check whether the file extension is on the unwanted list
@@ -666,7 +663,7 @@ abstract class UploadBase {
                }
 
                if ( $this->mFileSize == 0 ) {
-                       $warnings['emptyfile'] = true;
+                       $warnings['empty-file'] = true;
                }
 
                $exists = self::getExistsWarning( $localFile );
index 7346a90..49a7163 100644 (file)
@@ -18,6 +18,8 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
+use MediaWiki\Session\BotPasswordSessionProvider;
+
 /**
  * Utility class for bot passwords
  * @since 1.27
@@ -401,9 +403,7 @@ class BotPassword implements IDBAccessObject {
                }
 
                $manager = MediaWiki\Session\SessionManager::singleton();
-               $provider = $manager->getProvider(
-                       'MediaWiki\\Session\\BotPasswordSessionProvider'
-               );
+               $provider = $manager->getProvider( BotPasswordSessionProvider::class );
                if ( !$provider ) {
                        return Status::newFatal( 'botpasswords-no-provider' );
                }
index 027edf9..a272b37 100644 (file)
@@ -3467,10 +3467,9 @@ class User implements IDBAccessObject {
         */
        public function addWatch( $title, $checkRights = self::CHECK_USER_RIGHTS ) {
                if ( !$checkRights || $this->isAllowed( 'editmywatchlist' ) ) {
-                       WatchedItemStore::getDefaultInstance()->addWatchBatch( [
-                               [ $this, $title->getSubjectPage() ],
-                               [ $this, $title->getTalkPage() ],
-                       ]
+                       WatchedItemStore::getDefaultInstance()->addWatchBatchForUser(
+                               $this,
+                               [ $title->getSubjectPage(), $title->getTalkPage() ]
                        );
                }
                $this->invalidateCache();
index 72c620e..1117357 100644 (file)
@@ -105,6 +105,10 @@ class MWCryptHash {
         * @return string An hmac hash of the data + key
         */
        public static function hmac( $data, $key, $raw = true ) {
+               if ( !is_string( $key ) ) {
+                       // a fatal error in HHVM; an exception will at least give us a stack trace
+                       throw new InvalidArgumentException( 'Invalid key type: ' . gettype( $key ) );
+               }
                return hash_hmac( self::hashAlgo(), $data, $key, $raw );
        }
 
index 93ce8eb..f13f9d6 100644 (file)
@@ -443,7 +443,7 @@ class Language {
         * @return array
         * @since 1.19
         */
-       function getFallbackLanguages() {
+       public function getFallbackLanguages() {
                return self::getFallbacksFor( $this->mCode );
        }
 
@@ -451,7 +451,7 @@ class Language {
         * Exports $wgBookstoreListEn
         * @return array
         */
-       function getBookstoreList() {
+       public function getBookstoreList() {
                return self::$dataCache->getItem( $this->mCode, 'bookstoreList' );
        }
 
@@ -520,7 +520,7 @@ class Language {
         *
         * @return array
         */
-       function getFormattedNamespaces() {
+       public function getFormattedNamespaces() {
                $ns = $this->getNamespaces();
                foreach ( $ns as $k => $v ) {
                        $ns[$k] = strtr( $v, '_', ' ' );
@@ -539,7 +539,7 @@ class Language {
         * @param int $index The array key of the namespace to return
         * @return string|bool String if the namespace value exists, otherwise false
         */
-       function getNsText( $index ) {
+       public function getNsText( $index ) {
                $ns = $this->getNamespaces();
                return isset( $ns[$index] ) ? $ns[$index] : false;
        }
@@ -557,7 +557,7 @@ class Language {
         * @param int $index The array key of the namespace to return
         * @return string Namespace name without underscores (empty string if namespace does not exist)
         */
-       function getFormattedNsText( $index ) {
+       public function getFormattedNsText( $index ) {
                $ns = $this->getNsText( $index );
                return strtr( $ns, '_', ' ' );
        }
@@ -570,7 +570,7 @@ class Language {
         * @return string
         * @since 1.18
         */
-       function getGenderNsText( $index, $gender ) {
+       public function getGenderNsText( $index, $gender ) {
                global $wgExtraGenderNamespaces;
 
                $ns = $wgExtraGenderNamespaces +
@@ -585,7 +585,7 @@ class Language {
         * @return bool
         * @since 1.18
         */
-       function needsGenderDistinction() {
+       public function needsGenderDistinction() {
                global $wgExtraGenderNamespaces, $wgExtraNamespaces;
                if ( count( $wgExtraGenderNamespaces ) > 0 ) {
                        // $wgExtraGenderNamespaces overrides everything
@@ -618,7 +618,7 @@ class Language {
        /**
         * @return array
         */
-       function getNamespaceAliases() {
+       public function getNamespaceAliases() {
                if ( is_null( $this->namespaceAliases ) ) {
                        $aliases = self::$dataCache->getItem( $this->mCode, 'namespaceAliases' );
                        if ( !$aliases ) {
@@ -662,7 +662,7 @@ class Language {
        /**
         * @return array
         */
-       function getNamespaceIds() {
+       public function getNamespaceIds() {
                if ( is_null( $this->mNamespaceIds ) ) {
                        global $wgNamespaceAliases;
                        # Put namespace names and aliases into a hashtable.
@@ -692,7 +692,7 @@ class Language {
         * @param string $text
         * @return int|bool An integer if $text is a valid value otherwise false
         */
-       function getNsIndex( $text ) {
+       public function getNsIndex( $text ) {
                $lctext = $this->lc( $text );
                $ns = MWNamespace::getCanonicalIndex( $lctext );
                if ( $ns !== null ) {
@@ -709,7 +709,7 @@ class Language {
         * @param bool $usemsg Use the "variantname-xyz" message if it exists
         * @return string
         */
-       function getVariantname( $code, $usemsg = true ) {
+       public function getVariantname( $code, $usemsg = true ) {
                $msg = "variantname-$code";
                if ( $usemsg && wfMessage( $msg )->exists() ) {
                        return $this->getMessageFromDB( $msg );
@@ -726,7 +726,7 @@ class Language {
        /**
         * @return array
         */
-       function getDatePreferences() {
+       public function getDatePreferences() {
                return self::$dataCache->getItem( $this->mCode, 'datePreferences' );
        }
 
@@ -740,7 +740,7 @@ class Language {
        /**
         * @return array|string
         */
-       function getDefaultDateFormat() {
+       public function getDefaultDateFormat() {
                $df = self::$dataCache->getItem( $this->mCode, 'defaultDateFormat' );
                if ( $df === 'dmy or mdy' ) {
                        global $wgAmericanDates;
@@ -753,7 +753,7 @@ class Language {
        /**
         * @return array
         */
-       function getDatePreferenceMigrationMap() {
+       public function getDatePreferenceMigrationMap() {
                return self::$dataCache->getItem( $this->mCode, 'datePreferenceMigrationMap' );
        }
 
@@ -769,14 +769,14 @@ class Language {
         * @return array
         * @since 1.24
         */
-       function getImageFiles() {
+       public function getImageFiles() {
                return self::$dataCache->getItem( $this->mCode, 'imageFiles' );
        }
 
        /**
         * @return array
         */
-       function getExtraUserToggles() {
+       public function getExtraUserToggles() {
                return (array)self::$dataCache->getItem( $this->mCode, 'extraUserToggles' );
        }
 
@@ -899,7 +899,7 @@ class Language {
         * @param string $msg Message name
         * @return string
         */
-       function getMessageFromDB( $msg ) {
+       public function getMessageFromDB( $msg ) {
                return $this->msg( $msg )->text();
        }
 
@@ -917,14 +917,14 @@ class Language {
         * @param string $key
         * @return string
         */
-       function getMonthName( $key ) {
+       public function getMonthName( $key ) {
                return $this->getMessageFromDB( self::$mMonthMsgs[$key - 1] );
        }
 
        /**
         * @return array
         */
-       function getMonthNamesArray() {
+       public function getMonthNamesArray() {
                $monthNames = [ '' ];
                for ( $i = 1; $i < 13; $i++ ) {
                        $monthNames[] = $this->getMonthName( $i );
@@ -936,7 +936,7 @@ class Language {
         * @param string $key
         * @return string
         */
-       function getMonthNameGen( $key ) {
+       public function getMonthNameGen( $key ) {
                return $this->getMessageFromDB( self::$mMonthGenMsgs[$key - 1] );
        }
 
index 0c51902..e03ef78 100644 (file)
        "recentchangeslinked-page": "Bladsynaam:",
        "recentchangeslinked-to": "Besigtig wysigings aan bladsye met skakels na die bladsy",
        "recentchanges-page-added-to-category": "[[:$1]] by kategorie gevoeg",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] en {{PLURAL:$2|een bladsy|$2 bladsye}} by kategorie gevoeg",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] en [[Special:WhatLinksHere/$1|{{PLURAL:$2|een bladsy|$2 bladsye}}]] by kategorie gevoeg",
        "recentchanges-page-removed-from-category": "[[:$1]] uit kategorie verwyder",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] en {{PLURAL:$2|een bladsy|$2 bladsye}} van kategorie verwyder",
        "autochange-username": "Outomatiese MediaWiki-wysiging",
index a7d5d44..3aea3f9 100644 (file)
        "cancel": "Cancelar",
        "moredotdotdot": "Más...",
        "mypage": "Pachina",
-       "mytalk": "Pachina de discusión",
+       "mytalk": "Pachina de descusión",
        "anontalk": "Pachina de descusión d'ista IP",
        "navigation": "Navego",
        "and": "&#32;y",
        "watchlisttools-view": "Amostrar cambeos",
        "watchlisttools-edit": "Veyer y editar a lista de seguimiento",
        "watchlisttools-raw": "Editar a lista de seguimiento en formato texto",
-       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|discusión]])",
+       "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|descusión]])",
        "duplicate-defaultsort": "Pare cuenta: A clau d'ordenación por defecto «$2» anula l'anterior clau d'ordenación por defecto «$1».",
        "version": "Versión",
        "version-extensions": "Estensions instalatas",
index 1370b5a..a4f71be 100644 (file)
        "uploadstash-badtoken": "لم ينجح أداء ذلك العمل، ربما لأن وثائق تفويض التحرير الخاصة بك منتهية الصلاحية. حاول مرة أخرى.",
        "uploadstash-errclear": "فشلت عملية مسح الملفات.",
        "uploadstash-refresh": "تحديث قائمة الملفات",
+       "uploadstash-thumbnail": "اعرض صورة مصغرة",
        "invalid-chunk-offset": "قطعة أوفست غير صالحة",
        "img-auth-accessdenied": "رفض الوصول",
        "img-auth-nopathinfo": "PATH_INFO مفقود.\nخادومك ليس مضبوطاً لتمرير هذه المعلومة.\nقد يكون مبنياً على نظام CGI ولا يمكنه دعم img_auth.\nراجع https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "apihelp-no-such-module": "الوحدة \"$1\" غير موجودة.",
        "apisandbox": "ملعب API",
        "apisandbox-jsonly": "الجافا سكريبت مطلوبة لاستخدام ملعب API",
+       "apisandbox-api-disabled": "واجهة برمجة التطبيق API معطلة في هذا الموقع.",
        "apisandbox-fullscreen": "وسع اللوحة",
        "apisandbox-unfullscreen": "أظهر الصفحة",
        "apisandbox-submit": "عمل الطلب",
        "sessionprovider-generic": "جلسات $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "جلسات قائمة على ملفات تعريف الارتباط (كوكيز)",
        "sessionprovider-nocookies": "قد يتم تعطيل الكوكيز. تأكد من تمكين ملفات تعريف الأرتباط وأبد مرةأخرى.",
-       "randomrootpage": "صفحة جذر عشوائية"
+       "randomrootpage": "صفحة جذر عشوائية",
+       "log-action-filter-block": "نوع المنع:",
+       "log-action-filter-delete": "نوع الحذف:",
+       "log-action-filter-protect": "نوع الحماية:",
+       "log-action-filter-upload": "نوع الرفع:",
+       "log-action-filter-all": "الكل",
+       "log-action-filter-block-block": "منع",
+       "log-action-filter-block-reblock": "منع التعديل",
+       "log-action-filter-block-unblock": "رفع المنع",
+       "log-action-filter-delete-delete": "حذف الصفحات",
+       "log-action-filter-delete-event": "حذف السجلات",
+       "log-action-filter-delete-revision": "حذف المراجعات",
+       "log-action-filter-protect-protect": "حماية",
+       "log-action-filter-protect-modify": "تعديل الحماية",
+       "log-action-filter-protect-unprotect": "رفع الحماية",
+       "log-action-filter-upload-upload": "رفع جديد",
+       "log-action-filter-upload-overwrite": "إعادة الرفع"
 }
index 58851fd..579de23 100644 (file)
@@ -23,7 +23,8 @@
                        "З. ӘЙЛЕ",
                        "Янмурза Баки",
                        "Айсар",
-                       "Lizalizaufa"
+                       "Lizalizaufa",
+                       "Кутлубаева Кунсулу Закиевна"
                ]
        },
        "tog-underline": "Һылтанмалар аҫтына һыҙыу:",
        "cannotloginnow-title": "Хәҙер үк инеп булмай",
        "cannotloginnow-text": "$1 файҙалланған ваҡытта инергә ярамай",
        "yourdomainname": "Һеҙҙең домен",
-       "password-change-forbidden": "Был викила серһүҙегеҙҙе үҙгәртә алмайһығыҙ.",
+       "password-change-forbidden": "Был викиҙа серһүҙегеҙҙе үҙгәртә алмайһығыҙ.",
        "externaldberror": "Тышҡы мәғлүмәт базаһы менән танылғанда хата барлыҡҡа килде йәки тышҡы үҙ көйләүҙәрегеҙҙе үҙгәртер өсөн хоҡуҡтарығыҙ етәрле түгел.",
        "login": "Танылыу",
        "nav-login-createaccount": "Танылыу йәки теркәлеү",
        "prefs-common-css-js": "Бөтә күренештәр өсөн дөйөм CSS/JS:",
        "prefs-reset-intro": "Был битте, көйләүҙәрегеҙҙе ғәҙәттәге көйләүҙәргә ташлатыу өсөн ҡулланып була.\nРаҫлағандан һуң ғәмәлде кире ҡайтарып булмаясаҡ.",
        "prefs-emailconfirm-label": "Электрон почтаны раҫлау:",
-       "youremail": "Электрон почта *",
+       "youremail": "Электрон почта :",
        "username": "{{GENDER:$1|Ҡулланыусы исеме}}:",
        "prefs-memberingroups": "{{GENDER:$2|Ағза}} {{PLURAL:$1|төркөмө|төркөмдәре}}:",
        "prefs-registration": "Теркәлеү ваҡыты:",
-       "yourrealname": "Һеҙҙең ысын исемегеҙ (*)",
+       "yourrealname": "Һеҙҙең ысын исемегеҙ:",
        "yourlanguage": "Тышҡы күренештә ҡулланылған тел:",
        "yourvariant": "Эстәлектең тел варианты:",
        "prefs-help-variant": "Вики биттәренең эстәлеген күрһәтеү өсөн өҫтөнлөк бирелгән тел йәки орфография.",
        "uploadstash-badtoken": "Был ғәмәлде башҡарып булманы, һеҙҙең төҙәтеү яҙмағыҙ ғәмәлдән сыҡҡан булыуы ихтимал. Яңынан ҡабатлап ҡарағыҙ.",
        "uploadstash-errclear": "Файлдарҙы таҙартып булманы.",
        "uploadstash-refresh": "Файлдар исемлеген яңыртырға",
+       "uploadstash-thumbnail": "һүрәттәрҙе ҡарау",
        "invalid-chunk-offset": "Ҡабул ителмәгән фрагмент шылыуы",
        "img-auth-accessdenied": "Керергә рөхсәт ителмәй",
        "img-auth-nopathinfo": "PATH_INFO юҡ.\nҺеҙҙең сервер был мәғлүмәтте ебәреү өсөн көйләнмәгән.\nУның CGI нигеҙендә эшләүе һәм img_auth ҡулланмауы мөмкин.\nТулыраҡ мәғлүмәт: https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "duration-hours": "$1 {{PLURAL:$1|1=сәғәт|сәғәт}}",
        "duration-days": "$1 {{PLURAL:$1|көн}}",
        "duration-weeks": "$1 {{PLURAL:$1|аҙна}}",
-       "duration-years": "$1 {{PLURAL:$1|йыл|йылдар}}",
+       "duration-years": "$1 {{PLURAL:$1|йыл}}",
        "duration-decades": "$1 {{PLURAL:$1|1=ун йыллыҡ|ун йыллыҡтар}}",
        "duration-centuries": "$1 {{PLURAL:$1|1=быуат|быуаттар}}",
        "duration-millennia": "$1 {{PLURAL:$1|1=меңйыллыҡ|меңйыллыҡтар}}",
        "sessionprovider-generic": "$1 сессия",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "куки нигеҙендә сессиялар",
        "sessionprovider-nocookies": "Ярҙам кәрәкме?",
-       "randomrootpage": "Ярҙам кәрәкме?"
+       "randomrootpage": "Ярҙам кәрәкме?",
+       "log-action-filter-block": "Блоклау төрө:",
+       "log-action-filter-delete": "Юйҙырыу төрө:",
+       "log-action-filter-patrol": "Патруль төрө:",
+       "log-action-filter-protect": "Һаҡлау төрө:",
+       "log-action-filter-upload": "Күсереү төрө:",
+       "log-action-filter-all": "Барыһы",
+       "log-action-filter-block-block": "Бикләргә",
+       "log-action-filter-block-reblock": "Бикте үҙгәртеү",
+       "log-action-filter-block-unblock": "Бикте алырға",
+       "log-action-filter-delete-delete": "Битте юйыуҙар",
+       "log-action-filter-delete-restore": "Битте тергеҙеү",
+       "log-action-filter-delete-event": "Журналды юйыу",
+       "log-action-filter-delete-revision": "Версияны алып ташларға",
+       "log-action-filter-patrol-patrol": "Ҡулдан патруль яһау",
+       "log-action-filter-patrol-autopatrol": "Автоматик патруль",
+       "log-action-filter-protect-protect": "Һаҡлау",
+       "log-action-filter-protect-modify": "Яңынан тейәү",
+       "log-action-filter-protect-unprotect": "Һаҡты алып ташлау",
+       "log-action-filter-upload-upload": "Яңы күсереү",
+       "log-action-filter-upload-overwrite": "Ҡабаттан тейәү"
 }
index bc80b86..887941a 100644 (file)
        "right-applychangetags": "дадаваць [[Special:Tags|меткі]] пры рэдагаваньні",
        "right-changetags": "дадаваць і выдаляць адвольныя [[Special:Tags|меткі]] да асобных вэрсіяў і запісаў у журнале падзеяў",
        "grant-generic": "Набор правоў «$1»",
-       "grant-group-page-interaction": "Узаемадзеньне з старонкамі",
+       "grant-group-page-interaction": "Узаемадзеяньне з старонкамі",
        "grant-group-file-interaction": "Узаемадзеяньне з мэдыяфайламі",
        "grant-group-watchlist-interaction": "Узаемадзеяньне з вашым сьпісам назіраньня",
        "grant-group-email": "Адпраўка лістоў электроннай пошты",
        "uploaded-script-svg": "У загружаным SVG-файле знойдзены небясьпечны элемэнт з падтрымкай сцэнароў «$1».",
        "uploaded-hostile-svg": "Знойдзены небясьпечны CSS у элемэнце стылю загружанага SVG-файла.",
        "uploaded-event-handler-on-svg": "Усталёўваць атрыбуты апрацоўніка падзеяў <code>$1=\"$2\"</code> не дазволена для SVG-файлаў.",
+       "uploaded-href-attribute-svg": "href-атрыбутам у SVG-файлах дазволена весьці толькі на http:// ці https://, знойдзена <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploaded-href-unsafe-target-svg": "У загружаным SVG-файле знойдзеная спасылка на небясьпечныя зьвесткі: URI-мэты <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploaded-animate-svg": "У загружаным SVG-файле знойдзены тэг «animate», які можа зьмяняць спасылку з дапамогай атрыбуту «from» <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "uploaded-setting-event-handler-svg": "Усталёўка атрыбутаў апрацоўкі падзеяў заблякаваная, у загружаным SVG-файле знойдзены код <code>&lt;$1 $2=\"$3\"&gt;</code>.",
        "upload-too-many-redirects": "URL-адрас утрымлівае зашмат перанакіраваньняў",
        "upload-http-error": "Узьнікла памылка HTTP: $1",
        "upload-copy-upload-invalid-domain": "Капіяваньне загрузак не дазволенае ў гэтым дамэне.",
+       "upload-foreign-cant-upload": "Гэтая вікі не наладжаная для загрузкі файлаў у запытанае вонкавае сховішча файлаў.",
        "upload-dialog-title": "Загрузка файла",
        "upload-dialog-button-cancel": "Адмяніць",
        "upload-dialog-button-done": "Зроблена",
        "uploadstash-summary": "Гэтая старонка прадстаўляе доступ да файлаў, якія загружаныя (ці знаходзяцца ў працэсе загрузкі), але яшчэ не апублікаваныя ў {{GRAMMAR:месны|{{SITENAME}}}}. Гэтыя файлы нябачныя нікому, акрамя ўдзельнікаў, якія іх загрузілі.",
        "uploadstash-clear": "Ачысьціць схаваныя файлы",
        "uploadstash-nofiles": "Вы ня маеце схаваных файлаў.",
-       "uploadstash-badtoken": "Немагчыма выканаць гэтае дзеяньне, верагодна скончыўся тэрмін дзеяньня Вашага дазволу на рэдагаваньне. Паспрабуйце зноў.",
+       "uploadstash-badtoken": "Не атрымалася выканаць гэтае дзеяньне. Верагодна, скончыўся тэрмін дзеяньня вашых уліковых зьвестак. Калі ласка, паспрабуйце зноў.",
        "uploadstash-errclear": "Не атрымалася ачысьціць файлы.",
        "uploadstash-refresh": "Абнавіць сьпіс файлаў.",
+       "uploadstash-thumbnail": "прагляд мініятуры",
        "invalid-chunk-offset": "Няслушнае зрушэньне фрагмэнту",
        "img-auth-accessdenied": "Доступ забаронены",
        "img-auth-nopathinfo": "Адсутнічае PATH_INFO.\nВаш сэрвэр не ўстаноўлены на пропуск гэтай інфармацыі.\nМагчма, ён працуе праз CGI і не падтрымлівае img_auth.\nГлядзіце https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "apihelp": "Даведка API",
        "apihelp-no-such-module": "Модуль «$1» ня знойдзены.",
        "apisandbox": "Пясочніца API",
+       "apisandbox-jsonly": "Для выкарыстаньня API-пясочніцы патрэбны JavaScript.",
        "apisandbox-api-disabled": "API забаронены на гэтым сайце.",
        "apisandbox-intro": "Выкарыстоўвайце гэтую старонку для экспэрымэнтаў з <strong>API вэб-сэрвісу MediaWiki</strong>.\nЗьвяртайцеся да [[mw:API:Main page|дакумэнтацыі API]] для дадатковай інфармацыі па выкарыстаньні API. Напрыклад, [//www.mediawiki.org/wiki/API#A_simple_example як атрымаць зьмест галоўнай старонкі]. Абярыце дзеяньне, каб пабачыць болей узораў.\n\nЗьвярніце ўвагу, што нягледзячы на тое, што гэта пясочніца, вашыя дзеяньні могуць унесьці зьмены ў вікі.",
+       "apisandbox-fullscreen": "Разгарнуць панэль",
+       "apisandbox-fullscreen-tooltip": "Разгарнуць панэль пясочніцы, каб запоўніць акно браўзэра.",
+       "apisandbox-unfullscreen": "Паказаць старонку",
+       "apisandbox-unfullscreen-tooltip": "Паменшыць панэль пясочніцы, каб былі даступныя навігацыйныя спасылкі MediaWiki.",
        "apisandbox-submit": "Зрабіць запыт",
        "apisandbox-reset": "Ачысьціць",
        "apisandbox-examples": "Прыклады",
index df3b02a..2ddea11 100644 (file)
@@ -25,7 +25,8 @@
                        "Artificial123",
                        "Macofe",
                        "Matma Rex",
-                       "Goshaproject"
+                       "Goshaproject",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Падкрэсліваць спасылкі:",
        "recentchangeslinked-page": "Назва старонкі:",
        "recentchangeslinked-to": "Паказваць, замест гэтага, змяненні на старонках, што спасылаюцца сюды",
        "recentchanges-page-added-to-category": "[[:$1]] дададзена ў катэгорыю",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] і яшчэ {{PLURAL:$2|адна старонка дададзена|$2 старонкі дададзены|$2 старонак дададзена}} ў катэгорыю",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] і яшчэ [[Special:WhatLinksHere/$1|{{PLURAL:$2|адна старонка дададзена|$2 старонкі дададзены|$2 старонак дададзена}}]] ў катэгорыю",
        "recentchanges-page-removed-from-category": "[[:$1]] выдалена з катэгорыі",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] і яшчэ {{PLURAL:$2|адна старонка выдалена|$2 старонкі выдалены|$2 старонак выдалена}} з катэгорыі",
        "autochange-username": "Аўтаматычная змена MediaWiki",
        "changecontentmodel-reason-label": "Прычына:",
        "changecontentmodel-submit": "Змяніць",
        "logentry-contentmodel-change-revertlink": "адкаціць",
+       "logentry-contentmodel-change-revert": "адкат",
        "protectlogpage": "Журнал аховы",
        "protectlogtext": "Ніжэй прыведзены журнал змен абароны старонкі.\nВы можаце таксама прагледзець [[Special:ProtectedPages|пералік старонак пад аховай]].",
        "protectedarticle": "пад аховай «[[$1]]»",
        "protect-othertime": "Іншы час:",
        "protect-othertime-op": "іншы час",
        "protect-existing-expiry": "Вызначаны час сканчэння: $3, $2",
+       "protect-existing-expiry-infinity": "Наяўны тэрмін дзеяння: бясконца",
        "protect-otherreason": "Іншая ці дадатковая прычына:",
        "protect-otherreason-op": "Іншая прычына",
        "protect-dropdown": "*Звычайныя прычыны пастаноўкі аховы\n** Празмерны ўзровень вандалізму\n** Празмерны ўзровень спаму\n** Шкодная вайна правак\n** Старонка з высокай наведвальнасцю",
        "block-log-flags-hiddenname": "схаванае імя ўдзельніка",
        "range_block_disabled": "Не дазволена адміністратарская магчымасць ставіць блокі на адрасныя дыяпазоны.",
        "ipb_expiry_invalid": "Некарэктны час сканчэння.",
+       "ipb_expiry_old": "Час сканчэння — у мінулым.",
        "ipb_expiry_temp": "Скрытыя блокі на імёны ўдзельнікаў мусяць быць сталымі.",
        "ipb_hide_invalid": "Немагчыма заглушыць гэты рахунак; для яго маецца больш за {{PLURAL:$1|адну праўку|$1 праўкі|$1 правак}}.",
        "ipb_already_blocked": "\"$1\" ужо знаходзіцца пад блокам",
        "import-interwiki-history": "Капіраваць усе гістарычныя версіі гэтай старонкі",
        "import-interwiki-templates": "Разам з усімі шаблонамі",
        "import-interwiki-submit": "Імпартаваць",
+       "import-mapping-namespace": "Імпартаваць у прастору назваў:",
+       "import-mapping-subpage": "Імпартаваць як падстаронкі наступнай старонкі:",
        "import-upload-filename": "Назва файла:",
        "import-comment": "Каментарый:",
        "importtext": "Калі ласка, экспартуйце файл з крынічнай вікі з дапамогай [[Special:Export|прылады экспарту]].\nЗахавайце яго на свой камп'ютар, а потым загрузіце сюды.",
        "javascripttest": "JavaScript-тэсты",
        "javascripttest-pagetext-noframework": "Гэта старонка зарэзервавана для запуску тэстаў JavaScript",
        "javascripttest-pagetext-unknownframework": "Невядомая бібліятэка тэставання «$1».",
+       "javascripttest-pagetext-unknownaction": "Невядомае дзеянне \"$1\".",
        "javascripttest-pagetext-frameworks": "Калі ласка, выберыце адну з прапанаваных бібліятэк тэставання: $1",
        "javascripttest-pagetext-skins": "Выберыце афармленне для тэставання:",
        "javascripttest-qunit-intro": "Глядзіце [$1 дакументацыю па тэставанні] на mediawiki.org.",
        "pageinfo-protect-cascading-yes": "Да",
        "pageinfo-protect-cascading-from": "Каскадная ахова ад",
        "pageinfo-category-info": "Звесткі аб катэгорыі",
+       "pageinfo-category-total": "Агульная колькасць членаў",
        "pageinfo-category-pages": "Колькасць старонак",
        "pageinfo-category-subcats": "Колькасць падкатэгорый",
        "pageinfo-category-files": "Колькасць файлаў",
        "markaspatrolleddiff": "Пазначыць як ухваленае",
        "markaspatrolledtext": "Пазначыць старонку як ухваленую",
+       "markaspatrolledtext-file": "Пазначыць версію файла як ухваленую",
        "markedaspatrolled": "Пазначана як ухваленае",
        "markedaspatrolledtext": "Азначаная версія [[:$1]] пазначана як ухваленая.",
        "rcpatroldisabled": "Не працуе Ухваленне Нядаўніх Правак",
        "patrol-log-page": "Журнал ухваленых",
        "patrol-log-header": "Журнал ухваленых версій",
        "log-show-hide-patrol": "$1 журнал ухваленняў",
+       "log-show-hide-tag": "$1 журнал бірак",
        "deletedrevision": "Сцёрта старая версія $1",
        "filedeleteerror-short": "Памылка пры сціранні файла: $1",
        "filedeleteerror-long": "Памылкі пры спробе сцірання файла:\n\n$1",
        "svg-long-error": "Няспраўны файл SVG: $1",
        "show-big-image": "Арыгінальны файл",
        "show-big-image-preview": "Памер пры папярэднім праглядзе: $1.",
+       "show-big-image-preview-differ": "Памер гэтага $3-прагляду для $2-файла: $1.",
        "show-big-image-other": "{{PLURAL:$2|Іншы дазвол|Іншыя дазволы}}: $1.",
        "show-big-image-size": "$1 × $2 піхеляў",
        "file-info-gif-looped": "закальцаваныя",
        "newimages-legend": "Фільтр",
        "newimages-label": "Назва файла (або яе частка):",
        "newimages-showbots": "Паказваць укладанні ботамі",
+       "newimages-hidepatrolled": "Без паказу ўхваленых ўкладанняў",
        "noimages": "Тут нічога няма.",
        "ilsubmit": "Знайсці",
        "bydate": "п. датаў",
        "exif-compression-4": "CCITT Group 4, факсавае кадзіраванне",
        "exif-copyrighted-true": "Ахоўваецца аўтарскім правам",
        "exif-copyrighted-false": "Статус аўтарства не ўстаноўлены",
+       "exif-photometricinterpretation-1": "Чорны і белы (чорны — 0)",
        "exif-unknowndate": "Невядомая дата",
        "exif-orientation-1": "Звычайна",
        "exif-orientation-2": "Адлюстравана злева ўправа",
        "scarytranscludefailed-httpstatus": "[Не ўдалося атрымаць шаблон для $1: HTTP $2]",
        "scarytranscludetoolong": "[Занадта доўгі URL]",
        "deletedwhileediting": "'''Увага''': гэтая старонка была сцёрта пасля таго, як вы пачалі з ёй працаваць!",
-       "confirmrecreate": "Удзельнік [[User:$1|$1]] ([[User talk:$1|размова]]) сцёр гэты артыкул пасля таго, як вы пачалі працу з ім, падаўшы прычыну:\n: ''$2''\nПацвердзіце свой намер аднавіць гэты артыкул.",
+       "confirmrecreate": "{{GENDER:$1|Удзельнік|Удзельніца}} [[User:$1|$1]] ([[User talk:$1|размова]]) {{GENDER:$1|сцёр|сцерла}} гэты артыкул пасля таго, як вы пачалі працу з ім, падаўшы прычыну:\n: <em>$2</em>\nПацвердзіце свой намер аднавіць гэты артыкул.",
        "confirmrecreate-noreason": "{{GENDER:$1|Удзельнік|Удзельніца}} [[User:$1|$1]] ([[User talk:$1|размовы]]) {{GENDER:$1|сцёр|сцёрла}} гэту старонку пасля таго, як вы пачалі яе рэдагаваць.\nКалі ласка, пацвердзіце, што вы сапраўды жадаеце аднавіць гэтую старонку.",
        "recreate": "Аднавіць",
        "unit-pixel": "крпк",
        "timezone-local": "Мясцовы",
        "duplicate-defaultsort": "Увага: прадвызначаная клавіша ўпарадкавання \"$2\" замяніла ранейшую такую клавішу \"$1\".",
        "duplicate-displaytitle": "<strong>Папярэджанне:</strong> Паказаная назва \"$2\" перасягае ранейшую назву \"$1\".",
+       "invalid-indicator-name": "<strong>Памылка:</strong> Атрыбут <code>name</code> індыкатараў статусу старонкі не можа быць пустым.",
        "version": "Версія",
        "version-extensions": "Устаноўленыя прыстаўкі",
        "version-skins": "Устаноўленыя вокладкі",
        "redirect-page": "Ідэнтыфікатар старонкі",
        "redirect-revision": "Версія старонкі",
        "redirect-file": "Назва файла",
+       "redirect-logid": "ID журнала",
        "redirect-not-exists": "Значэнне не знойдзена",
        "fileduplicatesearch": "Пошук дублікатных файлаў",
        "fileduplicatesearch-summary": "Пошук дублікатных файлах на падставе іх хэшаў.",
        "specialpages-group-wiki": "Вікізвесткі і прылады",
        "specialpages-group-redirects": "Адмысловыя старонкі-перасылкі",
        "specialpages-group-spam": "Прылады супраць спама",
+       "specialpages-group-developer": "Інструменты распрацоўшчыка",
        "blankpage": "Пустая старонка",
        "intentionallyblankpage": "Старонка наўмысна пакінута пустой, і ўжываецца для вымярэння хуткасці і падобнага.",
        "external_image_whitelist": " #Гэты радок пакіньце ў такім самым выглядзе<pre>\n#Упішыце часткі рэгулярных выразаў (тое, што пішуць паміж знакамі //) ніжэй\n#Гэта будзе параўноўвацца з адрасамі URL вонкавых выяваў, на якія ёсць спасылкі\n#Тыя з іх, дзе атрымаецца адпаведнасць, будуць паказаныя як выявы, а іначай толькі як спасылкі\n#Радкі, якія пачынаюцца з знака #, лічацца каментарамі\n#Малыя і вялікія літары не адрозніваюцца\n\n#Усе часткі рэгулярных выразаў павінны быць над гэтым радком. Сам радок пакіньце ў такім самым выглядзе</pre>",
        "tags-activate": "актываваць",
        "tags-deactivate": "адключыць",
        "tags-hitcount": "$1 {{PLURAL:$1|змена|змены|змен}}",
+       "tags-create-heading": "Стварыць новую бірку",
+       "tags-create-explanation": "Калі не ўказана іншае, новыя біркі будуць даступны для выкарыстання ўдзельнікам і робатам.",
        "tags-create-tag-name": "Назва біркі:",
        "tags-create-reason": "Прычына:",
        "tags-create-submit": "Стварыць",
+       "tags-create-no-name": "Вы мусіце ўказаць назву біркі.",
+       "tags-create-invalid-chars": "Назвы бірак не павінны ўтрымліваць коскі (<code>,</code>) або касыя рысы (<code>/</code>).",
+       "tags-create-invalid-title-chars": "Назвы бірак не павінны ўтрымліваць сімвалы, якія нельга выкарыстоўваць у назвах старонак.",
        "tags-create-already-exists": "Бірка \"$1\" ужо ёсць.",
        "tags-create-warnings-below": "Вы хочаце прадоўжыць стварэнне біркі?",
        "tags-delete-title": "Сцерці бірку",
        "tags-delete-explanation-warning": "Гэта дзеянне <strong>незваротнае</strong> і <strong>не можа быць адкочана</strong> нават адміністратарамі базы звестак. Упэўніцеся, што гэта тая бірка, што вы хочаце выдаліць.",
        "tags-delete-reason": "Прычына:",
        "tags-delete-submit": "Незваротна сцерці гэту бірку",
+       "tags-delete-not-found": "Бірка \"$1\" не існуе.",
+       "tags-delete-too-many-uses": "Бірка \"$1\" прыменена ў больш чым $2 {{PLURAL:$2|версіі|версіях}}, а значыць, яна не можа быць сцёрта.",
+       "tags-delete-warnings-after-delete": "Бірка \"$1\" была сцёрта, але {{PLURAL:$2|1=атрымана наступнае папярэджанне|атрыманы наступныя папярэджанні}}:",
+       "tags-activate-title": "Актываваць бірку",
+       "tags-activate-question": "Вы збіраецеся актываваць бірку \"$1\".",
+       "tags-activate-reason": "Прычына:",
+       "tags-activate-not-allowed": "Немагчыма актываваць бірку \"$1\".",
+       "tags-activate-not-found": "Бірка \"$1\" не існуе.",
+       "tags-activate-submit": "Актываваць",
+       "tags-deactivate-title": "Дэактываваць бірку",
+       "tags-deactivate-question": "Вы збіраецеся дэактываваць бірку \"$1\".",
+       "tags-deactivate-reason": "Прычына:",
+       "tags-deactivate-not-allowed": "Немагчыма дэактываваць бірку \"$1\".",
+       "tags-deactivate-submit": "Дэактываваць",
+       "tags-edit-title": "Правіць біркі",
+       "tags-edit-existing-tags": "Наяўныя біркі:",
+       "tags-edit-new-tags": "Новыя біркі:",
+       "tags-edit-add": "Дадаць гэтыя біркі:",
+       "tags-edit-reason": "Прычына:",
        "comparepages": "Параўнанне старонак",
        "compare-page1": "Старонка 1",
        "compare-page2": "Старонка 2",
index bae6d56..d6c4533 100644 (file)
        "filereadonlyerror": "«$1» ئی فایلئ تغیر داتین ممکن نه اینت چون ه «$2» ئی فایلي مخزن فقط بی وانتینی ئین  حالت ئی تا قرار داریت.\n\nمدیری که آیرا قُلپ کورته ایرنگ توضیح داته:  «$3».",
        "invalidtitle-knownnamespace": "نا موتبرین ئنوان گو نامئ فضای  «$2» و متن ئی  «$3»",
        "invalidtitle-unknownnamespace": "ناموتبرین ئنوان گو نا زاتین نامئ فضای شماره  $1 و متن ئی «$2»",
-       "exception-nologin": "لاگین نه بوته ئیت",
+       "exception-nologin": "لاگین نه بوتهئیت",
        "exception-nologin-text": "مهربانی بئ [[Special:Userlogin|تا داخل بیئت]] تا بتوانیت بئ ای تاکدیما دسترسی داشته بئیت.",
        "exception-nologin-text-manual": "مهربانئ بکنیت  $1  تا بتوانیت بئ ای تاکدیم یا عمل ئا دسترسی داشته بئیت .",
        "virus-badscanner": "بدین پیکربندی: نازانتین ویروس ئی سکن کورتین: ''$1''",
        "userloginnocreate": "داخل بوتین",
        "logout": "در بوتین",
        "userlogout": "در بوتین",
-       "notloggedin": "لاگین نه بوته ئیت",
+       "notloggedin": "لاگین نه بوتهئیت",
        "userlogin-noaccount": "شما کار زوروکین حسابئ نداریت؟",
        "userlogin-joinproject": "بی  {{SITENAME}} تا نام‌نویسی کنیت!",
        "nologin": "شما کار زوروکین حسابئ نداریت ؟ $1.",
        "watchlisttools-view": "مربوتین تغیرانی دیستین",
        "watchlisttools-edit": "دیدارلیست ئی دیستین و ایڈیٹ کورتین",
        "watchlisttools-raw": "واچلیستئ آمگین لیستانی ایڈیٹ",
+       "iranian-calendar-m1": "مولمان",
+       "iranian-calendar-m2": "کرا",
+       "iranian-calendar-m3": "سوچکان",
+       "iranian-calendar-m4": "جلکان",
+       "iranian-calendar-m5": "جلکشان",
+       "iranian-calendar-m6": "سچان",
+       "iranian-calendar-m7": "تۆمشان",
+       "iranian-calendar-m8": "سرتان",
+       "iranian-calendar-m9": "گوبشان",
+       "iranian-calendar-m10": "تاکشان",
+       "iranian-calendar-m11": "بهاران",
+       "iranian-calendar-m12": "اوسته‌مان",
        "signature": "[[{{ns:user}}:$1|$2]] ([[{{ns:user_talk}}:$1|گپ و حبر]])",
        "version": "نخسه",
        "version-extensions": "لچیته گین اپزونه ئان",
index 21ba46b..83d271e 100644 (file)
@@ -58,6 +58,7 @@
        "tog-watchlisthidebots": "Sakrij izmjene botova sa spiska praćenih članaka",
        "tog-watchlisthideminor": "Sakrij manje izmjene sa spiska praćenih članaka",
        "tog-watchlisthideliu": "Sakrij izmjene prijavljenih korisnika sa spiska praćenih članaka",
+       "tog-watchlistreloadautomatically": "Automatski osvježi spisak praćenja kad god se izmijeni filter (potreban JavaScript)",
        "tog-watchlisthideanons": "Sakrij izmjene anonimnih korisnika sa spiska praćenih članaka",
        "tog-watchlisthidepatrolled": "Sakrij patrolirane izmjene sa spiska praćenja",
        "tog-watchlisthidecategorization": "Sakrij kategorizaciju stranica",
        "userrights-changeable-col": "Grupe koje možete mijenjati",
        "userrights-unchangeable-col": "Grupe koje ne možete mijenjati",
        "userrights-conflict": "Sukob u izmjeni korisničkih prava! Molimo da razmotrite i potvrdite Vaše promjene.",
-       "userrights-removed-self": "Uspješno ste uklonili vlastite prava. Zbog toga više niste u stanju pristupiti ovoj stranici.",
+       "userrights-removed-self": "Uklonili ste vlastita prava. Zbog toga više ne možete pristupiti ovoj stranici.",
        "group": "Grupa:",
        "group-user": "Korisnici",
        "group-autoconfirmed": "Potvrđeni korisnici",
        "right-managechangetags": "Napravi i briši [[Special:Tags|oznake]] iz baze podataka",
        "right-applychangetags": "Primijeni [[Special:Tags|oznake]] na nečije izmjene",
        "right-changetags": "Dodavanje ili uklanjanje raznih [[Special:Tags|oznaka]] na pojedinačnim verzijama i unosima zapisnika",
+       "grant-group-page-interaction": "Upravljanje stranicama",
+       "grant-group-watchlist-interaction": "Upravljanje Vašim spiskom praćenja",
+       "grant-group-high-volume": "Izvršavanje velikog broja radnji",
+       "grant-group-customization": "Prilagodbe i postavke",
+       "grant-group-other": "Raznovrsno djelovanje",
        "grant-createeditmovepage": "Pravljenje, uređivanje i premještanje stranica",
+       "grant-editmycssjs": "Uređivanje Vašeg korisničkog CSS-a ili JavaScripta",
+       "grant-editmyoptions": "Uređivanje Vaših postavki",
        "grant-editmywatchlist": "Uređivanje Vašeg spiska praćenja",
        "grant-editpage": "Uređivanje postojećih stranica",
        "grant-editprotected": "Uređivanje zaštićenih stranica",
-       "grant-highvolume": "Uređivanja velikog opsega",
+       "grant-highvolume": "Veliki broj izmjena",
+       "grant-patrol": "Patroliranje izmjena stranica",
        "grant-uploadeditmovefile": "Postavljanje, zamjena i premještanje datoteka",
        "grant-uploadfile": "Postavljanje novih datoteka",
+       "grant-basic": "Osnovna prava",
        "grant-viewmywatchlist": "Pregled Vašeg spiska praćenja",
        "newuserlogpage": "Zapisnik novih korisnika",
        "newuserlogpagetext": "Ovo je zapisnik o registraciji novih korisnika.",
        "recentchangeslinked-page": "Naslov stranice:",
        "recentchangeslinked-to": "Pokaži promjene stranica koji su povezane sa datom stranicom",
        "recentchanges-page-added-to-category": "[[:$1]] dodana je u kategoriju",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] i još {{PLURAL:$2|jedna stranica|$2 stranice|$2 stranica}} su dodane u kategoriju",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] i još [[Special:WhatLinksHere/$1|{{PLURAL:$2|jedna stranica|$2 stranice|$2 stranica}}]] su dodane u kategoriju",
        "recentchanges-page-removed-from-category": "[[:$1]] je uklonjena iz kategorije",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] i još {{PLURAL:$2|jedna stranica|$2 stranice|$2 stranica}} su uklonjene iz kategorije",
        "autochange-username": "Automatska promjena MediaWikija",
        "wlshowlast": "Prikaži posljednjih $1 sati $2 dana",
        "watchlist-hide": "Sakrij",
        "watchlist-submit": "Prikaži",
-       "wlshowtime": "Prikaži posljednjih:",
+       "wlshowtime": "Vremensko razdoblje za prikaz:",
        "wlshowhideminor": "manje izmjene",
        "wlshowhidebots": "botove",
        "wlshowhideliu": "registrovane korisnike",
        "tooltip-feed-rss": "RSS za ovu stranicu",
        "tooltip-feed-atom": "Atom za ovu stranicu",
        "tooltip-t-contributions": "Pogledajte spisak doprinosa {{GENDER:$1|ovog korisnika|ove korisnice|ove osobe}}",
-       "tooltip-t-emailuser": "Pošaljite pismo ovom korisniku",
+       "tooltip-t-emailuser": "Pošaljite e-poruku {{GENDER:$1|ovom korisniku}}",
        "tooltip-t-info": "Više informacija o ovoj stranici",
        "tooltip-t-upload": "Postavi slike i druge medije",
        "tooltip-t-specialpages": "Spisak svih posebnih stranica",
        "tags-edit-revision-legend": "Dodaj ili ukloni oznake sa {{PLURAL:$1|ove verzije|svih $1 verzija}}",
        "tags-edit-logentry-legend": "Dodaj ili ukloni oznake sa {{PLURAL:$1|ove zapisničke stavke|svih $1 zapisničkih stavki}}",
        "tags-edit-existing-tags": "Postojeće oznake:",
-       "tags-edit-existing-tags-none": "\"Nema\"",
+       "tags-edit-existing-tags-none": "<em>Nema</em>",
        "tags-edit-new-tags": "Nove oznake:",
        "tags-edit-add": "Dodaj ove oznake:",
        "tags-edit-remove": "Ukloni ove oznake:",
        "tags-edit-reason": "Razlog:",
        "tags-edit-revision-submit": "Primijeni izmjene {{PLURAL:$1|ovoj verziji|svim $1 verzijama}}",
        "tags-edit-logentry-submit": "Primijeni izmjene {{PLURAL:$1|ovom zapisničkom unosu|svim $1 zapisničkim unosima}}",
-       "tags-edit-success": "Izmjene su uspješno primijenjene.",
+       "tags-edit-success": "Izmjene su primijenjene.",
        "tags-edit-failure": "Nije bilo moguće primijeniti izmjene:\n$1",
        "tags-edit-nooldid-title": "Neispravna odredišna verzija",
        "tags-edit-nooldid-text": "Niste izabrali odredišnu verziju na koju treba primijeniti ovu funkciju, ili odredišna verzija na postoji.",
index 9ac9fb8..2689ce5 100644 (file)
        "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",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] i {{PLURAL:$2|una pàgina|$2 pàgines}} més afegides a la categoria",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] i [[Special:WhatLinksHere/$1|{{PLURAL:$2|una pàgina|$2 pàgines}}]] més afegides a la categoria",
        "recentchanges-page-removed-from-category": "[[:$1]] treta de la categoria",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] i {{PLURAL:$2|una pàgina|$2 pàgines}} més tretes de la categoria",
        "autochange-username": "Canvi automàtic del MediaWiki",
index c4acdf4..4a69007 100644 (file)
@@ -10,7 +10,8 @@
                        "아라",
                        "Kaganer",
                        "Исмаил Садуев",
-                       "Macofe"
+                       "Macofe",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "КӀел сиз хьакха хьажорган:",
        "recentchangeslinked-page": "АгӀон цӀе:",
        "recentchangeslinked-to": "Кхечу агӀор, гайта хийцамаш агӀонашца, хӀоттийначу агӀонтӀе хьажорг йолуш",
        "recentchanges-page-added-to-category": "[[:$1]] категори чу тоьхна",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] а, {{PLURAL:$2|цхьа агӀо|$2 агӀо}} а категорин тӀетоьхна",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] а, [[Special:WhatLinksHere/$1|{{PLURAL:$2|цхьа агӀо|$2 агӀо}}]] а категорин тӀетоьхна",
        "recentchanges-page-removed-from-category": "[[:$1]] дӀаяьккхина категори чура",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] а, {{PLURAL:$2|цхьа агӀо|$2 агӀо}} а категорин чура дӀаяьккхина",
        "autochange-username": "MediaWiki авто-хийцамбар",
        "tags-hitcount-header": "Билгалдина нисдарш",
        "tags-actions-header": "Дийраш",
        "tags-active-yes": "ХӀаъ",
-       "tags-active-no": "ХӀахӀа",
+       "tags-active-no": "ХӀан-хӀа",
        "tags-source-extension": "Билгалйо шоралица",
        "tags-source-none": "Кхий лелош яц",
        "tags-edit": "нисъе",
index 1bac2e1..089bfc3 100644 (file)
        "nov": "ноя",
        "dec": "дек",
        "pagecategories": "{{PLURAL:$1|1=Саифенинъ категориясы|Саифенинъ категориялары}}",
-       "category_header": "\"$1\" категориясындаки саифелер",
+       "category_header": "«$1» категориясындаки саифелер",
        "subcategories": "Алт категориялар",
-       "category-media-header": "\"$1\" категориясындаки медиа файллары",
+       "category-media-header": "«$1» категориясындаки медиа файллары",
        "category-empty": "''Ишбу категорияда ич бир саифе я да медиа файл ёкъ.''",
        "hidden-categories": "Гизли {{PLURAL:$1|1=категория|категориялар}}",
        "hidden-category-category": "Гизли категориялар",
        "perfcachedts": "Ашагъыдаки малюмат кэштен алынды, кэшнинъ сонъки янъартылгъан вакъты: $1. Кэште энъ чокъ {{PLURAL:$1|1=бир нетидже|$1 нетидже}} сакъланып тура.",
        "querypage-no-updates": "Бу саифени денъиштирмеге шимди изин ёкъ. Бу малюмат аман янъартылмайджакъ.",
        "viewsource": "Менба кодуны косьтер",
-       "viewsource-title": "$1 саифесининъ менба коду",
+       "viewsource-title": "«$1» саифесининъ менба коду",
        "actionthrottled": "Арекет токъталды",
        "actionthrottledtext": "Спамгъа къаршы куреш себебинден бу арекетни аз вакъыт ичинде чокъ кере текрарлап оламайсынъыз. Мумкюн олгъан къарардан зияде арекет яптынъыз. Бир къач дакъкъадан сонъ текрарлап бакъынъыз.",
        "protectedpagetext": "Бу саифеде денъиштирме я да башкъа бир арекет япылмасын деп о блок этильди.",
        "updated": "(Янъарды)",
        "note": "'''Ихтар:'''",
        "previewnote": "'''Бу тек бакъып чыкъув, метин аля даа сакъланмагъан!'''",
+       "continue-editing": "Денъиштирюв пенджересине къайт",
        "previewconflict": "Бу бакъып чыкъув юкъары тарир пенджересиндеки метиннинъ сакъланувдан сонъ оладжакъ корюнишини акс эте.",
        "session_fail_preview": "''' Сервер сиз япкъан денъиштирмелерни сессия идентификаторы джоюлгъаны себебинден сакълап оламады.\nБу вакътынджа проблемадыр. Лютфен, текрар сакълап бакъынъыз.\nБундан да сонъ олып чыкъмаса, малюмат локаль файлгъа сакъланъыз да браузеринъизни бир къапатып ачынъыз.'''",
        "session_fail_preview_html": "'''Афу этинъиз! HTML сессиянынъ малюматлары гъайып олгъаны себебинден сизинъ денъиштирмелеринъизни къабул этмеге имкян ёкътыр.'''",
        "editing": "«$1» саифесини денъиштиреятасыз",
        "creating": "«$1» саифесини яратув",
        "editingsection": "«$1» саифесинде болюк денъиштиреятасыз",
-       "editingcomment": "$1 саифесини денъиштиреятасыз (янъы болюк)",
+       "editingcomment": "«$1» саифесини денъиштиреятасыз (янъы болюк)",
        "editconflict": "Денъиштирмелер чатышмасы: $1",
        "explainconflict": "Сиз саифени денъиштиргенде башкъа бири де денъиштирме япты.\nЮкъарыдаки язы саифенинъ шимдики алыны косьтере.\nСизинъ денъиштирмелеринъиз астында косьтерильди.\nШимди япкъан денъиштирмелеринъизни ашагъы пенджереден юкъары пенджереге авуштырмакъ керексинъиз.\n\"{{int:savearticle}}\"гъа баскъанда '''тек''' юкъарыдаки язы сакъланаджакъ.",
        "yourtext": "Сизинъ метнинъиз",
        "randompage": "Тесадюфий саифе",
        "randompage-nopages": "\"$1\" {{PLURAL:$2|1=исим фезасында|исим фезаларында}} ич бир саифе ёкъ.",
        "randomredirect": "Тесадюфий ёллама саифеси",
-       "randomredirect-nopages": "\"$1\" исим фезасында ич бир ёллама саифеси ёкъ.",
+       "randomredirect-nopages": "«$1» исим фезасында ич бир ёллама саифеси ёкъ.",
        "statistics": "Статистика",
        "statistics-header-pages": "Саифе статистикасы",
        "statistics-header-edits": "Денъиштирюв статистикасы",
        "protectlogtext": "Ашагъыдаки, къорчалавгъа алув/къорчалавдан чыкъарув иле багълы денъишмелер журналыдыр.\nКъорчалангъан саифелер [[Special:ProtectedPages|там джедвелини]] де коре билесинъиз.",
        "protectedarticle": "\"[[$1]]\" къорчалав алтына алынды",
        "modifiedarticleprotection": "«[[$1]]» ичюн къорчалав севиеси денъиштирильди",
-       "unprotectedarticle": "\"[[$1]]\" саифесинден къорчалав чыкъарлыды",
+       "unprotectedarticle": "«[[$1]]» саифесинден къорчалав чыкъарлыды",
        "prot_1movedto2": "[[$1]] саифесининъ ады [[$2]] деп денъиштирильди",
        "protect-legend": "Къорчалавны тасдыкъла",
        "protectcomment": "Себеп:",
        "sp-contributions-newonly": "Тек янъы саифе яраткъан денъиштирмелерни косьтер",
        "sp-contributions-submit": "Къыдыр",
        "whatlinkshere": "Бу саифеге багълантылар",
-       "whatlinkshere-title": "$1 саифесине багъланты олгъан саифелер",
+       "whatlinkshere-title": "«$1» саифесине багъланты олгъан саифелер",
        "whatlinkshere-page": "Саифе:",
        "linkshere": "'''[[:$1]]''' саифесине багъланты берген саифелер:",
        "nolinkshere": "'''[[:$1]]''' саифесине багъланты берген саифе ёкъ.",
        "ip_range_invalid": "Рухсетсиз IP аралыгъы.",
        "lockdb": "Малюмат базасы килитли",
        "lockbtn": "Малюмат базасы килитли",
-       "move-page": "$1 саифесининъ адыны денъиштиреятасыз",
+       "move-page": "«$1» саифесининъ адыны денъиштиреятасыз",
        "move-page-legend": "Саифенинъ адыны денъиштирюв",
        "movepagetext": "Ашагъыдаки форма къулланылып саифенинъ ады денъиштирилир. Бунынънен берабер денъиштирмелер журналы да янъы адгъа авуштырылыр.\nЭски ады янъы адына ёнетме олур. Эски серлевагъа ёнетип тургъан саифелерни автоматик оларакъ янъартып оласынъыз. Бу арекетни автоматик япмагъа истемесенъиз, бутюн [[Special:DoubleRedirects|чифт]] ве [[Special:BrokenRedirects|йыртыкъ]] ёнетме саифелерини озюнъиз тешкермеге меджбур олурсынъыз. Багълантылар эндиден берли догъру чалышмасындан эмин олмалысынъыз.\n\nЯнъы адда бир саифе энди бар олса, ад денъиштирилюви <strong>япылмайджакъ</strong>, анджакъ бар олгъан саифе ёнетме я да бош олса ад денъиштирилюви мумкюн оладжакъ. Бу демек ки, саифенинъ адыны янълыштан денъиштирген олсанъыз деминки адыны кери къайтарып оласынъыз, амма бар олгъан саифени тесадюфен ёкъ этамайсынъыз.\n\n<strong>ТЕНБИ!</strong>\nАд денъиштирилюви популяр саифелер ичюн буюк ве бекленмеген денъишмелерге себеп ола билир. Лютфен, денъиштирме япмаздан эвель ола биледжеклерни козь огюне алынъыз.",
        "movepagetalktext": "Къошулгъан музакере саифесининъ де (бар олса)\nады автоматик тарзда денъиштириледжек. '''Мустесналар:'''\n\n* Айны бу адда бош олмагъан бир музакере саифеси энди бар;\n* Ашагъыдаки бошлукъкъа ишарет къоймадынъыз.\n\nБойле алларда, керек олса, саифелерни къолнен ташымагъа я да бирлештирмеге меджбур олурсынъыз.",
index 9333f95..ffdd83c 100644 (file)
        "nov": "noy",
        "dec": "dek",
        "pagecategories": "{{PLURAL:$1|Saifeniñ kategoriyası|Saifeniñ kategoriyaları}}",
-       "category_header": "\"$1\" kategoriyasındaki saifeler",
+       "category_header": "“$1” kategoriyasındaki saifeler",
        "subcategories": "Alt kategoriyalar",
-       "category-media-header": "\"$1\" kategoriyasındaki media faylları",
+       "category-media-header": "“$1” kategoriyasındaki media faylları",
        "category-empty": "''İşbu kategoriyada iç bir saife ya da media fayl yoq.''",
        "hidden-categories": "Gizli {{PLURAL:$1|kategoriya|kategoriyalar}}",
        "hidden-category-category": "Gizli kategoriyalar",
        "formerror": "Hata: formanıñ malümatını yollamaqnıñ iç çaresi yoq",
        "badarticleerror": "Siz yapmağa istegen işlev bu saifede yapılıp olamay.",
        "cannotdelete": "\"$1\" saife ya da faylı yoq etilip olamadı. Başqa bir qullanıcı tarafından yoq etilgen ola bile.",
-       "cannotdelete-title": "\"$1\" saifesini yoq etmege olmaz",
+       "cannotdelete-title": "“$1” saifesini yoq etmege olmaz",
        "delete-hook-aborted": "Yoq etüv çengel protsedurasınen toqtatıldı.\nİç bir izaat berilmedi.",
        "badtitle": "Ruhsetsiz serleva",
        "badtitletext": "İstenilgen saife adı doğru degil, o boştır, yahut tillerara bağlantı ya da vikilerara bağlantı doğru yazılmağan. Belki saife adında yasaqlanğan işaretler bar.",
        "perfcachedts": "Aşağıdaki malümat keşten alındı, keşniñ soñki yañartılğan vaqtı: $1. Keşte eñ çoq {{PLURAL:$1|bir netice|$1 netice}} saqlanıp tura.",
        "querypage-no-updates": "Bu saifeni deñiştirmege şimdi izin yoq. Bu malümat aman yañartılmaycaq.",
        "viewsource": "Menba kodunı köster",
-       "viewsource-title": "$1 saifesiniñ menba kodu",
+       "viewsource-title": "“$1” saifesiniñ menba kodu",
        "actionthrottled": "Areket toqtaldı",
        "actionthrottledtext": "Spamğa qarşı küreş sebebinden bu areketni az vaqıt içinde çoq kere tekrarlap olamaysıñız. Mümkün olğan qarardan ziyade areket yaptıñız. Bir qaç daqqadan soñ tekrarlap baqıñız.",
        "protectedpagetext": "Bu saifede deñiştirme ya da başqa bir areket yapılmasın dep o blok etildi.",
        "updated": "(Yañardı)",
        "note": "'''İhtar:'''",
        "previewnote": "'''Bu tek baqıp çıquv, metin alâ daa saqlanmağan!'''",
+       "continue-editing": "Deñiştirüv penceresine qayt",
        "previewconflict": "Bu baqıp çıquv yuqarı tarir penceresindeki metinniñ saqlanuvdan soñ olacaq körünişini aks ete.",
        "session_fail_preview": "''' Server siz yapqan deñiştirmelerni sessiya identifikatorı\ncoyulğanı sebebinden saqlap olamadı. Bu vaqtınca problemadır. Lütfen, tekrar saqlap baqıñız.\nBundan da soñ olıp çıqmasa, malümat lokal faylğa saqlañız da brauzeriñizni bir qapatıp\naçıñız.'''",
        "session_fail_preview_html": "'''Afu etiñiz! HTML sessiyanıñ malümatları ğayıp olğanı sebebinden siziñ deñiştirmeleriñizni qabul etmege imkân yoqtır.'''",
        "editing": "“$1” saifesini deñiştireyatasız",
        "creating": "“$1” saifesini yaratuv",
        "editingsection": "“$1” saifesinde bölük deñiştireyatasız",
-       "editingcomment": "$1 saifesini deñiştireyatasız (yañı bölük)",
+       "editingcomment": "“$1” saifesini deñiştireyatasız (yañı bölük)",
        "editconflict": "Deñiştirmeler çatışması: $1",
        "explainconflict": "Siz saifeni deñiştirgende başqa biri de deñiştirme yaptı.\nYuqarıdaki yazı saifeniñ şimdiki alını köstere.\nSiziñ deñiştirmeleriñiz astında kösterildi. Şimdi yapqan deñiştirmeleriñizni aşağı pencereden yuqarı pencerege avuştırmaq kereksiñiz.\n\"{{int:savearticle}}\"ğa basqanda '''tek''' yuqarıdaki yazı saqlanacaq.",
        "yourtext": "Siziñ metniñiz",
        "randompage": "Tesadüfiy saife",
        "randompage-nopages": "\"$1\" {{PLURAL:$2|isim fezasında|isim fezalarında}} iç bir saife yoq.",
        "randomredirect": "Tesadüfiy yollama saifesi",
-       "randomredirect-nopages": "\"$1\" isim fezasında iç bir yollama saifesi yoq.",
+       "randomredirect-nopages": "“$1” isim fezasında iç bir yollama saifesi yoq.",
        "statistics": "Statistika",
        "statistics-header-pages": "Saife statistikası",
        "statistics-header-edits": "Deñiştirüv statistikası",
        "protectlogpage": "Qorçalav jurnalı",
        "protectlogtext": "Aşağıdaki, saifeni qorçalavğa aluv/qorçalavdan çıqaruv ile bağlı deñişmeler jurnalıdır.\nQorçalanğan saifeler [[Special:ProtectedPages|tam cedvelini]] de köre bilesiñiz.",
        "protectedarticle": "\"[[$1]]\" qorçalav altına alındı",
-       "modifiedarticleprotection": "\"[[$1]]\" içün qorçalav seviyesi deñiştirildi",
-       "unprotectedarticle": "\"[[$1]]\" saifesinden qorçalav çıqarlıdı",
+       "modifiedarticleprotection": "“[[$1]]” içün qorçalav seviyesi deñiştirildi",
+       "unprotectedarticle": "“[[$1]]” saifesinden qorçalav çıqarlıdı",
        "prot_1movedto2": "[[$1]] saifesiniñ adı [[$2]] dep deñiştirildi",
        "protect-legend": "Qorçalavnı tasdıqla",
        "protectcomment": "Sebep:",
        "sp-contributions-newonly": "Tek yañı saife yaratqan deñiştirmelerni köster",
        "sp-contributions-submit": "Qıdır",
        "whatlinkshere": "Bu saifege bağlantılar",
-       "whatlinkshere-title": "$1 saifesine bağlantı bergen saifeler",
+       "whatlinkshere-title": "“$1” saifesine bağlantı bergen saifeler",
        "whatlinkshere-page": "Saife:",
        "linkshere": "'''[[:$1]]''' saifesine bağlantı bergen saifeler:",
        "nolinkshere": "'''[[:$1]]''' saifesine bağlantı bergen saife yoq.",
        "ip_range_invalid": "Ruhsetsiz IP aralığı.",
        "lockdb": "Malümat bazası kilitli",
        "lockbtn": "Malümat bazası kilitli",
-       "move-page": "$1 saifesiniñ adını deñiştireyatasız",
+       "move-page": "“$1” saifesiniñ adını deñiştireyatasız",
        "move-page-legend": "Saifeniñ adını deñiştirüv",
        "movepagetext": "Aşağıdaki forma qullanılıp saifeniñ adı deñiştirilir. Bunıñnen beraber deñiştirmeler jurnalı da yañı adğa avuştırılır.\nEski adı yañı adına yönetme olur. Eski serlevağa yönetip turğan saifelerni avtomatik olaraq yañartıp olasıñız. Bu areketni avtomatik yapmağa istemeseñiz, bütün [[Special:DoubleRedirects|çift]] ve [[Special:BrokenRedirects|yırtıq]] yönetme saifelerini özüñiz teşkermege mecbur olursıñız. Bağlantılar endiden berli doğru çalışmasından emin olmalısıñız.\n\nYañı adda bir saife endi bar olsa, ad deñiştirilüvi <strong>yapılmaycaq</strong>, ancaq bar olğan saife yönetme ya da boş olsa ad deñiştirilüvi mümkün olacaq. Bu demek ki, saifeniñ adını yañlıştan deñiştirgen olsañız deminki adını keri qaytarıp olasıñız, amma bar olğan saifeni tesadüfen yoq etamaysıñız.\n\n<strong>TENBİ!</strong>\nAd deñiştirilüvi populâr saifeler içün büyük ve beklenmegen deñişmelerge sebep ola bilir. Lütfen, deñiştirme yapmazdan evel ola bileceklerni köz ögüne alıñız.",
        "movepagetalktext": "Qoşulğan muzakere saifesiniñ de (bar olsa) adı avtomatik tarzda deñiştirilecek. '''Müstesnalar:'''\n\n*Aynı bu isimde boş olmağan bir muzakere saifesi endi bar;\n*Aşağıdaki boşluqqa işaret qoymadıñız.\n\nBöyle allarda, kerek olsa, saifelerni qolnen taşımağa ya da birleştirmege mecbur olursıñız.",
        "move-watch": "Bu saifeni közet",
        "movepagebtn": "Adını deñiştir",
        "pagemovedsub": "Saifeniñ adı deñiştirildi",
-       "movepage-moved": "'''\"$1\" saifesiniñ adı \"$2\" olaraq deñiştirildi'''",
+       "movepage-moved": "'''“$1” saifesiniñ adı “$2” olaraq deñiştirildi'''",
        "movepage-moved-redirect": "Bir yollama yaratıldı.",
        "movepage-moved-noredirect": "Yollama yaratıluvı bastırıldı.",
        "articleexists": "Bu adda bir saife endi bar ya da siz yazğan ad yasaqlı.\nLütfen, başqa bir ad saylap yazıñız.",
index a6205df..5847af6 100644 (file)
        "uploadstash-badtoken": "Operace se nezdařila. Možná vypršela platnost vašeho oprávnění k editaci. Zkuste to znovu.",
        "uploadstash-errclear": "Soubory se nepodařilo vymazat.",
        "uploadstash-refresh": "Aktualizovat seznam souborů",
+       "uploadstash-thumbnail": "zobrazit náhled",
        "invalid-chunk-offset": "Neplatný posun bloku",
        "img-auth-accessdenied": "Přístup odepřen",
        "img-auth-nopathinfo": "Chybí PATH_INFO.\nVáš server není nastaven tak, aby tuto informaci poskytoval.\nMožná funguje pomocí CGI a img_auth na něm nemůže fungovat.\nVizte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "sessionprovider-generic": "relace pomocí $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "relace pomocí cookies",
        "sessionprovider-nocookies": "Možná jsou zakázány cookies. Ujistěte se, že máte cookies povoleny a zkuste to znovu.",
-       "randomrootpage": "Náhodná kořenová stránka"
+       "randomrootpage": "Náhodná kořenová stránka",
+       "log-action-filter-block": "Typ zablokování:",
+       "log-action-filter-delete": "Typ smazání:",
+       "log-action-filter-patrol": "Typ prověření:",
+       "log-action-filter-protect": "Typ zamčení:",
+       "log-action-filter-upload": "Typ nahrání:",
+       "log-action-filter-all": "Všechny",
+       "log-action-filter-block-block": "Zablokování",
+       "log-action-filter-block-reblock": "Změna zablokování",
+       "log-action-filter-block-unblock": "Odblokování",
+       "log-action-filter-delete-delete": "Smazání stránky",
+       "log-action-filter-delete-restore": "Obnovení stránky",
+       "log-action-filter-delete-event": "Smazání záznamu",
+       "log-action-filter-delete-revision": "Smazání revize",
+       "log-action-filter-patrol-patrol": "Manuální prověření",
+       "log-action-filter-patrol-autopatrol": "Automatické prověření",
+       "log-action-filter-protect-protect": "Zamknutí",
+       "log-action-filter-protect-modify": "Změna zámku",
+       "log-action-filter-protect-unprotect": "Odemknutí",
+       "log-action-filter-upload-upload": "Nové načtení",
+       "log-action-filter-upload-overwrite": "Znovunačtení"
 }
index d76acad..3ff54a8 100644 (file)
@@ -15,7 +15,8 @@
                        "아라",
                        "Macofe",
                        "Matma Rex",
-                       "Diafol"
+                       "Diafol",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Tanlinellu cysylltiadau:",
        "moredotdotdot": "Rhagor...",
        "morenotlisted": "Nid yw'r rhestr hon yn llawn.",
        "mypage": "Tudalen defnyddiwr",
-       "anonuserpage": "Defnyddiwr anhysbys",
        "mytalk": "Sgwrs",
        "anontalk": "Sgwrs",
        "navigation": "Panel llywio",
        "recentchangeslinked-page": "Tudalen:",
        "recentchangeslinked-to": "Dangos newidiadau i'r tudalennau â chyswllt arnynt sy'n arwain at y dudalen a enwir",
        "recentchanges-page-added-to-category": "Ychwanegwyd [[:$1]] at y categori",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] ac {{PLURAL:$2|un ddalen|$2 dalen}} wedi'u hychwanegu at y categori",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] ac [[Special:WhatLinksHere/$1|{{PLURAL:$2|un ddalen|$2 dalen}}]] wedi'u hychwanegu at y categori",
        "recentchanges-page-removed-from-category": "Symudwyd [[:$1]] o'r categori",
        "upload": "Uwchlwytho ffeil",
        "uploadbtn": "Uwchlwytho ffeil",
index 8263cf6..068164e 100644 (file)
@@ -56,7 +56,8 @@
                        "Mads Haupt",
                        "Stefan2",
                        "Ribewiki",
-                       "Jens Jensen"
+                       "Jens Jensen",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Understreg henvisninger:",
        "recentchangeslinked-page": "Sidenavn:",
        "recentchangeslinked-to": "Vis ændringer i sider der henviser til den angivne side i stedet",
        "recentchanges-page-added-to-category": "[[:$1]] tilføjet til kategori",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] og {{PLURAL:$2|én side|$2 sider}} tilføjet til kategori",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] og [[Special:WhatLinksHere/$1|{{PLURAL:$2|én side|$2 sider}}]] tilføjet til kategori",
        "upload": "Læg en fil op",
        "uploadbtn": "Læg en fil op",
        "reuploaddesc": "Tilbage til formularen til at lægge filer op.",
index d7f2c90..408ebed 100644 (file)
        "uploadstash-badtoken": "Das Entfernen der vorab gespeicherten Dateien ist fehlgeschlagen, da vielleicht deine Sitzungsdaten abgelaufen sind. Bitte versuche es erneut.",
        "uploadstash-errclear": "Das Entfernen der vorab gespeicherten Dateien ist fehlgeschlagen.",
        "uploadstash-refresh": "Liste der Dateien aktualisieren",
+       "uploadstash-thumbnail": "Vorschaubild ansehen",
        "invalid-chunk-offset": "Ungültiger Startpunkt",
        "img-auth-accessdenied": "Zugriff verweigert",
        "img-auth-nopathinfo": "Die Angabe PATH_INFO fehlt.\nDer Server ist nicht dafür eingerichtet, diese Information weiterzugeben.\nSie könnte CGI-gestützt sein und kann daher „img_auth“ (Authentifizierung des Dateiaufrufs) nicht unterstützen.\nSiehe auch https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization (englisch).",
        "sessionprovider-generic": "$1-Sitzungen",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "cookiebasierten Sitzungen",
        "sessionprovider-nocookies": "Cookies sind eventuell deaktiviert. Stelle sicher, dass Cookies aktiviert sind und versuche es erneut.",
-       "randomrootpage": "Zufällige Stammseite"
+       "randomrootpage": "Zufällige Stammseite",
+       "log-action-filter-block": "Sperrtyp:",
+       "log-action-filter-delete": "Löschtyp:",
+       "log-action-filter-patrol": "Kontrolltyp:",
+       "log-action-filter-protect": "Schutztyp:",
+       "log-action-filter-upload": "Hochladetyp:",
+       "log-action-filter-all": "Alle",
+       "log-action-filter-block-block": "Sperren",
+       "log-action-filter-block-reblock": "Sperrveränderung",
+       "log-action-filter-block-unblock": "Freigaben",
+       "log-action-filter-delete-delete": "Seitenlöschung",
+       "log-action-filter-delete-restore": "Seitenwiederherstellung",
+       "log-action-filter-delete-event": "Logbucheintrag-Löschung",
+       "log-action-filter-delete-revision": "Versionslöschung",
+       "log-action-filter-patrol-patrol": "Manuelle Kontrolle",
+       "log-action-filter-patrol-autopatrol": "Automatische Kontrolle",
+       "log-action-filter-protect-protect": "Schutz",
+       "log-action-filter-protect-modify": "Schutzveränderung",
+       "log-action-filter-protect-unprotect": "Freigaben",
+       "log-action-filter-upload-upload": "Neue Hochladung",
+       "log-action-filter-upload-overwrite": "Wiederhochladung"
 }
index 16d8c33..0141f08 100644 (file)
@@ -45,7 +45,8 @@
                        "Stam.nikos",
                        "Giorgos456",
                        "SucreRouge",
-                       "Gts-tg"
+                       "Gts-tg",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Υπογράμμιση συνδέσμων:",
        "recentchangeslinked-page": "Όνομα σελίδας:",
        "recentchangeslinked-to": "Εμφάνιση αλλαγών σε σελίδες συνδεδεμένες με την δεδομένη σελίδα αντί αυτής",
        "recentchanges-page-added-to-category": "Η σελίδα [[:$1]] προστέθηκε στην κατηγορία",
-       "recentchanges-page-added-to-category-bundled": "Η σελίδα [[:$1]] και {{PLURAL:$2|μία ακόμα σελίδα|$2 ακόμα σελίδες}} προστέθηκαν στην κατηγορία",
+       "recentchanges-page-added-to-category-bundled": "Η σελίδα [[:$1]] και [[Special:WhatLinksHere/$1|{{PLURAL:$2|μία ακόμα σελίδα|$2 ακόμα σελίδες}}]] προστέθηκαν στην κατηγορία",
        "recentchanges-page-removed-from-category": "Η σελίδα [[:$1]] αφαιρέθηκε από την κατηγορία",
        "recentchanges-page-removed-from-category-bundled": "Η σελίδα [[:$1]] και {{PLURAL:$2|μία ακόμα σελίδα|$2 ακόμα σελίδες}} αφαιρέθηκαν από την κατηγορία",
        "autochange-username": "Αυτόματη αλλαγή MediaWiki",
index c405b38..b7c0ac6 100644 (file)
        "special-characters-group-ipa": "IPA",
        "special-characters-group-symbols": "Symbols",
        "special-characters-group-greek": "Greek",
+       "special-characters-group-greekextended": "Greek extended",
        "special-characters-group-cyrillic": "Cyrillic",
        "special-characters-group-arabic": "Arabic",
        "special-characters-group-arabicextended": "Arabic extended",
        "sessionprovider-generic": "$1 sessions",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "cookie-based sessions",
        "sessionprovider-nocookies": "Cookies may be disabled. Ensure you have cookies enabled and start again.",
-       "randomrootpage": "Random root page"
+       "randomrootpage": "Random root page",
+       "log-action-filter-block": "Type of block:",
+       "log-action-filter-delete": "Type of deletion:",
+       "log-action-filter-patrol": "Type of patrol:",
+       "log-action-filter-protect": "Type of protection:",
+       "log-action-filter-upload": "Type of upload:",
+       "log-action-filter-all": "All",
+       "log-action-filter-block-block": "Block",
+       "log-action-filter-block-reblock": "Block modification",
+       "log-action-filter-block-unblock": "Unblock",
+       "log-action-filter-delete-delete": "Page deletion",
+       "log-action-filter-delete-restore": "Page undeletion",
+       "log-action-filter-delete-event": "Log deletion",
+       "log-action-filter-delete-revision": "Revision deletion",
+       "log-action-filter-patrol-patrol": "Manual patrol",
+       "log-action-filter-patrol-autopatrol": "Automatic patrol",
+       "log-action-filter-protect-protect": "Protection",
+       "log-action-filter-protect-modify": "Protection modification",
+       "log-action-filter-protect-unprotect": "Unprotection",
+       "log-action-filter-upload-upload": "New upload",
+       "log-action-filter-upload-overwrite": "Reupload"
 }
index 8e163a7..c675544 100644 (file)
        "botpasswords-label-resetpassword": "Rekomencigi la pasvorton",
        "botpasswords-label-restrictions": "Limigoj de uzado:",
        "botpasswords-bad-appid": "La robota nomo \"$1\" estas malvalida.",
+       "botpasswords-insert-failed": "Aldono de la robota nomo \"$1\" ne sukcesis. Ĉu ĝi jam estis aldonita?",
+       "botpasswords-update-failed": "Ĝisdatigo de la robota nomo \"$1\" ne sukcesis. Ĉu ĝi estis forigita?",
        "botpasswords-created-title": "Robota pasvorto kreita",
-       "botpasswords-created-body": "La robota pasvorto \"$1\" estis sukcese kreita.",
+       "botpasswords-created-body": "La robota pasvorto por robota nomo \"$1\" de la uzanto \"$2\" estis kreita.",
        "botpasswords-updated-title": "Robota pasvorto ĝisdatigita",
-       "botpasswords-updated-body": "La robota pasvorto \"$1\" estis sukcese ĝisdatigita.",
+       "botpasswords-updated-body": "La robota pasvorto por robota nomo \"$1\" de la uzanto \"$2\" estis ĝisdatigita.",
        "botpasswords-deleted-title": "Robota pasvorto forigita",
-       "botpasswords-deleted-body": "La robota pasvorto \"$1\" estis forigita.",
+       "botpasswords-deleted-body": "La robota pasvorto por robota nomo \"$1\" de la uzanto \"$2\" estis forigita.",
        "resetpass_forbidden": "Pasvortoj ne estas ŝanĝeblaj",
        "resetpass-no-info": "Vi devas ensaluti por atingi ĉi tiun paĝon rekte.",
        "resetpass-submit-loggedin": "Ŝanĝi pasvorton",
        "mergehistory-empty": "Neniuj versioj estas kunigeblaj.",
        "mergehistory-done": "$3 {{PLURAL:$3|versio|versioj}} de $1 sukcese estis {{PLURAL:$3|kunigita|kunigitaj}} en [[:$2]].",
        "mergehistory-fail": "Ne povis fari la historian kunigon; bonvolu konstati la paĝajn kaj tempajn parametrojn.",
+       "mergehistory-fail-bad-timestamp": "Tempomarko estas malvalida.",
        "mergehistory-fail-invalid-source": "Fonta paĝo estas malvalida.",
+       "mergehistory-fail-invalid-dest": "Cela paĝo estas malvalida.",
        "mergehistory-fail-toobig": "Ne eblas kunigi historiojn ĉar pli ol sojlo de $1 {{PLURAL:$1|revizio|revizioj}} estus {{PLURAL:$1|movita|movitaj}}.",
        "mergehistory-no-source": "Fontpaĝo $1 ne ekzistas.",
        "mergehistory-no-destination": "Celpaĝo $1 ne ekzistas.",
index d84ac8c..e9ccda5 100644 (file)
                        "YoViajo",
                        "Asierog",
                        "Mgpena",
-                       "Transonlohk"
+                       "Transonlohk",
+                       "Eloy"
                ]
        },
        "tog-underline": "Subrayar los enlaces:",
        "copyrightpage": "{{ns:project}}:Derechos de autor",
        "currentevents": "Actualidad",
        "currentevents-url": "Project:Actualidad",
-       "disclaimers": "Aviso legal",
+       "disclaimers": "Descargos",
        "disclaimerpage": "Project:Descargo general",
        "edithelp": "Ayuda de edición",
        "helppage-top-gethelp": "Ayuda",
        "nocookieslogin": "{{SITENAME}} utiliza <em>cookies</em> para la autenticación de usuarios. Las <em>cookies</em> están desactivadas en tu navegador. Por favor, actívalas e inténtalo de nuevo.",
        "nocookiesfornew": "No se pudo crear la cuenta de usuario, porque no pudimos confirmar su origen.\nAsegúrate de que tienes las cookies activadas, luego recarga esta página e inténtalo de nuevo.",
        "noname": "No se ha especificado un nombre de usuario válido.",
-       "loginsuccesstitle": "Has accedido correctamente",
+       "loginsuccesstitle": "Has accedido",
        "loginsuccess": "<strong>Has accedido a {{SITENAME}} como «$1».</strong>",
        "nosuchuser": "No existe ningún usuario llamado «$1».\nLos nombres de usuario son sensibles a las mayúsculas.\nRevisa tu ortografía, o [[Special:UserLogin/signup|crea una cuenta nueva]].",
        "nosuchusershort": "No existe ningún usuario llamado «$1». Comprueba que lo has escrito correctamente.",
        "botpasswords-label-delete": "Borrar",
        "botpasswords-label-resetpassword": "Restablecer la contraseña",
        "botpasswords-label-grants": "Permisos aplicables:",
+       "botpasswords-help-grants": "Cada concesión le da acceso a los permisos listados que el usuario ya posea. Véase la [[Special:ListGrants|lista de concesiones]] para más información.",
        "botpasswords-label-restrictions": "Restricciones de uso:",
        "botpasswords-label-grants-column": "Concedido",
        "botpasswords-bad-appid": "El nombre del bot \"$1\" no es válido.",
        "mergehistory-empty": "No hay revisiones fusionables.",
        "mergehistory-done": "Se {{PLURAL:$3|fusionó una revisión|fusionaron $3 revisiones}} de $1 en [[:$2]].",
        "mergehistory-fail": "No se puede realizar la fusión de historiales, por favor revisa la página y los parámetros de tiempo.",
+       "mergehistory-fail-bad-timestamp": "La marca de tiempo no es válida.",
        "mergehistory-fail-invalid-source": "La página de origen no es válida.",
        "mergehistory-fail-invalid-dest": "La página de destino no es válida.",
+       "mergehistory-fail-no-change": "La fusión historiales no fusionó ninguna revisión. Vuelve a comprobar los parámetros de página y tiempo.",
        "mergehistory-fail-permission": "Permisos insuficientes para fusionar el historial.",
        "mergehistory-fail-self-merge": "Las páginas de origen y destino son la misma.",
        "mergehistory-fail-toobig": "No se puede fusionar el historial ya que más del límite de $1 {{PLURAL:$1|revisión|revisiones}} se moverían.",
        "recentchangeslinked-page": "Nombre de la página:",
        "recentchangeslinked-to": "Mostrar los cambios en páginas enlazadas con la página seleccionada",
        "recentchanges-page-added-to-category": "[[:$1]] añadida a la categoría",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] y {{PLURAL:$2|una página|$2 páginas}} añadidas a la categoría",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] y [[Special:WhatLinksHere/$1|{{PLURAL:$2|una página añadida|$2 páginas añadidas}}]] a la categoría",
        "recentchanges-page-removed-from-category": "[[:$1]] eliminada de la categoría",
-       "recentchanges-page-removed-from-category-bundled": "[[:$1]] y {{PLURAL:$2|una página|$2 páginas}} eliminadas de la categoría",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] y [[Special:WhatLinksHere/$1|{{PLURAL:$2|una página eliminada|$2 páginas eliminadas}}]] de la categoría",
        "autochange-username": "Cambio automático de MediaWiki",
        "upload": "Subir archivo",
        "uploadbtn": "Subir un archivo",
        "uploaded-script-svg": "Se encontró el elemento habilitado para secuencias de órdenes «$1» en el archivo SVG cargado.",
        "uploaded-hostile-svg": "Se encontró código CSS no seguro en el elemento de estilo del archivo SVG cargado.",
        "uploaded-event-handler-on-svg": "No está permitido configurar atributos controladores de eventos <code>$1=\"$2\"</code> en los archivos SVG.",
-       "uploaded-href-unsafe-target-svg": "Se encontró un \"href\" hacia un destino inseguro <code><$1 $2=\"$3\"></code> en el archivo SVG cargado.",
+       "uploaded-href-attribute-svg": "Los atributos <code>href</code> en archivos SVG sólo tienen permitido enlazar a objetivos http:// o https://, se encontró <code>&lt;$1 $2=\"$3\"&gt;</code>.",
+       "uploaded-href-unsafe-target-svg": "Se encontró un <code>href</code> hacia un destino inseguro <code><$1 $2=\"$3\"></code> en el archivo SVG cargado.",
        "uploaded-animate-svg": "Se encontró un etiqueta \"animate\" que puede estar cambiando \"href\", mediante el atributo \"from\" <code>&lt;$1 $2=\"$3\"&gt;</code> en el archivo SVG cargado.",
        "uploaded-setting-event-handler-svg": "Está bloqueada la configuración de atributos controladores de eventos. Se encontró <code>&lt;$1 $2=\"$3\"&gt;</code> en el archivo SVG cargado.",
        "uploaded-setting-href-svg": "Está bloqueado el uso de la etiqueta \"set\" para añadir un atributo \"href\" al elemento padre.",
        "upload-options": "Opciones de subida",
        "watchthisupload": "Vigilar este archivo",
        "filewasdeleted": "Un archivo con este nombre se subió con anterioridad y posteriormente ha sido borrado. Deberías revisar el $1 antes de subirlo de nuevo.",
+       "filename-thumb-name": "Esto luce como el título de una miniatura. Por favor, no vuelva a subir miniaturas a la misma wiki. Si no es el caso, por favor corrija el nombre del archivo por uno que tenga más sentido, y no tenga el prefijo de miniatura.",
        "filename-bad-prefix": "El nombre del archivo que estás subiendo comienza por <strong>«$1»</strong>, un nombre nada descriptivo de su contenido. Es un típico nombre de los que asignan automáticamente las cámaras digitales.\nElige un nombre más descriptivo para tu archivo.",
        "filename-prefix-blacklist": " #<!-- deja esta línea exactamente como está --> <pre>\n# La sintaxis de esta página es la siguiente:\n#   * Todo texto que se encuentre después del carácter \"#\" hasta el final de la línea se tratará como un comentario y será ignorado\n#   * Cualquier línea que no esté en blanco será interpretada como un prefijo típico en nombres de archivo que suelen asignar automáticamente las cámaras digitales\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # algunos teléfonos móviles / celulares\nIMG # genérico\nJD # Jenoptik\nMGP # Pentax\nPICT # misc.\n #</pre> <!-- deja esta línea exactamente como está -->",
        "upload-proto-error": "Protocolo incorrecto",
        "uploadstash-badtoken": "No se pudo realizar la acción. Es posible que haya finalizado el tiempo de espera de la sesión. Inténtalo de nuevo.",
        "uploadstash-errclear": "Falló el borrado de los archivos.",
        "uploadstash-refresh": "Actualizar la lista de archivos",
+       "uploadstash-thumbnail": "ver miniatura",
        "invalid-chunk-offset": "Desplazamiento inválido del fragmento",
        "img-auth-accessdenied": "Acceso denegado",
        "img-auth-nopathinfo": "Falta PATH_INFO.\nEl servidor no está configurado para proporcionar esta información.\nEs posible que esté basado en CGI y que no sea compatible con img_auth.\nConsulte https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "apihelp": "Ayuda de la API",
        "apihelp-no-such-module": "No se encontró el módulo \"$1\".",
        "apisandbox": "Zona de pruebas API",
+       "apisandbox-jsonly": "Se requiere JavaScript para utilizar la zona de pruebas de API.",
        "apisandbox-api-disabled": "La API está desactivada en este sitio.",
-       "apisandbox-intro": "Usa esta página para experimentar con la '''API de servicio web de MediaWiki'''.\nPara más detalles sobre el uso de la API, visita [//www.mediawiki.org/wiki/API:Main_page su documentación]. Ejemplo: [//www.mediawiki.org/wiki/API#A_simple_example obtener el contenido de una Página principal]. Selecciona una acción para ver más ejemplos.\n\nObserva que, aunque sea una página de pruebas, las acciones que realices en esta página pueden modificar el wiki.",
+       "apisandbox-intro": "Usa esta página para experimentar con la <strong>API de servicio web de MediaWiki</strong>.\nPara más detalles sobre el uso de la API, visita [[mw:API:Main page|su documentación]]. Ejemplo: [//www.mediawiki.org/wiki/API#A_simple_example obtener el contenido de una Página principal]. Selecciona una acción para ver más ejemplos.\n\nObserva que, aunque sea una página de pruebas, las acciones que realices en esta página pueden modificar el wiki.",
        "apisandbox-fullscreen": "Expandir panel",
+       "apisandbox-fullscreen-tooltip": "Expande el panel de la zona de pruebas hasta llenar la ventana del navegador.",
        "apisandbox-unfullscreen": "Mostrar página",
+       "apisandbox-unfullscreen-tooltip": "Reduce el panel de la zona de pruebas, para que los enlaces de navegación MediaWiki estén disponibles.",
        "apisandbox-submit": "Realizar solicitud",
        "apisandbox-reset": "Limpiar",
        "apisandbox-retry": "Reintentar",
        "apisandbox-dynamic-parameters-add-placeholder": "Nombre del parámetro",
        "apisandbox-dynamic-error-exists": "Ya existe un parámetro llamado \"$1\".",
        "apisandbox-deprecated-parameters": "Parámetros desaconsejados",
+       "apisandbox-fetch-token": "Auto-llenar el token",
        "apisandbox-submit-invalid-fields-title": "Algunos campos no son válidos",
        "apisandbox-submit-invalid-fields-message": "Por favor, corrige los campos señalados e inténtalo de nuevo.",
        "apisandbox-results": "Resultados",
        "activeusers-hidesysops": "Ocultar administradores",
        "activeusers-noresult": "No se encontraron usuarios.",
        "activeusers-submit": "Mostrar usuarios activos",
-       "listgrouprights": "Permisos del grupo de usuarios",
-       "listgrouprights-summary": "La siguiente es una lista de los grupos de usuario definidos en esta wiki y de sus privilegios de acceso asociados.\nPuede haber información adicional sobre privilegios individuales en [[{{MediaWiki:Listgrouprights-helppage}}]]",
+       "listgrouprights": "Permisos de los grupos de usuarios",
+       "listgrouprights-summary": "La siguiente es una lista de los grupos de usuarios definidos en esta wiki y de sus permisos de acceso asociados.\nPuede haber [[{{MediaWiki:Listgrouprights-helppage}}|información adicional]] sobre permisos individuales.",
        "listgrouprights-key": "Leyenda:\n* <span class=\"listgrouprights-granted\">Derecho concedido</span>\n* <span class=\"listgrouprights-revoked\">Derecho revocado</span>",
        "listgrouprights-group": "Grupo",
        "listgrouprights-rights": "Derechos",
-       "listgrouprights-helppage": "Help:Derechos de grupos",
+       "listgrouprights-helppage": "Help:Permisos de grupos",
        "listgrouprights-members": "(ver los miembros de este grupo)",
        "listgrouprights-addgroup": "Agregar {{PLURAL:$2|grupo|grupos}}: $1",
        "listgrouprights-removegroup": "Eliminar {{PLURAL:$2|grupo|grupos}}: $1",
        "listgrouprights-namespaceprotection-header": "Restricciones del espacio de nombres",
        "listgrouprights-namespaceprotection-namespace": "Espacio de nombres",
        "listgrouprights-namespaceprotection-restrictedto": "Derechos de usuario para editar",
-       "listgrants": "Subvenciones",
+       "listgrants": "Concesiones",
+       "listgrants-summary": "La siguiente es una lista de concesiones con sus permisos de usuario asociados. Los usuarios pueden autorizar aplicaciones para que usen sus cuentas, pero con permisos limitados basados en las concesiones que el usuario le dio a la aplicación. De todas formas, una aplicación actuando a nombre de un usuario no puede hacer uso de permisos que el usuario no posea.\nPuede haber [[{{MediaWiki:Listgrouprights-helppage}}|información adicional]] sobre permisos individuales.",
        "listgrants-grant": "Conceder",
        "listgrants-rights": "Derechos",
        "trackingcategories": "Categorías de seguimiento",
        "sp-contributions-uploads": "subidas",
        "sp-contributions-logs": "registros",
        "sp-contributions-talk": "discusión",
-       "sp-contributions-userrights": "gestión de permisos del usuario",
+       "sp-contributions-userrights": "gestión de permisos de usuario",
        "sp-contributions-blocked-notice": "Este usuario está actualmente bloqueado. La última entrada del registro de bloqueos es presentada debajo para mayor referencia:",
        "sp-contributions-blocked-notice-anon": "Esta dirección IP se encuentra actualmente bloqueada.\nA continuación se muestra la última entrada del registro de bloqueos para mayor referencia.",
        "sp-contributions-search": "Buscar contribuciones",
        "months": "{{PLURAL:$1|$1 mes|$1 meses}}",
        "years": "{{PLURAL:$1|$1 año|$1 años}}",
        "ago": "hace $1",
-       "just-now": "Ahora mismo",
+       "just-now": "ahora mismo",
        "hours-ago": "hace $1 {{PLURAL:$1|hora|horas}}",
        "minutes-ago": "hace {{PLURAL:$1|un minuto|$1 minutos}}",
        "seconds-ago": "hace $1 {{PLURAL:$1|segundo|segundos}}",
-       "monday-at": "El lunes a las $1",
-       "tuesday-at": "El martes a las $1",
-       "wednesday-at": "El miércoles a las $1",
-       "thursday-at": "El jueves a las $1",
-       "friday-at": "El viernes a las $1",
-       "saturday-at": "El sábado a las $1",
-       "sunday-at": "El domingo a las $1",
-       "yesterday-at": "Ayer a las $1",
+       "monday-at": "el lunes a las $1",
+       "tuesday-at": "el martes a las $1",
+       "wednesday-at": "el miércoles a las $1",
+       "thursday-at": "el jueves a las $1",
+       "friday-at": "el viernes a las $1",
+       "saturday-at": "el sábado a las $1",
+       "sunday-at": "el domingo a las $1",
+       "yesterday-at": "ayer a las $1",
        "bad_image_list": "El formato es el siguiente:\n\nSolo se reconocen elementos de lista (líneas que comienzan con «*»).\nEl primer enlace de cada línea debe ser un enlace al archivo que se quiere bloquear.\nTodos los demás enlaces en la misma línea se tomarán como excepciones (es decir, páginas donde sí se puede usar el archivo).",
        "metadata": "Metadatos",
        "metadata-help": "Este archivo contiene información adicional, probablemente añadida por la cámara digital o el escáner usado para crearlo o digitalizarlo.\nSi el archivo ha sido modificado desde su estado original, pueden haberse perdido algunos detalles.",
        "mw-widgets-titleinput-description-new-page": "la página aún no existe",
        "mw-widgets-titleinput-description-redirect": "redirigir a $1",
        "api-error-blacklisted": "Elige un título diferente, más descriptivo.",
-       "sessionmanager-tie": "No se pueden combinar múltiples tipos de autentificación de solicitudes: $1",
+       "sessionmanager-tie": "No se pueden combinar múltiples tipos de autenticación de solicitudes: $1.",
        "sessionprovider-generic": "sesiones $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sesiones basadas en cookies",
        "sessionprovider-nocookies": "Puede que las cookies estén desactivadas. Actívalas y comienza de nuevo.",
-       "randomrootpage": "Página raíz aleatoria"
+       "randomrootpage": "Página raíz aleatoria",
+       "log-action-filter-block": "Tipo de bloqueo:",
+       "log-action-filter-delete": "Tipo de eliminación:",
+       "log-action-filter-patrol": "Tipo de verificación:",
+       "log-action-filter-protect": "Tipo de protección:",
+       "log-action-filter-upload": "Tipo de subida:",
+       "log-action-filter-all": "Todas",
+       "log-action-filter-block-block": "Bloquear",
+       "log-action-filter-block-reblock": "Modificación de bloqueo",
+       "log-action-filter-block-unblock": "Desbloquear",
+       "log-action-filter-delete-delete": "Eliminación de páginas",
+       "log-action-filter-delete-restore": "Restauración de páginas",
+       "log-action-filter-delete-event": "Eliminación de registros",
+       "log-action-filter-delete-revision": "Eliminación de revisión",
+       "log-action-filter-patrol-patrol": "Verificación manual",
+       "log-action-filter-patrol-autopatrol": "Verificación automática",
+       "log-action-filter-protect-protect": "Protección",
+       "log-action-filter-protect-modify": "Modificación de protección",
+       "log-action-filter-protect-unprotect": "Desprotección",
+       "log-action-filter-upload-upload": "Subida nueva",
+       "log-action-filter-upload-overwrite": "Volver a subir"
 }
index 5ce1955..ad15418 100644 (file)
        "recentchangeslinked-page": "Lehekülje nimi:",
        "recentchangeslinked-to": "Näita hoopis muudatusi lehekülgedel, mis sellele lehele lingivad",
        "recentchanges-page-added-to-category": "kategooriasse lisatud \"[[:$1]]\"",
-       "recentchanges-page-added-to-category-bundled": "kategooriasse lisatud \"[[:$1]]\" ja veel {{PLURAL:$2|üks lehekülg|$2 lehekülge}}",
+       "recentchanges-page-added-to-category-bundled": "kategooriasse lisatud \"[[:$1]]\" ja veel [[Special:WhatLinksHere/$1|{{PLURAL:$2|üks lehekülg|$2 lehekülge}}]]",
        "recentchanges-page-removed-from-category": "kategooriast eemaldatud \"[[:$1]]\"",
        "recentchanges-page-removed-from-category-bundled": "kategooriast eemaldatud \"[[:$1]]\" ja veel {{PLURAL:$2|üks lehekülg|$2 lehekülge}}",
        "autochange-username": "MediaWiki automaatne muudatus",
index cf13d37..e018dca 100644 (file)
        "recentchanges-noresult": "هیچ تغییری در طول دورهٔ تعیین‌شده با این معیارها هم‌خوانی نداشت.",
        "recentchanges-feed-description": "آخرین تغییرات ویکی را در این خوراک پی‌گیری کنید.",
        "recentchanges-label-newpage": "این ویرایش صفحه‌ای تازه ایجاد کرد",
-       "recentchanges-label-minor": "این یک ویرایش جزئیاست",
+       "recentchanges-label-minor": "این یک ویرایش جزئی است",
        "recentchanges-label-bot": "این ویرایش را یک ربات انجام داده است",
        "recentchanges-label-unpatrolled": "این ویرایش هنوز گشت‌زنی نشده است",
        "recentchanges-label-plusminus": "حجم صفحه به اندازه این مقدار بایت تغییر یافته است",
        "recentchangeslinked-page": "نام صفحه:",
        "recentchangeslinked-to": "نمایش تغییرات صفحه‌هایی که به صفحهٔ داده‌شده پیوند دارند",
        "recentchanges-page-added-to-category": "[[:$1]] به رده اضافه شد",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] و {{PLURAL:$2|یک صفحه|$2 صفحه}}ٔ دیگر به رده اضافه شدند",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] و [[Special:WhatLinksHere/$1|{{PLURAL:$2|یک صفحه|$2 صفحه}}]]دیگر به رده اضافه شدند",
        "recentchanges-page-removed-from-category": "[[:$1]] از رده حذف شد",
-       "recentchanges-page-removed-from-category-bundled": "[[:$1]] و {{PLURAL:$2|یک صفحه|$2 صفحه}}ٔ دیگر از رده حذف شدند",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] و [[Special:WhatLinksHere/$1|{{PLURAL:$2|یک صفحه|$2 صفحه}}]] دیگر از رده حذف شدند",
        "autochange-username": "تغییرات خودکار مدیاویکی",
        "upload": "بارگذاری پرونده",
        "uploadbtn": "بارگذاری پرونده",
        "uploadstash-badtoken": "انجام این اقدام ناموفق بود، احتمالاً به این دلیل که اعتبار ویرایش شما به اتمام رسیده است. لطفاً دوباره امتحان کنید.",
        "uploadstash-errclear": "پاک‌کردن پرونده‌ها ناموفق بود.",
        "uploadstash-refresh": "تازه کردن فهرست پرونده‌ها",
+       "uploadstash-thumbnail": "نمایش بندانگشتی",
        "invalid-chunk-offset": "جابجایی نامعتبر قطعه",
        "img-auth-accessdenied": "منع دسترسی",
        "img-auth-nopathinfo": "PATH_INFO موجود نیست.\nسرور شما برای ردکردن این مقدار تنظیم نشده‌است.\nممکن است مبتنی بر سی‌جی‌آی باشد و از img_auth پشتیبانی نکند.\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization را ببینید.",
        "sessionprovider-generic": "$1 فصل",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "فصل‌های کوکی‌محور",
        "sessionprovider-nocookies": "کوکی‌ها ممکن است غیر فعال شده باشند. اطمینان کسب کنید که کوکی‌ها را فعال کرده‌اید و دوباره آغاز کنید.",
-       "randomrootpage": "صفحهٔ ریشهٔ تصادفی"
+       "randomrootpage": "صفحهٔ ریشهٔ تصادفی",
+       "log-action-filter-block": "نوع بسته شدن:",
+       "log-action-filter-delete": "نوع حذف:",
+       "log-action-filter-patrol": "نوع گشت:",
+       "log-action-filter-protect": "نوع محافظت",
+       "log-action-filter-upload": "نوع بارگذاری",
+       "log-action-filter-all": "همه",
+       "log-action-filter-block-block": "بستن",
+       "log-action-filter-block-unblock": "باز شدن",
+       "log-action-filter-delete-delete": "حذف صفحه",
+       "log-action-filter-delete-restore": "احیای صفحه",
+       "log-action-filter-delete-event": "حذف سیاهه",
+       "log-action-filter-patrol-autopatrol": "گشت خودکار",
+       "log-action-filter-protect-protect": "محافظت",
+       "log-action-filter-protect-unprotect": "خروج از محافظت",
+       "log-action-filter-upload-overwrite": "بارگذاری دوباره"
 }
index 126c430..7e301a8 100644 (file)
@@ -47,7 +47,8 @@
                        "Macofe",
                        "Beluga",
                        "Pyscowicz",
-                       "Olimar"
+                       "Olimar",
+                       "Mikahama"
                ]
        },
        "tog-underline": "Linkkien alleviivaus:",
        "botpasswords-label-delete": "Poista",
        "botpasswords-label-resetpassword": "Uudista salasana",
        "botpasswords-label-grants": "Valittavissa olevat toimintaoikeudet:",
-       "botpasswords-label-restrictions": "Käytön rajoitukset:",
+       "botpasswords-label-restrictions": "Käytrajoitukset:",
        "resetpass_forbidden": "Salasanoja ei voi vaihtaa.",
        "resetpass-no-info": "Et voi nähdä tätä sivua kirjautumatta sisään.",
        "resetpass-submit-loggedin": "Muuta salasana",
        "recentchangeslinked-page": "Sivun nimi:",
        "recentchangeslinked-to": "Näytä sen sijaan muutokset sivuihin, joista on linkki tähän sivuun",
        "recentchanges-page-added-to-category": "[[:$1]] lisätty luokkaan",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] ja {{PLURAL:$2|one page|$2 pages}} lisätty luokkaan",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] ja [[Special:WhatLinksHere/$1|{{PLURAL:$2|yksi sivu|$2 sivua}}]] lisätty luokkaan",
        "recentchanges-page-removed-from-category": "[[:$1]] poistettu luokasta",
-       "recentchanges-page-removed-from-category-bundled": "[[:$1]] ja {{PLURAL:$2|one page|$2 pages}} poistettu luokasta",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] ja [[Special:WhatLinksHere/$1|{{PLURAL:$2|yksi sivu|$2 sivua}}]] poistettu luokasta",
        "autochange-username": "MediaWiki automaattinen muutos",
        "upload": "Tallenna tiedosto",
        "uploadbtn": "Tallenna tiedosto",
        "uploadstash-badtoken": "Toiminnon suoritus epäonnistui. Tähän voi olla syynä muokkausvaltuuksien vanhentuminen. Yritä uudelleen.",
        "uploadstash-errclear": "Muistin tyhjennys epäonnistui.",
        "uploadstash-refresh": "Päivitä tiedostoluettelo",
+       "uploadstash-thumbnail": "näytä pienoiskuva",
        "invalid-chunk-offset": "Kelpaamaton siirtymä lohkoissa",
        "img-auth-accessdenied": "Pääsy estetty",
        "img-auth-nopathinfo": "PATH_INFO puuttuu.\nPalvelintasi ei ole asetettu välittämään tätä tietoa.\nSe saattaa olla CGI-pohjainen eikä voi tukea img_authia.\nLisätietoja löytyy sivulta https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "statistics-header-hooks": "Muut tilastot",
        "statistics-articles": "Sisältösivuja",
        "statistics-pages": "Sivuja",
-       "statistics-pages-desc": "Kaikki sivut, sisältäen keskustelusivut, ohjaukset ja muut.",
+       "statistics-pages-desc": "Kaikki wikissä olevat sivut, mukaan lukien keskustelusivut, ohjaussivut ynnä muut.",
        "statistics-files": "Tallennettuja tiedostoja",
        "statistics-edits": "Muokkauksia {{GRAMMAR:genitive|{{SITENAME}}}} perustamisen jälkeen",
-       "statistics-edits-average": "Keskimäärin yhtä sivua muokattu",
+       "statistics-edits-average": "Muokkausten keskiarvo yhdellä sivulla",
        "statistics-users": "Rekisteröityneitä [[Special:ListUsers|käyttäjiä]]",
        "statistics-users-active": "Aktiivisia käyttäjiä",
        "statistics-users-active-desc": "Käyttäjät, jotka ovat suorittaneet jonkin toiminnon {{PLURAL:$1|edellisen päivän|edellisten $1 päivän}} aikana.",
        "apisandbox-api-disabled": "API on poistettu käytöstä tällä sivustolla.",
        "apisandbox-intro": "Tämä on '''MediaWiki API:n''' hiekkalaatikko.\n[//www.mediawiki.org/wiki/API:Main_page API-dokumentaatio] kertoo lisää API:en käytöstä.",
        "apisandbox-fullscreen": "Laajenna paneeli",
-       "apisandbox-unfullscreen": "Näytä sivu",
+       "apisandbox-unfullscreen": "Palaa sivunäkymään",
        "apisandbox-submit": "Tee pyyntö",
        "apisandbox-reset": "Tyhjennä",
        "apisandbox-retry": "Yritä uudestaan",
index bcea637..9859a05 100644 (file)
        "viewyourtext": "Vous pouvez voir et copier le contenu de <strong>vos modifications</strong> à cette page.",
        "protectedinterface": "Cette page fournit du texte d'interface pour le logiciel sur ce wiki, et est protégée pour éviter les abus.\nPour ajouter ou modifier des traductions sur tous les wikis, veuillez utiliser [//translatewiki.net/ translatewiki.net], le projet de localisation de MediaWiki.",
        "editinginterface": "<strong>Attention :</strong> vous êtes en train de modifier une page utilisée pour créer le texte de l’interface du logiciel.\nLes changements sur cette page se répercuteront sur l’apparence de l’interface utilisateur pour les autres utilisateurs de ce wiki.",
-       "translateinterface": "Pour ajouter ou modifier des traductions pour tous les wikis, veuillez utiliser [//translatewiki.net/ translatewiki.net], le projet de localisation de MédiaWiki.",
+       "translateinterface": "Pour ajouter ou modifier des traductions pour tous les wikis, veuillez utiliser [//translatewiki.net/ translatewiki.net], le projet de localisation de MediaWiki.",
        "cascadeprotected": "Cette page est protégée contre les modifications car elle est transcluse par {{PLURAL:$1|la page suivante, qui a été protégée|les pages suivantes, qui ont été protégées}} avec l’option « protection en cascade » activée :\n$2",
        "namespaceprotected": "Vous n'avez pas la permission de modifier les pages de l'espace de noms « '''$1''' ».",
        "customcssprotected": "Vous n'avez pas la permission de modifier cette page de CSS, car elle contient les paramètres personnels d'un autre utilisateur.",
        "rows": "Rangées :",
        "columns": "Colonnes :",
        "searchresultshead": "Filtrer avec cette valeur",
-       "stub-threshold": "Seuil pour le formatage des liens bouchons ($1) :",
+       "stub-threshold": "Seuil pour le formatage des liens d’ébauche ($1) :",
        "stub-threshold-sample-link": "exemple",
        "stub-threshold-disabled": "Désactivé",
        "recentchangesdays": "Nombre de jours à afficher dans les modifications récentes :",
        "grant-createaccount": "Créer des comptes",
        "grant-createeditmovepage": "Créer, modifier et déplacer des pages",
        "grant-delete": "Supprimer les pages, les révisions et les entrées du journal",
-       "grant-editinterface": "Modifier l’espace de noms MédiaWiki et le CSS/JavaScript utilisateur",
+       "grant-editinterface": "Modifier l’espace de noms MediaWiki et le CSS/JavaScript utilisateur",
        "grant-editmycssjs": "Modifier votre CSS/JavaScript utilisateur",
        "grant-editmyoptions": "Modifier vos préférences utilisateur",
        "grant-editmywatchlist": "Modifier votre liste de suivi",
        "recentchanges-page-added-to-category-bundled": "[[:$1]] et [[Special:WhatLinksHere/$1|{{PLURAL:$2|une page ajoutée|$2 pages ajoutées}}]] à la catégorie",
        "recentchanges-page-removed-from-category": "[[:$1]] supprimé de la catégorie",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] et [[Special:WhatLinksHere/$1|{{PLURAL:$2|une page|$2 pages}}]] {{PLURAL:$2|retirée|retirées}} de la catégorie",
-       "autochange-username": "Modification automatique de MédiaWiki",
+       "autochange-username": "Modification automatique de MediaWiki",
        "upload": "Importer un fichier",
        "uploadbtn": "Importer le fichier",
        "reuploaddesc": "Annuler et retourner au formulaire d'import",
        "uploadstash-badtoken": "L’exécution de cette action a échoué, peut-être parce que vos informations d’identification ont expiré. Veuillez réessayer.",
        "uploadstash-errclear": "La suppression des fichiers a échoué.",
        "uploadstash-refresh": "Actualiser la liste des fichiers",
+       "uploadstash-thumbnail": "afficher la vignette",
        "invalid-chunk-offset": "Offset de segment non valide",
        "img-auth-accessdenied": "Accès refusé",
        "img-auth-nopathinfo": "PATH_INFO manquant.\nVotre serveur n'est pas paramétré pour transmettre cette information.\nIl fonctionne peut-être en CGI et ne supporte pas img_auth.\nVoir : https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "apisandbox-fullscreen": "Développer le panneau",
        "apisandbox-fullscreen-tooltip": "Étendre le panneau du bac à sable pour remplir la fenêtre du navigateur.",
        "apisandbox-unfullscreen": "Afficher la page",
-       "apisandbox-unfullscreen-tooltip": "Réduire le panneau du bac à sable, pour que les liens de navigation de MédiaWiki soient disponibles.",
+       "apisandbox-unfullscreen-tooltip": "Réduire le panneau du bac à sable, pour que les liens de navigation de MediaWiki soient disponibles.",
        "apisandbox-submit": "Faire la demande",
        "apisandbox-reset": "Effacer",
        "apisandbox-retry": "Réessayer",
        "sessionprovider-generic": "sessions $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sessions basées sur les cookies",
        "sessionprovider-nocookies": "Les cookies peuvent être désactivés. Assurez-vous que vous avez activé les cookies et recommencez.",
-       "randomrootpage": "Page racine aléatoire"
+       "randomrootpage": "Page racine aléatoire",
+       "log-action-filter-block": "Type de blocage :",
+       "log-action-filter-delete": "Type de suppression :",
+       "log-action-filter-patrol": "Type de patrouille :",
+       "log-action-filter-protect": "Type de protection :",
+       "log-action-filter-upload": "Type de téléchargement:",
+       "log-action-filter-all": "Tout",
+       "log-action-filter-block-block": "Bloc",
+       "log-action-filter-block-reblock": "Modification de bloc",
+       "log-action-filter-block-unblock": "Débloquer",
+       "log-action-filter-delete-delete": "Suppression de pages",
+       "log-action-filter-delete-restore": "Restitution de page",
+       "log-action-filter-delete-event": "Suppression du journal",
+       "log-action-filter-delete-revision": "Supression de révison",
+       "log-action-filter-patrol-patrol": "Patrouille manuelle",
+       "log-action-filter-patrol-autopatrol": "Patrouille automatique",
+       "log-action-filter-protect-protect": "Protection",
+       "log-action-filter-protect-modify": "Modification de la protection",
+       "log-action-filter-protect-unprotect": "Levée de la protection",
+       "log-action-filter-upload-upload": "Nouveau téléversement",
+       "log-action-filter-upload-overwrite": "Reitérer le téléversement"
 }
index f58c6f2..41227b0 100644 (file)
@@ -16,7 +16,7 @@
        "tog-hidepatrolled": "Cachiér los changements gouardâs dedens los dèrriérs changements",
        "tog-newpageshidepatrolled": "Cachiér les pâges gouardâyes dedens la lista de les pâges novèles",
        "tog-hidecategorization": "Cachiér la catègorisacion de les pâges",
-       "tog-extendwatchlist": "Èpatar la lista de gouârda por montrar tôs los changements et pas ren que los ples novéls",
+       "tog-extendwatchlist": "Èpatar la lista de gouârda por montrar tôs los changements et pas mas que los ples novéls",
        "tog-usenewrc": "Rassemblar los changements per pâge dedens los dèrriérs changements et la lista de gouârda",
        "tog-numberheadings": "Numerotar ôtomaticament los titros de sèccion",
        "tog-showtoolbar": "Montrar la bârra d’outils de changement",
        "tog-uselivepreview": "Empleyér l’apèrçu rapido",
        "tog-forceeditsummary": "Mè balyér na semonce quand j’é pas buchiê de rèsumâ de changement",
        "tog-watchlisthideown": "Cachiér mos changements dedens la lista de gouârda",
-       "tog-watchlisthidebots": "Cachiér los changements fêts per des robots dedens la lista de gouârda",
+       "tog-watchlisthidebots": "Cachiér los changements fêts per los robots dedens la lista de gouârda",
        "tog-watchlisthideminor": "Cachiér los petiôts changements dedens la lista de gouârda",
-       "tog-watchlisthideliu": "Cachiér los changements fêts per des utilisators branchiês dedens la lista de gouârda",
+       "tog-watchlisthideliu": "Cachiér los changements fêts per los utilisators branchiês dedens la lista de gouârda",
        "tog-watchlistreloadautomatically": "Rechargiér ôtomaticament la lista de gouârda quand los chouèx de filtrâjo sont changiês (JavaScript nècèssèro)",
-       "tog-watchlisthideanons": "Cachiér los changements fêts per des utilisators anonimos dedens la lista de gouârda",
+       "tog-watchlisthideanons": "Cachiér los changements fêts per los utilisators anonimos dedens la lista de gouârda",
        "tog-watchlisthidepatrolled": "Cachiér los changements gouardâs dedens la lista de gouârda",
        "tog-watchlisthidecategorization": "Cachiér la catègorisacion de les pâges",
        "tog-ccmeonemails": "Mè mandar na copia des mèssâjos que mando ux ôtros utilisators",
@@ -52,7 +52,7 @@
        "tog-showhiddencats": "Montrar les catègories cachiêes",
        "tog-norollbackdiff": "Pas fâre vêre la dif sur na rèvocacion",
        "tog-useeditwarning": "Mè balyér na semonce quand quito na pâge de changement sen encartar los changements",
-       "tog-prefershttps": "Empleyér tot lo temps un branchement sècurisâ en étent branchiê(e)",
+       "tog-prefershttps": "Empleyér tot lo temps un branchement sècurisâ en étent branchiê",
        "underline-always": "Tot lo temps",
        "underline-never": "Jamés",
        "underline-default": "Valor per dèfôt de l’habelyâjo du navegator",
        "pagecategories": "Catègori{{PLURAL:$1|a|es}}",
        "category_header": "Pâges dedens la catègoria « $1 »",
        "subcategories": "Sot-catègories",
-       "category-media-header": "Fichiérs multimèdiâ dedens la catègoria « $1 »",
-       "category-empty": "<em>Ora cela catègoria contint gins de pâge de fichiér multimèdiâ.</em>",
+       "category-media-header": "Mèdiâ dedens la catègoria « $1 »",
+       "category-empty": "<em>Ora cela catègoria contint gins de pâge de mèdiâ.</em>",
        "hidden-categories": "{{PLURAL:$1|Catègoria cachiêe|Catègories cachiêes}}",
        "hidden-category-category": "Catègories cachiêes",
        "category-subcat-count": "Cela catègoria at {{PLURAL:$2|mas que cela sot-catègoria-que.|{{PLURAL:$1|cela sot-catègoria|celes $1 sot-catègories}}-que, sur na soma de $2.}}",
        "qbedit": "Changiér",
        "qbpageoptions": "Cela pâge",
        "qbmyoptions": "Mes pâges",
-       "faq": "Quèstions sovent posâyes",
-       "faqpage": "Project:Quèstions sovent posâyes",
+       "faq": "Quèstions sovent pôses",
+       "faqpage": "Project:Quèstions sovent pôses",
        "actions": "Accions",
        "namespaces": "Èspâços de noms",
        "variants": "Vèrsions",
        "viewdeleted": "Vos voléd vêre $1 ?",
        "restorelink": "{{PLURAL:$1|un changement suprimâ|$1 changements suprimâs}}",
        "feedlinks": "Flux :",
-       "feed-invalid": "Tipo d’abonement du flux pas justo.",
+       "feed-invalid": "Tipo d’abonament du flux pas justo.",
        "feed-unavailable": "Los flux de sindicacion sont pas disponiblos",
        "site-rss-feed": "Flux RSS de $1",
        "site-atom-feed": "Flux Atom de $1",
        "sort-ascending": "Betar en ôrdre crèssent",
        "nstab-main": "Pâge",
        "nstab-user": "Pâge utilisator",
-       "nstab-media": "Fichiér multimèdiâ",
+       "nstab-media": "Pâge mèdiâ",
        "nstab-special": "Pâge spèciâla",
        "nstab-project": "Pâge projèt",
        "nstab-image": "Fichiér",
        "nocookieslogin": "{{SITENAME}} emplèye de raportiors (<em>cookies</em>) por lo branchement mas vos los éd dèsactivâs.\nSe vos plét, activâd-los et pués tornâd èprovar.",
        "nocookiesfornew": "Lo comptio utilisator est pas étâ fêt, nos ens pas possu confirmar son origina.\nControlâd que vos éd activâ los raportiors (<em>cookies</em>), rechargiéd la pâge et pués tornâd èprovar.",
        "noname": "Vos éd pas spècifiâ un nom d’utilisator justo.",
-       "loginsuccesstitle": "Branchiê(e)",
+       "loginsuccesstitle": "Branchiê",
        "loginsuccess": "<strong>Ora vos éte branchiê{{GENDER:$1||e}} a {{SITENAME}} coment « $1 ».</strong>",
        "nosuchuser": "Y at gins d’utilisator avouéc lo nom « $1 ».\nLos noms d’utilisator sont sensiblos a la câssa.\nSe vos plét, controlâd l’ortografia ou ben [[Special:UserLogin/signup|féte un comptio novél]].",
        "nosuchusershort": "Y at gins d’utilisator avouéc lo nom « $1 ».\nSe vos plét, controlâd l’ortografia.",
        "passwordsent": "Un contresegno novél est étâ mandâ a l’adrèce èlèctronica de l’utilisator « $1 ».\nSe vos plét, tornâd-vos branchiér aprés l’avêr reçu.",
        "blocked-mailpassword": "Voutron adrèce IP est blocâye en ècritura, la fonccion de sovegnence du contresegno est vêr dèsactivâye por èvitar los abus.",
        "eauthentsent": "Un mèssâjo de confirmacion est étâ mandâ a l’adrèce èlèctronica spècifiâye.\nDevant qu’un ôtro mèssâjo seye mandâ a cél comptio, vos devréd siuvre les enstruccions du mèssâjo et pués confirmar que lo comptio est franc lo voutro.",
-       "throttled-mailpassword": "Un mèssâjo de remês’a zérô de voutron contresegno est ja étâ mandâ pendent {{PLURAL:$1|l’hora passâye|les $1 hores passâyes}}.\nPor èvitar los abus, ren que yon serat mandâ per {{PLURAL:$1|hora|entèrvalo de $1 hores}}.",
+       "throttled-mailpassword": "Un mèssâjo de remês’a zérô de voutron contresegno est ja étâ mandâ pendent {{PLURAL:$1|l’hora passâye|les $1 hores passâyes}}.\nPor èvitar los abus, mas que yon serat mandâ per {{PLURAL:$1|hora|entèrvalo de $1 hores}}.",
        "mailerror": "Fôta pendent l’èxpèdicion du mèssâjo : $1",
        "acct_creation_throttle_hit": "Des vesitors de cél vouiqui qu’emplèyont voutron adrèce IP ant fêt $1 comptio{{PLURAL:$1||s}} pendent lo jorn passâ, cen qu’est lo més ôtorisâ dens ceti temps.\nDu côp los vesitors qu’emplèyont cel’adrèce IP pôvont fâre gins de comptio por lo moment.",
        "emailauthenticated": "Voutron adrèce èlèctronica est étâye confirmâye lo $2 a $3.",
        "image_sample": "Ègzemplo.jpg",
        "image_tip": "Fichiér apondu",
        "media_sample": "Ègzemplo.ogg",
-       "media_tip": "Lim de vers un fichiér multimèdiâ",
+       "media_tip": "Lim de vers un fichiér",
        "sig_tip": "Voutra signatura avouéc l’horodatâjo",
        "hr_tip": "Legne plana (pas nen abusar)",
        "summary": "Rèsumâ :",
        "previewconflict": "Cél apèrçu fât vêre lo tèxto de la zona de changement de d’amont coment aparêtrat se vos chouèsésséd de l’encartar.",
        "session_fail_preview": "Dèsolâ ! Nos povens pas encartar voutron changement a côsa d’una pèrda d’enformacions sur voutra sèssion.\n\nPôt-étre vos éte étâ dèbranchiê. <strong>Se vos plét, controlâd que vos éte adés branchiê et pués tornâd èprovar.</strong>\nSe cen tôrne pas reussir, èprovâd de vos [[Special:UserLogout|dèbranchiér]] et pués de vos tornar branchiér, et controlâd que voutron navegator accèpte los raportiors (<em>cookies</em>) de cél seto.",
        "session_fail_preview_html": "Dèsolâ ! Nos povens pas encartar voutron changement a côsa d’una pèrda d’enformacions sur voutra sèssion.\n\n<em>Perce que {{SITENAME}} at activâ l’HTML bruto, l’apèrçu est étâ cachiê por prèvegnir les ataques per JavaScript.</em>\n\n<strong>Se l’èprôva de changement est lèg·itima, se vos plét tornâd èprovar.</strong>\nSe cen tôrne pas reussir, èprovâd de vos [[Special:UserLogout|dèbranchiér]] et pués de vos tornar branchiér, et controlâd que voutron navegator accèpte los raportiors (<em>cookies</em>) de cél seto.",
-       "token_suffix_mismatch": "<strong>Voutron changement est pas étâ accèptâ, voutron cliant at mècllâ los caractèros de ponctuacion dedens lo jeton de changement.</strong>\nLo changement est étâ refusâ por empachiér la corrupcion du tèxto de la pâge.\nDes côps cél problèmo arreve quand vos empleyéd un sèrviço de sèrvior mandatèro (<em>proxy</em>) Vouèbe anonimo qu’est pas de sûr.",
+       "token_suffix_mismatch": "<strong>Voutron changement est pas étâ accèptâ, voutron cliant at mècllo los caractèros de ponctuacion dedens lo jeton de changement.</strong>\nLo changement est étâ refusâ por empachiér la corrupcion du tèxto de la pâge.\nDes côps cél problèmo arreve quand vos empleyéd un sèrviço de sèrvior mandatèro (<em>proxy</em>) Vouèbe anonimo qu’est pas de sûr.",
        "edit_form_incomplete": "<strong>Doux-três parties du formulèro de changement ant pas avengiê lo sèrvior ; controlâd que voutros changements sont entactos et pués tornâd èprovar.</strong>",
        "editing": "Changement de $1",
        "creating": "Crèacion de $1",
        "copyrightwarning": "Se vos plét, notâd que totes les contribucions a {{SITENAME}} sont considèrâyes coment publeyêes desot los tèrmos de la $2 (vêde $1 por més de dètalys).\nSe vos voléd pas que voutros ècrits seyont changiês sen pediêt et pués redistribuâs a volontât, adonc mandâd-los pas ique.<br />\nVos nos assurâd asse-ben que vos éd cen ècrit vos-mémo ou ben que vos l’éd copiyê d’una sôrsa que vint du domêno publico ou d’un’ôtra ressôrsa libra.\n<strong>Empleyéd gins d’ôvra desot drêt d’ôtor sen pèrmission èxprèssa !</strong>",
        "copyrightwarning2": "Se vos plét, notâd que totes les contribucions a {{SITENAME}} pôvont étre changiêes enlevâyes per d’ôtros contributors.\nSe vos voléd pas que voutros ècrits seyont changiês sen pediêt, adonc mandâd-los pas ique.<br />\nVos nos assurâd asse-ben que vos éd cen ècrit vos-mémo ou ben que vos l’éd copiyê d’una sôrsa que vint du domêno publico ou d’un’ôtra ressôrsa libra (vêde $1 por més de dètalys).\n<strong>Empleyéd gins d’ôvra desot drêt d’ôtor sen pèrmission èxprèssa !</strong>",
        "editpage-cannot-use-custom-model": "Lo modèlo de contegnu de cela pâge pôt pas étre changiê.",
-       "longpageerror": "<strong>Fôta : lo tèxto que vos éd mandâ fât {{PLURAL:$1|un Kio|$1 Kio}}, cen que dèpâsse la limita fixâye a {{PLURAL:$2|un Kio|$2 Kio}}.</strong>\nPôt pas étre encartâ.",
+       "longpageerror": "<strong>Fôta : lo tèxto que vos éd mandâ fât {{PLURAL:$1|un Kio|$1 Kio}}, cen que dèpâsse la limita fixa a {{PLURAL:$2|un Kio|$2 Kio}}.</strong>\nPôt pas étre encartâ.",
        "readonlywarning": "<strong>Atencion : la bâsa de balyês est étâye cotâye por na rotina d’entretin, cen fât que vos porréd vêr pas encartar voutros changements orendrêt.</strong>\nVos pouede copiyér et côlar voutron tèxto dedens un fichiér tèxto et pués l’encartar por ples târd.\n\nL’administrator sistèmo que l’at cotâ at balyê cel’èxplicacion : $1",
        "protectedpagewarning": "<strong>Atencion : cela pâge est étâye protègiêe por que solament los utilisators qu’ant los drêts d’administrator la pouessont changiér.</strong>\nLa dèrriére entrâ du jornâl est balyêe ce-desot coment rèference :",
        "semiprotectedpagewarning": "<strong>Nota :</strong> cela pâge est étâye protègiêe por que solament los utilisators encartâs la pouessont changiér.\nLa dèrriére entrâ du jornâl est balyêe ce-desot coment rèference :",
        "right-upload": "Tèlèchargiér de fichiérs",
        "right-reupload": "Ècllafar un fichiér ègzistent",
        "right-reupload-own": "Ècllafar un fichiér ègzistent tèlèchargiê per sè-mémo",
-       "right-reupload-shared": "Ècllafar localament un fichiér present sur un dèpôt de fichiérs multimèdiâ partagiê",
+       "right-reupload-shared": "Ècllafar localament un fichiér present sur un dèpôt mèdiâ partagiê",
        "right-upload_by_url": "Tèlèchargiér un fichiér dês un’URL",
        "right-purge": "Purgiér lo cacho du seto d’una pâge sen confirmacion",
        "right-autoconfirmed": "Pas étre afèctâ per les limitacions de dèbit liyêes a les adrèces IP",
        "right-changetags": "Apondre et enlevar de façon arbitrèra de [[Special:Tags|balises]] sur des vèrsions endividuèles et des entrês de jornâl",
        "grant-generic": "Ensemblo de drêts « $1 »",
        "grant-group-page-interaction": "Entèrag·ir avouéc de pâges",
-       "grant-group-file-interaction": "Entèrag·ir avouéc de fichiérs multimèdiâ",
+       "grant-group-file-interaction": "Entèrag·ir avouéc de mèdiâs",
        "grant-group-watchlist-interaction": "Entèrag·ir avouéc voutra lista de gouârda",
        "grant-group-email": "Mandar un mèssâjo",
        "grant-group-high-volume": "Fâre un’activitât de grôs volumo",
        "recentchangeslinked-page": "Nom de la pâge :",
        "recentchangeslinked-to": "Montrar per contre los changements de les pâges qu’ant un lim de vers la pâge balyêe",
        "recentchanges-page-added-to-category": "[[:$1]] apondua a la catègoria",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] et {{PLURAL:$2|na pâge apondua|$2 pâges apondues}} a la catègoria",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] et [[Special:WhatLinksHere/$1|{{PLURAL:$2|na pâge apondua|$2 pâges apondues}}]] a la catègoria",
        "recentchanges-page-removed-from-category": "[[:$1]] enlevâye de la catègoria",
-       "recentchanges-page-removed-from-category-bundled": "[[:$1]] et {{PLURAL:$2|na pâge enlevâye|$2 pâges enlevâyes}} de la catègoria",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] et [[Special:WhatLinksHere/$1|{{PLURAL:$2|na pâge enlevâye|$2 pâges enlevâyes}}]] de la catègoria",
        "autochange-username": "Changement ôtomatico de MediaWiki",
        "upload": "Tèlèchargiér un fichiér",
        "uploadbtn": "Tèlèchargiér lo fichiér",
        "reuploaddesc": "Anular lo tèlèchargement et pués tornar u formulèro de tèlèchargement",
        "upload-tryagain": "Mandar la dèscripcion du fichiér changiê",
-       "uploadnologin": "Pas branchiê(ye)",
+       "uploadnologin": "Pas branchiê",
        "uploadnologintext": "Se vos plét, vos vos dête $1 por povêr tèlèchargiér de fichiérs.",
        "upload_directory_missing": "Lo rèpèrtouèro de tèlèchargement ($1) est entrovâblo et at pas possu étre fêt per lo sèrvior Vouèbe.",
-       "upload_directory_read_only": "Lo rèpèrtouèro de tèlèchargement ($1) est pas enscriptiblo dês lo sèrvior Vouèbe.",
+       "upload_directory_read_only": "Lo rèpèrtouèro de tèlèchargement ($1) est pas enscriptiblo per lo sèrvior Vouèbe.",
        "uploaderror": "Fôta pendent lo tèlèchargement",
        "upload-recreate-warning": "<strong>Atencion : un fichiér avouéc cél nom est étâ suprimâ dèplaciê.</strong>\n\nLo jornâl de les suprèssions et des dèplacements de cela pâge est balyê ique por comoditât :",
        "uploadtext": "Empleyéd lo formulèro ce-desot por tèlèchargiér de fichiérs.\nPor vêre rechèrchiér de fichiérs tèlèchargiês dês devant, vêde la [[Special:FileList|lista des fichiérs tèlèchargiês]]. Los (re-)tèlèchargements sont asse-ben encartâs dessus lo [[Special:Log/upload|jornâl des tèlèchargements]], et les suprèssions dessus lo [[Special:Log/delete|jornâl de les suprèssions]].\n\nPor rapondre un fichiér dedens na pâge, empleyéd un lim de yona de celes fôrmes-que :\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Fichiér.jpg]]</nowiki></code></strong> por empleyér la vèrsion en plêna largior du fichiér\n* <strong><code><nowiki>[[</nowiki>{{ns:file}}<nowiki>:Fichiér.png|200px|thumb|left|tèxto dèscriptif]]</nowiki></code></strong> por empleyér na miniatura de 200 pixèls de lârjo dedens na bouèt’a gôche avouéc « tèxto dèscriptif » coment dèscripcion\n* <strong><code><nowiki>[[</nowiki>{{ns:media}}<nowiki>:Fichiér.ogg]]</nowiki></code></strong> por liyér tot drêt vers lo fichiér sen lo fâre vêre",
        "uploaded-animate-svg": "La balisa « animate » est étâye trovâye que porrêt changiér lo href en empleyent l’atribut « from » <code>&lt;$1 $2=\"$3\"&gt;</code> dedens lo fichiér SVG tèlèchargiê.",
        "uploaded-setting-event-handler-svg": "La dèfinicion d’atributs de maneyor d’èvènement est dèfendua, <code>&lt;$1 $2=\"$3\"&gt;</code> est étâ trovâ dedens lo fichiér SVG tèlèchargiê.",
        "uploaded-setting-href-svg": "L’usâjo de la balisa « set » por apondre un atribut « href » a la piéce parenta est dèfendu.",
-       "uploaded-wrong-setting-svg": "L’usâjo de la balisa « set » por apondre na ciba distanta/balyês/scripte a un atribut quint que seye est dèfendu. <code>&lt;set to=\"$1\"&gt;</code> est étâ trovâ dedens lo fichiér SVG tèlèchargiê.",
-       "uploaded-setting-handler-svg": "Los SVG que dèfenéssont l’atribut « handler » avouéc distant/balyês/scripte sont dèfendus. <code>$1=\"$2\"</code> est étâ trovâ dedens lo fichiér SVG tèlèchargiê.",
+       "uploaded-wrong-setting-svg": "L’usâjo de la balisa « set » por apondre na ciba distanta / balyês / scripte a un atribut quint que seye est dèfendu. <code>&lt;set to=\"$1\"&gt;</code> est étâ trovâ dedens lo fichiér SVG tèlèchargiê.",
+       "uploaded-setting-handler-svg": "Los SVG que dèfenéssont l’atribut « handler » avouéc distant / balyês / scripte sont dèfendus. <code>$1=\"$2\"</code> est étâ trovâ dedens lo fichiér SVG tèlèchargiê.",
        "uploaded-remote-url-svg": "Los SVG que dèfenéssont un atribut de stilo quint que seye avouéc un’URL distanta sont dèfendus. <code>$1=\"$2\"</code> est étâ trovâ dedens lo fichiér SVG tèlèchargiê.",
        "uploaded-image-filter-svg": "Un filtro d’émâge avouéc URL est étâ trovâ : <code>&lt;$1 $2=\"$3\"&gt;</code> dedens lo fichiér SVG tèlèchargiê.",
        "uploadscriptednamespace": "Cél fichiér SVG contint un èspâço de noms « $1 » pas ôtorisâ.",
        "uploadstash-badtoken": "L’ègzécucion de cel’accion at pas reussi. Pôt-étre perce que voutros identifients de changement ant èxpirâ. Se vos plét, tornâd èprovar.",
        "uploadstash-errclear": "La vouegiê des fichiérs at pas reussi.",
        "uploadstash-refresh": "Rafrèchir la lista des fichiérs",
+       "uploadstash-thumbnail": "vêre la miniatura",
        "invalid-chunk-offset": "Dèplacement de bocon pas justo",
        "img-auth-accessdenied": "Accès refusâ",
        "img-auth-nopathinfo": "PATH_INFO entrovâblo.\nVoutron sèrvior est pas configurâ por passar cel’enformacion.\nPôt-étre que fonccione en CGI et recognêt vêr pas img_auth.\nVêde https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "upload_source_file": "(lo fichiér que vos éd chouèsi dês voutron ordenator)",
        "listfiles-delete": "suprimar",
        "listfiles-summary": "Cela pâge spèciâla montre tôs los fichiérs tèlèchargiês.",
-       "listfiles_search_for": "Rechèrchiér un nom de fichiér multimèdiâ :",
+       "listfiles_search_for": "Rechèrchiér un nom de mèdiâ :",
        "listfiles-userdoesnotexist": "Lo comptio utilisator « $1 » est pas encartâ.",
        "imgfile": "fichiér",
        "listfiles": "Lista de fichiérs",
        "protectedpages-unknown-timestamp": "Encognua",
        "protectedpages-unknown-performer": "Utilisator encognu",
        "protectedtitles": "Titros protègiês",
-       "protectedtitles-summary": "Cela pâge liste los titros que sont ora protègiês contre la crèacion. Por na lista de les pâges ègzistentes protègiêes, vêde [[{{#special:ProtectedPages}}|{{int:protectedpages}}]].",
+       "protectedtitles-summary": "Cela pâge liste los titros que sont ora protègiês contre la crèacion. Por na lista de les pâges ègzistentes que sont protègiêes, vêde [[{{#special:ProtectedPages}}|{{int:protectedpages}}]].",
        "protectedtitlesempty": "Ora nion titro est protègiê avouéc celos paramètros.",
        "protectedtitles-submit": "Fâre vêre los titros",
        "listusers": "Lista des utilisators",
        "cachedspecial-refresh-now": "Vêre la ples novèla.",
        "categories": "Catègories",
        "categories-submit": "Montrar",
-       "categoriespagetext": "{{PLURAL:$1|Cela catègoria-que contint|Celes catègories-que contegnont}} de pâges de fichiérs multimèdiâ.\nLes [[Special:UnusedCategories|catègories pas empleyêes]] sont pas montrâyes ique.\nVêde avouéc les [[Special:WantedCategories|catègories demandâyes]].",
+       "categoriespagetext": "{{PLURAL:$1|Cela catègoria-que contint|Celes catègories-que contegnont}} de pâges de mèdiâs.\nLes [[Special:UnusedCategories|catègories pas empleyêes]] sont pas montrâyes ique.\nVêde avouéc les [[Special:WantedCategories|catègories demandâyes]].",
        "categoriesfrom": "Fâre vêre les catègories dês :",
        "special-categories-sort-count": "chouèx per comptâjo",
        "special-categories-sort-abc": "chouèx alfabètico",
        "ipbnounblockself": "Vos éte pas ôtorisâ{{GENDER:||ye}} a vos dèblocar vos-mém{{GENDER:|o|a}}.",
        "lockdb": "Cotar la bâsa de balyês",
        "unlockdb": "Dècotar la bâsa de balyês",
-       "lockdbtext": "Lo vèrroly de la bâsa de balyês empachierat tôs los utilisators de changiér de pâges, d’encartar lors prèferences, de changiér lor lista de gouârda et pués de fâre totes les ôtres opèracions qu’ant fôta de changements dedens la bâsa de balyês.\nSe vos plét, confirmâd qu’o est franc cen que vos voléd fâre et que vos la dècoteréd setout que voutra rotina d’entretin serat chavonâye.",
+       "lockdbtext": "Lo vèrroly de la bâsa de balyês empachierat tôs los utilisators de changiér de pâges, d’encartar lors prèferences, de changiér lor lista de gouârda et pués de fâre totes les ôtres opèracions qu’ant fôta de changements dedens la bâsa de balyês.\nSe vos plét, confirmâd qu’o est franc cen que vos voléd fâre et que vos la dècoteréd setout que voutra rotina d’entretin serat chavona.",
        "unlockdbtext": "La fin du vèrroly de la bâsa de balyês tornerat pèrmetre a tôs los utilisators de changiér de pâges, d’encartar lors prèferences, de changiér lor lista de gouârda et pués de fâre totes les ôtres opèracions qu’ant fôta de changements dedens la bâsa de balyês.\nSe vos plét, confirmâd qu’o est franc cen que vos voléd fâre.",
        "lockconfirm": "Ouè, confirmo que vuel cotar la bâsa de balyês.",
        "unlockconfirm": "Ouè, confirmo que vuel dècotar la bâsa de balyês.",
        "locknoconfirm": "Vos éd pas pouentâ la câsa de confirmacion.",
        "lockdbsuccesssub": "Vèrroly de la bâsa de balyês reussi",
        "unlockdbsuccesssub": "Vèrroly de la bâsa de balyês enlevâ",
-       "lockdbsuccesstext": "La bâsa de balyês est étâye cotâye.<br />\nOubliâd pas de la [[Special:UnlockDB|dècotar]] quand vos aréd chavonâ voutra rotina d’entretin.",
+       "lockdbsuccesstext": "La bâsa de balyês est étâye cotâye.<br />\nOubliâd pas de la [[Special:UnlockDB|dècotar]] quand vos aréd chavono voutra rotina d’entretin.",
        "unlockdbsuccesstext": "La bâsa de balyês est étâye dècotâye.",
-       "lockfilenotwritable": "Lo fichiér de vèrroly de la bâsa de balyês est pas enscriptiblo.\nPor cotar dècotar la bâsa de balyês, dêt étre enscriptiblo dês lo sèrvior Vouèbe.",
+       "lockfilenotwritable": "Lo fichiér de vèrroly de la bâsa de balyês est pas enscriptiblo.\nPor cotar dècotar la bâsa de balyês, dêt étre enscriptiblo per lo sèrvior Vouèbe.",
        "databasenotlocked": "La bâsa de balyês est pas cotâye.",
        "lockedbyandtime": "(per {{GENDER:$1|$1}} lo $2 a $3)",
        "move-page": "Dèplaciér $1",
        "movepagetalktext": "Se vos pouentâd cela câsa, la pâge de discussion associyêe serat asse-ben dèplaciêe ôtomaticament, a muens qu’una pâge de discussion pas voueda ègzisteye ja desot lo novél nom.\n\nDens cél câs, vos devréd dèplaciér fusionar la pâge a la man se vos o voléd.",
        "moveuserpage-warning": "<strong>Atencion :</strong> vos éte prèst a dèplaciér na pâge utilisator. Se vos plét, notâd que solament la pâge serat dèplaciêe et que l’utilisator serat <em>pas</em> renomâ.",
        "movecategorypage-warning": "<strong>Atencion :</strong> vos éte prèst a dèplaciér na pâge de catègoria. Se vos plét, notâd que solament la pâge serat dèplaciêe et que <em>pas yona</em> de les pâges de la vielye catègoria serat betâye dedens la novèla.",
-       "movenologintext": "Vos dête étre un utilisator encartâ et [[Special:UserLogin|branchiê]] por povêr dèplaciér na pâge.",
+       "movenologintext": "Vos dête étre un utilisator encartâ et pués étre [[Special:UserLogin|branchiê]] por povêr dèplaciér na pâge.",
        "movenotallowed": "Vos éd pas la pèrmission de dèplaciér de pâges.",
        "movenotallowedfile": "Vos éd pas la pèrmission de dèplaciér de fichiérs.",
        "cant-move-user-page": "Vos éd pas la pèrmission de dèplaciér de pâges utilisator (en defôr de sot-pâges).",
        "tooltip-t-permalink": "Lim fixo de vers cela vèrsion de la pâge",
        "tooltip-ca-nstab-main": "Vêre la pâge de contegnu",
        "tooltip-ca-nstab-user": "Vêre la pâge utilisator",
-       "tooltip-ca-nstab-media": "Vêre la pâge du fichiér multimèdiâ",
+       "tooltip-ca-nstab-media": "Vêre la pâge mèdiâ",
        "tooltip-ca-nstab-special": "O est na pâge spèciâla que pôt pas étre changiêe",
        "tooltip-ca-nstab-project": "Vêre la pâge projèt",
        "tooltip-ca-nstab-image": "Vêre la pâge du fichiér",
        "patrol-log-page": "Jornâl de gouârda",
        "patrol-log-header": "Vê-que un jornâl de les vèrsions gouardâyes.",
        "log-show-hide-patrol": "$1 lo jornâl de gouârda",
-       "deletedrevision": "La vielye vèrsion $1 at étâ suprimâ.",
-       "filedeleteerror-short": "Èrror pendent la suprèssion du fichiér : $1",
-       "filedeleteerror-long": "Des èrrors ont étâ rencontrâs pendent la suprèssion du fichiér :\n\n$1",
-       "filedelete-missing": "Lo fichiér « $1 » pôt pas étre suprimâ perce qu’ègziste pas.",
-       "filedelete-old-unregistered": "La vèrsion du fichiér spècefiâ « $1 » est pas dens la bâsa de balyês.",
-       "filedelete-current-unregistered": "Lo fichiér spècefiâ « $1 » est pas dens la bâsa de balyês.",
-       "filedelete-archive-read-only": "Lo dossiér d’arch·ivâjo « $1 » pôt pas étre changiê per lo sèrvor.",
+       "log-show-hide-tag": "$1 lo jornâl de les balises",
+       "deletedrevision": "Vielye vèrsion $1 suprimâye",
+       "filedeleteerror-short": "Fôta pendent la suprèssion du fichiér : $1",
+       "filedeleteerror-long": "Des fôtes sont étâyes rencontrâyes pendent la suprèssion du fichiér :\n\n$1",
+       "filedelete-missing": "Lo fichiér « $1 » pôt pas étre suprimâ, ègziste pas.",
+       "filedelete-old-unregistered": "La vèrsion du fichiér spècifiâye « $1 » est pas dedens la bâsa de balyês.",
+       "filedelete-current-unregistered": "Lo fichiér spècifiâ « $1 » est pas dedens la bâsa de balyês.",
+       "filedelete-archive-read-only": "Lo rèpèrtouèro d’arch·ivâjo « $1 » est pas enscriptiblo per lo sèrvior Vouèbe.",
        "previousdiff": "← Changement devant",
        "nextdiff": "Changement aprés →",
-       "mediawarning": "'''Atencion :''' ceti tipo de fichiér pôt contegnir de code mâlvelyent.\nSe vos l’ègzécutâd, voutron sistèmo pôt étre compromês.",
-       "imagemaxsize": "Format lo ples grant de les émâges :<br />''(por les pâges de dèscripcion d’émâges)''",
-       "thumbsize": "Talye de la figura :",
+       "mediawarning": "<strong>Atencion :</strong> cél tipo de fichiér pôt contegnir de code mâlvelyent.\nSe vos l’ègzécutâd, voutron sistèmo pôt étre compromètu.",
+       "imagemaxsize": "Talye maximon de les émâges :<br /><em>(por les pâges de dèscripcion de fichiérs)</em>",
+       "thumbsize": "Talye de la miniatura :",
        "widthheightpage": "$1 × $2, $3 pâge{{PLURAL:$3||s}}",
        "file-info": "Talye du fichiér : $1, tipo MIME : $2",
        "file-info-size": "$1 × $2 pixèls, talye du fichiér : $3, tipo MIME : $4",
        "file-info-size-pages": "$1 × $2 pixèls, talye du fichiér : $3, tipo MIME : $4, $5 pâge{{PLURAL:$5||s}}",
-       "file-nohires": "Gins de rèsolucion ples hôta disponibla.",
-       "svg-long-desc": "Fichiér SVG, rèsolucion de $1 × $2 pixèls, talye : $3",
-       "svg-long-error": "Fichiér SVG envalido : $1",
+       "file-nohires": "Niona rèsolucion ples hôta disponibla.",
+       "svg-long-desc": "Fichiér SVG, nominalament $1 × $2 pixèls, talye du fichiér : $3",
+       "svg-long-desc-animated": "Fichiér SVG animâ, nominalament $1 × $2 pixèls, talye du fichiér : $3",
+       "svg-long-error": "Fichiér SVG pas justo : $1",
        "show-big-image": "Fichiér d’origina",
-       "show-big-image-preview": "Talye de ceti apèrçu : $1.",
+       "show-big-image-preview": "Talye de cél apèrçu : $1.",
+       "show-big-image-preview-differ": "Talye de cél apèrçu $3 du fichiér $2 : $1.",
        "show-big-image-other": "{{PLURAL:$2|Ôtra rèsolucion|Ôtres rèsolucions}} : $1.",
        "show-big-image-size": "$1 × $2 pixèls",
        "file-info-gif-looped": "en boclla",
        "file-info-png-looped": "en boclla",
        "file-info-png-repeat": "jouyê $1 côp{{PLURAL:$1||s}}",
        "file-info-png-frames": "$1 émâge{{PLURAL:$1||s}}",
-       "newimages": "Galerie des novéls fichiérs",
-       "imagelisttext": "Vê-que una lista de '''$1''' {{PLURAL:$1|fichiér rengiê|fichiérs rengiês}} $2.",
-       "newimages-summary": "Ceta pâge spèciâla montre los dèrriérs fichiérs tèlèchargiês.",
-       "newimages-legend": "Nom du fichiér",
-       "newimages-label": "Nom du fichiér (ou ben una partia de ceti) :",
-       "noimages": "Gins de fichiér a fâre vêre.",
+       "file-no-thumb-animation": "<strong>Nota : a côsa de limitacions tècniques, les miniatures de cél fichiér seront pas animâyes.</strong>",
+       "file-no-thumb-animation-gif": "<strong>Nota : a côsa de limitacions tècniques, les miniatures d’émâges GIF en hôta rèsolucion coment ceta seront pas animâyes.</strong>",
+       "newimages": "Galeria des novéls fichiérs",
+       "imagelisttext": "Vê-que na lista de <strong>$1</strong> {{PLURAL:$1|fichiér rengiê|fichiérs rengiês}} $2.",
+       "newimages-summary": "Cela pâge spèciâla montre los dèrriérs fichiérs tèlèchargiês.",
+       "newimages-legend": "Filtro",
+       "newimages-label": "Nom du fichiér (ou ben na partia de ceti) :",
+       "newimages-showbots": "Montrar los tèlèchargements per los robots",
+       "newimages-hidepatrolled": "Cachiér los tèlèchargements gouardâs",
+       "noimages": "Ren a fâre vêre.",
        "ilsubmit": "Rechèrchiér",
        "bydate": "per dâta",
        "sp-newimages-showfrom": "Montrar los novéls fichiérs dês lo $1 a $2",
        "minutes": "$1 menut{{PLURAL:$1|a|es}}",
        "hours": "$1 hor{{PLURAL:$1|a|es}}",
        "days": "$1 jorn{{PLURAL:$1||s}}",
+       "weeks": "$1 seman{{PLURAL:$1|a|es}}",
+       "months": "{{PLURAL:$1|$1 mês}}",
+       "years": "$1 an{{PLURAL:$1||s}}",
        "ago": "cen fât $1",
        "just-now": "drêt-ora",
-       "bad_image_list": "Lo format est ceti :\n\nSolament les listes d’ènumèracion (que començont per *) sont considèrâs.\nLo premiér lim d’una legne dêt étre vers celi d’una crouye émâge.\nLos ôtros lims sur la méma legne sont considèrâs coment des èxcèpcions, per ègzemplo des pâges sur lesquintes l’émâge pôt aparêtre.",
+       "hours-ago": "cen fât $1 hor{{PLURAL:$1|a|es}}",
+       "minutes-ago": "cen fât $1 menut{{PLURAL:$1|a|es}}",
+       "seconds-ago": "cen fât $1 second{{PLURAL:$1|a|es}}",
+       "monday-at": "Delon a $1",
+       "tuesday-at": "Demârs a $1",
+       "wednesday-at": "Demécro a $1",
+       "thursday-at": "Dejô a $1",
+       "friday-at": "Devendro a $1",
+       "saturday-at": "Dessando a $1",
+       "sunday-at": "Demenge a $1",
+       "yesterday-at": "Hièr a $1",
+       "bad_image_list": "Lo format est ceti :\n\nSolament les piéces de lista (les legnes que començont per *) sont considèrâyes.\nLo premiér lim d’una legne dêt étre celi d’un crouyo fichiér.\nLos ôtros lims sur la méma legne sont considèrâs coment d’èxcèpcions, per ègzemplo des pâges que lo fichiér pôt aparêtre dessus.",
        "metadata": "Mètabalyês",
-       "metadata-help": "Ceti fichiér contint des enformacions de ples, probâblament apondues per l’aparèly-fotô numerico ou ben lo scanor utilisâ por lo fâre.\nSe lo fichiér at étâ changiê dês son ètat originâl, quârques dètalys pôvont pas reflètar a chavon l’émâge changiê.",
-       "metadata-expand": "Montrar los dètalys ètendus",
-       "metadata-collapse": "Cachiér los dètalys ètendus",
-       "metadata-fields": "Los champs de mètabalyês d’émâge listâs dens cél mèssâjo seront betâs dedens la pâge de dèscripcion de l’émâge quand la trâbla de mètabalyês serat rèduita.\nLos ôtros champs seront cachiês per dèfôt.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
+       "metadata-help": "Cél fichiér contint d’enformacions de més, probâblament apondues per l’aparèly-fotô numerico lo scanor empleyê por lo fâre numerisar.\nSe lo fichiér est étâ changiê dês son ètat originâl, quârques dètalys pôvont pas remandar a chavon lo fichiér changiê.",
+       "metadata-expand": "Montrar los dètalys de més",
+       "metadata-collapse": "Cachiér los dètalys de més",
+       "metadata-fields": "Los champs de mètabalyês d’émâge listâs dens cél mèssâjo seront rapondus dedens la pâge de dèscripcion de l’émâge quand la trâbla de mètabalyês serat rèduita.\nLos ôtros champs seront cachiês per dèfôt.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
        "metadata-langitem": "'''$2 :''' $1",
        "exif-imagewidth": "Largior",
        "exif-imagelength": "Hôtior",
        "exif-samplesperpixel": "Nombro de composentes",
        "exif-planarconfiguration": "Arrengement de les balyês",
        "exif-ycbcrsubsampling": "Quota de sot-èchantelyonâjo de Y a C",
-       "exif-ycbcrpositioning": "Posicionement Y et C",
+       "exif-ycbcrpositioning": "Posicionament Y et C",
        "exif-xresolution": "Rèsolucion plana",
        "exif-yresolution": "Rèsolucion drêta",
-       "exif-stripoffsets": "Emplacement de les balyês de l’émâge",
+       "exif-stripoffsets": "Endrêt de les balyês de l’émâge",
        "exif-rowsperstrip": "Nombro de legnes per benda",
-       "exif-stripbytecounts": "Talye en octèts per benda",
+       "exif-stripbytecounts": "Octèts per benda comprimâye",
        "exif-jpeginterchangeformat": "Posicion du SOI JPEG",
-       "exif-jpeginterchangeformatlength": "Talye en octèts de les balyês JPEG",
+       "exif-jpeginterchangeformatlength": "Octèts de les balyês JPEG",
        "exif-whitepoint": "Cromaticitât du pouent blanc",
        "exif-primarychromaticities": "Cromaticitât de les colors primères",
        "exif-ycbcrcoefficients": "Factors de la matrice de transformacion de l’èspâço colorimètrico",
-       "exif-referenceblackwhite": "Valors de refèrence nêr et blanc",
+       "exif-referenceblackwhite": "Cobla de valors de rèference nêr et blanc",
        "exif-datetime": "Dâta et hora de changement du fichiér",
        "exif-imagedescription": "Titro de l’émâge",
        "exif-make": "Fabrecant de l’aparèly-fotô",
        "exif-model": "Modèlo de l’aparèly-fotô",
-       "exif-software": "Programeria utilisâ",
+       "exif-software": "Programeria empleyêe",
        "exif-artist": "Ôtor",
-       "exif-copyright": "Dètentor du drêt d’ôtor",
+       "exif-copyright": "Dètentior des drêts d’ôtor",
        "exif-exifversion": "Vèrsion Exif",
-       "exif-flashpixversion": "Vèrsion FlashPix recognua",
+       "exif-flashpixversion": "Vèrsion Flashpix recognua",
        "exif-colorspace": "Èspâço colorimètrico",
        "exif-componentsconfiguration": "Significacion de châque composenta",
        "exif-compressedbitsperpixel": "Fôrma de comprèssion de l’émâge",
        "exif-pixelydimension": "Largior de l’émâge",
        "exif-pixelxdimension": "Hôtior de l’émâge",
-       "exif-usercomment": "Comentèros a l’usanciér",
+       "exif-usercomment": "Comentèros de l’utilisator",
        "exif-relatedsoundfile": "Fichiér ôdiô associyê",
-       "exif-datetimeoriginal": "Dâta et hora de la g·ènèracion de les balyês",
+       "exif-datetimeoriginal": "Dâta et hora de la prêsa originâla",
        "exif-datetimedigitized": "Dâta et hora de la numerisacion",
-       "exif-subsectime": "Dâta et hora en fraccions de secondes de changement du fichiér",
-       "exif-subsectimeoriginal": "Dâta et hora en fraccions de secondes de la g·ènèracion de les balyês",
-       "exif-subsectimedigitized": "Dâta et hora en fraccions de secondes de la numerisacion",
+       "exif-subsectime": "Dâta et hora en fraccions de seconda",
+       "exif-subsectimeoriginal": "Dâta et hora de la prêsa originâla en fraccions de seconda",
+       "exif-subsectimedigitized": "Dâta et hora de la numerisacion en fraccions de seconda",
        "exif-exposuretime": "Temps d’èxposicion",
-       "exif-exposuretime-format": "$1 s ($2)",
-       "exif-fnumber": "Nombro f",
+       "exif-exposuretime-format": "$1 s ($2 s)",
+       "exif-fnumber": "Uvèrtura",
        "exif-exposureprogram": "Programo d’èxposicion",
        "exif-spectralsensitivity": "Sensibilitât spèctrâla",
        "exif-isospeedratings": "Sensibilitât ISO",
        "exif-shutterspeedvalue": "Vitèsse d’ètopâ de l’APEX",
        "exif-aperturevalue": "Uvèrtura de l’APEX",
-       "exif-brightnessvalue": "Luminance APEX",
-       "exif-exposurebiasvalue": "Corrèccion d’èxposicion",
-       "exif-maxaperturevalue": "Uvèrtura la ples granta",
-       "exif-subjectdistance": "Distance du sujèt",
+       "exif-brightnessvalue": "Brilyent de l’APEX",
+       "exif-exposurebiasvalue": "Corrèccion d’èxposicion de l’APEX",
+       "exif-maxaperturevalue": "Uvèrtura maximon",
+       "exif-subjectdistance": "Distance de la chousa",
        "exif-meteringmode": "Fôrma de mesera",
        "exif-lightsource": "Sôrsa de lumiére",
        "exif-flash": "Èludo",
        "exif-focallength": "Longior focâla",
-       "exif-subjectarea": "Emplacement du sujèt",
-       "exif-flashenergy": "Nèrf de l’èludo",
+       "exif-subjectarea": "Sôl de la chousa",
+       "exif-flashenergy": "Ènèrg·ia de l’èludo",
        "exif-focalplanexresolution": "Rèsolucion plana de la vision focâla",
        "exif-focalplaneyresolution": "Rèsolucion drêta de la vision focâla",
        "exif-focalplaneresolutionunit": "Unitât de rèsolucion de la vision focâla",
-       "exif-subjectlocation": "Posicion du sujèt",
-       "exif-exposureindex": "Endèxe d’èxposicion",
+       "exif-subjectlocation": "Endrêt de la chousa",
+       "exif-exposureindex": "Endèx d’èxposicion",
        "exif-sensingmethod": "Tipo de captior",
        "exif-filesource": "Sôrsa du fichiér",
        "exif-scenetype": "Tipo de scèna",
        "exif-customrendered": "Rendu d’émâge pèrsonalisâ",
        "exif-exposuremode": "Fôrma d’èxposicion",
        "exif-whitebalance": "Balance des blancs",
-       "exif-digitalzoomratio": "Quota d’agrantissement numerico (''zoom'')",
-       "exif-focallengthin35mmfilm": "Longior focâla por un filme 35 mm",
-       "exif-scenecapturetype": "Tipo de prêsa de la scèna",
-       "exif-gaincontrol": "Contrôlo de scèna",
-       "exif-contrast": "Contraste",
+       "exif-digitalzoomratio": "Quota d’agrantissement numerico (<em>zoom</em>)",
+       "exif-focallengthin35mmfilm": "Longior focâla por un filmo 35 mm",
+       "exif-scenecapturetype": "Tipo de captura de la scèna",
+       "exif-gaincontrol": "Contrôlo de la scèna",
+       "exif-contrast": "Contrasto",
        "exif-saturation": "Saturacion",
-       "exif-sharpness": "Prècision",
+       "exif-sharpness": "Nètetât",
        "exif-devicesettingdescription": "Dèscripcion de la configuracion du dispositif",
-       "exif-subjectdistancerange": "Distance du sujèt",
-       "exif-imageuniqueid": "Numerô solèt de l’émâge",
+       "exif-subjectdistancerange": "Èchiéla de distance de la chousa",
+       "exif-imageuniqueid": "Identifient solèt de l’émâge",
        "exif-gpsversionid": "Vèrsion de la balisa GPS",
-       "exif-gpslatituderef": "Latituda bise (''nord'') ou mié-jorn (''sud'')",
+       "exif-gpslatituderef": "Latituda bise (<em>nord</em>) ou ben mié-jorn (<em>sud</em>)",
        "exif-gpslatitude": "Latituda",
-       "exif-gpslongituderef": "Longituda levant (''èst'') ou ponant (''ouèst'')",
+       "exif-gpslongituderef": "Longituda levant (<em>èste</em>) ou ben cuchient (<em>ouèste</em>)",
        "exif-gpslongitude": "Longituda",
-       "exif-gpsaltituderef": "Refèrence d’hôtior",
+       "exif-gpsaltituderef": "Rèference d’hôtior",
        "exif-gpsaltitude": "Hôtior",
        "exif-gpstimestamp": "Hora GPS (relojo atomico)",
-       "exif-gpssatellites": "Satèlites utilisâs por la mesera",
+       "exif-gpssatellites": "Satèlitos empleyês por la mesera",
        "exif-gpsstatus": "Ètat du recevior",
        "exif-gpsmeasuremode": "Fôrma de mesera",
        "exif-gpsdop": "Prècision de la mesera",
-       "exif-gpsspeedref": "Unitât de vitèsse du recevior GPS",
+       "exif-gpsspeedref": "Unitât de vitèsse",
        "exif-gpsspeed": "Vitèsse du recevior GPS",
-       "exif-gpstrackref": "Refèrence por la dirèccion du mouvement",
+       "exif-gpstrackref": "Rèference por la dirèccion du mouvement",
        "exif-gpstrack": "Dirèccion du mouvement",
-       "exif-gpsimgdirectionref": "Refèrence por la dirèccion de l’émâge",
+       "exif-gpsimgdirectionref": "Rèference por la dirèccion de l’émâge",
        "exif-gpsimgdirection": "Dirèccion de l’émâge",
-       "exif-gpsmapdatum": "Sistèmo g·eodèsico utilisâ",
-       "exif-gpsdestlatituderef": "Refèrence por la latituda de la dèstinacion",
+       "exif-gpsmapdatum": "Balyês de sondâjo g·eodèsico empleyêes",
+       "exif-gpsdestlatituderef": "Rèference por la latituda de la dèstinacion",
        "exif-gpsdestlatitude": "Latituda de la dèstinacion",
-       "exif-gpsdestlongituderef": "Refèrence por la longituda de la dèstinacion",
+       "exif-gpsdestlongituderef": "Rèference por la longituda de la dèstinacion",
        "exif-gpsdestlongitude": "Longituda de la dèstinacion",
-       "exif-gpsdestbearingref": "Refèrence por lo relèvament de la dèstinacion",
+       "exif-gpsdestbearingref": "Rèference por lo relèvament de la dèstinacion",
        "exif-gpsdestbearing": "Relèvament de la dèstinacion",
-       "exif-gpsdestdistanceref": "Refèrence por la distance a la dèstinacion",
+       "exif-gpsdestdistanceref": "Rèference por la distance a la dèstinacion",
        "exif-gpsdestdistance": "Distance a la dèstinacion",
-       "exif-gpsprocessingmethod": "Nom du tipo de trètament du GPS",
-       "exif-gpsareainformation": "Nom de la zona GPS",
+       "exif-gpsprocessingmethod": "Nom de la mètoda de trètament du GPS",
+       "exif-gpsareainformation": "Nom du sôl GPS",
        "exif-gpsdatestamp": "Dâta GPS",
        "exif-gpsdifferential": "Corrèccion difèrencièla GPS",
        "exif-jpegfilecomment": "Comentèro de fichiér JPEG",
        "exif-keywords": "Mots-cllâfs",
-       "exif-worldregioncreated": "Règ·ion du mondo que la fotô at étâ prêsa",
-       "exif-countrycreated": "Payis que la fotô at étâ prêsa",
-       "exif-countrycodecreated": "Code du payis que la fotô at étâ prêsa",
-       "exif-provinceorstatecreated": "Province ou ben ètat que la fotô at étâ prêsa",
-       "exif-citycreated": "Vela que la fotô at étâ prêsa",
-       "exif-sublocationcreated": "Partia de la vela que la fotô at étâ prêsa",
-       "exif-worldregiondest": "Règ·ion du mondo montrâ",
+       "exif-worldregioncreated": "Règ·ion du mondo yô que la fotô est étâye prêsa",
+       "exif-countrycreated": "Payis yô que la fotô est étâye prêsa",
+       "exif-countrycodecreated": "Code du payis yô que la fotô est étâye prêsa",
+       "exif-provinceorstatecreated": "Province Ètat yô que la fotô est étâye prêsa",
+       "exif-citycreated": "Vela yô que la fotô est étâye prêsa",
+       "exif-sublocationcreated": "Partia de la vela yô que la fotô est étâye prêsa",
+       "exif-worldregiondest": "Règ·ion du mondo montrâye",
        "exif-countrydest": "Payis montrâ",
        "exif-countrycodedest": "Code du payis montrâ",
-       "exif-provinceorstatedest": "Province ou ben ètat montrâ",
-       "exif-citydest": "Vela montrâ",
-       "exif-sublocationdest": "Partia de la vela montrâ",
+       "exif-provinceorstatedest": "Province Ètat montrâ(ye)",
+       "exif-citydest": "Vela montrâye",
+       "exif-sublocationdest": "Partia de la vela montrâye",
        "exif-objectname": "Titro côrt",
        "exif-specialinstructions": "Enstruccions spèciâles",
        "exif-headline": "Titro",
        "exif-credit": "Crèdit / fornissor",
        "exif-source": "Sôrsa",
        "exif-editstatus": "Statut èditoriâl de l’émâge",
-       "exif-urgency": "Urgence",
-       "exif-fixtureidentifier": "Nom de l’outil",
+       "exif-urgency": "Prèssa",
+       "exif-fixtureidentifier": "Nom de la colona",
        "exif-locationdest": "Endrêt fotografiâ",
        "exif-locationdestcode": "Code de l’endrêt fotografiâ",
-       "exif-objectcycle": "Moment de la jornâ que ceti mèdia est dèstinâ",
-       "exif-contact": "Enformacions de contacte",
+       "exif-objectcycle": "Temps de la jornâ que cél mèdiâ y est dèstinâ",
+       "exif-contact": "Enformacions de contacto",
        "exif-writer": "Ôtor",
        "exif-languagecode": "Lengoua",
        "exif-iimversion": "Vèrsion IIM",
-       "exif-iimcategory": "Catègorie",
-       "exif-iimsupplementalcategory": "Catègories de ples",
-       "exif-datetimeexpires": "Pas utilisar aprés",
+       "exif-iimcategory": "Catègoria",
+       "exif-iimsupplementalcategory": "Catègories de s",
+       "exif-datetimeexpires": "Pas empleyér aprés",
        "exif-datetimereleased": "Paru lo",
-       "exif-originaltransmissionref": "Code de l’endrêt de la transmission originâla",
-       "exif-identifier": "Numerô",
-       "exif-lens": "Lentelye utilisâ",
+       "exif-originaltransmissionref": "Code d’endrêt de la transmission originâla",
+       "exif-identifier": "Identifient",
+       "exif-lens": "Lentelye empleyêe",
        "exif-serialnumber": "Numerô de sèria de l’aparèly-fotô",
        "exif-cameraownername": "Propriètèro de l’aparèly-fotô",
        "exif-label": "Lambél",
        "exif-datetimemetadata": "Dâta du dèrriér changement de les mètabalyês",
-       "exif-nickname": "Nom enformèl de l’émâge",
+       "exif-nickname": "Nom famelyér de l’émâge",
        "exif-rating": "Nota (sur 5)",
-       "exif-rightscertificate": "Cèrtificat d’administracion des drêts",
+       "exif-rightscertificate": "Cèrtificat de maneyance des drêts",
        "exif-copyrighted": "Statut des drêts d’ôtor",
-       "exif-copyrightowner": "Propriètèro du drêt d’ôtor",
+       "exif-copyrightowner": "Dètentior des drêts d’ôtor",
        "exif-usageterms": "Condicions d’usâjo",
-       "exif-webstatement": "Dècllaracion des drêts d’ôtor en legne",
-       "exif-originaldocumentid": "Numerô solèt du document originâl",
-       "exif-licenseurl": "URL de la licence",
+       "exif-webstatement": "Dècllaracion de drêts d’ôtor en legne",
+       "exif-originaldocumentid": "Identifient solèt du document originâl",
+       "exif-licenseurl": "URL de la licence des drêts d’ôtor",
        "exif-morepermissionsurl": "Enformacions sur les licences altèrnatives",
-       "exif-attributionurl": "Pendent lo reusâjo de cela ôvra, volyéd liyér a",
-       "exif-preferredattributionname": "Pendent lo reusâjo de cela ôvra, volyéd crèditar",
+       "exif-attributionurl": "Pendent lo reusâjo de cel’ôvra, se vos plét liyéd a",
+       "exif-preferredattributionname": "Pendent lo reusâjo de cel’ôvra, se vos plét crèditâd",
        "exif-pngfilecomment": "Comentèro de fichiér PNG",
-       "exif-disclaimer": "Avèrtissement",
-       "exif-contentwarning": "Avèrtissement sur lo contegnu",
+       "exif-disclaimer": "Semonce de nan-rèsponsabilitât",
+       "exif-contentwarning": "Semonce sur lo contegnu",
        "exif-giffilecomment": "Comentèro de fichiér GIF",
-       "exif-intellectualgenre": "Tipo d’èlèment",
-       "exif-subjectnewscode": "Code du sujèt",
+       "exif-intellectualgenre": "Tipo de piéce",
+       "exif-subjectnewscode": "Code de la chousa",
        "exif-scenecode": "Code de scèna IPTC",
        "exif-event": "Èvènement fotografiâ",
-       "exif-organisationinimage": "Organisacion fotografiâ",
-       "exif-personinimage": "Pèrsona fotografiâ",
-       "exif-originalimageheight": "Hôtior de l’émâge devant qu’el èye étâ tornâ cadrar",
-       "exif-originalimagewidth": "Largior de l’émâge devant qu’el èye étâ tornâ cadrar",
-       "exif-compression-1": "Pas comprèssâ",
-       "exif-compression-2": "CCITT tropa 3 longior du codâjo Huffman changiê de dimension 1",
-       "exif-compression-3": "CCITT tropa 3 codâjo du faxe",
-       "exif-compression-4": "CCITT tropa 4 codâjo du faxe",
+       "exif-organisationinimage": "Organisacion fotografiâye",
+       "exif-personinimage": "Pèrsona fotografiâye",
+       "exif-originalimageheight": "Hôtior de l’émâge devant que seye étâye recadrâye",
+       "exif-originalimagewidth": "Largior de l’émâge devant que seye étâye recadrâye",
+       "exif-compression-1": "Pas damâ",
+       "exif-compression-2": "CCITT Groupo 3 Longior du codâjo Huffman changiê de dimension 1",
+       "exif-compression-3": "CCITT Groupo 3 codâjo du faxe",
+       "exif-compression-4": "CCITT Groupo 4 codâjo du faxe",
        "exif-compression-6": "JPEG (viely)",
-       "exif-copyrighted-true": "Somês a drêt d’ôtor",
-       "exif-copyrighted-false": "Domêno publico",
+       "exif-copyrighted-true": "Protègiê per los drêts d’ôtor",
+       "exif-copyrighted-false": "Ètat des drêts d’ôtor pas dèfeni",
+       "exif-photometricinterpretation-1": "Nêr et blanc (0 por lo nêr)",
        "exif-unknowndate": "Dâta encognua",
        "exif-orientation-1": "Normala",
-       "exif-orientation-2": "Envèrsâ d’aplan",
-       "exif-orientation-3": "Veriê de 180°",
-       "exif-orientation-4": "Envèrsâ d’aplomb",
-       "exif-orientation-5": "Veriê de 90° dens la dirèccion antihorèra et envèrsâ d’aplomb",
-       "exif-orientation-6": "Veriê de 90° dens la dirèccion antihorèra",
-       "exif-orientation-7": "Veriê de 90° dens la dirèccion horèra et envèrsâ d’aplomb",
-       "exif-orientation-8": "Veriê de 90° dens la dirèccion horèra",
-       "exif-planarconfiguration-1": "Balyês ategnentes",
-       "exif-planarconfiguration-2": "Balyês sèparâs",
+       "exif-orientation-2": "Envèrsâye d’aplan",
+       "exif-orientation-3": "Veriêe de 180°",
+       "exif-orientation-4": "Envèrsâye d’aplomb",
+       "exif-orientation-5": "Veriêe de 90° du fllanc antihorèro et envèrsâye d’aplomb",
+       "exif-orientation-6": "Veriêe de 90° du fllanc antihorèro",
+       "exif-orientation-7": "Veriêe de 90° du fllanc horèro et envèrsâye d’aplomb",
+       "exif-orientation-8": "Veriêe de 90° du fllanc horèro",
+       "exif-planarconfiguration-1": "format en bocons",
+       "exif-planarconfiguration-2": "format plan",
        "exif-colorspace-65535": "Pas calibrâ",
-       "exif-componentsconfiguration-0": "Ã\88gziste pas",
+       "exif-componentsconfiguration-0": "ègziste pas",
        "exif-componentsconfiguration-5": "V",
        "exif-exposureprogram-0": "Pas dèfeni",
-       "exif-exposureprogram-1": "Manuèl",
+       "exif-exposureprogram-1": "Manuâl",
        "exif-exposureprogram-2": "Programo normal",
        "exif-exposureprogram-3": "Prioritât a l’uvèrtura",
        "exif-exposureprogram-4": "Prioritât a l’ètopior",
        "exif-exposureprogram-5": "Programo crèacion (prèference a la provondior de champ)",
        "exif-exposureprogram-6": "Programo accion (prèference a la vitèsse d’ètopâ)",
-       "exif-exposureprogram-7": "Fôrma portrèt (por clich·ês de prés avouéc fond pas nèt)",
-       "exif-exposureprogram-8": "Fôrma payisâjo (por des clich·ês de payisâjos nèts)",
-       "exif-subjectdistance-value": "$1 mètre{{PLURAL:$1||s}}",
+       "exif-exposureprogram-7": "Fôrma portrèt (por visions de prés avouéc dèrriér troblo)",
+       "exif-exposureprogram-8": "Fôrma payisâjo (por visions de payisâjos avouéc dèrriér nèt)",
+       "exif-subjectdistance-value": "$1 mètro{{PLURAL:$1||s}}",
        "exif-meteringmode-0": "Encognua",
        "exif-meteringmode-1": "Moyena",
-       "exif-meteringmode-2": "Moyena èquilibrâ u centro",
+       "exif-meteringmode-2": "Moyena d’aplomb u centro",
        "exif-meteringmode-3": "Pouent",
        "exif-meteringmode-4": "MultiPouent",
        "exif-meteringmode-5": "Modèlo",
index 0306e65..e5b4171 100644 (file)
@@ -10,7 +10,8 @@
                        "아라",
                        "Purodha",
                        "Macofe",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Ferwisangen onerstrik:",
        "recentchangeslinked-page": "Sidjennööm:",
        "recentchangeslinked-to": "Wise feranrangen üüb sidjen, diar heerhen ferwise.",
        "recentchanges-page-added-to-category": "[[:$1]] tu kategorii saat",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] an {{PLURAL:$2|ian sidj muar|$2 muar sidjen}} tu kategorii saat",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] an [[Special:WhatLinksHere/$1|{{PLURAL:$2|ian sidj muar|$2 muar sidjen}}]] tu kategorii saat",
        "recentchanges-page-removed-from-category": "[[:$1]] faan't kategorii wechnimen",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] an {{PLURAL:$2|ian sidj muar|$2 muar sidjen}} faan det kategorii wechnimen",
        "upload": "Datei huuchschüür",
index fce0339..170d19e 100644 (file)
        "actions": "Gníomhartha",
        "namespaces": "Ainmspásanna",
        "variants": "Leaganacha Malartacha",
+       "navigation-heading": "Roghchlár nascleanúna",
        "errorpagetitle": "Earráid",
        "returnto": "Fill ar ais go $1.",
        "tagline": "Ó {{SITENAME}}.",
        "nstab-template": "Teimpléad",
        "nstab-help": "Cabhair",
        "nstab-category": "Catagóir",
+       "mainpage-nstab": "An príomhleathanach",
        "nosuchaction": "Níl a leithéid de ghníomh ann",
        "nosuchactiontext": "Níl aithníonn an vicí an gníomh atá ann san URL.\nAn ndearna tú botún san URL, no ar lean tú nasc mícheart?\nAn bhfuil fadhb sna bogearraí atá in usáid ar {{SITENAME}}?",
        "nosuchspecialpage": "Níl a leithéid de leathanach speisialta ann",
        "welcomecreation-msg": "Cruthaíodh do chuntas.",
        "yourname": "D'ainm úsáideora",
        "userlogin-yourname": "Ainm úsáideora",
+       "userlogin-yourname-ph": "Iontráil d'ainm úsáideora",
        "yourpassword": "D'fhocal faire",
+       "userlogin-yourpassword": "Pasfhocal",
+       "userlogin-yourpassword-ph": "Iontráil do phasfhocal",
+       "createacct-yourpassword-ph": "Iontráil pasfhocal",
        "yourpasswordagain": "Athiontráil d'fhocal faire",
+       "createacct-yourpasswordagain": "Deimhnigh an pasfhocal",
+       "createacct-yourpasswordagain-ph": "Iontráil an pasfhocal arís",
        "remembermypassword": "Cuimhnigh ar m'fhocal faire ar an ríomhaire seo (ar feadh uastréimhse de $1 {{PLURAL:$1|lá|lá}})",
+       "userlogin-remembermypassword": "Coinnigh logáilte isteach mé",
        "yourdomainname": "D'fhearann",
        "externaldberror": "Bhí earráid bhunachair sonraí ann maidir le fíordheimhniú seachtrach, nóThere was either an external authentication database error or you are not allowed to update your external account.",
        "login": "Logáil isteach",
        "logout": "Logáil amach",
        "userlogout": "Logáil amach",
        "notloggedin": "Níl tú logáilte isteach",
+       "userlogin-noaccount": "Níl cuntas agat?",
+       "userlogin-joinproject": "Cláraigh le {{SITENAME}}",
        "nologin": "Nach bhfuil logáil isteach agat? '''$1'''.",
        "nologinlink": "Cruthaigh cuntas",
        "createaccount": "Cruthaigh cuntas nua",
        "gotaccount": "An bhfuil cuntas agat cheana féin? '''$1'''.",
        "gotaccountlink": "Logáil isteach",
        "userlogin-resetlink": "Sonraí logála isteach dearmadta agat?",
+       "userlogin-resetpassword-link": "Pasfhocal dearmadta?",
+       "userlogin-helplink2": "Cabhair le logáil isteach",
        "createacct-emailrequired": "Seoladh ríomhphoist",
+       "createacct-emailoptional": "Seoladh ríomhphoist (roghnach)",
        "createacct-email-ph": "Iontráil do sheoladh ríomhphoist",
        "createacct-another-email-ph": "Iontráil seoladh ríomhphoist",
        "createaccountmail": "le ríomhphost",
        "createaccount-title": "Cuntas cruthú le {{SITENAME}}",
        "createaccount-text": "Chruthaigh duine éigin cuntas do do sheoladh ríomhphoist ar {{SITENAME}} ($4) leis an ainm \"$2\" agus pasfhocal \"$3\". Ba cheart duit logáil isteach agus do phasfhocal a athrú anois. Is féidir leat neamhaird a thabhairt don teachtaireacht seo má cruthaíodh trí earráid í.",
        "loginlanguagelabel": "Teanga: $1",
+       "pt-login": "Logáil isteach",
+       "pt-login-button": "Logáil isteach",
+       "pt-createaccount": "Cruthaigh cuntas",
+       "pt-userlogout": "Logáil amach",
        "php-mail-error-unknown": "Earráid anaithnid i bhfeidhm mail() de chuid PHP",
        "changepassword": "Athraigh d'fhocal faire",
        "resetpass_announce": "Tá tú logáilte isteach le cód sealadach a seoladh chugat i r-phost.\nChun d'iarratas logáil isteach a chríochnú, caithfidh tú focal faire nua a roghnú anseo:",
        "action-minoredit": "an athrú seo a mharcáil mar mionathrú",
        "action-upload": "uaslódáil an comhad",
        "nchanges": "{{PLURAL:$1|Athrú amháin|$1 athruithe}}",
+       "enhancedrc-history": "stair",
        "recentchanges": "Athruithe is déanaí",
        "recentchanges-legend": "Roghanna do na hathruithe is déanaí",
        "recentchanges-summary": "Déan faire ar na hathruithe is déanaí sa vicí ar an leathanach seo.",
        "recentchanges-feed-description": "Rianaigh na n-athruite vicí is déanaí sa fotha seo.",
+       "recentchanges-label-newpage": "Cruthaíodh lch nua leis an eagarthóireacht seo",
        "recentchanges-label-minor": "Mionathrú é seo",
        "recentchanges-label-bot": "Chomhlíon róbó an t-athrú seo",
+       "recentchanges-legend-heading": "<strong>Eochair:</strong>",
        "recentchanges-legend-newpage": "$1 - leathanach nua",
        "rcnotefrom": "Is iad seo a leanas na hathruithe ó <b>$2</b> (go dti <b>$1</b> taispeánaithe).",
        "rclistfrom": "Taispeáin athruithe nua ó $3 $2 anuas",
        "rcshowhideminor": "$1 mionathruithe",
+       "rcshowhideminor-show": "Taispeáin",
+       "rcshowhideminor-hide": "Folaigh",
        "rcshowhidebots": "$1 róbónna",
-       "rcshowhideliu": "$1 úsáideoirí atá logáilte isteach",
+       "rcshowhidebots-show": "Taispeáin",
+       "rcshowhidebots-hide": "Folaigh",
+       "rcshowhideliu": "$1 úsáideoir cláraithe",
+       "rcshowhideliu-hide": "Folaigh",
        "rcshowhideanons": "$1 úsáideoirí gan ainm",
+       "rcshowhideanons-show": "Taispeáin",
+       "rcshowhideanons-hide": "Folaigh",
        "rcshowhidepatr": "$1 athruithe faoi phatról",
        "rcshowhidemine": "$1 mo chuid athruithe",
+       "rcshowhidemine-show": "Taispeáin",
+       "rcshowhidemine-hide": "Folaigh",
        "rclinks": "Taispeáin an $1 athrú is déanaí sa $2 lá seo caite<br />$3",
        "diff": "difr",
        "hist": "stair",
        "boteditletter": "r",
        "number_of_watching_users_pageview": "[{{PLURAL:$1|úsáideoir amháin|$1 úsáideoirí}} ag faire]",
        "rc_categories_any": "Aon chatagóir",
+       "rc-change-size-new": "$1 {{PLURAL:$1|bheart|beart}} tar éis an athraithe",
        "newsectionsummary": "/* $1 */ mír nua",
        "rc-enhanced-expand": "Taispeáin mionsonraithe (JavaScript riachtanach)",
        "rc-enhanced-hide": "Folaigh shonraí",
        "pager-older-n": "{{PLURAL:$1|1 níos sine|$1 níos sine}}",
        "booksources": "Leabharfhoinsí",
        "booksources-search-legend": "Cuardaigh le foinsí leabhar",
+       "booksources-search": "Cuardaigh",
        "specialloguserlabel": "Úsáideoir:",
        "speciallogtitlelabel": "Teideal:",
        "log": "Logaí",
        "contributions": "Dréachtaí {{GENDER:$1|úsáideora}}",
        "contributions-title": "Dréachtaí úsáideora do $1",
        "mycontris": "Dréachtaí",
+       "anoncontribs": "Dréachtaí",
        "contribsub2": "Do $1 ($2)",
        "nocontribs": "Ní bhfuarthas aon athrú a bhí cosúil le na crítéir seo.",
        "uctop": " (barr)",
        "tooltip-pt-anonuserpage": "Leathanach úsáideora don IP ina dhéanann tú do chuid athruithe",
        "tooltip-pt-mytalk": "Do leathanach phlé",
        "tooltip-pt-anontalk": "Plé maidir le na hathruithe a dhéantar ón seoladh IP seo",
-       "tooltip-pt-preferences": "Mo chuid sainroghanna",
+       "tooltip-pt-preferences": "{{GENDER:|Do}}  chuid sainroghanna",
        "tooltip-pt-watchlist": "Liosta de na leathanaigh a bhfuil tú á bhfaire ar athruithe",
        "tooltip-pt-mycontris": "Liosta do chuid dréachtaí",
        "tooltip-pt-login": "Moltar duit logáil isteach, ach níl sé riachtanach.",
        "file-nohires": "Níl aon taifeach is mó ar fáil.",
        "svg-long-desc": "Comhad SVG, ainmniúil $1 × $2 picteilíni, méid comhaid: $3",
        "show-big-image": "Taispeáin leagan ardtaifigh den íomhá",
+       "show-big-image-size": "$1 × $2 picteilín",
        "newimages": "Gailearaí na n-íomhánna nua",
        "imagelisttext": "Tá liosta thíos de {{PLURAL:$1|comhad amháin|$1 comhaid $2}}.",
        "newimages-label": "Comhadainm (nó cuid de):",
        "specialpages-group-wiki": "Sonraí vicí agus uirslí",
        "specialpages-group-spam": "Uirlisí turscar",
        "blankpage": "Leathanach bán",
+       "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|chlib amháin|clib}}]]: $2)",
        "htmlform-selectorother-other": "Eile",
+       "logentry-move-move": "{{GENDER:$2|Bhog}} $1 an leathanach $3 go $4",
        "feedback-cancel": "Cealaigh",
        "feedback-message": "Teachtaireacht:",
        "searchsuggest-search": "Cuardaigh",
index 2a211ef..8312954 100644 (file)
        "uploadstash-badtoken": "A acción fallou, probablemente porque caducou a información de acceso. Por favor, inténteo de novo.",
        "uploadstash-errclear": "Fallou o borrado de ficheiros.",
        "uploadstash-refresh": "Actualizar a lista de ficheiros",
+       "uploadstash-thumbnail": "ver miniatura",
        "invalid-chunk-offset": "Desprazamento inválido do fragmento",
        "img-auth-accessdenied": "Acceso rexeitado",
        "img-auth-nopathinfo": "Falta a PATH_INFO.\nO seu servidor non está configurado para pasar esta información.\nPode ser que estea baseado en CGI e non soporte img_auth.\nVéxase https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "sessionprovider-generic": "sesións $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sesións baseadas nas cookies",
        "sessionprovider-nocookies": "As cookies poden estar desactivadas. Asegúrese de que ten activas as cookies e comece de novo.",
-       "randomrootpage": "Páxina raíz ao chou"
+       "randomrootpage": "Páxina raíz ao chou",
+       "log-action-filter-block": "Tipo de bloqueo:",
+       "log-action-filter-delete": "Tipo de borrado:",
+       "log-action-filter-patrol": "Tipo de vixilancia:",
+       "log-action-filter-protect": "Tipo de protección:",
+       "log-action-filter-upload": "Tipo de subida:",
+       "log-action-filter-all": "Todas",
+       "log-action-filter-block-block": "Bloquear",
+       "log-action-filter-block-reblock": "Modificación de bloqueo",
+       "log-action-filter-block-unblock": "Desbloquear",
+       "log-action-filter-delete-delete": "Borrado de páxinas",
+       "log-action-filter-delete-restore": "Restauración de páxinas",
+       "log-action-filter-delete-event": "Borrado de rexistros",
+       "log-action-filter-delete-revision": "Borrado de revisión",
+       "log-action-filter-patrol-patrol": "Verificación manual",
+       "log-action-filter-patrol-autopatrol": "Verificación automática",
+       "log-action-filter-protect-protect": "Protección",
+       "log-action-filter-protect-modify": "Modificación de protección",
+       "log-action-filter-protect-unprotect": "Desproteccion",
+       "log-action-filter-upload-upload": "Nova subida",
+       "log-action-filter-upload-overwrite": "Resubida"
 }
index 77cfb9e..6a82cac 100644 (file)
        "recentchangeslinked-page": "Syte:",
        "recentchangeslinked-to": "Zeig Änderige uf Syte, wu uff die Syte verwyyse",
        "recentchanges-page-added-to-category": "[[:$1]] zur Kategorie derzue ta",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] und {{PLURAL:$2|ei|$2}} anderi Syte zur Kategorie derzue ta",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] und [[Special:WhatLinksHere/$1|{{PLURAL:$2|ei|$2}}]] anderi Syte zur Kategorie derzue ta",
        "recentchanges-page-removed-from-category": "[[:$1]] vor Kategorie furtgnoh",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] und {{PLURAL:$2|ei|$2}} anderi Syte vor Kategorie furtgnoh",
        "autochange-username": "Automatischi MediaWiki-Änderig",
index 3ae47f8..7c9e962 100644 (file)
        "noemail": "לא רשומה כתובת דואר אלקטרוני עבור ה{{GENDER:$1|משתמש|משתמשת}} \"$1\".",
        "noemailcreate": "יש לספק כתובת דואר אלקטרוני תקינה.",
        "passwordsent": "סיסמה חדשה נשלחה לכתובת הדואר האלקטרוני הרשומה עבור \"$1\".\nאנא היכנסו חזרה לאתר אחרי שתקבלו אותה.",
-       "blocked-mailpassword": "כתובת ה־IP שלך נחסמה מעריכה, ולפיכך אינך מורשה להשתמש באפשרות שחזור הסיסמה, וזאת כדי למנוע ניצול לרעה של התכונה.",
+       "blocked-mailpassword": "כתובת ה־IP שלך נחסמה מעריכה. אינך מורשה להשתמש באפשרות שחזור הסיסמה, וזאת כדי למנוע ניצול לרעה של התכונה.",
        "eauthentsent": "דוא\"ל אימות נשלח לכתובת הדוא\"ל שצוינה.\nלפני שדברי דוא\"ל אחרים יישלחו לחשבון הזה, יהיה עליכם לפעול לפי ההוראות בדוא\"ל, כדי לאשר שהחשבון אכן שייך לכם.",
        "throttled-mailpassword": "כבר נשלח דוא\"ל לאיפוס הסיסמה ב{{PLURAL:$1|שעה האחרונה|שעתיים האחרונות|־$1 השעות האחרונות}}.\nכדי למנוע ניצול לרעה, יכול להישלח רק דוא\"ל אחד כזה בכל {{PLURAL:$1|שעה|שעתיים|$1 שעות}}.",
        "mailerror": "שגיאה בשליחת דואר: $1",
        "parser-unstrip-loop-warning": "נמצאה לולאה בפריסה",
        "parser-unstrip-recursion-limit": "עומק הרקורסיה של הפריסה עבר את המגבלה ($1)",
        "converter-manual-rule-error": "התגלתה שגיאה בכלל המרת שפה ידני",
-       "undo-success": "ניתן לבטל את העריכה. אנא בִדקו את השוואת הגרסאות למטה כדי לוודא שזה מה שאתם רוצים לעשות, ואז שמרו את השינויים למטה כדי לבצע את ביטול העריכה.",
+       "undo-success": "ניתן לבטל את העריכה.\nאנא בִּדקו את השוואת הגרסאות למטה כדי לוודא שזה אכן מה שאתם רוצים לעשות, ואז שִׁמרו את השינויים למטה כדי לבצע את ביטול העריכה.",
        "undo-failure": "לא ניתן היה לבטל את העריכה עקב התנגשות עם עריכות מאוחרות יותר.",
        "undo-norev": "לא ניתן היה לבטל את העריכה כי היא אינה קיימת או כי היא נמחקה.",
        "undo-nochange": "נראה שהעריכה כבר בוטלה.",
        "uploadstash-badtoken": "ביצוע הפעולה נכשל, אולי בגלל פקיעת תוקפו של אסימון העריכה שלכם. נא לנסות שוב.",
        "uploadstash-errclear": "מחיקת הקבצים נכשלה.",
        "uploadstash-refresh": "רענון רשימת הקבצים",
+       "uploadstash-thumbnail": "הצגת תמונה ממוזערת",
        "invalid-chunk-offset": "היסט גוש לא תקין",
        "img-auth-accessdenied": "הגישה נדחתה",
        "img-auth-nopathinfo": "PATH_INFO חסר.\nהשרת אינו מוגדר להעברת מידע זה.\nייתכן שהוא מבוסס על CGI ולכן אינו יכול לתמוך ב־img_auth.\nראו https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "log-edit-tags": "עריכת התגיות של רשומות היומן שנבחרו",
        "checkbox-select": "בחירה: $1",
        "checkbox-all": "הכול",
-       "checkbox-none": "×\9c×\90 ×\9b×\9c×\95×\9d",
-       "checkbox-invert": "×\9c×\94פ×\95×\9a",
+       "checkbox-none": "כלום",
+       "checkbox-invert": "×\94פ×\99×\9b×\94",
        "allpages": "כל הדפים",
        "nextpage": "הדף הבא ($1)",
        "prevpage": "הדף הקודם ($1)",
        "allpagesfrom": "הצגת דפים החל מ:",
        "allpagesto": "הצגת דפים עד:",
        "allarticles": "כל הדפים",
-       "allinnamespace": "כל הדפים (מרחב שם $1)",
+       "allinnamespace": "×\9b×\9c ×\94×\93פ×\99×\9d (×\9eר×\97×\91 ×\94ש×\9d $1)",
        "allpagessubmit": "הצגה",
        "allpagesprefix": "הדפים ששמם מתחיל ב־:",
        "allpagesbadtitle": "כותרת הדף שניתנה הייתה בלתי־תקינה או שהייתה בה קידומת של קישור לשפה אחרת או לוויקי אחר.\nייתכן שהיא מכילה תו אחד או יותר האסורים לשימוש בכותרות.",
        "movepage-moved-redirect": "נוצרה הפניה.",
        "movepage-moved-noredirect": "יצירת ההפניה בוטלה.",
        "articleexists": "קיים כבר דף באותו שם, או שהשם שבחרת אינו תקין.\nנא לבחור שם אחר.",
-       "cantmove-titleprotected": "×\90×\99× ×\9a ×\9e×\95רש×\94 ×\9c×\94×¢×\91×\99ר ×\90ת ×\94×\93×£ ×\9cש×\9d ×\96×\94 ×\9b×\99×\95×\95×\9f ×©×\94ש×\9d ×\94×\97×\93ש ×\9e×\95×\92×\9f ×\9eפנ×\99 ×\99צ×\99ר×\94",
+       "cantmove-titleprotected": "×\90×\99×\9f ×\91×\90פשר×\95ת×\9b×\9d ×\9c×\94×¢×\91×\99ר ×\90ת ×\94×\93×£ ×\9cש×\9d ×\96×\94 ×\9eש×\95×\9d ×©×\94ש×\9d ×\94×\97×\93ש ×\9e×\95×\92×\9f ×\9eפנ×\99 ×\99צ×\99ר×\94.",
        "movetalk": "העברה גם של דף השיחה",
        "move-subpages": "העברת כל דפי המשנה (עד $1)",
        "move-talk-subpages": "העברת כל דפי המשנה של דף השיחה (עד $1)",
        "tooltip-t-emailuser": "שליחת דואר אלקטרוני {{GENDER:$1|למשתמש זה|למשתמשת זו}}",
        "tooltip-t-info": "מידע נוסף על דף זה",
        "tooltip-t-upload": "העלאת קבצים",
-       "tooltip-t-specialpages": "רש×\99×\9eת כל הדפים המיוחדים",
+       "tooltip-t-specialpages": "רש×\99×\9e×\94 ×©×\9c כל הדפים המיוחדים",
        "tooltip-t-print": "גרסה להדפסה של דף זה",
        "tooltip-t-permalink": "קישור קבוע לגרסה זו של הדף",
        "tooltip-ca-nstab-main": "צפייה בדף התוכן",
        "revdelete-uname-unhid": "הסתרת שם המשתמש בוטלה",
        "revdelete-restricted": "נוספו הגבלות למפעילי מערכת",
        "revdelete-unrestricted": "הוסרו הגבלות ממפעילי מערכת",
-       "logentry-block-block": "$1 {{GENDER:$2|×\97ס×\9d\97ס×\9e×\94}} ×\90ת {{GENDER:$4|$3}} ×¢×\9d ×\96×\9e×\9f ×¤×§×\99×¢×\94 ×©×\9c $5 $6",
+       "logentry-block-block": "$1 {{GENDER:$2|×\97ס×\9d\97ס×\9e×\94}} ×\90ת {{GENDER:$4|$3}} ×\9c×\9eש×\9a $5 $6",
        "logentry-block-unblock": "$1 {{GENDER:$2|שחרר|שחררה}} את החסימה של {{GENDER:$4|$3}}",
        "logentry-block-reblock": "$1 {{GENDER:$2|שינה|שינתה}} את הגדרות החסימה של {{GENDER:$4|$3}} עם זמן פקיעה של $5 $6",
        "logentry-suppress-block": "$1 {{GENDER:$2|חסם|חסמה}} את {{GENDER:$4|$3}} עם זמן פקיעה של $5 $6",
        "logentry-import-upload": "$1 {{GENDER:$2|ייבא|ייבאה}} את $3 באמצעות העלאת קובץ",
        "logentry-import-upload-details": "$1 {{GENDER:$2|ייבא|ייבאה}} את $3 באמצעות העלאת קובץ ({{PLURAL:$4|גרסה אחת|$4 גרסאות}})",
        "logentry-import-interwiki": "$1 {{GENDER:$2|ייבא|ייבאה}} את $3 מאתר ויקי אחר",
-       "logentry-import-interwiki-details": "$1 {{GENDER:$2|ייבא|ייבאה}} את $3 מ־$5 ({{PLURAL:$4|גרסה אחת|$4 גרסאות}})",
+       "logentry-import-interwiki-details": "$1 {{GENDER:$2|ייבא|ייבאה}} את $3 מ־$5&rlm; ({{PLURAL:$4|גרסה אחת|$4 גרסאות}})&rlm;",
        "logentry-merge-merge": "$1 {{GENDER:$2|מיזג|מיזגה}} את $3 לתוך $4 (גרסאות עד $5)",
-       "logentry-move-move": "$1 {{GENDER:$2|העביר|העבירה}} את הדף $3 ל{{GRAMMAR:תחילית|$4}}",
+       "logentry-move-move": "$1 {{GENDER:$2|העביר|העבירה}} את הדף $3 ל{{GRAMMAR:תחילית|$4}}&rlm;",
        "logentry-move-move-noredirect": "$1 {{GENDER:$2|העביר|העבירה}} את הדף $3 ל{{GRAMMAR:תחילית|$4}} בלי להשאיר הפניה",
        "logentry-move-move_redir": "$1 {{GENDER:$2|העביר|העבירה}} את הדף $3 ל{{GRAMMAR:תחילית|$4}} תוך דריסת הפניה",
        "logentry-move-move_redir-noredirect": "$1 {{GENDER:$2|העביר|העבירה}} את הדף $3 ל{{GRAMMAR:תחילית|$4}} תוך דריסת הפניה ובלי להשאיר הפניה",
        "logentry-newusers-autocreate": "חשבון המשתמש $1 {{GENDER:$2|נוצר}} אוטומטית",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|העביר|העבירה}} את הגדרות ההגנה מהדף $4 אל הדף $3",
        "logentry-protect-unprotect": "$1 {{GENDER:$2|הסיר|הסירה}} את ההגנה מהדף $3",
-       "logentry-protect-protect": "$1 {{GENDER:$2|×\94×\92×\9f\94×\92× ×\94}} על הדף $3 $4",
-       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|×\94×\92×\9f\94×\92× ×\94}} על הדף $3 $4 [מדורג]",
+       "logentry-protect-protect": "$1 {{GENDER:$2|×\94פע×\99×\9c\94פע×\99×\9c×\94}} ×\94×\92× ×\94 על הדף $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|×\94פע×\99×\9c\94פע×\99×\9c×\94}} ×\94×\92× ×\94 על הדף $3 $4 [מדורג]",
        "logentry-protect-modify": "$1 {{GENDER:$2|שינה|שינתה}} את רמת ההגנה של הדף $3 $4",
        "logentry-protect-modify-cascade": "$1 {{GENDER:$2|שינה|שינתה}} את רמת ההגנה של הדף $3 $4 [מדורג]",
        "logentry-rights-rights": "$1 {{GENDER:$2|שינה|שינתה}} את ההרשאות של $3 מ{{GRAMMAR:תחילית|$4}} ל{{GRAMMAR:תחילית|$5}}&rlm;",
        "sessionprovider-generic": "התחברויות של $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "התחברויות המבוססות על עוגיות",
        "sessionprovider-nocookies": "ייתכן שאפשרות השימוש בעוגיות כבויה. יש לוודא שאפשרות השימוש בעוגיות מופעלת ולהתחיל מחדש.",
-       "randomrootpage": "דף שורש אקראי"
+       "randomrootpage": "דף שורש אקראי",
+       "log-action-filter-block": "סוג החסימות:",
+       "log-action-filter-delete": "סוג המחיקות:",
+       "log-action-filter-patrol": "סוג השינויים הבדוקים:",
+       "log-action-filter-protect": "סוג ההגנות:",
+       "log-action-filter-upload": "סוג ההעלאות:",
+       "log-action-filter-all": "הכול",
+       "log-action-filter-block-block": "חסימות",
+       "log-action-filter-block-reblock": "שינויי חסימה",
+       "log-action-filter-block-unblock": "שחרורי חסימה",
+       "log-action-filter-delete-delete": "מחיקת דפים",
+       "log-action-filter-delete-restore": "שחזור דפים מחוקים",
+       "log-action-filter-delete-event": "מחיקת יומנים",
+       "log-action-filter-delete-revision": "מחיקת גרסאות",
+       "log-action-filter-patrol-patrol": "סימוניים ידניים כבדוק",
+       "log-action-filter-patrol-autopatrol": "סימונים אוטומטיים כבדוק",
+       "log-action-filter-protect-protect": "הגנות",
+       "log-action-filter-protect-modify": "שינויי הגנה",
+       "log-action-filter-protect-unprotect": "הסרות הגנה",
+       "log-action-filter-upload-upload": "העלאות חדשות",
+       "log-action-filter-upload-overwrite": "דריסת קבצים קיימים"
 }
index 8477c66..3dfd4bb 100644 (file)
@@ -71,7 +71,9 @@
                        "Niharika29",
                        "जनक राज भट्ट",
                        "YmKavishwar",
-                       "Upendradutt93"
+                       "Upendradutt93",
+                       "Nemo bis",
+                       "Wassan.anmol"
                ]
        },
        "tog-underline": "कड़ियाँ अधोरेखन:",
        "laggedslavemode": "'''चेतावनी:''' यह पृष्ठ अद्यतनीत जानकारी-युक्त ना होने की आशंका है।",
        "readonly": "डाटाबेस लॉक किया हुआ है",
        "enterlockreason": "लॉक करने का कारण दीजिए, साथ ही लॉक खुलने के समय का लगभग आकलन दीजिये।",
-       "readonlytext": "शायद मेंटेनन्स के चलते डाटाबेस नये संपादन और अन्य बदलावों से लॉक किया गया है, जिसके बाद यह सामान्य स्थिति में आ जाना चाहिये।\n\nजिस प्रबंधक ने यह लॉक किया था उसने यह कारण दिया है: $1",
+       "readonlytext": "शायद à¤®à¥\87à¤\82à¤\9fà¥\87ननà¥\8dस à¤\95à¥\87 à¤\9aलतà¥\87 à¤¡à¤¾à¤\9fाबà¥\87स à¤¨à¤¯à¥\87 à¤¸à¤\82पादन à¤\94र à¤\85नà¥\8dय à¤¬à¤¦à¤²à¤¾à¤µà¥\8bà¤\82 à¤¸à¥\87 à¤²à¥\89à¤\95 à¤\95िया à¤\97या à¤¹à¥\88, à¤\9cिसà¤\95à¥\87 à¤¬à¤¾à¤¦ à¤¯à¤¹ à¤¸à¤¾à¤®à¤¾à¤¨à¥\8dय à¤¸à¥\8dथिति à¤®à¥\87à¤\82 à¤\86 à¤\9cाना à¤\9aाहियà¥\87।\n\nà¤\9cिस à¤\95ारà¥\8dयà¤\95ारà¥\80 à¤ªà¥\8dरबà¤\82धà¤\95 à¤¨à¥\87 à¤¯à¤¹ à¤²à¥\89à¤\95 à¤\95िया à¤¥à¤¾ à¤\89सनà¥\87 à¤¯à¤¹ à¤\95ारण à¤¦à¤¿à¤¯à¤¾ à¤¹à¥\88: $1",
        "missing-article": "डाटाबेस में $2 के अंदर कहीं भी \"$1\" नहीं मिला।\n\nआम तौर पर हटाए जा चुके पृष्ठ की इतिहास कड़ी का प्रयोग करने पर ऐसा होता है।\n\nअगर ऐसा नहीं है, तो शायद आपने सॉफ़्टवेयर में त्रुटि खोज ली है।\nकृपया यू॰आर॰एल पते समेत किसी [[Special:ListUsers/sysop|प्रबंधक]] को इसका ब्यौरा दें।",
        "missingarticle-rev": "(अवतरण#: $1)",
        "missingarticle-diff": "(अंतर: $1, $2)",
        "mypreferencesprotected": "आपके पास अपनी वरीयताएँ बदलने की अनुमति नहीं है।",
        "ns-specialprotected": "विशेष पृष्ठ सम्पादित नहीं किये जा सकते।",
        "titleprotected": "सदस्य [[User:$1|$1]] ने इस शीर्षक का पृष्ठ बनाने से सुरक्षित किया हुआ है।\nइसके लिये निम्न कारण दिया गया है: <em>$2</em>",
-       "filereadonlyerror": "\"$1\" फ़ाइल को बदलने में असक्षम क्योंकि भण्डार \"$2\" इस समय 'केवल पाठन हेतु' (रीड ओनली) है।\n\nजिस प्रबंधक ने ये प्रबंध लगाया है उन्होंने निम्न विवरण प्रदान किया है: \"$3\"।",
+       "filereadonlyerror": "\"$1\" à¤«à¤¼à¤¾à¤\87ल à¤\95à¥\8b à¤¬à¤¦à¤²à¤¨à¥\87 à¤®à¥\87à¤\82 à¤\85सà¤\95à¥\8dषम à¤\95à¥\8dयà¥\8bà¤\82à¤\95ि à¤­à¤£à¥\8dडार \"$2\" à¤\87स à¤¸à¤®à¤¯ 'à¤\95à¥\87वल à¤ªà¤¾à¤ à¤¨ à¤¹à¥\87तà¥\81' (रà¥\80ड à¤\93नलà¥\80) à¤¹à¥\88।\n\nà¤\9cिस à¤\95ारà¥\8dयà¤\95ारà¥\80 à¤ªà¥\8dरबà¤\82धà¤\95 à¤¨à¥\87 à¤¯à¥\87 à¤ªà¥\8dरबà¤\82ध à¤²à¤\97ाया à¤¹à¥\88 à¤\89नà¥\8dहà¥\8bà¤\82नà¥\87 à¤¨à¤¿à¤®à¥\8dन à¤µà¤¿à¤µà¤°à¤£ à¤ªà¥\8dरदान à¤\95िया à¤¹à¥\88: \"$3\"।",
        "invalidtitle-knownnamespace": "\"$2\" नामस्थान और \"$3\" नाम वाला गलत शीर्षक",
        "invalidtitle-unknownnamespace": "अज्ञात नामस्थान संख्या $1 और नाम \"$2\" वाला गलत शीर्षक",
        "exception-nologin": "लॉग इन नहीं किया है",
        "continue-editing": "संपादन क्षेत्र को जाएँ",
        "previewconflict": "यह झलक ऊपरी पाठ सम्पादन क्षेत्र में हुए बदलाव दिखाती है, और यदि आप अभी संजोते हैं तो यही पाठ संजोया जाएगा।",
        "session_fail_preview": "'''क्षमा करें! सेशन डाटा के नष्ट होने के कारण आपके बदलाव संजोये नहीं जा सके।'''\nकृपया पुन: यत्न करें। अगर इसके बाद भी ऐसा ही होता है तो कृपया [[Special:UserLogout|लॉग आउट]] कर के पुनः लॉग इन करें।",
-       "session_fail_preview_html": "'''क्षमा करें! सेशन डाटा के नष्ट होने के कारण आपके बदलाव संजोये नहीं जा सके।'''\n\n''चूँकि {{SITENAME}} पर raw HTML सक्षम है, जावास्क्रिप्ट हमलों से बचाव के लिये झलक नहीं दिखाई गई है।''\n\n'''अगर यह आपका वैध संपादन यत्न था, तो कृपया पुनः यत्न करें।'''\nअगर इसके बाद भी ऐसा ही होता है तो कृपया [[Special:UserLogout|लॉग आउट]] कर के पुनः लॉग इन करें।",
+       "session_fail_preview_html": "क्षमा करें! सेशन डाटा के नष्ट होने के कारण आपके बदलाव संजोये नहीं जा सके।\n\n<em>चूँकि {{SITENAME}} पर raw HTML सक्षम है, जावास्क्रिप्ट हमलों से बचाव के लिये झलक नहीं दिखाई गई है।</em>\n\n<strong>अगर यह आपका वैध संपादन यत्न था, तो कृपया पुनः यत्न करें।</strong>\nअगर इसके बाद भी ऐसा ही होता है तो कृपया [[Special:UserLogout|लॉग आउट]] कर के पुनः लॉग इन करें तथा जांचिए यदि आपका ब्राउज़र इस साइट से कुकीज़ की अनुमति देता है।",
        "token_suffix_mismatch": "'''आपके द्वारा किये गये बदलाव रद्द कर दिये गये हैं क्योंकि आपके क्लायंट ने आपके संपादन टोकन में दिये हुए विरामचिन्हों में बदलाव किये हैं।'''\nलेख के पाठ में खराबी ना आये इसलिये आपके बदलाव रद्द कर दिये गये हैं।\nऐसा तब भी हो सकता है यदि आप कोई खराब वेब-आधारित अनामक प्रौक्सी प्रयोग कर रहे हों।",
        "edit_form_incomplete": "'''सम्पादन फ़ॉर्म के कुछ भाग सर्वर तक नहीं पहुँच पाए; जाँच लें कि आपके द्वारा किये बदलाव अक्षुण्ण हैं, और सहेजने का पुनः यत्न करें।'''",
        "editing": "$1 सम्पादन",
        "copyrightwarning2": "{{SITENAME}} पर किया कोई भी योगदान अन्य सदस्यों द्वारा बदला जा सकता है और हटाया भी जा सकता है।\nअगर आपको अपने लिखे हुए पाठ में संपादन होना नामंजूर है तो यहाँ पर न लिखें।<br />\nआप हमें यह भी वचन देतें हैं कि यह आपने स्वयं लिखा है अथवा सार्वजनिक क्षेत्र या किसी समान मुक्त स्रोत से प्रतिलिपित किया है (अधिक जानकारी के लिये $1 देखें)।\n'''कॉपीराइट सुरक्षित कार्यों को बिना अनुमति के यहाँ न डालें!'''",
        "editpage-cannot-use-custom-model": "इस पृष्ठ का मुख्य सामग्री परिवर्तित नहीं हुआ।",
        "longpageerror": "'''त्रुटि: आपका दिया हुआ पाठ {{PLURAL:|$1 किलोबाइट|$1 किलोबाइट}} लंबा है, जो {{PLURAL:|$2 किलोबाइट|$2 किलोबाइट}} की सीमा से बाहर है।\nइसे संजोया नहीं जा सकता।'''",
-       "readonlywarning": "'''सावधान: डाटाबेस को रख-रखाव के लिये बंद कर दिया गया है, इसलिये अभी आपके बदलाव संजोए नहीं जा सकते।\nअगर आप चाहें तो इस सामग्री को बाद के लिए कॉपी-पेस्ट कर के किसी टेक्स्ट फ़ाइल में रख सकते हैं।'''\n\nबंद करने वाले प्रबंधक ने बंद करने का यह कारण दिया है: $1",
+       "readonlywarning": "<strong>सावधान: डाटाबेस को रख-रखाव के लिये बंद कर दिया गया है, इसलिये अभी आपके बदलाव संजोए नहीं जा सकते।\nअगर आप चाहें तो इस सामग्री को बाद के लिए कॉपी-पेस्ट कर के किसी टेक्स्ट फ़ाइल में रख सकते हैं।</strong>\n\nबंद करने वाले कार्यकारी प्रबंधक ने बंद करने का यह कारण दिया है: $1",
        "protectedpagewarning": "'''चेतावनी: इस पृष्ठ को सुरक्षित कर दिया गया है और इसे केवल प्रबंधक ही सम्पादित कर सकते हैं।'''\nनवीनतम लॉग प्रविष्टि संदर्भ के लिये नीचे दी है:",
        "semiprotectedpagewarning": "'''सूचना:''' यह पृष्ठ सुरक्षित कर दिया गया है और इसे केवल पंजीकृत सदस्य ही सम्पादित कर सकते हैं।\nनवीनतम लॉग प्रविष्टि संदर्भ के लिये नीचे दी है:",
        "cascadeprotectedwarning": "'''सावधान:''' यह पृष्ठ निम्नलिखित सुरक्षा-सीढ़ी {{PLURAL:$1|पृष्ठ से|पन्नों से}} जुड़ा हुआ होने के कारण सुरक्षित है, और केवल प्रबंधक ही इसमें बदलाव कर सकते हैं:",
        "permissionserrors": "अधिकार त्रुटि",
        "permissionserrorstext": "निम्नलिखित {{PLURAL:$1|कारण|कारणों}} से आपको ऐसा करने की अनुमति नहीं हैं:",
        "permissionserrorstext-withaction": "आपको $2 की अनुमति नहीं हैं, निम्नलिखित {{PLURAL:$1|कारण|कारणों}} की वजह से:",
-       "contentmodelediterror": "à¤\86प à¤\87स à¤ªà¥\83षà¥\8dठ à¤\95ा à¤\87तिहास à¤®à¥\87à¤\82 à¤¸à¤®à¥\8dपादन à¤¨à¤¹à¥\80à¤\82 à¤\95र à¤¸à¤\95तà¥\87 à¤¹à¥\88à¤\82 à¤\95à¥\8dयà¥\8bà¤\82à¤\95ि à¤\87सà¤\95ा à¤¸à¤¾à¤®à¤\97à¥\8dरà¥\80 <code>$1</code>, à¤\94र à¤µà¤°à¥\8dतमान à¤¸à¤¾à¤®à¤\97à¥\8dरà¥\80 <code>$2</code> है।",
+       "contentmodelediterror": "à¤\86प à¤\87स à¤ªà¥\83षà¥\8dठ à¤\95ा à¤\87तिहास à¤®à¥\87à¤\82 à¤¸à¤®à¥\8dपादन à¤¨à¤¹à¥\80à¤\82 à¤\95र à¤¸à¤\95तà¥\87 à¤¹à¥\88à¤\82 à¤\95à¥\8dयà¥\8bà¤\82à¤\95ि à¤\87सà¤\95ा à¤¸à¤¾à¤®à¤\97à¥\8dरà¥\80 <code>$1</code>, à¤\9cà¥\8b à¤\95à¥\80 à¤µà¤°à¥\8dतमान à¤¸à¤¾à¤®à¤\97à¥\8dरà¥\80 à¤¸à¥\87 <code>$2</code> à¤\85लà¤\97 है।",
        "recreate-moveddeleted-warn": "'''चेतावनी: आप एक पहले हटाए गए पृष्ठ को पुनर्निर्मित कर रहे हैं।'''\n\nआप को विचार करना चाहिये कि क्या इस पृष्ठ का संपादन जारी रखना उचित होगा।\nइस पृष्ट के हटाने व स्थानांतरण का लॉग सुविधा के लिये उपलब्ध है:",
        "moveddeleted-notice": "यह पृष्ठ हटाया जा चुका है।\nपृष्ठ के हटाने और स्थानांतरण का लॉग संदर्भ के लिए नीचे दिया गया है।",
        "moveddeleted-notice-recent": "क्षमा करें, यह पृष्ठ कुछ ही समय पहले हटाया गया है। (24 घण्टों के भीतर)\nइसके हटाये और स्थानांतरित करने का लोग नीचे दिया हुआ है।",
        "revdelete-unsuppress": "पुनर्स्थापित अवतरणों पर से प्रतिबन्ध हटाएँ",
        "revdelete-log": "कारण:",
        "revdelete-submit": "चयनित {{PLURAL:$1|अवतरण|अवतरणों}} पर लागू करें",
-       "revdelete-success": "'''अवतरण दृश्यता सफलतापूर्वक अद्यातानीत की गई।'''",
+       "revdelete-success": "अवतरण दृश्यता सफलतापूर्वक अद्यातानीत की गई।",
        "revdelete-failure": "'''अवतरण दृश्यता अद्यातानीत नहीं की जा सकी:'''\n$1",
        "logdelete-success": "लॉग दृष्यता बदली गई।",
        "logdelete-failure": "'''लॉग दृश्यता का जमाव नहीं किया जा सका:'''\n$1",
        "recentchangeslinked-page": "पृष्ठ नाम:",
        "recentchangeslinked-to": "इसके बदले में दिये हुए पृष्ठसे जुडे पन्नोंके बदलाव दर्शायें",
        "recentchanges-page-added-to-category": "[[:$1]] श्रेणी में जुड़ा",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] और {{PLURAL:$2|एक पृष्ठ|$2 पृष्ठ}} श्रेणी में जुड़ा",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] और [[Special:WhatLinksHere/$1|{{PLURAL:$2|एक पृष्ठ|$2 पृष्ठ}}]] श्रेणी में जुड़ा",
        "recentchanges-page-removed-from-category": "[[:$1]] श्रेणी से हटा",
-       "recentchanges-page-removed-from-category-bundled": "[[:$1]] और {{PLURAL:$2|एक पृष्ठ|$2 पृष्ठ}} श्रेणी से हटा",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] और [[Special:WhatLinksHere/$1|{{PLURAL:$2|एक पृष्ठ|$2 पृष्ठ}}]] श्रेणी से हटा",
        "autochange-username": "मीडियाविकि स्वतः परिवर्तन",
        "upload": "फ़ाइल अपलोड करें",
        "uploadbtn": "फ़ाइल अपलोड करें",
        "uploadstash-badtoken": "वह कार्य असफल रहा, सम्भवतः आपके सम्पादन प्रमाणपत्र की अवधि समाप्त हो गई है। पुनः प्रयास करें।",
        "uploadstash-errclear": "फ़ाइलों को साफ़ करना असफल रहा।",
        "uploadstash-refresh": "फ़ाइलों की सूची रिफ़्रेश करें",
+       "uploadstash-thumbnail": "छवि देखें",
        "invalid-chunk-offset": "अग्राह्य चंक ऑफ़सेट",
        "img-auth-accessdenied": "अनुमति नहीं है",
        "img-auth-nopathinfo": "PATH_INFO मौजूद नहीं है।\nआपके सर्वर में इस जानकारी को भेजने के लिए जमाव नहीं है।\nयह सी॰जी॰आई-आधारित हो सकता है और img_auth को स्वीकार नहीं करता है।\nhttps://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization देखें।",
        "emailccsubject": "आपके ई-मेल की प्रति जो $1 को भेजा गया: $2",
        "emailsent": "ई-मेल भेज दिया गया है।",
        "emailsenttext": "आपका ई-मेल संदेश भेज दिया गया है।",
-       "emailuserfooter": "इस ई-मेल को $1 द्वारा $2 को भेजा गया था जिसके लिए \"{{int:emailuser}}\" कार्य को {{SITENAME}} पर प्रयोग में लाया गया था।",
+       "emailuserfooter": "इस ई-मेल को $1 {{GENDER:$1|द्वारा}} {{GENDER:$2|$2}} को भेजा गया था जिसके लिए \"{{int:emailuser}}\" कार्य को {{SITENAME}} पर प्रयोग में लाया गया था।",
        "usermessage-summary": "प्रणाली सन्देश छोड़ रहा है।",
        "usermessage-editor": "सिस्टम दूत",
        "watchlist": "ध्यानसूची",
        "watchlistanontext": "अपनी ध्यानसूची में मौजूद पृष्ठ देखने या फिर संपादित करने के लिये कॄपया लॉग इन करें।",
        "watchnologin": "लॉग इन नहीं किया है",
        "addwatch": "ध्यानसूची में जोड़ें",
-       "addedwatchtext": "à¤\86पà¤\95à¥\80 [[Special:Watchlist|धà¥\8dयानसà¥\82à¤\9aà¥\80]] à¤®à¥\87à¤\82 \"[[:$1]]\" à¤ªà¥\83षà¥\8dठ à¤\9cà¥\8bड़ à¤¦à¤¿à¤¯à¤¾ à¤\97या à¤¹à¥\88।\nभविषà¥\8dय à¤®à¥\87à¤\82 à¤\87स à¤ªà¥\83षà¥\8dठ à¤¤à¤¥à¤¾ à¤\87सà¤\95à¥\87 à¤µà¤¾à¤°à¥\8dता à¤ªà¥\83षà¥\8dठ à¤®à¥\87à¤\82 à¤¹à¥\8bनà¥\87 à¤µà¤¾à¤²à¥\87 à¤¬à¤¦à¤²à¤¾à¤µ à¤\86पà¤\95à¥\80 à¤§à¥\8dयानसà¥\82à¤\9aà¥\80 à¤®à¥\87à¤\82 à¤¦à¤¿à¤\96à¥\87à¤\82à¤\97à¥\87।",
+       "addedwatchtext": "à¤\86पà¤\95à¥\80 [[Special:Watchlist|धà¥\8dयानसà¥\82à¤\9aà¥\80]] à¤®à¥\87à¤\82 \"[[:$1]]\" à¤\94र à¤\87सà¤\95à¥\87 à¤\9aरà¥\8dà¤\9aा à¤ªà¥\83षà¥\8dठ à¤\9cà¥\8bड़ à¤¦à¤¿à¤\8f à¤\97à¤\8f à¤¹à¥\88à¤\82।",
        "addedwatchtext-short": "पृष्ठ \"$1\" को आपकी ध्यानसूची से जोड़ा गया है।",
        "removewatch": "ध्यानसूची से हटाएँ",
        "removedwatchtext": "\"[[:$1]]\" नामक पृष्ठ को आपकी [[Special:Watchlist|ध्यानसूची]] से हटा दिया गया है।",
index e656523..3489cc9 100644 (file)
        "recentchangeslinked-page": "Lap neve:",
        "recentchangeslinked-to": "Inkább az erre linkelő lapok változtatásait mutasd",
        "recentchanges-page-added-to-category": "[[:$1]] hozzáadva a kategóriához",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] és {{PLURAL:$2|egy oldal|$2 oldal}} hozzáadva a kategóriához",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] és [[Special:WhatLinksHere/$1|{{PLURAL:$2|egy oldal|$2 oldal}}]] hozzáadva a kategóriához",
        "recentchanges-page-removed-from-category": "[[:$1]] eltávolítva a kategóriából",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] és {{PLURAL:$2|egy oldal|$2 oldal}} eltávolítva a kategóriából",
        "upload": "Fájl feltöltése",
index 34755d7..244c5aa 100644 (file)
        "recentchangeslinked-page": "Nomine del pagina:",
        "recentchangeslinked-to": "Monstrar modificationes in paginas con ligamines al pagina specificate",
        "recentchanges-page-added-to-category": "[[:$1]] addite al categoria",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] e {{PLURAL:$2|un pagina|$2 paginas}} addite al categoria",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] e [[Special:WhatLinksHere/$1|{{PLURAL:$2|un pagina|$2 paginas}}]] addite al categoria",
        "recentchanges-page-removed-from-category": "[[:$1]] removite del categoria",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] e {{PLURAL:$2|un pagina|$2 paginas}} removite del categoria",
        "autochange-username": "Cambiamento automatic de MediaWiki",
        "uploadstash-badtoken": "Le execution de iste action ha fallite, forsan perque le datos del session ha expirate. Tenta lo de novo.",
        "uploadstash-errclear": "Le radimento del files ha fallite.",
        "uploadstash-refresh": "Refrescar le lista de files",
+       "uploadstash-thumbnail": "vider miniatura",
        "invalid-chunk-offset": "Position de segmento invalide",
        "img-auth-accessdenied": "Accesso refusate",
        "img-auth-nopathinfo": "PATH_INFO manca.\nLe servitor non ha essite configurate pro passar iste information.\nIllo pote esser basate super CGI e non pote supportar img_auth.\nVide https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "mostrevisions": "Paginas le plus modificate",
        "prefixindex": "Tote le paginas con prefixo",
        "prefixindex-namespace": "Tote le paginas con prefixo (spatio de nomines $1)",
+       "prefixindex-submit": "Monstrar",
        "prefixindex-strip": "Remover prefixo in lista",
        "shortpages": "Paginas curte",
        "longpages": "Paginas longe",
        "protectedpages-performer": "Protegite per",
        "protectedpages-params": "Parametros de protection",
        "protectedpages-reason": "Motivo",
+       "protectedpages-submit": "Monstrar paginas",
        "protectedpages-unknown-timestamp": "Incognite",
        "protectedpages-unknown-performer": "Usator incognite",
        "protectedtitles": "Titulos protegite",
        "protectedtitles-summary": "Iste pagina lista titulos actualmente protegite contra creation. Pro un lista de paginas existente que ha essite protegite, vide [[{{#special:ProtectedPages}}|{{int:protectedpages}}]].",
        "protectedtitlesempty": "Nulle titulos es actualmente protegite con iste parametros.",
+       "protectedtitles-submit": "Monstrar titulos",
        "listusers": "Lista de usatores",
        "listusers-editsonly": "Monstrar solmente usatores con modificationes",
        "listusers-creationsort": "Ordinar per data de creation",
        "usereditcount": "$1 {{PLURAL:$1|modification|modificationes}}",
        "usercreated": "{{GENDER:$3|Create}} le $1 a $2",
        "newpages": "Nove paginas",
+       "newpages-submit": "Monstrar",
        "newpages-username": "Nomine de usator:",
        "ancientpages": "Paginas le plus ancian",
        "move": "Renominar",
        "apihelp": "Adjuta con le API",
        "apihelp-no-such-module": "Modulo \"$1\" non trovate.",
        "apisandbox": "Cassa de sablo pro API",
+       "apisandbox-jsonly": "JavaScript es necessari pro usar le cassa a sablo del API.",
        "apisandbox-api-disabled": "Le API ha essite disactivate in iste sito.",
-       "apisandbox-intro": "Usa iste pagina pro experimentar con le '''API de servicio web de MediaWiki'''.\nConsulta [//www.mediawiki.org/wiki/API:Main_page le documentation del API] pro ulterior detalios concernente le uso del API. Per exemplo: [//www.mediawiki.org/wiki/API#A_simple_example obtener le contento de un Pagina principal]. Selige un action pro vider altere exemplos.",
+       "apisandbox-intro": "Usa iste pagina pro experimentar con le <strong>API de servicio web de MediaWiki</strong>.\nConsulta [[mw:API:Main page|le documentation del API]] pro ulterior detalios concernente le uso del API. Per exemplo: [//www.mediawiki.org/wiki/API#A_simple_example obtener le contento de un Pagina principal]. Selige un action pro vider altere exemplos.\n\nAttention: Ben que isto es un cassa a sablo, le actiones que tu exeque in iste pagina pote modificar tote le wiki.",
+       "apisandbox-fullscreen": "Expander pannello",
+       "apisandbox-fullscreen-tooltip": "Expander le pannello del cassa a sablo pro impler le fenestra del navigator.",
+       "apisandbox-unfullscreen": "Monstrar pagina",
+       "apisandbox-unfullscreen-tooltip": "Reducer le pannello del cassa a sablo de sorta que le ligamines de navigation de MediaWiki es disponibile.",
        "apisandbox-submit": "Facer requesta",
        "apisandbox-reset": "Rader",
-       "apisandbox-examples": "Exemplo",
-       "apisandbox-results": "Resultato",
+       "apisandbox-retry": "Reprobar",
+       "apisandbox-loading": "Carga information pro le modulo API \"$1\"...",
+       "apisandbox-load-error": "Un error ha occurrite durante le cargamento del information pro le modulo API \"$1\": $2",
+       "apisandbox-no-parameters": "Iste modulo API non ha parametros.",
+       "apisandbox-helpurls": "Ligamines de adjuta",
+       "apisandbox-examples": "Exemplos",
+       "apisandbox-dynamic-parameters": "Parametros additional",
+       "apisandbox-dynamic-parameters-add-label": "Adder parametro:",
+       "apisandbox-dynamic-parameters-add-placeholder": "Nomine del parametro",
+       "apisandbox-dynamic-error-exists": "Un parametro con le nomine \"$1\" jam existe.",
+       "apisandbox-deprecated-parameters": "Parametros obsolescente",
+       "apisandbox-fetch-token": "Auto-reimpler le indicio",
+       "apisandbox-submit-invalid-fields-title": "Alcun campos non es valide",
+       "apisandbox-submit-invalid-fields-message": "Per favor, corrige le campos marcate e reproba.",
+       "apisandbox-results": "Resultatos",
        "apisandbox-request-url-label": "URL de requesta:",
        "apisandbox-request-time": "Duration del requesta: $1",
        "booksources": "Fontes de libros",
index be3b009..c710172 100644 (file)
@@ -44,7 +44,8 @@
                        "Matma Rex",
                        "WongKentir",
                        "Rachmat.Wahidi",
-                       "Arief"
+                       "Arief",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Garis bawahi pranala:",
        "recentchangeslinked-page": "Nama halaman:",
        "recentchangeslinked-to": "Perlihatkan perubahan dari halaman-halaman yang terhubung dengan halaman yang disajikan",
        "recentchanges-page-added-to-category": "[[:$1]] ditambahkan pada kategori",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] dan {{PLURAL:$2|satu halaman|$2 halaman-halaman}} lagi halaman ditambahkan pada kategori",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] dan [[Special:WhatLinksHere/$1|{{PLURAL:$2|satu halaman|$2 halaman-halaman}}]] lagi halaman ditambahkan pada kategori",
        "recentchanges-page-removed-from-category": "[[:$1]] dihapus dari kategori",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] dan {{PLURAL:$2|satu halaman|$2 halaman-halaman}} lagi halaman dihapus dari kategori",
        "autochange-username": "Perubahan otomatis MediaWiki",
index 3268437..c39fece 100644 (file)
@@ -8,7 +8,8 @@
                        "Urhixidur",
                        "לערי ריינהארט",
                        "아라",
-                       "Macofe"
+                       "Macofe",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Pinag-ugisan ti silpo:",
        "recentchangeslinked-page": "Nagan ti panid:",
        "recentchangeslinked-to": "Ipakita dagiti sinukatan kadagiti panid nga imbes a naisilpo iti naited a panid",
        "recentchanges-page-added-to-category": "nainayon ti [[:$1]] iti kategoria",
-       "recentchanges-page-added-to-category-bundled": "nainayon ti [[:$1]] ken {{PLURAL:$2|maysa a panid|$2 a pampanid}} iti kategoria",
+       "recentchanges-page-added-to-category-bundled": "nainayon ti [[:$1]] ken [[Special:WhatLinksHere/$1|{{PLURAL:$2|maysa a panid|$2 a pampanid}}]] iti kategoria",
        "recentchanges-page-removed-from-category": "naikkat ti [[:$1]] manipud iti kategoria",
        "recentchanges-page-removed-from-category-bundled": "Naikkat ti [[:$1]] ken {{PLURAL:$2|maysa a panid|$2 a pampanid}} manipud iti kategoria",
        "autochange-username": "Automatiko a panagbaliw iti MediaWiki",
index 6b9434e..4279cce 100644 (file)
        "search": "Лахаp",
        "searchbutton": "Лахар",
        "go": "Дехьа г|о",
-       "searcharticle": "Дехьа г|о",
+       "searcharticle": "Дехьавала",
        "history": "Истори",
        "history_short": "Истори",
        "updatedmarker": "Со ханача денца хувцамаш хиннaд",
        "print": "Кепатохар",
        "view": "Б|аргтассам",
        "view-foreign": "Мазаоаг|он чу $1 хьажа",
-       "edit": "Ð¥Ñ\83вÑ\86а",
+       "edit": "Ð\9dийÑ\81де",
        "edit-local": "Хувца локальни йоазонца сурт оттадар",
        "create": "Хьаде",
        "create-local": "ТIатоха локальни йоазонца сурт оттадар",
        "specialpage": "Г|улакхадара оаг|ув",
        "personaltools": "Са г|ирсаш",
        "articlepage": "Йоазон т|а б|аргтасса",
-       "talk": "Дувцам",
+       "talk": "Дувца оттадар",
        "views": "БӀаргтассамаш",
        "toolbox": "ГӀирсаш",
        "userpage": "Доакъошхочун оаг|он т|а б|аргтасса",
        "imagepage": "Лурдара оаг|oн т|а б|аргтасса",
        "mediawikipage": "Xоаман оаг|ув хьахьокха",
        "templatepage": "Ч|абала оаг|oн т|а б|аргтасса",
-       "viewhelppage": "ГӀо деха",
+       "viewhelppage": "ГӀо хьаэцар",
        "categorypage": "Катага оаг|oн т|а б|аргтасса",
        "viewtalkpage": "Дувцамага б|аргтасса",
        "otherlanguages": "Кхыча меттаех",
        "emailconfirmlink": "Доаржален хоамни хьожадорг дIачIоагIаде",
        "loginlanguagelabel": "Мотт: $1",
        "pt-login": "Чувала/яла",
-       "pt-createaccount": "Ð\94акÑ\8aалаÑ\8cÑ\86аÑ\80Ñ\85о кхолла",
+       "pt-createaccount": "УÑ\87Ñ\91Ñ\82а Ñ\8fздаÑ\80 кхолла",
        "changepassword": "КъайладIоaгIа дIахувцар",
        "oldpassword": "Къаьна къайладIоагӀа:",
        "newpassword": "Керда къайладIоагӀа:",
        "nextn": "{{PLURAL:$1|тlехьайоагlар $1|тlехьайоагlараш $1|тlехьайоагlараш $1}}",
        "prevn-title": "{{PLURAL:$1|1=$1 хьалхара йоазув|$1 хьалхара йоазувнаш}}",
        "nextn-title": "{{PLURAL:$1|1=$1 тIехьара йоазув|$1 тIехьара йоазувнаш}}",
-       "shown-title": "УкÑ\85 Ð¾Ð°Ð³IÑ\83вни $1 {{PLURAL:$1|1=йоазÑ\83в|йоазÑ\83внаÑ\88}} Ñ\85Ñ\8cаÑ\85Ñ\8cокÑ\85а",
+       "shown-title": "Ð¥Ñ\8cóкÑ\85а $1 {{PLURAL:$1|даÑ\8c Ð¹Ð¾Ð°Ð·Ð¾|даÑ\8c Ð¹Ð¾Ð°Ð·Ð¾Ð½Ð°Ñ\88}} Ñ\83кÑ\85 Ð¾Ã¡Ð³IÑ\83вна Ñ\82Iа",
        "viewprevnext": "($1 {{int:pipe-separator}} $2) ($3) хьажа",
        "searchmenu-exists": "'''Укх масса-хьахьоадайтамач ер оаг|ув \"[[:$1]]\" я'''",
        "searchmenu-new": "'''Укх \"[[:$1]]\" масса-хьахоадайтамач оагIув хьае!'''",
        "action-read": "Укх оагIуви дешам",
        "action-edit": "Ер оагIув хувца",
        "nchanges": "$1 {{PLURAL:$1|1=хувцам|хувцамаш}}",
-       "enhancedrc-history": "Ð\98стори",
+       "enhancedrc-history": "истори",
        "recentchanges": "Керда хувцамаш",
        "recentchanges-legend": "Керда хувцамий оттамаш",
        "recentchanges-summary": "КIалхагIа лоарамий доаламе тIехьара оагIувний хувцамаш дIаязадаь да {{grammar:genitive|{{SITENAME}}}}.",
        "recentchanges-feed-description": "Укх ларамца тIехьара массахувцамашт теркам бе.",
-       "recentchanges-label-newpage": "Укх хувцамаца керда оагIув даь хиннад",
+       "recentchanges-label-newpage": "Укх хувцамаца керда оагIув яь хиннай",
        "recentchanges-label-minor": "ЗIамига хувцам я",
        "recentchanges-label-bot": "Ер хувцам бIатаца яь е",
        "recentchanges-label-unpatrolled": "Ер хувцам ший моттиге кхы дIадехьаяьккхаяц.",
        "filehist-filesize": "Паьла юстарал",
        "filehist-comment": "ХIамоалар",
        "imagelinks": "Паьлий пайда эца",
-       "linkstoimage": "{{PLURAL:$1|1=ТIехьайоагIа $1 оагIув Iинк ду|ТIехьайоагIа $1 оагIувнаш Iинкаш ду}} укх паьла тIа:",
+       "linkstoimage": "{{PLURAL:$1|1=ТIехьайоагIача $1 оагIуво тIахьожаву|ТIехьайоагIача $1 оагIувнаша тIахьожаву}} укх файла тIа:",
        "nolinkstoimage": "Йола паьла тIа  Iинк ю оагIувнаш дац",
        "sharedupload": "Ер паьла $1чера я, кхыча хьахьоадайтамча хьахайраде йийшайолаш я.",
        "sharedupload-desc-here": "Ер паьл $1чара я, кхыдола хьахьоадайтамача хайрамбе йийш йолаш да.\nЦун [$2 лоацама оагIувца] лоаца маIандар кIалхагIа латта.",
        "namespace": "ЦIерий аренаш",
        "invert": "Хьаржар юхадаккха",
        "blanknamespace": "(Корта)",
-       "contributions": "{{GENDER:$1|Ð\94акÑ\8aалаÑ\8cÑ\86аÑ\80хочунна}} къахьегам",
+       "contributions": "{{GENDER:$1|Ð\94оакÑ\8aаÑ\88хочунна}} къахьегам",
        "contributions-title": "$1 дакъалаьцархочунна къахьегам",
        "mycontris": "Са къахьегам",
        "contribsub2": "{{GENDER:$3|$1}} ($2) баь болх",
        "tooltip-pt-mycontris": "Шун хувцамаш",
        "tooltip-pt-login": "Укхаза хьай цIи аьле чувала/яла йиша я, амма чуцаваьлача/ялача хIама а дац",
        "tooltip-pt-logout": "Аравала/яла",
-       "tooltip-pt-createaccount": "Хьа бокъо я лоархIама яздар кхелла система чу вала, амма декхар долаш дац из.",
+       "tooltip-pt-createaccount": "Хьа бокъо я учёта яздар кхелла система чу вала, амма декхар долаш дац из.",
        "tooltip-ca-talk": "ОагIувна чулоацаме дувцам",
-       "tooltip-ca-edit": "Ð¥Ñ\83вÑ\86а ер оагIув",
+       "tooltip-ca-edit": "Ð\9dийÑ\81Ñ\8aе ер оагIув",
        "tooltip-ca-addsection": "Керда декъам хьаде",
        "tooltip-ca-viewsource": "Ер оагIув хувцамах лораяь я, амма шун цунна гIувамага хьажа бокъо я.",
        "tooltip-ca-history": "Укх оагIувни хувцама таптар",
        "tooltip-n-currentevents": "ХIанзара хоаман дагарле",
        "tooltip-n-recentchanges": "ТӀехьара хувцамий дагарче",
        "tooltip-n-randompage": "Бе йоаца оагӀув ела",
-       "tooltip-n-help": "Новкъостала моттиг",
+       "tooltip-n-help": "Новкъостал лаха мегаш йола моттиг",
        "tooltip-t-whatlinkshere": "Массайола оагIувий дагарле, укх оагIув тIа Iинкаш луш йола",
        "tooltip-t-recentchangeslinked": "ОагIувнаш тIа тIехьара хувцамаш, укх оагIувнера Iинк яь йола",
        "tooltip-feed-rss": "Укх оагIувна RSSчу гойтар",
        "tooltip-feed-atom": "Укх оаг|увна Atomчу гойтар",
-       "tooltip-t-contributions": "Укх дакъалаьцархочу хьийца йола оагIувнаш хьахьокха",
+       "tooltip-t-contributions": "{{GENDER:$1|Укх доакъашхочо хийца}} йола оагIувнаш",
        "tooltip-t-emailuser": "Укх дакъалаьцархочоа зIы яхьийта",
        "tooltip-t-upload": "Паьлаш чуяьккха",
        "tooltip-t-specialpages": "ГIулакха оагIувний дагарчe",
        "tooltip-t-permalink": "Укх оагIув доржама даим латта Iинк",
        "tooltip-ca-nstab-main": "Йоазува чулоацам",
        "tooltip-ca-nstab-user": "Дакъалаьцархочунна ший оагIув",
-       "tooltip-ca-nstab-special": "Ер гIулакха оагIув я, из хувца хьо бокъо йолаш вац/яц.",
+       "tooltip-ca-nstab-special": "Ер гIулакха оагIув я, из хувца бокъо яц",
        "tooltip-ca-nstab-project": "Хьахьоадайтама оагIув",
        "tooltip-ca-nstab-image": "Паьла оагIув",
        "tooltip-ca-nstab-template": "ЧIабала оагIув",
-       "tooltip-ca-nstab-help": "ГӀона оагIув",
+       "tooltip-ca-nstab-help": "ГӀон оагIув",
        "tooltip-ca-nstab-category": "Цатега оагIув",
        "tooltip-minoredit": "Ер хувцар башха доаца санна белгалде",
        "tooltip-save": "Хувцамаш кходе",
        "metadata-fields": "Укх дагарченгахь дагaрадаь метахIамаша суртий мугIаш, сурт оагIув тIа хьахьекха хургья, чуерзaяь метахIамашийца. Вож мугIанаш ха йоалаш къайла хургья.\n* make\n* model\n* datetimeoriginal\n* exposuretime\n* fnumber\n* isospeedratings\n* focallength\n* artist\n* copyright\n* imagedescription\n* gpslatitude\n* gpslongitude\n* gpsaltitude",
        "exif-imagewidth": "Шерал",
        "exif-imagelength": "Лакхал",
+       "exif-orientation": "Суртан белгало",
        "exif-imagedescription": "Сурта цIи",
        "exif-artist": "Яздархо",
        "exif-colorspace": "Басара аре",
        "exif-pixelydimension": "Сурта шерал",
        "exif-pixelxdimension": "Сурта лакхал",
+       "exif-datetimedigitized": "Оцифровк яь таьрахь а, ха а",
        "exif-writer": "Яздама да",
        "exif-languagecode": "Мотт",
        "exif-iimcategory": "Цатег",
        "version-software-version": "Доржам",
        "fileduplicatesearch-filename": "ПаьлацIи:",
        "fileduplicatesearch-submit": "Лаха",
-       "specialpages": "Ð\93\83лакÑ\85ий оагIувнаш",
+       "specialpages": "Ð\9bаÑ\8cÑ\80Ñ\85Ñ\85Iа Ð¹Ð¾Ð»Ð° оагIувнаш",
        "specialpages-group-users": "Дакъалаьцархой, цара бокъо",
        "specialpages-group-pages": "ОагIувний дагарченаш",
        "specialpages-group-pagetools": "ОагIувнаша гIирсаш",
        "htmlform-submit": "ДIадахьийта",
        "htmlform-reset": "Хувцамаш юхадаккха",
        "htmlform-selectorother-other": "Кхыдола",
+       "logentry-newusers-create": "{{GENDER:$2|Доакъашхочо кхеллай}} учёта яздар $1",
        "rightsnone": "(а)",
        "revdelete-summary": "хувцамий лоацам",
        "searchsuggest-search": "Лаха",
index a6bcb25..9e0fd9f 100644 (file)
@@ -23,7 +23,8 @@
                        "Jonbg",
                        "Matma Rex",
                        "Xð",
-                       "Sveinki"
+                       "Sveinki",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Undirstrika tengla:",
        "recentchangeslinked-page": "Síðutitill:",
        "recentchangeslinked-to": "Sýna breytingar á síðum sem tengjast uppgefinni síðu í staðinn",
        "recentchanges-page-added-to-category": "[[:$1]] bætt við flokk",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] og $2 {{PLURAL:$2|síðu|síðum}} bætt við flokk",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] og $2 [[Special:WhatLinksHere/$1|{{PLURAL:$2|síðu|síðum}}]] bætt við flokk",
        "recentchanges-page-removed-from-category": "[[:$1]] fjarlægð úr flokki",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] og $2 {{PLURAL:$2|síðu|síðum}} fjarlægð úr flokki",
        "autochange-username": "Sjálfvirk MediaWiki-breyting",
index 94a8160..1b2b603 100644 (file)
        "mergelog": "Unioni",
        "revertmerge": "Annulla unioni",
        "mergelogpagetext": "Di seguito sono elencate le ultime operazioni di unione della cronologia di due pagine.",
-       "history-title": "$1: cronologia delle modifiche",
-       "difference-title": "$1: differenze tra le versioni",
-       "difference-title-multipage": "$1 e $2: differenze tra le pagine",
+       "history-title": "Cronologia delle modifiche di \"$1\"",
+       "difference-title": "Differenze tra le versioni di \"$1\"",
+       "difference-title-multipage": "Differenze tra le pagine \"$1\" e \"$2\"",
        "difference-multipage": "(Differenze fra le pagine)",
        "lineno": "Riga $1:",
        "compareselectedversions": "Confronta le versioni selezionate",
        "uploadstash-badtoken": "Esecuzione dell'azione non riuscita, forse perché le tue credenziali di modifica sono scadute. Prova ancora.",
        "uploadstash-errclear": "La pulizia dei file non è riuscita.",
        "uploadstash-refresh": "Aggiorna l'elenco dei file",
+       "uploadstash-thumbnail": "vedi miniatura",
        "invalid-chunk-offset": "Offset della parte non valido.",
        "img-auth-accessdenied": "Accesso negato",
        "img-auth-nopathinfo": "PATH_INFO mancante.\nIl server non è impostato per passare questa informazione.\nPotrebbe essere basato su CGI e non può supportare img_auth.\nVedi https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "sessionprovider-generic": "sessioni $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sessioni basate su cookie",
        "sessionprovider-nocookies": "I cookie possono essere disattivati. Assicurati di avere i cookie abilitati e ha inizia nuovamente.",
-       "randomrootpage": "Pagina radice casuale"
+       "randomrootpage": "Pagina radice casuale",
+       "log-action-filter-block": "Tipo di blocco:",
+       "log-action-filter-delete": "Tipo di cancellazione:",
+       "log-action-filter-patrol": "Tipo di verifica:",
+       "log-action-filter-protect": "Tipo di protezione:",
+       "log-action-filter-upload": "Tipo di caricamento:",
+       "log-action-filter-all": "Tutto",
+       "log-action-filter-block-block": "Blocco",
+       "log-action-filter-block-reblock": "Modifica blocco",
+       "log-action-filter-block-unblock": "Sblocco",
+       "log-action-filter-delete-delete": "Cancellazione pagina",
+       "log-action-filter-delete-restore": "Ripristino pagina",
+       "log-action-filter-delete-event": "Cancellazione registro",
+       "log-action-filter-delete-revision": "Cancellazione versione",
+       "log-action-filter-patrol-patrol": "Verifica manuale",
+       "log-action-filter-patrol-autopatrol": "Verifica automatica",
+       "log-action-filter-protect-protect": "Protezione",
+       "log-action-filter-protect-modify": "Modifica protezione",
+       "log-action-filter-protect-unprotect": "Sprotezione",
+       "log-action-filter-upload-upload": "Nuovo caricamento",
+       "log-action-filter-upload-overwrite": "Ricaricamento"
 }
index 09f9963..32a4205 100644 (file)
        "rollback-success": "$1による編集を差し戻しました。\n$2による直前の版へ変更されました。",
        "sessionfailure-title": "セッションの失敗",
        "sessionfailure": "ログインのセッションに問題が発生しました。\nセッション乗っ取りを防ぐため、操作を取り消しました。\n前のページへ戻って再度読み込んだ後に、もう一度試してください。",
-       "changecontentmodel": "ã\83\9aã\83¼ã\82¸ã\81®ã\82³ã\83³ã\83\86ã\83³ã\83\88・モデルの変更",
+       "changecontentmodel": "ã\83\9aã\83¼ã\82¸ã\81®ã\82³ã\83³ã\83\86ã\83³ã\83\84・モデルの変更",
        "changecontentmodel-legend": "コンテンツモデルを変更",
        "changecontentmodel-title-label": "ページ名",
        "changecontentmodel-model-label": "新しい コンテンツ モデル",
        "changecontentmodel-reason-label": "理由:",
        "changecontentmodel-submit": "変更",
-       "changecontentmodel-success-title": "ã\82³ã\83³ã\83\86ã\83³ã\83\88・モデルは変更されました",
-       "changecontentmodel-success-text": "[[:$1]]ã\81®ã\82³ã\83³ã\83\86ã\83³ã\83\88ã\83»ã\82¿ã\82¤ã\83\97ã\81¯å¤\89æ\9b´ã\81\95ã\82\8cã\81¦ã\81\84ã\81¾ã\81\99。",
+       "changecontentmodel-success-title": "ã\82³ã\83³ã\83\86ã\83³ã\83\84・モデルは変更されました",
+       "changecontentmodel-success-text": "[[:$1]]ã\81®ã\82³ã\83³ã\83\86ã\83³ã\83\84ã\83»ã\82¿ã\82¤ã\83\97ã\81¯å¤\89æ\9b´ã\81\95ã\82\8cã\81¾ã\81\97ã\81\9f。",
        "changecontentmodel-cannot-convert": "[[:$1]]上のコンテントは$2の型には変換できません。",
        "changecontentmodel-nodirectediting": "$1 コンテント・モデルは、ダイレクト編集をサポートしていません。",
        "log-name-contentmodel": "コンテント・モデル変更記録",
-       "log-description-contentmodel": "ã\83\9aã\83¼ã\82¸ã\81®ã\82³ã\83³ã\83\86ã\83³ã\83\88ã\83»ã\83¢ã\83\87ã\83«ã\81«é\96¢é\80£ã\81\99ã\82\8bã\82¤ã\83\99ã\83³ã\83\88",
-       "logentry-contentmodel-change": "$1 ã\81\8cã\83\9aã\83¼ã\82¸ $3 ã\81®ã\82³ã\83³ã\83\86ã\83³ã\83\88・モデルを \"$4\" から \"$5\" に{{GENDER:$2|変更しました}}",
+       "log-description-contentmodel": "ã\83\9aã\83¼ã\82¸ã\81®ã\82³ã\83³ã\83\86ã\83³ã\83\84ã\83»ã\83¢ã\83\87ã\83«ã\81«é\96¢é\80£ã\81\99ã\82\8bå\87ºæ\9d¥äº\8b",
+       "logentry-contentmodel-change": "$1 ã\81\8cã\83\9aã\83¼ã\82¸ $3 ã\81®ã\82³ã\83³ã\83\86ã\83³ã\83\84・モデルを \"$4\" から \"$5\" に{{GENDER:$2|変更しました}}",
        "logentry-contentmodel-change-revertlink": "差し戻し",
        "logentry-contentmodel-change-revert": "差し戻し",
        "protectlogpage": "保護記録",
index 0fe94da..bd1ee65 100644 (file)
@@ -13,7 +13,8 @@
                        "아라",
                        "Macofe",
                        "Batyrbek.kz",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Сілтеменің астын сызу:",
        "october-date": "Қазан $1",
        "november-date": "Қараша $1",
        "december-date": "Желтоқсан $1",
+       "period-am": "Түстен бұрыңғы",
+       "period-pm": "Түстен кейінгі",
        "pagecategories": "{{PLURAL:$1|Санат|Санат}}",
        "category_header": "«$1» санатындағы беттер",
        "subcategories": "Санатшалар",
        "laggedslavemode": "<strong>Ескерту:</strong> Бетте жуықтағы жаңартулар болмауы мүмкін.",
        "readonly": "Дерекқоры құлыпталған",
        "enterlockreason": "Құлыптау себебін, қай уақытқа дейін құлыпталғанын кірістіріп, енгізіңіз.",
-       "readonlytext": "Ð\91ұл Ð´ÐµÑ\80екÒ\9bоÑ\80 Ð¶Ð°Ò£Ð°Ð´Ð°Ð½ Ð¶Ð°Ð·Ñ\83 Ð¶Ó\99не Ð±Ð°Ñ\81Ò\9bа Ó©Ð·Ð³ÐµÑ\80Ñ\96Ñ\81Ñ\82еÑ\80 Ð¶Ð°Ñ\81аÑ\83дан Ð°Ò\93Ñ\8bмда Ò\9bұлÑ\8bпÑ\82алÑ\8bнÒ\93ан, Ð¼Ò¯Ð¼ÐºÑ\96н ÐºÒ¯Ð½Ð´Ðµ-күн Ð´ÐµÑ\80екÒ\9bоÑ\80дÑ\8b Ð±Ð°Ð¿Ñ\82аÑ\83 Ò¯Ñ\88Ñ\96н, Ð±Ò±Ð½Ñ\8b Ð±Ñ\96Ñ\82Ñ\96Ñ\80геннен Ñ\81оң Ò\9bалÑ\8bпÑ\82Ñ\8b Ñ\96Ñ\81ке Ò\9bайÑ\82аÑ\80Ñ\8bладÑ\8b.\n\nÒ\9aұлÑ\8bпÑ\82аÒ\93ан Ó\99кÑ\96мÑ\88Ñ\96 Ð±Ò±Ð½Ñ\8b Ð±Ñ\8bлай Ñ\82Ò¯Ñ\81Ñ\96ндÑ\96Ñ\80едÑ\96: $1",
+       "readonlytext": "Ð\9cүмкÑ\96н Ð¶Ð¾Ñ\81паÑ\80лÑ\8b Ð´ÐµÑ\80екÒ\9bоÑ\80 Ñ\82екникалÑ\8bÒ\9b Ò\9bÑ\8bзмеÑ\82 ÐºÓ©Ñ\80Ñ\81еÑ\82Ñ\83Ñ\96 Ò¯Ñ\88Ñ\96н Ð±Ò±Ð» Ð´ÐµÑ\80екÒ\9bоÑ\80 Ð¶Ð°Ò£Ð° ÐµÐ½Ð³Ñ\96зÑ\96лÑ\96мдеÑ\80 Ð¶Ó\99не Ð±Ð°Ñ\81Ò\9bа Ó©Ð·Ð³ÐµÑ\80Ñ\96Ñ\81Ñ\82еÑ\80 Ð¶Ð°Ñ\81аÑ\83дан Ò\9bазÑ\96Ñ\80гÑ\96 Ñ\83аÒ\9bÑ\8bÑ\82Ñ\82а Ò\9bұлÑ\8bпÑ\82алÑ\8bнÒ\93ан, Ð±Ò±Ð½Ñ\8b Ð±Ñ\96Ñ\82Ñ\96Ñ\80геннен Ñ\81оң Ò\9bалÑ\8bпÑ\82Ñ\8b Ñ\96Ñ\81ке Ò\9bайÑ\82аÑ\80Ñ\8bладÑ\8b.\n\nÒ\9aұлÑ\8bпÑ\82аÒ\93ан Ð¶Ò¯Ð¹Ðµ Ó\99кÑ\96мÑ\88Ñ\96Ñ\81Ñ\96 Ð¼Ñ\8bна Ñ\82Ò¯Ñ\81Ñ\96ндÑ\96Ñ\80менÑ\96 Ò\9bалдÑ\8bÑ\80дÑ\8b: $1",
        "missing-article": "Бар болуы жөн былай аталған бет мәтіні дерекқорда табылмады: «$1» $2.\n\nБұл ескірген айырма сілтемесіне немесе жойылған бет тарихы сілтемесіне ергеннен бола береді.\n\nЕгер бұл орынды болмаса, бағдарламалық жасақтамадағы қатеге тап болуыңыз мүмкін.\nБұл туралы нақты URL жайына аңғартпа жасап, [[Special:ListUsers/sysop|әкімшіге]] баяндаңыз.",
        "missingarticle-rev": "(түзету нұсқасы#: $1)",
        "missingarticle-diff": "(Айырым: $1, $2)",
        "mypreferencesprotected": "Сізде баптауларыңызды өңдеуге рұқсатыңыз жоқ.",
        "ns-specialprotected": "Арнайы беттер өңдеуге келмейді.",
        "titleprotected": "Бұл атауды бастаудан [[User:$1|$1]] қорғаған.\nКелтірілген себебі: <em>$2</em>.",
-       "filereadonlyerror": "«$2» файл қоры тек қана оқу тәртіптемесінде тұрғасын «$1» файлын өзгерту мүмкін емес.\nБұл тәртіптемені қондырған әкімші келесі түсіндірмені қалдырды: «$3»",
+       "filereadonlyerror": "«$2» файл қоры тек қана оқу тәртіптемесінде тұрғасын «$1» файлын өзгерту мүмкін емес.\n\nЖүйе әкімшісі оны кім құлыптағанын бұл түсіндірмені ұсынды: «$3»",
        "invalidtitle-knownnamespace": "«$2» есім кеңістік түрі және  «$3» мәтіні жарамсыз",
        "invalidtitle-unknownnamespace": "Нөмері $1 белгісіз есім кеңістік атауы және «$2» мәтіні жарамсыз",
        "exception-nologin": "Кірмегенсіз",
        "virus-scanfailed": "скайнерлеу орындалмады (коды: $1)",
        "virus-unknownscanner": "белгісіз антивирус:",
        "logouttext": "<strong>Жүйеден шықтыңыз.</strong>\n\nКейбір беттер браузеріңіздің кэшін тазартқанша әлі де жүйеге кіріп отырғаныңыздай көрінуі мүмкіндігін ескеріңіз.",
+       "cannotlogoutnow-title": "Қазір шығу мүмкін емес",
+       "cannotlogoutnow-text": "$1 қолданған кезде шығу мүмкін емес.",
        "welcomeuser": "Қош келдіңіз, $1!",
        "welcomecreation-msg": "Сіз тіркелдіңіз.\n{{SITENAME}} [[Special:Preferences|баптауларыңызды]] өзіңіз қалауыңыз бойынша өзгерте аласыз.",
        "yourname": "Қатысушы аты:",
        "remembermypassword": "Тіркелгімді осы браузерде ұмытпа (ең көбі $1 {{PLURAL:$1|күн|күн}})",
        "userlogin-remembermypassword": "Мені жүйеде сақтап қою",
        "userlogin-signwithsecure": "Қауіпсіз байланысуды қолдану",
+       "cannotloginnow-title": "Қазір шығу мүмкін емес",
+       "cannotloginnow-text": "$1 қолданған кезде шығу мүмкін емес.",
        "yourdomainname": "Үйшігіңіз:",
        "password-change-forbidden": "Сіз бұл уикиде құпия сөзіңізді өзгерте алмайсыз.",
        "externaldberror": "Осы арада не шеттік растау дерекқорында қате болды, немесе шеттік тіркелгіңізді жаңалау рұқсаты жоқ.",
        "wrongpasswordempty": "Құпия сөз бос болған.\nҚайта байқап көріңіз.",
        "passwordtooshort": "Құпиясөзде кем дегенде {{PLURAL:$1|1таңба|таңба}} болуы керек.",
        "passwordtoolong": "Құпиясөз {{PLURAL:$1|1таңбадан|таңбадан}} көп болмау керек.",
+       "passwordtoopopular": "Көп жағдайда таңдалатын құпиясөзді қолдана алмайсыз. Басқа бірегей құпиясөз таңдаңыз.",
        "password-name-match": "Құпия сөзіңіз қатысушы атынан өзгеше болуы қажет.",
        "password-login-forbidden": "Бұл қатысушы аты мен құпия сөзін пайдалануға тыйым салынған.",
        "mailmypassword": "Құпия сөзді қалпына кеттіру",
        "createaccount-title": "{{SITENAME}} жобасына тіркелу",
        "createaccount-text": "Әлдебіреу е-пошта мекенжайыңызды пайдаланып {{SITENAME}} жобасында ($4) «$2» деген атау, «$3» деген құпия сөзбен тіркелгі жасаған.\nҚазір жүйеге кіріуіңіз және құпия сөзіңізді өзгертуіңіз керек.\n\nЕгер бұл тіркелгі қателікпен жасалса осы хабарламаны елемеуіңізге болады.",
        "login-throttled": "Сіз жүйеге кіру үшін тым көп талпыныс жасадыңыз.\nҚайта байқап көрмес бұрын $1 күте тұрыңыз.",
-       "login-abort-generic": "Ð\96үйеге ÐºÑ\96Ñ\80Ñ\83 Ñ\81Ó\99Ñ\82Ñ\81Ñ\96з Ð±Ð¾Ð»ды - Доғарылды.",
+       "login-abort-generic": "СÑ\96здÑ\96Ò£ ÐºÑ\96Ñ\80Ñ\83Ñ\96Ò£Ñ\96з Ð¾Ñ\80Ñ\8bндалмады - Доғарылды.",
        "login-migrated-generic": "Тіркелгіңіздің тасымалданған болатын және сіздің қатысуыш есіміңіз бұдан былай осы уикиде болмайды.",
        "loginlanguagelabel": "Тіл: $1",
        "suspicious-userlogout": "Сіздің жүйеден шығу сұранымыңыз қабылданбады, өйткені бұл бұзылған браузер немесе кэштеуші прокси арқылы жіберілгенге ұқсайды.",
        "resetpass_submit": "Құпия сөзді қойыңыз да кіріңіз",
        "changepassword-success": "Құпия сөзіңіз өзгертілді!",
        "changepassword-throttled": "Сіз жақында кіруге тым көп әрекет жасадыңыз.\nҚайта байқап көру үшін $1 уақыт күте тұрыңыз.",
+       "botpasswords": "Бот құпиясөздері",
+       "botpasswords-disabled": "Бот құпиясөздері өшірілген.",
+       "botpasswords-no-central-id": "Бот құпиясөздерін қолдану үшін, орталықтандырылған тіркелгіңізбен кіруіңіз керек.",
+       "botpasswords-existing": "Бар бот құпиясөздері",
+       "botpasswords-createnew": "Жаңа бот құпиясөзін бастау",
+       "botpasswords-editexisting": "Бар бот құпиясөзін өңдеу",
+       "botpasswords-label-appid": "Бот атауы:",
+       "botpasswords-label-create": "Бастау",
        "botpasswords-label-update": "Жаңарту",
        "botpasswords-label-cancel": "Болдырмау",
        "botpasswords-label-delete": "Жою",
        "botpasswords-label-resetpassword": "Құпия сөзді қалпына кеттіру",
+       "botpasswords-label-grants": "Қолданылатын гранттар:",
+       "botpasswords-label-restrictions": "Пайдалану шектеулері:",
+       "botpasswords-bad-appid": "\"$1\" бот атауы жарамды емес.",
+       "botpasswords-insert-failed": "\"$1\" бот атауын қосу орындалмады. Ол әлдеқашан қосылған ба еді?",
+       "botpasswords-update-failed": "\"$1\" бот атауын жаңарту орындалмады. Ол әлдеқашан жойылған ба еді?",
+       "botpasswords-created-title": "Бот құпиясөзі құрылды",
+       "botpasswords-updated-title": "Бот құпиясөзі жаңартылды",
+       "botpasswords-deleted-title": "Бот құпиясөзі жойылды",
        "resetpass_forbidden": "Құпия сөз өзгертілмейді",
        "resetpass-no-info": "Бұл бетке тікелей ену үшін жүйеге кіруіңіз керек.",
        "resetpass-submit-loggedin": "Құпия сөзді өзгерту",
        "resetpass-submit-cancel": "Болдырмау",
-       "resetpass-wrong-oldpass": "Уақытша немесе қазіргі құпия сөзіңіз жарамсыз.\nМүмкін сіз құпия сөзді сәтті өзгерткенсіз немесе жаңа уақытша құпия сөзге сұраным жасағансыз.",
+       "resetpass-wrong-oldpass": "Уақытша немесе қазіргі құпия сөзіңіз жарамсыз.\nМүмкін сіз құпия сөзді өзгерткенсіз немесе жаңа уақытша құпия сөзге сұраным жасағансыз.",
        "resetpass-recycled": "Құпия сөзіңізді қазіргі құпия сөзіңізден өзгеше етіп өзгертіңіз.",
        "resetpass-temp-emailed": "Сіз уақытша email-ды кодпен кірдіңіз.\nКіруді аяқтау үшін жаңа құпия сөзді мында орнатуыңыз керек:",
        "resetpass-temp-password": "Уақытша құпия сөз:",
        "passwordreset-emailtext-ip": "Әлде кім (мүмкін сіз болуыңыз, $1 IP адресінен) {{SITENAME}} сайтында ($4) құпия сөзді өзгертуге өтініш білдірді. Мына қатысушы {{PLURAL:$3|аккаунты|аккаунттары}} осы электронды почта қатысты:\n\n$2\n\n{{PLURAL:$3|Бұл уақытша құпия сөз|Бұл уақытша құпия сөздер}} {{PLURAL:$5|бір күнде|$5 күнде}}уақыты аяқталады.\nСіз кіруіңіз және жаңа құпия сөзді таңдауыңыз керек. Егер бұл өтінішті басқа біреу жасаса, немесе сіз  бұрынғы құпия сөзіңізді еске түсірсеңіз және құпия сөзді ауыстыруды қаламасаңыз, сіз бұл хабарламаны ескермей және бұрынғы құпия сөзді қолдана беруіңізге болады.",
        "passwordreset-emailtext-user": "$1 есімді қатысушы {{SITENAME}} сайтында ($4) құпия сөзді өзгертуге өтініш білдірді. Мына қатысушы {{PLURAL:$3|аккаунт|аккаунттар}} осы електронды почта қатысты:\n\n$2\n\n{{PLURAL:$3|Бұл уақытша құпия сөз|Бұл уақытша құпия сөздер}} {{PLURAL:$5|бір күнде|$5 күнде}}уақыты аяқталады.\nСіз кіруіңіз және жаңа құпия сөзді таңдауыңыз керек. Егер бұл өтінішті басқа біреу жасаса, немесе сіз  бұрынғы құпия сөзіңізді еске түсірсеңіз, және құпия сөзді ауыстыруды қаламасаңыз, сіз бұл хабарламаны ескермей және бұрыңғы құпия сөзді қолдана беруіңізге болады.",
        "passwordreset-emailelement": "Қатысушы есімі: \n$1\n\nУақытша құпия сөз: \n$2",
-       "passwordreset-emailsentemail": "Құпия сөзді өзгерту электронды пошта арқылы жөнелтілді.",
+       "passwordreset-emailsentemail": "Бұл email мекенжайы тіркелгіңізге байланысқан, сол себепті құпия сөзді өзгерту электронды пошта арқылы жөнелтіледі.",
        "passwordreset-emailsent-capture": "Құпия сөзді өзгерту электронды пошта арқылы жөнелтілді, ол төменде көрсетілген.",
        "passwordreset-emailerror-capture": "Құпиясөзді өзгерту электрон хаты жасалды, ол төменде көрсетілген, бірақ ол {{GENDER:$2|қатысушыға}} жөнелтілмеді: $1",
        "changeemail": "Е-пошта мекенжайын өзгерту немесе аластау",
        "copyrightwarning": "{{SITENAME}} жобасына қосқан барлық үлестеріңіз $2 (көбірек ақпарат үшін: $1) аясында жарияланатынын ескеріңіз.\nЕгер еңбегіңіздің еркін өңделуін және ақысыз көпшілікке таралуын қаламасаңыз мұнда жарияламаңыз<br />\nТағы да бұл мәліметті өзіңіз жазғаныңызға не қоғам қазынасынан немесе сондай ашық қорлардан көшірілгеніне бізге уәде бересіз.\n<strong>Авторлық құқықпен қорғалған мәліметті рұқсатсыз жарияламаңыз!</strong>",
        "copyrightwarning2": "{{SITENAME}} жобасына қосқан барлық үлестеріңізді басқа үлескерлер өңдеуге, өзгертуге немесе аластауы мүмкін екенін ескеріңіз.\nЕгер еңбегіңіздің еркін өңделуін қаламасаңыз осында жарияламаңыз.<br />\nТағы да бұл мәліметті өзіңіз жазғаныңызға не қоғам қазынасынан немесе сондай ашық қорлардан көшірілгеніне бізге уәде бересіз. (көбірек ақпарат үшін $1 құжатын қараңыз).\n<strong>Авторлық құқықпен қорғалған мәліметті рұқсатсыз жарияламаңыз!</strong>",
        "longpageerror": "<strong>ҚАТЕЛІК: Сақтамақшы болған мәтініңіздің көлемі {{PLURAL:$1|бір килобайт|$1 килобайт}} ең көбі {{PLURAL:$2|килобайт|$2 килобайт}} рұқсат етілген көлемінен асқан.</strong>\nБұл сақталмайды.",
-       "readonlywarning": "<strong>Ð\95СÐ\9aÐ\95РТУ: Ð\94еÑ\80екÒ\9bоÑ\80 Ñ\82еÑ\85никалÑ\8bÒ\9b Ð¶Ò±Ð¼Ñ\8bÑ\81Ñ\82аÑ\80 Ð¶Ð°Ñ\81аÑ\83 Ò¯Ñ\88Ñ\96н Ò\9bұлÑ\8bпÑ\82алÒ\93ан Ñ\81ондÑ\8bÒ\9bÑ\82ан Ð´Ó\99л Ò\9bазÑ\96Ñ\80 Ó©Ò£Ð´ÐµÐ¼ÐµÒ£Ñ\96здÑ\96 Ñ\81аÒ\9bÑ\82ай Ð°Ð»Ð¼Ð°Ð¹Ñ\81Ñ\8bз.</strong>\nÐ\9aейÑ\96н Ñ\81аÒ\9bÑ\82аÑ\83 Ò¯Ñ\88Ñ\96н Ð¼Ó\99Ñ\82Ñ\96нÑ\96Ò£Ñ\96здÑ\96 Ð¼Ó\99Ñ\82Ñ\96н Ñ\84айлÑ\8bна ÐºÓ©Ñ\88Ñ\96Ñ\80Ñ\96п Ð°Ð»Ñ\83Ò£Ñ\8bзÒ\93а Ð±Ð¾Ð»Ð°Ð´Ñ\8b. \n\nÐ\90дминÑ\81Ñ\82Ñ\80аÑ\82оÑ\80 оны құлыптау себебін келесідей түсіндіреді: $1",
+       "readonlywarning": "<strong>Ð\95СÐ\9aÐ\95РТУ: Ð\94еÑ\80екÒ\9bоÑ\80 Ñ\82еÑ\85никалÑ\8bÒ\9b Ð¶Ò±Ð¼Ñ\8bÑ\81Ñ\82аÑ\80 Ð¶Ð°Ñ\81аÑ\83 Ò¯Ñ\88Ñ\96н Ò\9bұлÑ\8bпÑ\82алÒ\93ан Ñ\81ондÑ\8bÒ\9bÑ\82ан Ð´Ó\99л Ò\9bазÑ\96Ñ\80 Ó©Ò£Ð´ÐµÐ¼ÐµÒ£Ñ\96здÑ\96 Ñ\81аÒ\9bÑ\82ай Ð°Ð»Ð¼Ð°Ð¹Ñ\81Ñ\8bз.</strong>\nÐ\9aейÑ\96н Ñ\81аÒ\9bÑ\82аÑ\83 Ò¯Ñ\88Ñ\96н Ð¼Ó\99Ñ\82Ñ\96нÑ\96Ò£Ñ\96здÑ\96 Ð¼Ó\99Ñ\82Ñ\96н Ñ\84айлÑ\8bна ÐºÓ©Ñ\88Ñ\96Ñ\80Ñ\96п Ð°Ð»Ñ\83Ò£Ñ\8bзÒ\93а Ð±Ð¾Ð»Ð°Ð´Ñ\8b. \n\nÐ\96үйе Ð°Ð´Ð¼Ð¸Ð½Ñ\81Ñ\82Ñ\80аÑ\82оÑ\80Ñ\8b оны құлыптау себебін келесідей түсіндіреді: $1",
        "protectedpagewarning": "<strong>Ескерту: Бұл бет өңдеуден қорғалған сондықтан тек әкімші құқықтары бар қатысушылар ғана өңдей алады.</strong>\nТөменде соңғы журнал жазбасы көрсетілген:",
        "semiprotectedpagewarning": "<strong>Ескерту:</strong> Бет жартылай қорғалған, сондықтан осыны тек тіркелген қатысушылар өңдей алады.\nТөменде бет журналының соңғы жазбасы көрсетілген:",
        "cascadeprotectedwarning": "<strong>Ескерту:</strong> Бұл бет қорғалған, сондықтан тек әкімші құқықтары бар қатысушылар ғана өңдей алады, себебі бұл келесі «баулы қорғауы» бар {{PLURAL:$1|бетіне|беттеріне}} кірістілген бет:",
        "userrights": "Қатысушы құқықтарын реттеу",
        "userrights-lookup-user": "Қатысушы топтарын реттеу",
        "userrights-user-editname": "Қатысушы атын енгізіңіз:",
-       "editusergroup": "Қатысушы топтарын өңдеу",
+       "editusergroup": "{{GENDER:$1|Қатысушы}} топтарын өңдеу",
        "editinguser": "<strong>[[User:$1|$1]]</strong> $2 {{GENDER:$1|есімді қатысушының}} қатысушы құқықтарын өзгерту",
        "userrights-editusergroup": "Қатысушы топтарын өңдеу",
-       "saveusergroups": "Қатысушы топтарын сақтау",
+       "saveusergroups": "{{GENDER:$1|Қатысушы}} топтарын сақтау",
        "userrights-groupsmember": "Мүшелігі:",
        "userrights-groupsmember-auto": "Бұлтарасыз мүше:",
        "userrights-groups-help": "Бұл қатысушы кіретін топтарды реттей аласыз.\n* Құсбелгі қойылған көзі қатысушы бұл топқа кіргенін көрсетеді;\n* Құсбелгі алып тасталған көз қатысушы бұл топқа кірмегенін көрсетеді;\n* Келтірілген * топты бір үстегенінен кейін аластай алмайтындығын, не қарама-қарсысын көрсетеді.",
        "userrights-changeable-col": "Өзгерте алатын топтар",
        "userrights-unchangeable-col": "Өзгерте алмайтын топтар",
        "userrights-conflict": "Қатысушы құқықтарының қақтығысы! Өзгертулеріңізді қайта қарап шығыңыз және құптаңыз.",
-       "userrights-removed-self": "Өзіңіздің құқықтарыңызды сәтті алып тастадыңыз.  As such, you are no longer able to access this page.",
+       "userrights-removed-self": "Өзіңіздің құқықтарыңызды алып тастадыңыз.  Осылайша бұл бетке бұдан былай қатынай алмайсыз.",
        "group": "Топ:",
        "group-user": "Қатысушылар",
        "group-autoconfirmed": "Өздіктіқұпталған қатысушылар",
        "recentchangeslinked-page": "Бет атауы:",
        "recentchangeslinked-to": "Керісінше, келтірілген бетке сілтейтін беттердегі өзгерістерді көрсет",
        "recentchanges-page-added-to-category": "[[:$1]] бетіне санат қосты",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] және {{PLURAL:$2|бір бет|$2 бет}} санатқа қосылды",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] және [[Special:WhatLinksHere/$1|{{PLURAL:$2|бір бет|$2 бет}}]] санатқа қосылды",
        "recentchanges-page-removed-from-category": "[[:$1]] санаттан алынды",
-       "recentchanges-page-removed-from-category-bundled": "[[:$1]] және {{PLURAL:$2|бір бет|$2 бет}} санаттан алынды",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] және [[Special:WhatLinksHere/$1|{{PLURAL:$2|бір бет|$2 бет}}]] санаттан алынды",
        "autochange-username": "МедиаУики өздікті өзгерісі",
        "upload": "Файл жүктеу",
        "uploadbtn": "Файлды жүктеу",
        "backend-fail-read": "«$1» файлы оқылмайды.",
        "backend-fail-create": "«$1» файлы жазылмайды.",
        "backend-fail-maxsize": "\"$1\" файлы жазылмайды, себебі {{PLURAL:$2|1 байттан|$2 байттан}} үлкенірек.",
-       "backend-fail-readonly": "«$1» сақтау сервері қазіргі уақытта «тек оқу» режимінде орналасқан. Себебі: «<em>$2</em>»",
+       "backend-fail-readonly": "«$1» сақтау сервері қазіргі уақытта тек оқу режимінде орналасқан. Себебі: <em>$2</em>",
        "backend-fail-synced": "«$1» файлы ішкі сақтау серверінде келісімсіз жағдайда орналасқан",
        "backend-fail-connect": "«$1» сақтау серверіне байланыспады.",
        "backend-fail-internal": "«$1» сақтау серверінде белгісіз қате кездесті.",
        "emailccsubject": "$1 дегенге хатыңыздың көшірмесі: $2",
        "emailsent": "Хат жөнелтілді",
        "emailsenttext": "Е-пошта хатыңыз жөнелтілді.",
-       "emailuserfooter": "Бұл электронды хатты {{SITENAME}} сайтындағы «{{int:emailuser}}» функцияцы арқылы $1 деген $2 дегенге жіберген.",
+       "emailuserfooter": "Бұл электронды хатты {{SITENAME}} сайтындағы «{{int:emailuser}}» функцияцы арқылы $1 деген {{GENDER:$2|$2}} дегенге {{GENDER:$1|жіберген}}.",
        "usermessage-summary": "Жүйе хабарламасы қалдырылуда.",
        "usermessage-editor": "Жүйе мессенжері",
        "watchlist": "Бақылау тізімі",
        "watchlistanontext": "Бақылау тізіміңіздегі даналарды қарау не өңдеу үшін кіріңіз.",
        "watchnologin": "Кірмегенсіз",
        "addwatch": "Бақылау тізіміңізге қосу",
-       "addedwatchtext": "«[[:$1]]» Ð±ÐµÑ\82Ñ\96 [[Special:Watchlist|баÒ\9bÑ\8bлаÑ\83 Ñ\82Ñ\96зÑ\96мÑ\96Ò£Ñ\96зге]] Ò\9bоÑ\81Ñ\8bлдÑ\8b.\nÐ\91ұл Ð±ÐµÑ\82Ñ\82Ñ\96Ò£ Ð¶Ó\99не Ð±Ð°Ð¹Ð»Ð°Ð½Ñ\8bÑ\81Ñ\82Ñ\8b Ñ\82алÒ\9bÑ\8bлаÑ\83 Ð±ÐµÑ\82Ñ\96нÑ\96Ò£ ÐºÐµÐ»ÐµÑ\88екÑ\82егÑ\96 Ó©Ð·Ð³ÐµÑ\80Ñ\96Ñ\81Ñ\82еÑ\80Ñ\96 Ñ\81онда Ñ\82Ñ\96зÑ\96мделедÑ\96.",
+       "addedwatchtext": "«[[:$1]]» Ð¶Ó\99не Ð¾Ð½Ñ\8bÒ£ Ñ\82алÒ\9bÑ\8bлаÑ\83 Ð±ÐµÑ\82Ñ\96 [[Special:Watchlist|баÒ\9bÑ\8bлаÑ\83 Ñ\82Ñ\96зÑ\96мÑ\96Ò£Ñ\96зге]] Ò\9bоÑ\81Ñ\8bлдÑ\8b.",
        "addedwatchtext-short": "«$1» беті бақылау тізіміңізге қосылды.",
        "removewatch": "Бақылау тізіміңізден аластату",
-       "removedwatchtext": "«[[:$1]]» беті [[Special:Watchlist|бақылау тізіміңізден]] аласталды.",
+       "removedwatchtext": "«[[:$1]]» Ð¶Ó\99не Ð¾Ð½Ñ\8bÒ£ Ñ\82алÒ\9bÑ\8bлаÑ\83 Ð±ÐµÑ\82Ñ\96 [[Special:Watchlist|баÒ\9bÑ\8bлаÑ\83 Ñ\82Ñ\96зÑ\96мÑ\96Ò£Ñ\96зден]] Ð°Ð»Ð°Ñ\81Ñ\82алдÑ\8b.",
        "removedwatchtext-short": "«$1» беті бақылау тізіміңізден аласталды",
        "watch": "Бақылау",
        "watchthispage": "Бұл бетті бақылау",
        "delete-toobig": "Бұл бетте үлкен түзету тарихы бар, $1 {{PLURAL:$1|түзетуден|түзетуден}} астам.\nБұндай беттердің жоюы {{SITENAME}} торабын әлдеқалай үзіп тастауына бөгет салу үшін тиымдалған.",
        "delete-warning-toobig": "Бұл бетте үлкен өңдеу тарихы бар, $1 {{PLURAL:$1|түзетуден|түзетуден}} астам.\nБұның жоюы {{SITENAME}} торабындағы дерекқор әрекеттерді үзіп тастауын мүмкін;\nбұны абайлап өткізіңіз.",
        "deleteprotected": "Сіз бұл бетті жоя алмайсыз, себебі ол қорғалған.",
-       "deleting-backlinks-warning": "'''Ескерту:''' Сіз жоймақшы болған бетке [[Special:WhatLinksHere/{{FULLPAGENAME}}|басқа беттерден]] сілтенген немесе [[Special:WhatLinksHere/{{FULLPAGENAME}}|басқа беттерге]] кірістірілген.",
+       "deleting-backlinks-warning": "</strong>Ескерту:</strong>  Сіз жоймақшы болған бетке [[Special:WhatLinksHere/{{FULLPAGENAME}}|басқа беттерден]] сілтенген немесе [[Special:WhatLinksHere/{{FULLPAGENAME}}|басқа беттерге]] кірістірілген.",
        "rollback": "Өңдемелерді шегіндіру",
        "rollbacklink": "шегіндіру",
        "rollbacklinkcount": "$1 {{PLURAL:$1|өңдемені|өңдемені}} шегіндіру",
        "tooltip-pt-anonuserpage": "Бұл IP мекенжайдың жеке беті",
        "tooltip-pt-mytalk": "Талқылау бетіңіз",
        "tooltip-pt-anontalk": "Бұл IP мекенжай өңдемелерін талқылау",
-       "tooltip-pt-preferences": "Бапталымдарым",
+       "tooltip-pt-preferences": "{{GENDER:|Бапталымдарым}}",
        "tooltip-pt-watchlist": "Өзгерістерін бақылап тұрған беттер тізімім.",
-       "tooltip-pt-mycontris": "Өңдеулеріңіздің тізімі",
+       "tooltip-pt-mycontris": "{{GENDER:|Үлестеріңіздің}} тізімі",
        "tooltip-pt-anoncontribs": "Бұл IP мекенжаймен жасаған өңдемелер тізімі",
        "tooltip-pt-login": "Кіруіңізді ұсынамыз, ол міндетті емес.",
        "tooltip-pt-logout": "Шығу",
        "tooltip-t-recentchangeslinked": "Мыннан сілтенген беттердің жуықтағы өзгерістері",
        "tooltip-feed-rss": "Бұл беттің RSS арнасы",
        "tooltip-feed-atom": "Бұл беттің Atom арнасы",
-       "tooltip-t-contributions": "Осы қатысушының үлестерінің тізімі",
+       "tooltip-t-contributions": "{{GENDER:$1|Осы қатысушының}} үлестері тізімі",
        "tooltip-t-emailuser": "Осы қатысушыға хат жөнелту",
        "tooltip-t-info": "Бұл бет туралы көбірек мәлімет",
        "tooltip-t-upload": "Файлдарды жүктеу",
        "scarytranscludefailed-httpstatus": "[$1: HTTP $2 үшін үлгі келтіруі сәтсіз болды]",
        "scarytranscludetoolong": "[URL тым ұзын]",
        "deletedwhileediting": "Ескету: Бұл бетті өңдеуіңізді бастағанда, осы бет жойылды!",
-       "confirmrecreate": "Бұл бетті өңдеуіңізді бастағанда [[User:$1|$1]] ([[User talk:$1|талқылауы]]) осы бетті жойды, келтірген себебі:\n: ''$2''\nОсы бетті қайта бастауын нақты тілегеніңізді құптаңыз.",
+       "confirmrecreate": "Бұл бетті өңдеуіңізді бастағанда [[User:$1|$1]] ([[User talk:$1|талқылауы]]) осы бетті жойды, келтірген себебі:\n: <em>$2</em>\nОсы бетті қайта бастауын нақты тілегеніңізді құптаңыз.",
        "confirmrecreate-noreason": "Бұл бетті өңдеп бастағаныңызда [[User:$1|$1]] ([[User talk:$1|талқылауы]]) жойды. \nОсы бетті қайта бастауын нақты тілегеніңізді құптаңыз.",
        "recreate": "Қайта бастау",
        "unit-pixel": " нүкте",
        "tags-edit-revision-legend": "{{PLURAL:$1|Бұл нұсқадан|Барлық $1 нұсқадан}} тегтерді аластау не қосу",
        "tags-edit-logentry-legend": "{{PLURAL:$1|Бұл журнал жазбасынан|Барлық $1 журнал жазбасынан}} тегтерді аластау не қосу",
        "tags-edit-existing-tags": "Бар тегтер:",
-       "tags-edit-existing-tags-none": "«Ештеңе»",
+       "tags-edit-existing-tags-none": "<em>Ештеңе</em>",
        "tags-edit-new-tags": "Жаңа тегтер:",
        "tags-edit-add": "Мына тегтерді қосу:",
        "tags-edit-remove": "Мына тегтерді аластау:",
        "tags-edit-reason": "Себебі:",
        "tags-edit-revision-submit": "{{PLURAL:$1|Бұл нұсқадағы|$1 нұсқадағы}} өзгерістерді қолдану",
        "tags-edit-logentry-submit": "{{PLURAL:$1|Бұл журнал жазбасындағы|$1 журнал жазбасындағы}} өзгерістерді қолдану",
-       "tags-edit-success": "Өзгерістер сәтті қолданылды.",
+       "tags-edit-success": "Өзгерістер қолданылды.",
        "tags-edit-failure": "Өзгерістер қолданылмады: $1",
        "tags-edit-nooldid-title": "Нысана түзету жарамсыз",
        "tags-edit-nooldid-text": "Бұл функцияны орындау үшін толық нұсқасын сұрамағансыз немесе көрсетілген нұсқа жоқ.",
        "api-error-badaccess-groups": "Сізге бұл уикиге файл жүктеуге рұқсат етілмеген.",
        "api-error-badtoken": "Ішкі қате: Жаман байрақша",
        "api-error-copyuploaddisabled": "URL бойынша жүктеу бұл серверде өшірілген",
-       "api-error-duplicate": "{{PLURAL:$1|басқа файл|кейбір басқа файл}} әлеқашан сайтта басқа мазмұнда бар.",
+       "api-error-duplicate": "{{PLURAL:$1|басқа [$2 файл]|кейбір [$2 басқа файл]}} әлеқашан сайтта ,бірдей мазмұнда бар.",
        "api-error-empty-file": "Сіз жіберген файл бос.",
        "api-error-emptypage": "Бос бетті жаңадан бастау рұқсат етілмейді.",
        "api-error-fetchfileerror": "Ішкі қателік: Файлды алу барысында қате кетті.",
        "expand_templates_preview": "Қарап шығу",
        "expand_templates_preview_fail_html": "<em>Мұнда сессия деректері жоғалған, себебі {{SITENAME}} жобасында HTML іске қосылған, JavaScript шабуылдарына қарсы сақтық шарасы үшін алдын ала қарап шығу жасырылған.</em>\n\n<strong>Егер бұл өңдеме адал ниетті әрекет болса қайта байқап көріңіз.</strong> \nЕгер бұл әлі істемесе жүйеден [[Special:UserLogout|шығып]] қайта кіріп көріңіз.",
        "expand_templates_preview_fail_html_anon": "<em>JavaScript шабуылдарына қарсы сақтық шарасы үшін алдын ала қарап шығу жасырылған, себебі {{SITENAME}} жобасында HTML іске қосылған және сіз жүйеге кірмегенсіз,.</em>\n\n<strong>Егер бұл өңдеме адал ниетті әрекет болса қайта байқап көріңіз.</strong> \nЕгер бұл әлі істемесе, жүйеге [[Special:UserLogin|кіріп]] қайта байқап көріңіз.",
-       "pagelanguage": "ТÑ\96л Ñ\82аңдаÑ\83 Ð±ÐµÑ\82Ñ\96",
+       "pagelanguage": "Ð\91еÑ\82 Ñ\82Ñ\96лÑ\96н Ó©Ð·Ð³ÐµÑ\80Ñ\82Ñ\83",
        "pagelang-name": "Бет",
        "pagelang-language": "Тіл",
        "pagelang-use-default": "Әдепкі тілді қолдану",
        "pagelang-submit": "Жөнелту",
        "right-pagelang": "Бет тілін аудару",
        "action-pagelang": "бет тілін аудару",
-       "log-name-pagelang": "Тіл журналын өзгерту",
+       "log-name-pagelang": "Тіл өзгерту журналы",
        "log-description-pagelang": "Бұл бет тілдерін өзгерту журналы.",
        "logentry-pagelang-pagelang": "$1 $3 беті үшін $4 дегеннен $5 дегенге бет тілін {{GENDER:$2|өзгертті}}.",
        "default-skin-not-found-row-enabled": "* <code>$1</code> / $2 (ендірілген)",
index a180506..01e2da7 100644 (file)
@@ -9,7 +9,8 @@
                        "לערי ריינהארט",
                        "아라",
                        "TTO",
-                       "Macofe"
+                       "Macofe",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Dun de Lengks ongerschtriische:",
        "recentchangeslinked-page": "Dä Sigg ier Övverschreff:",
        "recentchangeslinked-to": "Zeisch de Änderonge aan dä Sigge, woh Lengks op di aanjejovve Sigg drop sin",
        "recentchanges-page-added-to-category": "Di Sigg [[:$1]] wood en di Saachjrop jedonn",
-       "recentchanges-page-added-to-category-bundled": "Di Sigg [[:$1]] un {{PLURAL:$2|noch ein Sigg wood|$2 Sigge woodte|kein Sigg wood}} en di Saachjrop jedonn",
+       "recentchanges-page-added-to-category-bundled": "Di Sigg [[:$1]] un [[Special:WhatLinksHere/$1|{{PLURAL:$2|noch ein Sigg wood|$2 Sigge woodte|kein Sigg wood}}]] en di Saachjrop jedonn",
        "recentchanges-page-removed-from-category": "Di Sigg [[:$1]] wood uß dä Saachjrop jenumme",
        "recentchanges-page-removed-from-category-bundled": "Di Sigg [[:$1]] un {{PLURAL:$2|noch ein Sigg woodte|$2 Sigge woodte|kein Sigg wood}} uß dä Saachjrop jenumme",
        "autochange-username": "Automattesche Ännderong aam MediaWiki",
        "mw-widgets-titleinput-description-new-page": "di Sigg jidd_et noch nit",
        "mw-widgets-titleinput-description-redirect": "ömleijde op „$1“",
        "api-error-blacklisted": "Söhk Der ene anndere Nahme uß, dä mih drövver säht.",
-       "randomrootpage": "Zofällige Aanfangs-Sigg"
+       "randomrootpage": "Zofällige Aanfangs-Sigg",
+       "log-action-filter-delete-delete": "En Sigg wohd fott jeschmeße"
 }
index 58fbcef..a9f3289 100644 (file)
        "gotaccountlink": "Nomen da",
        "userlogin-resetlink": "Num tesserae tuae oblitus es?",
        "userlogin-resetpassword-link": "Num tesserae oblitus es?",
+       "userlogin-helplink2": "auxilium dandi nominis",
        "createacct-emailrequired": "Inscriptio electronica",
        "createacct-emailoptional": "Inscriptio electronica (non necesse)",
        "createacct-email-ph": "Inscriptionem electronicam tuam inscribe",
        "resetpass-submit-loggedin": "Tesseram mutare",
        "resetpass-submit-cancel": "Dimittere",
        "resetpass-temp-password": "Tessera temporaria:",
+       "passwordreset": "Tesseram restituere",
        "passwordreset-username": "Nomen usoris:",
        "passwordreset-email": "Inscriptio electronica:",
        "passwordreset-emailelement": "Nomen usoris: \n$1\n\nMomentarius Tessera: \n$2",
        "newarticle": "(Nova)",
        "newarticletext": "Per nexum progressus es ad paginam quae nondum exsistit.\nNovam paginam si vis creare, in capsam infra praebitam scribe.\n(Vide [$1 paginam auxilii] si plura cognoscere vis.)\nSi hic es propter errorem, solum '''Retrorsum''' in navigatro tuo preme.",
        "anontalkpagetext": "----\n<em>Haec est pagina disputationis usoris anonymi vel potius loci IP cuiusdam.</em>\nMemento locos IP interdum mutari et ab usoribus vel pluribus adhiberi.\nSi ipse sis usor ignotus et ex improviso invenias querulas aliquas, nomen tibi [[Special:UserLogin/signup|impone]] vel [[Special:UserLogin|nomen tuum da]], ut decetero confusionem effugias!",
-       "noarticletext": "Hac in pagina non sunt litterae.\nPotes [[Special:Search/{{PAGENAME}}|hanc rem in aliis paginis quaerere]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} acta huius paginae videre]\naut [{{fullurl:{{FULLPAGENAME}}|action=edit}} hanc paginam creare]</span>.",
+       "noarticletext": "Hac in pagina non sunt litterae.\nLicet [[Special:Search/{{PAGENAME}}|hanc rem in aliis paginis quaerere]] vel\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} acta huius paginae inspicere]\nvel [{{fullurl:{{FULLPAGENAME}}|action=edit}} hanc paginam creare]</span>.",
        "noarticletext-nopermission": "Hac in pagina non sunt litterae.\nPotes [[Special:Search/{{PAGENAME}}|hanc rem in aliis paginis quaerere]] aut <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} acta huius paginae videre], sed tibi non licet hanc paginam creare.",
        "userpage-userdoesnotexist": "Usor \"<nowiki>$1</nowiki>\" non est. Visne re vera hanc paginam creare vel recensere?",
        "updated": "(Novata)",
        "suppress": "Censura",
        "booksources": "Librorum fontes",
        "booksources-search-legend": "Fontes impressas quaerere",
+       "booksources-search": "Quaerere",
        "specialloguserlabel": "Usor:",
        "speciallogtitlelabel": "Destinatum (titulus aut usor):",
        "log": "Acta",
        "tooltip-t-permalink": "Nexus perpetuus ad hanc paginae redactionem",
        "tooltip-ca-nstab-main": "Videre paginam",
        "tooltip-ca-nstab-user": "Videre paginam usoris",
-       "tooltip-ca-nstab-special": "Haec est pagina specialis. Pagina ipsa recenseri non potest.",
+       "tooltip-ca-nstab-special": "Ea est pagina specialis, quin recenseatur.",
        "tooltip-ca-nstab-project": "Videre paginam inceptorum",
        "tooltip-ca-nstab-image": "Videre paginam fasciculi",
        "tooltip-ca-nstab-mediawiki": "Videre nuntium systematis",
index 7a623c5..d253742 100644 (file)
@@ -15,7 +15,8 @@
                        "VT98Fan",
                        "Zinneke",
                        "לערי ריינהארט",
-                       "아라"
+                       "아라",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Linken ënnersträichen:",
        "createaccount-title": "Opmaache vun engem Benotzerkont op {{SITENAME}}",
        "createaccount-text": "Et gouf e Benotzerkont \"$2\" fir Iech op {{SITENAME}} ($4) ugeluecht mat dem Passwuert \"$3\".\nDir sollt Iech aloggen an Äert Passwuert elo änneren.\n\nWann dëse Benotzerkont ongewollt ugeluecht gouf, kënnt Dir dës Noriicht einfach ignoréieren.",
        "login-throttled": "Dir hutt zevill dacks versicht Iech anzeloggen.\nWaart w.e.g. $1 ier Dir et nach eng Kéier probéiert.",
-       "login-abort-generic": "Dir sidd net ageloggt - Aloggen ofgebrach",
+       "login-abort-generic": "Äert Aloggen huet net funktionéiert - Ofgebrach",
        "login-migrated-generic": "Äre Benotzerkont gouf migréiert an Äre Benotzernumm gëtt et net méi op dëser Wiki.",
        "loginlanguagelabel": "Sprooch: $1",
        "suspicious-userlogout": "Är Ufro fir Iech auszeloggen gouf refuséiert well et sou ausgesäit wéi wa se vun engem futtise Browser oder Proxy-Tëschespäicher kënnt.",
        "newarticle": "(Nei)",
        "newarticletext": "Dir hutt op e Link vun enger Säit geklickt, déi et nach net gëtt. Fir déi Säit unzeleeën, gitt w.e.g. Ären Text an déi Këscht hei drënner an (kuckt d'[$1 Hëllef Säit] fir méi Informatiounen). Wann Dir duerch een Iertum heihi komm sidd, da klickt einfach op de Knäppchen '''Zréck''' vun Ärem Browser.",
        "anontalkpagetext": "---- ''Dëst ass d'Diskussiounssäit fir en anonyme Benotzer deen nach kee Kont opgemaach huet oder en net benotzt. Dowéinst musse mir d'IP Adress benotzen, fir de Benotzer z'identifizéieren.\nSou eng IP Adress ka vun e puer Benotzer gedeelt ginn.\nWann Dir en anonyme Benotzer sidd an Dir irrelevant Bemierkunge krut, [[Special:UserLogin/signup|maacht w.e.g. e Kont op]] oder [[Special:UserLogin|loggt Iech an]], fir weider Verwiesselunge mat aneren anonyme Benotzer ze verhënneren.''",
-       "noarticletext": "Dës Säit huet momentan keen Text.\nDir kënnt op anere Säiten no [[Special:Search/{{PAGENAME}}|dësem Säitentitel sichen]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} an den entspriechende Logbicher nokucken] oder [{{fullurl:{{FULLPAGENAME}}|action=edit}} sou eng Säit uleeën]</span>.",
+       "noarticletext": "Dës Säit huet elo keen Text.\nDir kënnt op anere Säiten no [[Special:Search/{{PAGENAME}}|dësem Säitentitel sichen]],\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} an den entspriechende Logbicher nokucken] oder [{{fullurl:{{FULLPAGENAME}}|action=edit}} dës Säit uleeën]</span>.",
        "noarticletext-nopermission": "Elo ass keen Text op dëser Säit.\nDir kënnt op anere Säiten [[Special:Search/{{PAGENAME}}|no dësem Säitentitel sichen]], oder <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} an de Logbicher sichen]</span>, mä Dir hutt net déi néideg Rechter fir dës Säit unzeleeën.",
        "missing-revision": "D'Versioun #$1 vun der Säit mam Numm \"{{FULLPAGENAME}}\" gëtt et net.\n\nDat geschitt normalerweis wann Dir op e vereelste Link vun enger Versioun vun enger Säit klickt déi geläscht ginn ass.\nDetailer fannt Dir am [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} Logbuch vum Läschen].",
        "userpage-userdoesnotexist": "De Benotzerkont \"<nowiki>$1</nowiki>\" ass net registréiert.\nIwwerpréift w.e.g. op Dir dës Säit uleeën/ännere wëllt.",
        "grant-createaccount": "Benotzerkonten opmaachen",
        "grant-createeditmovepage": "Säiten uleeën, änneren a réckelen",
        "grant-delete": "Säiten, Versiounen a Rubriken a Logbicher läschen",
-       "grant-editinterface": "MediaWiki-Nummraum a Benotzer CSS/JS änneren",
-       "grant-editmycssjs": "Ären eegene Benotzer CSS/JavaScript änneren",
+       "grant-editinterface": "MediaWiki-Nummraum a Benotzer CSS/JavaScript änneren",
+       "grant-editmycssjs": "Äre Benotzer CSS/JavaScript änneren",
        "grant-editmyoptions": "Ännert Är Benotzerastellungen",
        "grant-editmywatchlist": "Ännert Är Iwwerwaachungslëscht",
        "grant-editpage": "Säiten déi et gëtt änneren",
        "grant-editprotected": "Gespaart Säiten änneren",
        "grant-oversight": "Benotzer verstoppen a Versioune läschen",
-       "grant-patrol": "Ännerungen op Säiten iwwerwaachen",
+       "grant-patrol": "Ännerungen op Säiten kontrolléieren",
        "grant-protect": "Säite spären an entspären",
        "grant-rollback": "Ännerungen op Säiten zrécksetzen",
        "grant-sendemail": "Anere Benotzer E-Maile schécken",
        "recentchangeslinked-page": "Säitennumm:",
        "recentchangeslinked-to": "Weis Ännerungen zu de verlinkte Säiten aplaz vun der gefroter Säit",
        "recentchanges-page-added-to-category": "[[:$1]] an d'Kategorie derbäigesat",
-       "recentchanges-page-added-to-category-bundled": "{{PLURAL:$2|}}[[:$1]] a(n) {{PLURAL:$2|eng Säit|$2 Säiten}} an d'Kategorie derbäigesat",
+       "recentchanges-page-added-to-category-bundled": "{{PLURAL:$2|}}[[:$1]] a(n) [[Special:WhatLinksHere/$1|{{PLURAL:$2|eng Säit|$2 Säiten}}]] an d'Kategorie derbäigesat",
        "recentchanges-page-removed-from-category": "[[:$1]] erausgeholl aus der Kategorie",
-       "recentchanges-page-removed-from-category-bundled": "{{PLURAL:$2|}}[[:$1]] a(n) {{PLURAL:$2|eng Säit|$2 Säiten}} aus der Kategorie erausgeholl",
+       "recentchanges-page-removed-from-category-bundled": "[[:$1]] a(n) [[Special:WhatLinksHere/$1|{{PLURAL:$2|eng Säit|$2 Säiten}}]] aus der Kategorie erausgeholl",
        "autochange-username": "Automatesch MediaWiki-Ännerung",
        "upload": "Eroplueden",
        "uploadbtn": "Fichier eroplueden",
        "uploadstash-badtoken": "D'Ausféiere vun dëser Aktioun huet net funktionéiert, vläicht well d'Informatiounen iwwer Är Rechter ofgelaf sinn. Probéiert et w.e.g. nach emol.",
        "uploadstash-errclear": "D'Läsche vun de Fichieren huet net funktionéiert.",
        "uploadstash-refresh": "Lëscht vun de Fichieren aktualiséieren",
+       "uploadstash-thumbnail": "Miniaturbild weisen",
        "img-auth-accessdenied": "Zougang refuséiert",
        "img-auth-nopathinfo": "PATH_INFO feelt.\nÄre Server ass net agestallt fir déi Informatioun weiderzeginn.\nEt kann u CGI leien an datt imag_auth net ënnerstëtzt gëtt.\nKuckt https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "img-auth-notindir": "De gefrote Pad ass net am Upload-Repertoire agestallt.",
        "mw-widgets-titleinput-description-redirect": "viruleeden op $1",
        "api-error-blacklisted": "Sicht w.e.g. en aneren Titel, dee méi iwwer de Sujet ausseet.",
        "sessionprovider-generic": "$1-Sessiounen",
-       "randomrootpage": "Zoufalls-Stammsäit"
+       "randomrootpage": "Zoufalls-Stammsäit",
+       "log-action-filter-block": "Typ vun der Spär:",
+       "log-action-filter-protect": "Typ vu Spär",
+       "log-action-filter-all": "All",
+       "log-action-filter-block-block": "Spären",
+       "log-action-filter-block-unblock": "Spär ophiewen",
+       "log-action-filter-delete-delete": "Säite läschen",
+       "log-action-filter-patrol-patrol": "Manuell Kontroll",
+       "log-action-filter-patrol-autopatrol": "Automatesch Kontroll",
+       "log-action-filter-protect-protect": "Spär",
+       "log-action-filter-protect-modify": "Spär-pÄnnerung"
 }
index 483b3a7..9ede18f 100644 (file)
@@ -11,7 +11,8 @@
                        "아라",
                        "V6rg",
                        "C.R.",
-                       "Macofe"
+                       "Macofe",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Sottolineâ i collegamenti",
        "recentchangeslinked-page": "Nómme da pàgina:",
        "recentchangeslinked-to": "Fanni védde sôlo i cangiaménti a-e pàgine colegæ a-a pàgina specificâ",
        "recentchanges-page-added-to-category": "[[:$1]] azonto a-a categoria",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] e {{PLURAL:$2|una paggina a l'è azonta|$2 paggine son azonte}} a-a categoria",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] e [[Special:WhatLinksHere/$1|{{PLURAL:$2|una paggina a l'è azonta|$2 paggine son azonte}}]] a-a categoria",
        "recentchanges-page-removed-from-category": "[[:$1]] rimosso da-a categoria",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] e {{PLURAL:$2|una paggina a l'è rimossa|$2 paggine son rimosse}} da-a categoria",
        "autochange-username": "Modiffica aotomattica MediaWiki",
index 1582bb3..3fd7e2f 100644 (file)
@@ -7,7 +7,8 @@
                        "Macofe",
                        "Mjbmr",
                        "Matma Rex",
-                       "Lakzon"
+                       "Lakzon",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "هوم پئیڤأند زیرخأط دار:",
        "protect-otherreason-op": "دألیل ھأنی",
        "protect-dropdown": "*دلیلیا جاافتائه سی پر و پیم کاری\n** خراوکاری گپ کلون\n** هرزه نیسی گپ کلون\n** جئن ویرایشتی وه درد نحور\n** بلگه فره تماشاکار دار",
        "protect-edit-reasonlist": "دلیلا پر و پیم بیین ویرایشت",
-       "protect-expiry-options": "۱ ساعأت:1 hour,۱ روٙز:1 day,۱ ھأفتە:1 week,۲ ھأفتە:2 weeks,۱ ما:1 month,۳ ما:3 months,۶ ما:6 months,۱ سال:1 year,بی حئسۉ:infinite",
+       "protect-expiry-options": "2 hours:2 hours,1 day:1 day,3 days:3 days,1 week:1 week,2 weeks:2 weeks,1 month:1 month,3 months:3 months,6 months:6 months,1 year:1 year,indefinite:infinite",
        "restriction-type": "دسرسی:",
        "restriction-level": "ریتراز محدودیت:",
        "minimum-size": "انازه کمترونه",
        "ipbenableautoblock": "بستن خودانجوم آخری تیرنشون آی پی وه کار گرته بیه وه دس کاریار و تیرنشونیا هنی که که د ونو سی ویرایشت وه سعی می کن.",
        "ipbsubmit": "نهاگری ای کاریار",
        "ipbother": "وخت هنی:",
-       "ipboptions": "۱ ساعأت:1 hour,۱ روٙز:1 day,۱ ھأفتە:1 week,۲ ھأفتە:2 weeks,۱ ما:1 month,۳ ما:3 months,۶ ما:6 months,۱ سال:1 year,بی حئسۉ:infinite",
+       "ipboptions": "2 hours:2 hours,1 day:1 day,3 days:3 days,1 week:1 week,2 weeks:2 weeks,1 month:1 month,3 months:3 months,6 months:6 months,1 year:1 year,indefinite:infinite",
        "ipbhidename": "نوم کاروری نه سی ویرایشت یا و نوم گه یا قام کو",
        "ipbwatchuser": "پی گری بلگه کاریاری و بلگه چک چنه ای کاریار",
        "ipb-disableusertalk": "نها ای کاریار نه اوسه که میها د بلگه چک چنه ش ویرایشت بکه و وه قلف بیه بئر",
index a366600..c0b33b8 100644 (file)
@@ -34,7 +34,8 @@
                        "Albertas",
                        "Macofe",
                        "Zygimantus",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Nuorodos pabraukimas:",
        "recentchangeslinked-page": "Puslapio pavadinimas:",
        "recentchangeslinked-to": "Rodyti su duotuoju puslapiu susijusių puslapių pakeitimus",
        "recentchanges-page-added-to-category": "[[:$1]] pridėta prie kategorijos",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] ir {{PLURAL:$2|vienas puslapis|$2 puslapiai}} pridėti prie kategorijos",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] ir [[Special:WhatLinksHere/$1|{{PLURAL:$2|vienas puslapis|$2 puslapiai}}]] pridėti prie kategorijos",
        "recentchanges-page-removed-from-category": "[[:$1]] pašalinta iš kategorijos",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] ir {{PLURAL:$2|vienas puslapis|$2 puslapiai}} pašalinti iš kategorijos",
        "autochange-username": "MediaWiki automatinis pakeitimas",
        "uploadstash-badtoken": "Scenos šį ieškinį, buvo nesėkmingas, galbūt todėl, kad jūsų redagavimo įgaliojimai pasibaigė. Bandykite dar kartą.",
        "uploadstash-errclear": "Kliringo failai buvo nesėkmingas.",
        "uploadstash-refresh": "Atnaujinti failų sąrašą",
+       "uploadstash-thumbnail": "rodyti miniatiūrą",
        "invalid-chunk-offset": "Neleistinas segmento poslinkis",
        "img-auth-accessdenied": "Prieiga uždrausta",
        "img-auth-nopathinfo": "Trūksta PATH_INFO.\nJūsų serveris nenustatytas perduoti šią informaciją.\nTai gali būti CGI paremta ir negali palaikyti img_auth.\nDaugiau informacijos https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization. žr.",
index d4544dd..7975cf9 100644 (file)
        "recentchanges-label-bot": "ई सम्पादन यांत्रिक छल।",
        "recentchanges-label-unpatrolled": "ऐ सम्पादनक पुनरीक्षण अखन धरि नै कएल गेल अछि।",
        "recentchanges-label-plusminus": "पन्नाके आकार इ बाइट संख्यासे बदलल गेल",
-       "recentchanges-legend-heading": "<strong>à¤\95à¥\81à¤\82जी:</strong>",
+       "recentchanges-legend-heading": "<strong>à¤\95à¥\81à¤\9eà¥\8dजी:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} ([[Special:NewPages|नयाँ पन्नसभके सूची]] सहो देखु)",
        "rcnotefrom": "नीचाँमे '''$2''' सँ भेल परिवर्तन अछि ('''$1''' धरि देखाएल)।",
        "rclistfrom": "$3 $2 सँ शुरू भेल नव परिवर्तन देखू",
index 83925c2..7468ee4 100644 (file)
        "sort-descending": "Fandaharana miiba",
        "sort-ascending": "Fandaharana miabo",
        "nstab-main": "Lahatsoratra",
-       "nstab-user": "Pejy ny mpikambana",
+       "nstab-user": "Pejim-pikambana",
        "nstab-media": "Pejy sary sy/na feo",
        "nstab-special": "Pejy Manokana",
        "nstab-project": "Tetikasa",
index 1470aec..1d68d63 100644 (file)
@@ -16,7 +16,8 @@
                        "לערי ריינהארט",
                        "아라",
                        "Milicevic01",
-                       "Macofe"
+                       "Macofe",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Потцртување на врски:",
        "recentchangeslinked-page": "Име на страницата:",
        "recentchangeslinked-to": "Прикажи ги промените на страниците поврзани со дадената страница",
        "recentchanges-page-added-to-category": "[[:$1]] ставена во категорија",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] и уште {{PLURAL:$2|една страница ставена|$2 страници ставеи}} во категорија",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] и уште [[Special:WhatLinksHere/$1|{{PLURAL:$2|една страница ставена|$2 страници ставеи}}]] во категорија",
        "recentchanges-page-removed-from-category": "[[:$1]] отстранета од категорија",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] и уште {{PLURAL:$2|една страница отстранета|$2 страници отстранети}} од категорија",
        "autochange-username": "Автоматски промени на МедијаВики",
index e313abe..0f9afb9 100644 (file)
        "recentchangeslinked-page": "താളിന്റെ പേര്:",
        "recentchangeslinked-to": "തന്നിരിക്കുന്ന താളിലെ മാറ്റങ്ങൾക്കു പകരം ബന്ധപ്പെട്ട താളുകളിലെ മാറ്റങ്ങൾ കാണിക്കുക",
        "recentchanges-page-added-to-category": "[[:$1]] വർഗ്ഗത്തിലേക്ക് ചേർത്തിരിക്കുന്നു",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] താളും ഒപ്പം {{PLURAL:$2|മറ്റൊരു താളും|$2 താളുകളും}} വർഗ്ഗത്തിലേക്ക് ചേർത്തിരിക്കുന്നു",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] താളും ഒപ്പം [[Special:WhatLinksHere/$1|{{PLURAL:$2|മറ്റൊരു താളും|$2 താളുകളും}}]] വർഗ്ഗത്തിലേക്ക് ചേർത്തിരിക്കുന്നു",
        "recentchanges-page-removed-from-category": "[[:$1]] വർഗ്ഗത്തിൽ നിന്ന് നീക്കംചെയ്തു",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] താളും ഒപ്പം {{PLURAL:$2|മറ്റൊരു താളും|$2 താളുകളും}} വർഗ്ഗത്തിൽ നിന്ന് നീക്കംചെയ്തിരിക്കുന്നു",
        "autochange-username": "മീഡിയവിക്കി സ്വയംപ്രവർത്തിത മാറ്റം",
index 1f7e833..2ba3513 100644 (file)
        "recentchangeslinked-page": "पृष्ठ नाव:",
        "recentchangeslinked-to": "याऐवजी दिलेल्या पानाला जोडलेल्या पानांवरील बदल दाखवा",
        "recentchanges-page-added-to-category": "[[:$1]] वर्गास जोडले",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] व {{PLURAL:$2|एक पान वर्गास जोडले|$2 पाने वर्गास जोडलीत}}",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] व [[Special:WhatLinksHere/$1|{{PLURAL:$2|एक पान वर्गास जोडले|$2 पाने वर्गास जोडलीत}}]]",
        "recentchanges-page-removed-from-category": "[[:$1]] ला वर्गातून हटविले",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] व {{PLURAL:$2|एक पान वर्गातून हटविले|$2 पाने वर्गातून हटविलीत}}",
        "autochange-username": "मिडियाविकि आपोआप बदल",
index aa44e04..d29a55d 100644 (file)
@@ -20,7 +20,8 @@
                        "아라",
                        "Pizza1016",
                        "Macofe",
-                       "Matma Rex"
+                       "Matma Rex",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Garis bawah pautan:",
        "recentchangeslinked-page": "Nama laman:",
        "recentchangeslinked-to": "Paparkan perubahan pada laman yang mengandungi pautan ke laman yang diberikan",
        "recentchanges-page-added-to-category": "[[:$1]] ditambahkan kepada kategori",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] dan {{PLURAL:$2|satu|$2}} lagi halaman ditambahkan kepada kategori",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] dan [[Special:WhatLinksHere/$1|{{PLURAL:$2|satu|$2}}]] lagi halaman ditambahkan kepada kategori",
        "recentchanges-page-removed-from-category": "[[:$1]] digugurkan dari kategori",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] dan {{PLURAL:$2|satu|$2}} lagi halaman digugurkan dari kategori",
        "autochange-username": "Perubahan automatik MediaWiki",
index 7ad983a..e465bdf 100644 (file)
@@ -22,7 +22,8 @@
                        "아라",
                        "9.sinistra",
                        "Ninjastrikers",
-                       "Penguinlay"
+                       "Penguinlay",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "လင့်ကို မျဉ်းသားသည့် ပုံစံ -",
        "revdelete-show-file-submit": "မှန်",
        "revdelete-selected-file": "[[:$2]] ၏ ရွေးချယ်ထားသော {{PLURAL:$1|ဖိုင်ဗားရှင်း|ဖိုင်ဗားရှင်းများ}}:",
        "revdelete-text-text": "ဖျက်လိုက်သည့် မူများသည် စာမျက်နှာရာဇဝင်တွင် ရှိနေဦးမည်ဖြစ်သော်လည်း ထိုပါဝင်အကြောင်းအရာသည် အများပြည်သူမှ မြင်ရတော့မည် မဟုတ်ပေ။",
+       "revdelete-text-file": "ဖျက်လိုက်သော ဖိုင်ဗားရှင်းများသည် ဖိုင်ရာဇဝင်ထဲတွင် ရှိနေဦးမည်ဖြစ်သော်လည်း ယင်းတို့ကို အများပြည်သူ ကြည့်ရှုနိုင်မည် မဟုတ်ပေ။",
        "logdelete-text": "ဖျက်လိုက်သော မှတ်တမ်းသည် မှတ်တမ်းများထဲတွင် ပေါ်နေဦးမည်ဖြစ်သော်လည်း ပါဝင်အကြောင်းအရာကို အများပြည်သူများ မြင်ရတော့မည် မဟုတ်ပေ။",
        "revdelete-text-others": "အပိုကန့်သတ်ချက်များကို မထည့်ထားပါက အခြားသော အက်ဒမင်များအနေဖြင့် ဝှက်ထားသော အကြောင်းအရာကို ကြည့်နိုင်ပြီး ဖျက်ထားခြင်းကို ပယ်ဖျက်နိုင်သည်။",
        "revdelete-confirm": "ဤသို့ ဖျက်ပစ်ရန် သင် အမှန်တကယ် ရည်ရွယ်လျက် နောက်ဆက်တွဲ အကျိုးဆက်များကို သိရှိနားလည်ပြီး [[{{MediaWiki:Policy-url}}|မူဝါဒ]]အတိုင်း လုပ်ဆောင်နေခြင်းဖြစ်ကြောင်းကို ကျေးဇူးပြု၍ အတည်ပြုပေးပါ။",
        "recentchangeslinked-page": "စာမျက်နှာ အမည် -",
        "recentchangeslinked-to": "ပေးထားသော စာမျက်နှာများအစား လင့်များနှင့် ဆက်စပ်နေသာ စာမျက်နှာများ၏ အပြောင်းအလဲများကို ပြရန်",
        "recentchanges-page-added-to-category": "ကဏ္ဍထဲသို့ [[:$1]] ကို ပေါင်းထည့်ခဲ့သည်",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] နှင့် {{PLURAL:$2|စာမျက်နှာ တစ်ခု|စာမျက်နှာ $2 ခု}}ကို ကဏ္ဍထဲသို့ ပေါင်းထည့်ခဲ့သည်",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] နှင့် [[Special:WhatLinksHere/$1|{{PLURAL:$2|စာမျက်နှာ တစ်ခု|စာမျက်နှာ $2 ခု}}]]ကို ကဏ္ဍထဲသို့ ပေါင်းထည့်ခဲ့သည်",
        "recentchanges-page-removed-from-category": "ကဏ္ဍထဲမှ [[:$1]] ကို ဖယ်ရှားခဲ့သည်",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] နှင့် {{PLURAL:$2|စာမျက်နှာ တစ်ခု|စာမျက်နှာ $2 ခု}}ကို ကဏ္ဍထဲမှ ဖယ်ရှားခဲ့သည်",
        "upload": "ဖိုင်​တင်​ရန်​",
index 69be88a..8bcfce5 100644 (file)
@@ -14,6 +14,7 @@
        "tog-hideminor": "Am chòe-kīn ê sió kái-piàn",
        "tog-hidepatrolled": "Am chòe-kīn sûn koè--ê  kái-piàn",
        "tog-newpageshidepatrolled": "Sin-ia̍h ê chheng-toaⁿ am sûn koè--ê",
+       "tog-hidecategorization": "Kā ia̍h ê lūi-pia̍t chhàng--khì-lâi",
        "tog-extendwatchlist": "thián-khui kàm-sī-toaⁿ, khoàⁿ choân-pō͘  kái ê, m̄-nā choè-kīn niā.",
        "tog-usenewrc": "共文章最近有改的佮監視列表囥做伙",
        "tog-numberheadings": "Phiau-tê chū-tōng pian-hō",
@@ -34,7 +35,7 @@
        "tog-shownumberswatching": "Hián-sī tng leh khoàⁿ ê iōng-chiá sò͘-bo̍k",
        "tog-oldsig": "Chit-má ê chhiam-miâ:",
        "tog-fancysig": "共我的簽名當做文章文字,(無需要自動連結)",
-       "tog-uselivepreview": "Ēng sui khoàⁿ-māi (chhì-giām--ê)",
+       "tog-uselivepreview": "Ēng sui khoàⁿ-māi",
        "tog-forceeditsummary": "Pian-chi̍p khài-iàu bô thiⁿ ê sî-chūn, kā goá thê-chhéⁿ",
        "tog-watchlisthideown": "Kàm-sī-toaⁿ bián hián-sī goá ê pian-chi̍p",
        "tog-watchlisthidebots": "Kàm-sī-toaⁿ bián hián-sī ki-khì pian-chi̍p",
@@ -42,6 +43,7 @@
        "tog-watchlisthideliu": "Kàm-sī-toaⁿ bián hián-sī iōng-chiá ū teng-ji̍p ê pian-chi̍p",
        "tog-watchlisthideanons": "Kàm-sī-toaⁿ bián hián-sī bû-bêng-sī ê pian-chi̍p",
        "tog-watchlisthidepatrolled": "Kàm-sī-toaⁿ bián hián-sī khoàⁿ-koè--ê pian-chi̍p",
+       "tog-watchlisthidecategorization": "Kā ia̍h ê lūi-pia̍t chhàng--khì-lâi",
        "tog-ccmeonemails": "Kià hō͘ pa̍t-lâng ê email sūn-soà kià copy hō͘ goá",
        "tog-diffonly": "Diff ē-pêng bián hián-sī ia̍h ê loē-iông",
        "tog-showhiddencats": "Hián-sī chhàng khí--lâi ê lūi-pia̍t",
        "october-date": "10月$1",
        "november-date": "11月$1",
        "december-date": "12月$1",
+       "period-am": "AM",
+       "period-pm": "PM",
        "pagecategories": "{{PLURAL:$1|Lūi-pia̍t|Lūi-pia̍t}}",
        "category_header": "Tī \"$1\" chit ê lūi-pia̍t ê bûn-chiuⁿ",
        "subcategories": "Ē-lūi-pia̍t",
        "morenotlisted": "這毋是完整的表",
        "mypage": "Ia̍h",
        "mytalk": "Thó-lūn",
-       "anontalk": "Chit ê IP ê thó-lūn-ia̍h",
+       "anontalk": "Thó-lūn",
        "navigation": "Se̍h chām",
        "and": "&#32;kap",
        "qbfind": "Chhōe",
        "pool-queuefull": "Tūi-lia̍t pâi moá ah",
        "pool-errorunknown": "M̄-chai siáⁿ chhò-gō͘",
        "pool-servererror": "無提供系統服務總數的統計。",
+       "poolcounter-usage-error": "Ēng-hoat chhò-gō͘: $1",
        "aboutsite": "Koan-hē {{SITENAME}}",
        "aboutpage": "Project:Koan-hē",
        "copyright": "Tû liáu ū lēng-goā kóng, nā bô loē-iông sī chiàu $1 tiâu-kiāⁿ tō thang sú-iōng.",
        "changeemail": "Kái tiān-chú-phoe ê tē-chí",
        "changeemail-oldemail": "Chit-má ê E-mail tē-chí:",
        "changeemail-newemail": "Sin E-mail ê chū-chí:",
+       "changeemail-password": "Lí-ê {{SITENAME}} bi̍t-bé:",
+       "changeemail-submit": "Kái-piàn tiān-chu-phoe",
+       "changeemail-throttled": "Lí chi̍t-ê-á teng-ji̍p liáu siuⁿ chē kái.\nChiáⁿ tan-thāi $1 kòe-āu chài chhì chi̍t pái.",
+       "changeemail-nochange": "Chhiáⁿ su-ji̍p chi̍t-ê bô-kâng ê sin tiān-chú-phoe chū-chí.",
        "bold_sample": "Chho·-thé bûn-jī",
        "bold_tip": "Chho·-thé jī",
        "italic_sample": "Chhú-thé ê bûn-jī",
        "recreate-moveddeleted-warn": "'''Sè-jī: Lí taⁿ chún-pī beh khui ê ia̍h, chêng bat hō͘ lâng thâi tiāu koè.''' Lí tio̍h chim-chiok soà-chiap pian-chi̍p chit ia̍h ê pit-iàu-sèng. Chia ū chit ia̍h ê san-tû kì-lo̍k (deletion log) hō͘ lí chham-khó:",
        "edit-conflict": "Siu-kái sio-chhiong",
        "defaultmessagetext": "Siat piān ê bûn-jī",
+       "content-model-wikitext": "wikitext",
+       "content-model-text": "sûn bûn-pún",
+       "content-model-javascript": "JavaScript",
+       "content-json-empty-object": "Khang bu̍t-kiāⁿ",
+       "content-json-empty-array": "Khang tīn-lia̍t",
        "post-expand-template-inclusion-warning": "'''Kéng-pò:'''Pau ji̍t lâi ê pán-bôo sioⁿ koè tsē ia̍h tuā.\nŪ chi̍t-koá-á ē bô pau ji̍t lâi.",
        "undo-success": "Pian-chi̍p í-keng chhú-siau. Chhiáⁿ khak-tēng, liáu-āu kā ē-kha ho̍k-goân ê kái-piàn pó-chûn--khí-lâi.",
        "undo-failure": "Pian-chi̍p bē-tàng chhú-siau, in-ūi chhiong tio̍h kî-kan chhah-ji̍p ê pian-chi̍p.",
        "localtime": "Chāi-tē sî-kan sī",
        "servertime": "Server sî-kan hiān-chāi sī",
        "guesstimezone": "Tùi liû-lám-khì chhau--lâi",
+       "timezoneregion-africa": "Hui-chiu",
+       "timezoneregion-america": "Bí-chiu",
+       "timezoneregion-antarctica": "Lâm-ke̍k-chiu",
+       "timezoneregion-arctic": "Pak-ke̍k",
+       "timezoneregion-asia": "A-chiu",
+       "timezoneregion-atlantic": "Tāi-se-iûⁿ",
+       "timezoneregion-australia": "Australia",
+       "timezoneregion-europe": "Au-chiu",
+       "timezoneregion-indian": "Ìn-tō͘-iûⁿ",
+       "timezoneregion-pacific": "Thài-pêng-iûⁿ",
        "allowemail": "Ún-chún pa̍t-ê iōng-chiá kià email kòe-lâi",
+       "prefs-searchoptions": "Cha-sûn",
+       "prefs-namespaces": "Miâ-khong-kan",
+       "default": "kì-tēng",
        "prefs-files": "Tóng-àn",
+       "prefs-custom-css": "Chū-siat CSS",
+       "prefs-custom-js": "Chū-siat JavaScript",
+       "prefs-common-css-js": "Só͘-ū gōa-phôe kong-ke ê CSS/JavaScript",
+       "prefs-reset-intro": "Lí ē-sài ēng pún ia̍h lâi chiong lí ê siat-tì têng-siat chò pún chām kì-tēng.\nChe bē hoat-tō͘ ho̍k-goân.",
+       "prefs-emailconfirm-label": "Tiān-chú-phoe khak-tēng:",
        "youremail": "Lí ê email:",
+       "username": "{{GENDER:$1|Ēng-chiá-miâ-hō}}:",
        "yourrealname": "Lí ê chin miâ:",
        "yourlanguage": "Kài-bīn gú-giân:",
        "yournick": "Lí ê sió-miâ (chhiam-miâ iōng):",
        "group-bureaucrat-member": "{{GENDER:$1|Koaⁿ-liâu}}",
        "grouppage-sysop": "{{ns:project}}:Hêng-chèng jîn-oân",
        "grouppage-bureaucrat": "{{ns:project}}:Koaⁿ-liâu",
+       "right-move-categorypages": "Sóa tōng ia̍h-bīn lūi-lia̍t",
+       "right-movefile": "Sóa tóng-àn",
+       "right-upload": "Kā tóng-àn chiūⁿ-bāng",
+       "right-upload_by_url": "Tùi 1-ê URL thoân thóng-àn",
        "right-writeapi": "用API寫",
+       "right-delete": "Thâi ia̍h",
        "newuserlogpage": "khui kháu-chō ji̍t-chì",
        "rightslogtext": "Chit-ê log lia̍t-chhut kái-piàn iōng-chiá koân-lī ê tōng-chok.",
        "action-edit": "Siu-kái chit ia̍h",
        "doubleredirects": "Siang-thâu choán-ia̍h",
        "brokenredirects": "Choán-ia̍h kò·-chiòng",
        "brokenredirectstext": "Í-hā ê choán-ia̍h liân kàu bô chûn-chāi ê ia̍h:",
+       "brokenredirects-edit": "siu-kái",
+       "brokenredirects-delete": "thâi",
        "withoutinterwiki": "Bô gí-giân liân-kiat ê ia̍h",
        "withoutinterwiki-summary": "Ē-kha ê ia̍h bô kî-thaⁿ gí-giân pán-pún ê liân-kiat:",
+       "withoutinterwiki-legend": "Jī-thâu",
+       "withoutinterwiki-submit": "Hían-sī",
        "fewestrevisions": "Siōng bô siu-tēng ê bûn-chiuⁿ",
        "nbytes": "$1 {{PLURAL:$1|jī-goân|jī-goân}}",
        "ncategories": "$1 {{PLURAL:$1|ê lūi-pia̍t |ê lūi-pia̍t}}",
-       "nlinks": "$1 ê liân-kiat",
+       "nlinks": "$1 ê {{PLURAL:$1|liân-kiat}}",
        "nmembers": "$1{{PLURAL:$1|ê sêng-oân}}",
-       "nrevisions": "$1 ê siu-tēng-pún",
+       "nmemberschanged": "$1 → $2 ê {{PLURAL:$2|sêng-oân}}",
+       "nrevisions": "$1 ê {{PLURAL:$1|siu-tēng-pún}}",
        "lonelypages": "Ko·-ia̍h",
        "uncategorizedpages": "Bô lūi-pia̍t ê ia̍h",
        "uncategorizedcategories": "Bô lūi-pia̍t ê lūi-pia̍t",
        "deadendpages": "Khu̍t-thâu-ia̍h",
        "deadendpagestext": "Ē-kha ê ia̍h bô liân kàu wiki lāi-té ê kî-thaⁿ ia̍h.",
        "protectedpages": "Siū pó-hō͘ ê ia̍h",
+       "protectedpages-page": "Ia̍h",
        "listusers": "Iōng-chiá lia̍t-toaⁿ",
        "newpages": "Sin ia̍h",
        "newpages-username": "Iōng-chiá miâ-chheng:",
        "move-watch": "Kàm-sī chit ia̍h",
        "movepagebtn": "Sóa ia̍h",
        "pagemovedsub": "Sóa-ūi sêng-kong",
+       "movepage-moved": "<strong>\"$1\" í-keng hong sóa khì \"$2\"</strong>",
        "articleexists": "Kāng miâ ê ia̍h í-keng tī leh, a̍h-sī lí kéng ê miâ bô-hāu. Chhiáⁿ kéng pa̍t ê miâ.",
        "movetalk": "Sūn-sòa sóa thó-lūn-ia̍h",
        "movepage-page-moved": "$1 í-keng sóa khì tī $2.",
+       "movepage-page-unmoved": "$1 chit ia̍h hô hoat-tō͘ sóa khì $2.",
        "movelogpagetext": "Ē-kha lia̍t-chhut hông soá-ūi ê ia̍h.",
        "movereason": "Lí-iû:",
        "revertmove": "hôe-tńg",
index d1b54bd..c3276c3 100644 (file)
@@ -12,7 +12,8 @@
                        "아라",
                        "Candalua",
                        "Macofe",
-                       "V6rg"
+                       "V6rg",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Sottolinia 'e jonte:",
        "moredotdotdot": "Cchiù...",
        "morenotlisted": "Chisto elenco nun è cumpreto.",
        "mypage": "Paggena",
-       "anonuserpage": "Utente scanusciuto",
        "mytalk": "'E chiàcchieriate mmie",
        "anontalk": "Chiacchierate",
        "navigation": "Navigazzione",
        "recentchangeslinked-page": "Nomme d' 'a paggena",
        "recentchangeslinked-to": "Mmusta sulamente 'e cagnamiente a 'e paggene cullegate a chilla specificata",
        "recentchanges-page-added-to-category": "[[:$1]] azzeccato â categurìa",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] e {{PLURAL:$2|na paggena|$2 paggene}} azzeccate â categurìa",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] e [[Special:WhatLinksHere/$1|{{PLURAL:$2|na paggena|$2 paggene}}]] azzeccate â categurìa",
        "recentchanges-page-removed-from-category": "[[:$1]] luvato d' 'a categurìa",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] e {{PLURAL:$2|na paggena|$2 paggena}} luvate d' 'a categurìa",
        "autochange-username": "Cagnamiento automateco MediaWiki",
index 4bdecee..073fe88 100644 (file)
@@ -47,7 +47,8 @@
                        "Kingu",
                        "Tarjeimo",
                        "Matma Rex",
-                       "SuperPotato"
+                       "SuperPotato",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Strek under lenker:",
        "recentchangeslinked-page": "Sidenavn:",
        "recentchangeslinked-to": "Vis endringer på sider som lenker til den gitte siden istedet",
        "recentchanges-page-added-to-category": "[[:$1]] lagt til kategori",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] og {{PLURAL:$2|én side|$2 sider}} lagt til kategori",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] og [[Special:WhatLinksHere/$1|{{PLURAL:$2|én side|$2 sider}}]] lagt til kategori",
        "recentchanges-page-removed-from-category": "[[:$1]] fjernet fra kategori",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] og {{PLURAL:$2|én side|$2 sider}} fjernet fra kategori",
        "autochange-username": "Automatisk MediaWiki-endring",
index ecc8830..acc2cd7 100644 (file)
@@ -73,7 +73,8 @@
                        "Matma Rex",
                        "Robin van der Vliet",
                        "Catrope",
-                       "Edoderoo"
+                       "Edoderoo",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Koppelingen onderstrepen:",
        "recentchangeslinked-page": "Paginanaam:",
        "recentchangeslinked-to": "Wijzigingen aan pagina's met koppelingen naar deze pagina bekijken",
        "recentchanges-page-added-to-category": "[[:$1]] aan categorie toegevoegd",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] en {{PLURAL:$2|één pagina|$2 pagina's}} zijn toegevoegd aan categorie",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] en [[Special:WhatLinksHere/$1|{{PLURAL:$2|één pagina|$2 pagina's}}]] zijn toegevoegd aan categorie",
        "recentchanges-page-removed-from-category": "[[:$1]] is verwijderd uit categorie",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] en {{PLURAL:$2|één pagina|$2 pagina's}} zijn verwijderd uit categorie",
        "autochange-username": "Automatische wijziging van MediaWiki",
        "apisandbox-api-disabled": "De API is uitgeschakeld op deze site.",
        "apisandbox-intro": "Gebruik deze pagina om te experimenteren met de <strong>MediaWiki-API</strong>.\nZie de [[mw:API:Main page|API-documentatie]] voor verdere details over het gebruik van de API. Voorbeeld: [//www.mediawiki.org/wiki/API#A_simple_example hoe de inhoud van een Hoofdpagina ophalen]. Selecteer een handeling om meer voorbeelden te zien.\n\nHoewel dit een testfunctie is, kunnen sommige handelingen toch wijzigingen in de wiki maken.",
        "apisandbox-fullscreen": "Paneel uitvouwen",
-       "apisandbox-fullscreen-tooltip": "Het zandbakvenster uitvoeren om het browservenster te vullen.",
+       "apisandbox-fullscreen-tooltip": "Het zandbakpaneel zo groot als het browservenster maken.",
        "apisandbox-unfullscreen": "Pagina weergeven",
        "apisandbox-unfullscreen-tooltip": "Het zandbakvenster samenvouwen zodat de navigatie voor MediaWiki weer beschikbaar is.",
        "apisandbox-submit": "Verzoek uitvoeren",
index d751514..f2dc823 100644 (file)
        "resetpass-wrong-oldpass": "Feil mellombels eller noverande passord.\nDu kan allereie ha byta passordet, eller ha bede om å få eit nytt mellombels passord.",
        "resetpass-temp-password": "Mellombels passord:",
        "resetpass-abort-generic": "Passordbytet vart stogga av ei utviding.",
+       "resetpass-validity-soft": "Passordet ditt er ikkje gyldig: $1\n\nGjer vel å velja eit nytt passord no, eller klikk «{{int:resetpass-submit-cancel}}» for å endra det seinare.",
        "passwordreset": "Attendestilling av passord",
        "passwordreset-text-one": "Fyll ut dette skjemaet for å attendestilla passordet ditt.",
        "passwordreset-disabled": "↓Tilbakestilling av passord er ikkje aktivert på denne wikien",
index b728295..854f847 100644 (file)
        "virus-badscanner": "ମନ୍ଦ ସଂରଚନା: ଅଜଣା ଭାଇରସ ସ୍କାନର: ''$1''",
        "virus-scanfailed": "ସ୍କାନ କରିବା ବିଫଳ ହେଲା (କୋଡ଼ $1)",
        "virus-unknownscanner": "ଅଜଣା ଆଣ୍ଟିଭାଇରସ:",
-       "logouttext": "<strong>ଲà¬\97-à¬\86à¬\89à¬\9f à¬¹à­\8bà¬\87à¬\97ଲା à¥¤</strong>\n\nà¬\86ପଣ à¬¨à¬¿à¬\9cର à¬¬à­\8dରାà¬\89à¬\9cରର à¬\85ସà­\8dଥାà­\9fà­\80 à¬¸à­\8dମତି (cache) à¬¨ à¬²à¬¿à¬­à¬¾à¬\87ବା à¬¯à¬¾à¬\8f à¬¹à­\81à¬\8fତ à¬\95ିà¬\9bି à¬ªà­\83ଷà­\8dଠାରà­\87 à¬²à¬\97-à¬\87ନ à¬¹à­\8bà¬\87 à¬°à¬¹à¬¿ପାରେ ।",
+       "logouttext": "<strong>à¬\86ପଣ à¬²à¬\97-à¬\86à¬\89à¬\9f à¬¹à­\8bà¬\87à¬\97ଲà­\87 à¥¤</strong>\n\nà¬\86ପଣ à¬¨à¬¿à¬\9cର à¬¬à­\8dରାà¬\89à¬\9cରର à¬\85ସà­\8dଥାà­\9fà­\80 à¬¸à­\8dମà­\83ତି (cache) à¬\96ାଲି à¬¨'à¬\95ରିବାଯାà¬\8f, à¬¹à­\81à¬\8fତ à¬\95ିà¬\9bି à¬ªà­\83ଷà­\8dଠାରà­\87 à¬²à¬\97-à¬\87ନ à¬¹à­\8bà¬\87ଥିବା à¬ªà¬°à¬¿ à¬¦à­\87à¬\96ାଯାà¬\87ପାରେ ।",
        "cannotlogoutnow-title": "ଲଗ ଆଉଟ ହେଇପାରିଲା ନାହିଁ",
        "cannotlogoutnow-text": "$1ବ୍ୟବହାର କରୁଥିବା ବେଳେ ଲଗ ଆଉଟ ହେଇପାରିବ ନାହିଁ ।",
        "welcomeuser": "ସ୍ଵାଗତ, $1!",
index 0a24d1b..c695d8a 100644 (file)
@@ -82,7 +82,9 @@
                        "PiotrAntosz",
                        "The Polish",
                        "Expert3222",
-                       "Mateuszek045"
+                       "Mateuszek045",
+                       "Sethakill",
+                       "Mateon1"
                ]
        },
        "tog-underline": "Podkreślenie linków:",
        "changepassword-success": "Twoje hasło zostało zmienione!",
        "changepassword-throttled": "Ostatnio zbyt wiele razy próbowałeś zalogować się na to konto.\nOdczekaj $1, zanim ponowisz próbę.",
        "botpasswords": "Hasła bota",
+       "botpasswords-summary": "<em>Hasła bota</em> pozwalają na dostęp do konta użytkownika za pośrednictwem interfejsu API bez korzystania z danych konta. Uprawnienia uczestnika przy użyciu hasła bota mogą być ograniczone.\n\nJeśli nie wiesz, dlaczego miałbyś je tworzyć, nie powinieneś tego robić. Nikt nie powinien prosić Cię o utworzyć i podanie tego hasła.",
+       "botpasswords-disabled": "Hasła robotów zostały wyłączone.",
+       "botpasswords-no-central-id": "Aby użyć hasła robotów, musisz być zalogowany na koncie uniwersalnym.",
+       "botpasswords-existing": "Istniejące hasło bota",
+       "botpasswords-createnew": "Stwórz nowe hasło bota",
+       "botpasswords-editexisting": "Edytuj istniejące hasło bota",
        "botpasswords-label-appid": "Nazwa bota:",
        "botpasswords-label-create": "Utwórz",
        "botpasswords-label-update": "Aktualizuj",
        "botpasswords-label-delete": "Usuń",
        "botpasswords-label-resetpassword": "Zresetuj hasło",
        "botpasswords-label-grants-column": "Przyznane",
+       "botpasswords-bad-appid": "Nazwa bota \"$1\" nie jest prawidłowa.",
+       "botpasswords-created-title": "Hasło bota stworzone",
+       "botpasswords-created-body": "Hasło bota \"$1\" użytkownika \"$2\" zostało utworzone.",
+       "botpasswords-updated-title": "Hasło bota zaktualizowane",
+       "botpasswords-updated-body": "Hasło bota \"$1\" użytkownika \"$2\" zostało zaktualizowane.",
+       "botpasswords-deleted-title": "Hasło bota usunięte",
+       "botpasswords-deleted-body": "Hasło bota \"$1\" użytkownika \"$2\" zostało usunięte.",
+       "botpasswords-not-exist": "Użytkownik \"$1\" nie ma hasła dla bota o nazwie \"$2\".",
        "resetpass_forbidden": "Hasła nie mogą zostać zmienione",
        "resetpass-no-info": "Musisz być zalogowany, by uzyskać bezpośredni dostęp do tej strony.",
        "resetpass-submit-loggedin": "Zmień hasło",
        "mergehistory-fail-bad-timestamp": "Znacznik czasu jest nieprawidłowy.",
        "mergehistory-fail-invalid-source": "Strona źródłowa jest nieprawidłowa.",
        "mergehistory-fail-invalid-dest": "Strona docelowa jest nieprawidłowa.",
+       "mergehistory-fail-permission": "Brak uprawnień aby połączyć historię.",
        "mergehistory-fail-self-merge": "Strona źródłowa i docelowa są takie same.",
        "mergehistory-fail-toobig": "Nie można połączyć historii, gdyż wymagałoby to przeniesienia więcej niż maksymalnej dopuszczalnej liczby $1 {{PLURAL:$1|wersji}}.",
        "mergehistory-no-source": "Strona źródłowa $1 nie istnieje.",
        "recentchangeslinked-page": "Tytuł strony:",
        "recentchangeslinked-to": "Pokaż zmiany nie na stronach linkowanych, a na stronach linkujących do podanej strony",
        "recentchanges-page-added-to-category": "dodano [[:$1]] do kategorii",
-       "recentchanges-page-added-to-category-bundled": "dodano [[:$1]] oraz {{PLURAL:$2|jedną stronę|$2 strony|$2 stron}} do kategorii",
+       "recentchanges-page-added-to-category-bundled": "dodano [[:$1]] oraz [[Special:WhatLinksHere/$1|{{PLURAL:$2|jedną stronę|$2 strony|$2 stron}}]] do kategorii",
        "recentchanges-page-removed-from-category": "usunięto [[:$1]] z kategorii",
-       "recentchanges-page-removed-from-category-bundled": "usunięto [[:$1]] oraz {{PLURAL:$2|jedną stronę|$2 strony|$2 stron}} z kategorii",
+       "recentchanges-page-removed-from-category-bundled": "usunięto [[:$1]] oraz [[Special:WhatLinksHere/$1|{{PLURAL:$2|jedną stronę|$2 strony|$2 stron}}]] z kategorii",
        "autochange-username": "Automatyczna zmiana MediaWiki",
        "upload": "Prześlij plik",
        "uploadbtn": "Prześlij plik",
        "uploadstash-badtoken": "Operacja nie powiodła się. Być może Twoje upoważnienie do edytowania wygasło. Spróbuj ponownie.",
        "uploadstash-errclear": "Czyszczenie plików nie powiodło się.",
        "uploadstash-refresh": "Odśwież listę plików",
+       "uploadstash-thumbnail": "pokaż miniaturkę",
        "invalid-chunk-offset": "Nieprawidłowe przesunięcie fragmentu",
        "img-auth-accessdenied": "Odmowa dostępu",
        "img-auth-nopathinfo": "Brak PATH_INFO.\nSerwer nie został skonfigurowany, tak aby przekazywał tę informację.\nMożliwe, że jest oparty na CGI i nie może obsługiwać img_auth.\nWięcej o informacji o autoryzacji grafik na https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "autoredircomment": "Przekierowanie do [[$1]]",
        "autosumm-new": "Utworzono nową stronę \"$1\"",
        "autosumm-newblank": "Utworzono pustą stronę",
-       "size-bytes": "$1&nbsp;B",
+       "size-bytes": "$1 {{PLURAL:$1|bajt|bajty|bajtów}}",
        "size-kilobytes": "$1&nbsp;KB",
        "size-megabytes": "$1&nbsp;MB",
        "size-gigabytes": "$1&nbsp;GB",
        "version-libraries-authors": "Autorzy",
        "redirect": "Przekierowanie z identyfikatora pliku, użytkownika, strony, wersji lub wpisu rejestru",
        "redirect-legend": "Przekieruj do pliku lub strony",
-       "redirect-summary": "Ta strona specjalna przekierowuje do: pliku (o podanej nazwie), do strony (o podanym numerze wersji lub identyfikatorze strony) albo do strony użytkownika (o podanym identyfikatorze numerycznym). Sposób użycia: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/revision/328429]] albo [[{{#Special:Redirect}}/user/101]].",
+       "redirect-summary": "Ta strona specjalna przekierowuje do: pliku (o podanej nazwie), do strony (o podanym numerze wersji lub identyfikatorze strony), do strony użytkownika (o podanym identyfikatorze numerycznym) albo do rejestru (o podanym numerze akcji). Sposób użycia: [[{{#Special:Redirect}}/file/Example.jpg]], [[{{#Special:Redirect}}/revision/328429]], [[{{#Special:Redirect}}/user/101]] albo [[{{#Special:Redirect}}/logid/186]].",
        "redirect-submit": "Przejdź",
        "redirect-lookup": "Wyszukaj:",
        "redirect-value": "Wartość:",
        "mw-widgets-titleinput-description-new-page": "strona jeszcze nie istnieje",
        "mw-widgets-titleinput-description-redirect": "przekierowanie do $1",
        "api-error-blacklisted": "Wybierz inny, opisowy tytuł.",
-       "randomrootpage": "Losowa strona (bez podstron)"
+       "randomrootpage": "Losowa strona (bez podstron)",
+       "log-action-filter-block": "Rodzaj blokady:",
+       "log-action-filter-delete": "Rodzaj usunięcia:",
+       "log-action-filter-protect": "Rodzaj zabezpieczenia:",
+       "log-action-filter-upload": "Rodzaj przesłanych:",
+       "log-action-filter-all": "Wszystkie",
+       "log-action-filter-block-block": "Zablokowanie",
+       "log-action-filter-block-reblock": "Zmiana blokady",
+       "log-action-filter-block-unblock": "Odblokowanie",
+       "log-action-filter-delete-delete": "Usunięcie strony",
+       "log-action-filter-delete-restore": "Odtworzenie strony",
+       "log-action-filter-delete-event": "Usunięcie wpisu rejestru",
+       "log-action-filter-delete-revision": "Usunięcie wersji",
+       "log-action-filter-protect-protect": "Zabezpieczenie",
+       "log-action-filter-protect-modify": "Zmiana zabezpieczenia",
+       "log-action-filter-protect-unprotect": "Odbezpieczenie",
+       "log-action-filter-upload-upload": "Nowe przesłane",
+       "log-action-filter-upload-overwrite": "Przesłane ponownie"
 }
index 8257539..80a23d8 100644 (file)
        "mw-widgets-dateinput-placeholder-month": "کککک-م م",
        "mw-widgets-titleinput-description-new-page": "تر اوسه پورې دا مخ نشته",
        "mw-widgets-titleinput-description-redirect": "$1 ته ورگرځېدنه",
-       "randomrootpage": "د ناټاکلې ريښې مخ"
+       "randomrootpage": "د ناټاکلې ريښې مخ",
+       "log-action-filter-all": "ټول",
+       "log-action-filter-block-block": "بنديز لگول"
 }
index 20b2d5e..a500393 100644 (file)
@@ -94,7 +94,8 @@
                        "HenriqueCrang",
                        "Caçador de Palavras",
                        "Luk3",
-                       "Ryuu"
+                       "Ryuu",
+                       "Luan"
                ]
        },
        "tog-underline": "Sublinhar links:",
        "content-json-empty-object": "Objeto vazio",
        "content-json-empty-array": "Array vazia",
        "duplicate-args-warning": "<strong> Aviso: </strong> [[:$1]] está chamando [[:$2]] com mais de um valor para o parâmetro \"$3\". Será utilizado apenas o último valor fornecido.",
-       "duplicate-args-category": "Páginas que utilizam argumentos duplicados ao chamar predefinições",
+       "duplicate-args-category": "Páginas com argumentos de predefinições duplicados",
        "duplicate-args-category-desc": "A pagina contem modelos que usam argumentos duplicados, como <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> ou <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "expensive-parserfunction-warning": "Aviso: Esta página contém muitas chamadas a funções do analisador \"parser\".\n\nDeveria ter menos de $2 {{PLURAL:$2|chamada|chamadas}}. Neste momento {{PLURAL:$1|há $1 chamada|existem $1 chamadas}}.",
        "expensive-parserfunction-category": "Páginas com muitas chamadas a funções do analisador \"parser\"",
        "post-expand-template-inclusion-warning": "'''Aviso''': a soma do tamanho de inclusão de predefinições é muito grande.\nAlgumas predefinições não serão processadas.",
-       "post-expand-template-inclusion-category": "Páginas onde a soma do tamanho de inclusão de predefinições é excedido",
+       "post-expand-template-inclusion-category": "Páginas com excesso de predefinições",
        "post-expand-template-argument-warning": "Aviso: Esta página contém pelo menos um argumento de predefinição com um tamanho muito grande.\nEstes argumentos foram omitidos.",
-       "post-expand-template-argument-category": "Páginas com omissões de argumentos em predefinições",
+       "post-expand-template-argument-category": "Páginas com argumentos de predefinições descartados",
        "parser-template-loop-warning": "Ciclo de predefinições detectado: [[$1]]",
        "parser-template-recursion-depth-warning": "O limite de profundidade de recursividade de predefinição foi ultrapassado ($1)",
        "language-converter-depth-warning": "O limite de profundidade do conversor de línguas excedeu a ($1)",
        "uploadstash-badtoken": "Não foi possível executar essa operação, talvez porque as suas credenciais de edição expiraram. Tente novamente.",
        "uploadstash-errclear": "Não foi possível apagar os arquivos.",
        "uploadstash-refresh": "Atualizar a lista de arquivos",
+       "uploadstash-thumbnail": "ver miniatura",
        "invalid-chunk-offset": "Deslocamento de fragmento inválido",
        "img-auth-accessdenied": "Acesso negado",
        "img-auth-nopathinfo": "PATH_INFO em falta.\nO seu servidor não está configurado para passar esta informação.\nPode ser baseado em CGI e não consegue suportar img_auth.\nConsulte a documentação em [//www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization Image Authorization].",
index 7a17015..6f189b5 100644 (file)
@@ -68,7 +68,8 @@
                        "Jkb8",
                        "Önni",
                        "Diniscoelho",
-                       "Josep Maria Roca Peña"
+                       "Josep Maria Roca Peña",
+                       "Luan"
                ]
        },
        "tog-underline": "Sublinhar ligações:",
        "content-json-empty-object": "Objeto vazio",
        "content-json-empty-array": "Matriz vazia",
        "duplicate-args-warning": "<strong>Aviso:</strong> [[:$1]] chama [[:$2]] com mais de um valor para o parâmetro \"$3\". Somente o último valor fornecido será utilizado.",
-       "duplicate-args-category": "Páginas que utilizam argumentos duplicados ao chamar predefinições",
+       "duplicate-args-category": "Páginas com argumentos de predefinições duplicados",
        "duplicate-args-category-desc": "A página contém campos de predefinições que utilizam duplicatas de argumentos, tais como <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> ou <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "expensive-parserfunction-warning": "'''Aviso:''' Esta página contém demasiadas chamadas de funções exigentes do analisador sintático.\n\nDevia ter menos de $2 {{PLURAL:$2|chamada|chamadas}}. Neste momento tem $1 {{PLURAL:$1|chamada|chamadas}}.",
        "expensive-parserfunction-category": "Páginas com demasiadas chamadas a funções exigentes",
        "post-expand-template-inclusion-warning": "Aviso: O tamanho de inclusão de predefinições é demasiado grande, algumas predefinições não serão incluídas.",
        "post-expand-template-inclusion-category": "Páginas onde o tamanho de inclusão de predefinições é excedido",
        "post-expand-template-argument-warning": "Aviso: Esta página contém pelo menos um argumento de predefinição com um tamanho expandido demasiado grande.\nEstes argumentos foram omitidos.",
-       "post-expand-template-argument-category": "Páginas com omissão de argumentos para predefinições",
+       "post-expand-template-argument-category": "Páginas com argumentos de predefinições descartados",
        "parser-template-loop-warning": "Ciclo de predefinições detetado: [[$1]]",
        "parser-template-recursion-depth-warning": "Foi excedido o limite da profundidade de recursividade nas predefinições ($1)",
        "language-converter-depth-warning": "O limite de profundidade do conversor de idiomas excedeu a ($1)",
        "uploadstash-badtoken": "Não foi possível executar a operação. Talvez as suas credenciais de edição tenham expirado. Tente novamente.",
        "uploadstash-errclear": "Não foi possível apagar os ficheiros.",
        "uploadstash-refresh": "Atualizar a lista de ficheiros",
+       "uploadstash-thumbnail": "ver miniatura",
        "invalid-chunk-offset": "Deslocamento de fragmento inválido",
        "img-auth-accessdenied": "Acesso negado",
        "img-auth-nopathinfo": "PATH_INFO em falta.\nO seu servidor não está configurado para passar esta informação.\nPode ser baseado em CGI e não consegue suportar img_auth.\nConsulte a documentação em https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "sessionprovider-generic": "Sessões $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sessões baseadas em cookie",
        "sessionprovider-nocookies": "Os cookies podem estar desativados. Certifique-se de que os cookies estão ativados e inicie novamente.",
-       "randomrootpage": "Página raiz aleatória"
+       "randomrootpage": "Página raiz aleatória",
+       "log-action-filter-block": "Tipo de bloqueio:",
+       "log-action-filter-delete": "Tipo de eliminação:",
+       "log-action-filter-patrol": "Tipo de patrulha:",
+       "log-action-filter-protect": "Tipo de proteção:",
+       "log-action-filter-upload": "Tipo de carregamento:",
+       "log-action-filter-all": "Todas",
+       "log-action-filter-block-block": "Bloquear",
+       "log-action-filter-block-reblock": "Alteração de bloqueio",
+       "log-action-filter-block-unblock": "Desbloquear",
+       "log-action-filter-delete-delete": "Eliminação de página",
+       "log-action-filter-delete-restore": "Restauro de página",
+       "log-action-filter-delete-event": "Eliminação de registo",
+       "log-action-filter-delete-revision": "Eliminação de revisão",
+       "log-action-filter-patrol-patrol": "Patrulha manual",
+       "log-action-filter-patrol-autopatrol": "Patrulha automática",
+       "log-action-filter-protect-protect": "Proteção",
+       "log-action-filter-protect-modify": "Alteração da proteção",
+       "log-action-filter-protect-unprotect": "Desproteção",
+       "log-action-filter-upload-upload": "Novo carregamento",
+       "log-action-filter-upload-overwrite": "Recarregar"
 }
index 0c588fa..379fe79 100644 (file)
        "grant-group-page-interaction": "{{Related|grant-group}}",
        "grant-group-file-interaction": "{{Related|grant-group}}",
        "grant-group-watchlist-interaction": "{{Related|grant-group}}",
-       "grant-group-email": "{{Related|grant-group}}\n{{Identical|E-mail}}",
-       "grant-group-high-volume": "{{Related|grant-group}}",
-       "grant-group-customization": "{{Related|grant-group}}",
-       "grant-group-administration": "{{Related|grant-group}}",
-       "grant-group-other": "{{Related|grant-group}}",
+       "grant-group-email": "{{Related|Grant-group}}\n{{Identical|E-mail}}",
+       "grant-group-high-volume": "{{Related|Grant-group}}",
+       "grant-group-customization": "{{Related|Grant-group}}",
+       "grant-group-administration": "{{Related|Grant-group}}",
+       "grant-group-other": "{{Related|Grant-group}}",
        "grant-blockusers": "Name for grant \"blockusers\".\n{{Related|grant}}",
        "grant-createaccount": "Name for grant \"createaccount\".\n{{Related|grant}}",
        "grant-createeditmovepage": "Name for grant \"createeditmovepage\".\n{{Related|grant}}",
        "special-characters-group-ipa": "IPA means a script: \"international phonetic alphabet\" here, and not \"international phonetic association\", the organization behind it.",
        "special-characters-group-symbols": "The section name for symbols\n\n{{Identical|Symbol}}",
        "special-characters-group-greek": "This is the name of a script, or alphabet, not a language.",
+       "special-characters-group-greekextended": "The name of the Greek Extended character set.",
        "special-characters-group-cyrillic": "This is the name of a script, or a group of alphabets, used mainly in Eastern Europe and North and Central Asia.\n{{related|Special-characters-group}}",
        "special-characters-group-arabic": "This is the name of a script, or alphabet, not a language.\n{{related|Special-characters-group}}",
        "special-characters-group-arabicextended": "This is a description of the additional group of Arabic script characters for languages such as a Persian, Urdu, Pashto and others. This message is supposed to be similar to {{msg-mw|special-characters-group-latinextended}}.\n{{related|Special-characters-group}}",
        "sessionprovider-generic": "Used to create a generic session type description when one isn't provided via the proper message. Should be phrased to make sense when added to a message such as {{msg-mw|cannotloginnow-text}}.\n\nParameters:\n* $1 - PHP classname.",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "Description of the sessions provided by the CookieSessionProvider class, which use HTTP cookies. Should be phrased to make sense when added to a message such as {{msg-mw|cannotloginnow-text}}.",
        "sessionprovider-nocookies": "Used to inform the user that sessions may be missing due to lack of cookies.",
-       "randomrootpage": "{{doc-special|RandomRootPage}}"
+       "randomrootpage": "{{doc-special|RandomRootPage}}",
+       "log-action-filter-block": "Which type of action to filter for in this log",
+       "log-action-filter-delete": "Which type of action to filter for in this log",
+       "log-action-filter-patrol": "Which type of action to filter for in this log",
+       "log-action-filter-protect": "Which type of action to filter for in this log",
+       "log-action-filter-upload": "Which type of action to filter for in this log",
+       "log-action-filter-all": "All types of action are allowed\n{{Identical|All}}",
+       "log-action-filter-block-block": "Action to filter for in this log\n{{Identical|Block}}",
+       "log-action-filter-block-reblock": "Action to filter for in this log",
+       "log-action-filter-block-unblock": "Action to filter for in this log\n{{Identical|Unblock}}",
+       "log-action-filter-delete-delete": "Action to filter for in this log",
+       "log-action-filter-delete-restore": "Action to filter for in this log",
+       "log-action-filter-delete-event": "Action to filter for in this log",
+       "log-action-filter-delete-revision": "Action to filter for in this log",
+       "log-action-filter-patrol-patrol": "Action to filter for in this log",
+       "log-action-filter-patrol-autopatrol": "Action to filter for in this log",
+       "log-action-filter-protect-protect": "Action to filter for in this log",
+       "log-action-filter-protect-modify": "Action to filter for in this log",
+       "log-action-filter-protect-unprotect": "Action to filter for in this log",
+       "log-action-filter-upload-upload": "Action to filter for in this log",
+       "log-action-filter-upload-overwrite": "Action to filter for in this log"
 }
index c1137ba..414123e 100644 (file)
@@ -28,7 +28,8 @@
                        "Macofe",
                        "ImGelu",
                        "Wintereu",
-                       "Rsocol"
+                       "Rsocol",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "Sublinierea legăturilor:",
        "recentchangeslinked-page": "Numele paginii:",
        "recentchangeslinked-to": "Arată în schimb modificările asupra paginilor care se leagă de pagina indicată",
        "recentchanges-page-added-to-category": "[[:$1]] a fost adăugată în categorii",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] și încă {{PLURAL:$2|o pagină|$2 pagini|$2 de pagini}} au fost adăugate în categorii",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] și încă [[Special:WhatLinksHere/$1|{{PLURAL:$2|o pagină|$2 pagini|$2 de pagini}}]] au fost adăugate în categorii",
        "recentchanges-page-removed-from-category": "[[:$1]] eliminată din categorii",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] și încă {{PLURAL:$2|o pagină|$2 pagini|$2 de pagini}} au fost eliminate din categorii",
        "autochange-username": "Modificare automată a MediaWiki",
index 17a1314..aa6dd44 100644 (file)
        "uploadstash-badtoken": "Не удалось выполнить указанные действия. Возможно, истёк срок действия ваших учётных данных. Пожалуйста, пробуйте ещё раз.",
        "uploadstash-errclear": "Очистка файлов не удалась.",
        "uploadstash-refresh": "Обновить список файлов",
+       "uploadstash-thumbnail": "показать миниатюру",
        "invalid-chunk-offset": "Недопустимое смещение фрагмента",
        "img-auth-accessdenied": "Доступ запрещён",
        "img-auth-nopathinfo": "Отсутствует <code>PATH_INFO</code>.\nВаш сервер не настроен для передачи этих сведений.\nВозможно, он работает на основе CGI и не поддерживает <code>img_auth</code>.\nСм. https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "sessionprovider-generic": "$1 сессий",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "сессий на основе куки",
        "sessionprovider-nocookies": "Могут быть отключены куки. Убедитесь, что у вас включены куки и начните заново.",
-       "randomrootpage": "Случайная корневая страница"
+       "randomrootpage": "Случайная корневая страница",
+       "log-action-filter-block": "Тип блокировки:",
+       "log-action-filter-delete": "Тип удаления:",
+       "log-action-filter-patrol": "Тип патрулирования:",
+       "log-action-filter-protect": "Тип защиты:",
+       "log-action-filter-upload": "Тип загрузки:",
+       "log-action-filter-all": "Все",
+       "log-action-filter-block-block": "Блокировка",
+       "log-action-filter-block-reblock": "Изменение блокировки",
+       "log-action-filter-block-unblock": "Разблокировка",
+       "log-action-filter-delete-delete": "Удаления страницы",
+       "log-action-filter-delete-restore": "Восстановление страницы",
+       "log-action-filter-delete-event": "Удаление журнала",
+       "log-action-filter-delete-revision": "Удаление версии",
+       "log-action-filter-patrol-patrol": "Ручное патрулирование",
+       "log-action-filter-patrol-autopatrol": "Автоматическое патрулирование",
+       "log-action-filter-protect-protect": "Защита",
+       "log-action-filter-protect-modify": "Изменение защиты",
+       "log-action-filter-protect-unprotect": "Снятие защиты",
+       "log-action-filter-upload-upload": "Новая загрузка",
+       "log-action-filter-upload-overwrite": "Повторно загрузить"
 }
index 1c1d534..9eae5d1 100644 (file)
        "listfiles-delete": "अपाक्रियताम्",
        "listfiles-summary": "एतद्विशेषपुटम् उत्तारितसञ्चिकाः प्रदर्शयति । \nयोजकेन शुद्धाः अतिनूतनं सञ्चिकाः केवलम् अत्र प्रदर्शयति ।",
        "listfiles_search_for": "माध्यमनामधेयार्थम् अन्विषतु ।",
-       "listfiles-userdoesnotexist": "\"$1\" à¤\87तà¥\8dयषा à¤¸à¤¦à¤¸à¥\8dयलà¥\87à¤\96ा à¤ªà¤\9eà¥\8dà¤\9cà¥\80à¤\95à¥\83तà¤\82 नास्ति ।",
+       "listfiles-userdoesnotexist": "\"$1\" à¤\87तà¥\8dयषा à¤¸à¤¦à¤¸à¥\8dयलà¥\87à¤\96ा à¤ªà¤\9eà¥\8dà¤\9cà¥\80à¤\95à¥\83ता नास्ति ।",
        "imgfile": "संचिका",
        "listfiles": "सञ्चिकावली ।",
        "listfiles_thumb": "अंगुष्ठनखाकारम् ।",
        "mycontris": "योगदानानि",
        "anoncontribs": "अंशदाता",
        "contribsub2": "($2) कृते {{GENDER:$3|$1}}",
-       "contributions-userdoesnotexist": "\"$1\" à¤\87तà¥\8dयषा à¤¸à¤¦à¤¸à¥\8dयलà¥\87à¤\96ा à¤ªà¤\9eà¥\8dà¤\9cà¥\80à¤\95à¥\83तà¤\82 नास्ति ।",
+       "contributions-userdoesnotexist": "\"$1\" à¤\87तà¥\8dयषा à¤¸à¤¦à¤¸à¥\8dयलà¥\87à¤\96ा à¤ªà¤\9eà¥\8dà¤\9cà¥\80à¤\95à¥\83ता नास्ति ।",
        "nocontribs": "एतादृशयोग्यताभिः समं परिवर्तनानि न दृष्टानि ।",
        "uctop": "वर्तमानः",
        "month": "अस्मात् मासात् (प्राक्तनानि च):",
index ffbdea6..98c4eb5 100644 (file)
        "recentchangeslinked-page": "Сирэй аата:",
        "recentchangeslinked-to": "Төттөрүтүн, ыйыллыбыт сирэйгэ сигэнэр сирэйдэри көрдөр",
        "recentchanges-page-added-to-category": "[[:$1]] категорияҕа эбилиннэ",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] уонна {{PLURAL:$2|биир сирэй|$2 сирэй}} категорияҕа эбилиннэ",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] уонна [[Special:WhatLinksHere/$1|{{PLURAL:$2|биир сирэй|$2 сирэй}}]] категорияҕа эбилиннэ",
        "recentchanges-page-removed-from-category": "[[:$1]] категорияттан сотулунна",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] уонна {{PLURAL:$2|биир сирэй|$2 сирэй}} категорияттан сотулунна",
        "autochange-username": "MediaWiki аптамаатынан уларыйыыта",
index 754df97..17ef183 100644 (file)
        "recentchangeslinked-page": "Naslov stranice:",
        "recentchangeslinked-to": "Pokaži promjene stranica koji su povezane sa datom stranicom",
        "recentchanges-page-added-to-category": "[[:$1]] pridodano kategoriji",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] i {{PLURAL:$2|stranica|$2 stranica}} {{PLURAL:$2|pridodana|pridodane}} kategoriji",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] i [[Special:WhatLinksHere/$1|{{PLURAL:$2|stranica|$2 stranica}} {{PLURAL:$2|pridodana|pridodane}}]] kategoriji",
        "recentchanges-page-removed-from-category": "[[:$1]] uklonjeno iz kategorije",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] i {{PLURAL:$2|stranica|$2 stranica}} {{PLURAL:$2|uklonjena|uklonjenne}} iz kategorije",
        "autochange-username": "MediaWiki automatska promjena",
index 9b85e15..0d812a0 100644 (file)
        "newarticle": "(Nový)",
        "newarticletext": "Sledovali ste odkaz na stránku, ktorá zatiaľ neexistuje.\nStránku vytvoríte tak, že začnete písať do poľa nižšie (viac informácií nájdete na stránkach [$1 nápovedy]).\nAk ste sa sem dostali nechtiac, kliknite na tlačidlo <strong>späť</strong> vo svojom prehliadači.",
        "anontalkpagetext": "----''Toto je diskusná stránka anonymného používateľa, ktorý nemá vytvorené svoje konto alebo ho nepoužíva.\nPreto musíme na jeho identifikáciu použiť numerickú IP adresu. Je možné, že takúto IP adresu používajú viacerí používatelia.\nAk ste anonymný používateľ a máte pocit, že vám boli adresované irelevantné diskusné príspevky, [[Special:UserLogin/signup|vytvorte si konto]] alebo sa [[Special:UserLogin|prihláste]], aby sa zamedzilo budúcim zámenám s inými anonymnými používateľmi.''",
-       "noarticletext": "Na tejto stránke sa momentálne nenachádza žiadny text.\nMôžete [[Special:Search/{{PAGENAME}}|vyhľadávať názov tejto stránky]] v obsahu iných stránok,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} vyhľadávať v súvisiacich záznamoch] alebo [{{fullurl:{{FULLPAGENAME}}|action=edit}} upravovať túto stránku]</span>.",
+       "noarticletext": "Na tejto stránke sa momentálne nenachádza žiadny text.\nMôžete [[Special:Search/{{PAGENAME}}|vyhľadávať názov tejto stránky]] v obsahu iných stránok,\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} vyhľadávať v súvisiacich záznamoch] alebo [{{fullurl:{{FULLPAGENAME}}|action=edit}} vytvoriť túto stránku]</span>.",
        "noarticletext-nopermission": "Táto stránka momentálne neobsahuje žiadny text.\nMôžete [[Special:Search/{{PAGENAME}}|hľadať názov tejto stránky]] v texte iných stránok\nalebo <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} hľadať v súvisiacich záznamoch]</span>, ale nemáte oprávnenie túto stránku vytvoriť.",
        "missing-revision": "Revízia #$1 stránky s názvom „{{FULLPAGENAME}}“ neexistuje.\n\nPravdepodobne ste nasledovali zastaraný odkaz na historickú verziu stránky, ktorá bola medzičasom odstránená.\nPodrobnosti nájdete v [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} zázname zmazaní].",
        "userpage-userdoesnotexist": "Používateľský účet „<nowiki>$1</nowiki>“ nie je registrovaný. Prosím, skontrolujte, či naozaj chcete vytvoriť/upravovať túto stránku.",
        "recentchangeslinked-page": "Názov stránky:",
        "recentchangeslinked-to": "Zobraziť zmeny na stránkach, ''ktoré odkazujú na'' zadanú stránku",
        "recentchanges-page-added-to-category": "[[:$1]] zaradená do kategórie",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] a {{PLURAL:$2|jedna ďalšia zaradené|$2 ďalšie zaradené|$2 ďalších zaradených}} do kategórie",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] a [[Special:WhatLinksHere/$1|{{PLURAL:$2|jedna ďalšia zaradené|$2 ďalšie zaradené|$2 ďalších zaradených}}]] do kategórie",
        "recentchanges-page-removed-from-category": "[[:$1]] vyradená z kategórie",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] a {{PLURAL:$2|jedna ďalšia vyradené|$2 ďalšie vyradené|$2 ďalších vyradených}} z kategórie",
        "autochange-username": "Automatická úprava MediaWiki",
        "log-edit-tags": "Editovať značky zvolených položiek záznamu",
        "checkbox-select": "Zvoliť: $1",
        "checkbox-all": "Všetky",
-       "checkbox-none": "Ždiadne",
+       "checkbox-none": "Žiadne",
        "checkbox-invert": "Invertovať",
        "allpages": "Všetky stránky",
        "nextpage": "Ďalšia stránka ($1)",
index 682ee36..63008eb 100644 (file)
        "uploadstash-badtoken": "Izvedba dejanja je spodletela. Morda zaradi izteklih poverilnic za urejanje. Prosimo, poskusite znova.",
        "uploadstash-errclear": "Čiščenje datotek je spodletelo.",
        "uploadstash-refresh": "Osveži seznam datotek",
+       "uploadstash-thumbnail": "ogled sličice",
        "invalid-chunk-offset": "Neveljaven odmik delčka",
        "img-auth-accessdenied": "Dostop zavrnjen",
        "img-auth-nopathinfo": "Manjka PATH_INFO.\nVaš strežnik ne poda te informacije.\nMorda temelji na CGI in ne more podpirati img_auth.\nOglejte si  https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization.",
        "sessionprovider-generic": "sej $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "sej, ki temeljijo na piškotkih",
        "sessionprovider-nocookies": "Piškotki so morda onemogočeni. Prepričaje se, da imate piškotke omogočene, in začnite znova.",
-       "randomrootpage": "Naključna korenska stran"
+       "randomrootpage": "Naključna korenska stran",
+       "log-action-filter-block": "Vrsta blokade:",
+       "log-action-filter-delete": "Vrsta izbrisa:",
+       "log-action-filter-patrol": "Vrsta nadzora:",
+       "log-action-filter-protect": "Vrsta zaščite:",
+       "log-action-filter-upload": "Vrsta nalaganja:",
+       "log-action-filter-all": "Vse",
+       "log-action-filter-block-block": "Blokada",
+       "log-action-filter-block-reblock": "Sprememba blokade",
+       "log-action-filter-block-unblock": "Odstranitev blokade",
+       "log-action-filter-delete-delete": "Izbris strani",
+       "log-action-filter-delete-restore": "Obnovitev strani",
+       "log-action-filter-delete-event": "Dnevnik brisanja",
+       "log-action-filter-delete-revision": "Izbris redakcije",
+       "log-action-filter-patrol-patrol": "Ročni nadzor",
+       "log-action-filter-patrol-autopatrol": "Samodejni nadzor",
+       "log-action-filter-protect-protect": "Zaščita",
+       "log-action-filter-protect-modify": "Sprememba zaščite",
+       "log-action-filter-protect-unprotect": "Odstranitev zaščite",
+       "log-action-filter-upload-upload": "Novo nalaganje",
+       "log-action-filter-upload-overwrite": "Ponovno nalaganje"
 }
index ccbdafb..dd4bb5d 100644 (file)
        "uploadstash-badtoken": "Misslyckades att utföra åtgärden. Dina redigeringsrättigheter har kanske löpt ut. Försök igen.",
        "uploadstash-errclear": "Rensning av filerna misslyckades.",
        "uploadstash-refresh": "Uppdatera listan över filer",
+       "uploadstash-thumbnail": "visa miniatyr",
        "invalid-chunk-offset": "Ogiltig segmentsförskjutning",
        "img-auth-accessdenied": "Åtkomst nekad",
        "img-auth-nopathinfo": "PATH_INFO saknas.\nDin server är inte inställd för att ge denna information.\nDen kan vara CGI-baserad och stöder inte img_auth.\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization Se bildbehörighet.]",
        "sessionprovider-generic": "$1-sessioner",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "cookiebaserade sessioner",
        "sessionprovider-nocookies": "Cookies kan vara inaktiverade. Se till att du har cookies aktiverat och försök igen.",
-       "randomrootpage": "Slumprotsida"
+       "randomrootpage": "Slumprotsida",
+       "log-action-filter-block": "Typ av blockering:",
+       "log-action-filter-delete": "Typ av radering:",
+       "log-action-filter-patrol": "Typ av patrullering:",
+       "log-action-filter-protect": "Typ av skydd:",
+       "log-action-filter-upload": "Typ av uppladdning:",
+       "log-action-filter-all": "Alla",
+       "log-action-filter-block-block": "Blockering",
+       "log-action-filter-block-reblock": "Blockeringsändring",
+       "log-action-filter-block-unblock": "Tog bort blockering",
+       "log-action-filter-delete-delete": "Radering av sida",
+       "log-action-filter-delete-restore": "Återställde sida",
+       "log-action-filter-delete-event": "Radering av logg",
+       "log-action-filter-delete-revision": "Radering av sidversion",
+       "log-action-filter-patrol-patrol": "Manuell patrullering",
+       "log-action-filter-patrol-autopatrol": "Automatisk patrullering",
+       "log-action-filter-protect-protect": "Skydd",
+       "log-action-filter-protect-modify": "Ändring av skydd",
+       "log-action-filter-protect-unprotect": "Tog bort skydd",
+       "log-action-filter-upload-upload": "Ny uppladdning",
+       "log-action-filter-upload-overwrite": "Återuppladdning"
 }
index 37ab024..a87091f 100644 (file)
@@ -46,7 +46,8 @@
                        "Dineshkumar Ponnusamy",
                        "Sharanrajindia",
                        "Maathavan",
-                       "தமிழ்க்குரிசில்"
+                       "தமிழ்க்குரிசில்",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "இணைப்புகளுக்கு அடிக்கோடிடு",
        "recentchangeslinked-page": "பக்கப் பெயர்:",
        "recentchangeslinked-to": "இதற்குப் பதிலாக இப்பக்கத்தினை இணைத்த பக்கங்களின் மாற்றங்களைக் காட்டவும்",
        "recentchanges-page-added-to-category": "[[:$1]] பகுப்பில் சேர்க்கப்பட்டது",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] மற்றும் {{PLURAL:$2|ஒரு பக்கம்|$2 பக்கங்கள்}} பகுப்பில் சேர்க்கப்பட்டது",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] மற்றும் [[Special:WhatLinksHere/$1|{{PLURAL:$2|ஒரு பக்கம்|$2 பக்கங்கள்}}]] பகுப்பில் சேர்க்கப்பட்டது",
        "recentchanges-page-removed-from-category": "[[:$1]] பகுப்பில் இருந்து நீக்கப்பட்டது",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] மற்றும் {{PLURAL:$2|ஒரு பக்கம்|$2 பக்கங்கள்}} பகுப்பிலிருந்து நீக்கப்பட்டது",
        "autochange-username": "மீடியாவிக்கி தானியக்க மாற்றம்",
index ef2c8a2..8f4ce43 100644 (file)
        "watchlist-submit": "చూపించు",
        "wlshowtime": "చూపించాల్సిన కాలం:",
        "wlshowhideminor": "చిన్న మార్పులు",
+       "wlshowhidebots": "బాట్లు",
        "wlshowhideliu": "నమోదైన వాడుకరులు",
        "wlshowhideanons": "అజ్ఞాత వాడుకరులు",
        "wlshowhidemine": "నా మార్పులు",
+       "wlshowhidecategorization": "పేజీ వర్గీకరణ",
        "watchlist-options": "వీక్షణ జాబితా ఎంపికలు",
        "watching": "గమనిస్తున్నారు...",
        "unwatching": "గమనించడం లేదు...",
index f214131..db06b86 100644 (file)
        "blocklist-tempblocks": "Geçici engellemeleri gizle",
        "blocklist-addressblocks": "Tek IP engellemelerini gizle",
        "blocklist-rangeblocks": "Dizi bloklarını gizle",
-       "blocklist-timestamp": "Tarih damgası",
+       "blocklist-timestamp": "Tarih",
        "blocklist-target": "Hedef",
        "blocklist-expiry": "Bitiş tarihi",
-       "blocklist-by": "Engeli koyan hizmetli",
+       "blocklist-by": "Engeli veren hizmetli",
        "blocklist-params": "Engel parametreleri",
        "blocklist-reason": "Gerekçe",
        "ipblocklist-submit": "Ara",
        "noautoblockblock": "otomatik engelleme devre dışı bırakıldı",
        "createaccountblock": "hesap açımı engellendi",
        "emailblock": "e-posta engellendi",
-       "blocklist-nousertalk": "kendi tartışma sayfasını değiştiremez",
+       "blocklist-nousertalk": "kendi mesaj sayfasını değiştiremez",
        "ipblocklist-empty": "Engelleme listesi boş.",
        "ipblocklist-no-results": "İstenen IP adresi ya da kullanıcı adı engellenmedi.",
        "blocklink": "engelle",
        "block-log-flags-nocreate": "hesap yaratımı engellendi",
        "block-log-flags-noautoblock": "Otomatik engelleme iptal edildi",
        "block-log-flags-noemail": "e-posta engellendi",
-       "block-log-flags-nousertalk": "kendi tartışma sayfasını değiştiremez",
+       "block-log-flags-nousertalk": "kendi mesaj sayfasını değiştiremez",
        "block-log-flags-angry-autoblock": "gelişmiş oto-engelleme devrede",
        "block-log-flags-hiddenname": "kullanıcı adı gizli",
        "range_block_disabled": "Hizmetliler için aralık engellemesi oluşturma yeteneği devre dışı.",
        "revdelete-unrestricted": "hizmetliler için kaldırılmış kısıtlamalar",
        "logentry-block-block": "$1 {{GENDER:$2|engelledi}} {{GENDER:$4|$3}} engelleme süresi: $5 $6",
        "logentry-block-unblock": "$1 kullanıcısının {{GENDER:$2|engeli kaldırıldı}} {{GENDER:$4|$3}}",
-       "logentry-block-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} engelleme süresi $5 $6",
+       "logentry-block-reblock": "$1, {{GENDER:$4|$3}} kullanıcısının engellenme süresini $5 $6 olarak {{GENDER:$2|değiştirdi}}",
        "logentry-suppress-block": "{{GENDER:$4|$3}} $1 tarafından {{GENDER:$2|engellendi}} Zamanaşımı: $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|changed}} block settings for {{GENDER:$4|$3}} engelleme süresi $5 $6",
        "logentry-import-upload": "$1 dosya yükleme ile {{GENDER:$2|içe aktardı}}: $3",
index 6fc58ba..de2a10d 100644 (file)
@@ -64,7 +64,8 @@
                        "Translatemyname",
                        "Dars",
                        "Mix Gerder",
-                       "E.belykh"
+                       "E.belykh",
+                       "Visem"
                ]
        },
        "tog-underline": "Підкреслювання посилань:",
        "uploadstash-badtoken": "Не вдалося виконати вказану дію. Можливо, вичерпаний термін дії сесії редагування. Будь ласка, спробуйте ще раз.",
        "uploadstash-errclear": "Очищення файлів зазнало невдачі.",
        "uploadstash-refresh": "Оновити список файлів",
+       "uploadstash-thumbnail": "перегляд мініатюри",
        "invalid-chunk-offset": "Неприпустимий зсув фрагмента",
        "img-auth-accessdenied": "Відмовлено в доступі",
        "img-auth-nopathinfo": "Відсутній PATH_INFO.\nВаш сервер не налаштовано для передачі цих даних.\nМожливо, він працює на основі CGI та не підтримує img_auth.\nПерегляньте [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization Відкриття доступу до зображень]",
        "sessionprovider-generic": "сесій $1",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "сесій на основі кук",
        "sessionprovider-nocookies": "Куки можуть бути відключені. Переконайтеся, що у Вас включені cookies і почніть знову.",
-       "randomrootpage": "Випадкова коренева сторінка"
+       "randomrootpage": "Випадкова коренева сторінка",
+       "log-action-filter-block": "Тип блокування:",
+       "log-action-filter-delete": "Тип вилучення:",
+       "log-action-filter-patrol": "Тип патрулювання:",
+       "log-action-filter-protect": "Тип захисту:",
+       "log-action-filter-upload": "Тип завантаження:",
+       "log-action-filter-all": "Усі",
+       "log-action-filter-block-block": "Блокування",
+       "log-action-filter-block-reblock": "Зміна блокування",
+       "log-action-filter-block-unblock": "Розблокування",
+       "log-action-filter-delete-delete": "Видалення сторінки",
+       "log-action-filter-delete-restore": "Відновлення сторінки",
+       "log-action-filter-delete-event": "Вилучення журналу",
+       "log-action-filter-delete-revision": "Вилучення версії",
+       "log-action-filter-patrol-patrol": "Ручне патрулювання",
+       "log-action-filter-patrol-autopatrol": "Автоматичне патрулювання",
+       "log-action-filter-protect-protect": "Захист",
+       "log-action-filter-protect-modify": "Зміна захисту",
+       "log-action-filter-protect-unprotect": "Зняття захисту",
+       "log-action-filter-upload-upload": "Нове завантаження",
+       "log-action-filter-upload-overwrite": "Повторне завантаження"
 }
index 3952b8e..dc92a01 100644 (file)
        "uploadstash-badtoken": "Tác vụ bị thất bại, có lẽ vì thông tin đăng nhập của bạn đã hết hạn. Hãy thử lại.",
        "uploadstash-errclear": "Việc dọn sạch các tập tin bị thất bại.",
        "uploadstash-refresh": "Làm mới danh sách tập tin",
+       "uploadstash-thumbnail": "xem hình thu nhỏ",
        "invalid-chunk-offset": "Khúc lệch (chunk offset) không hợp lệ",
        "img-auth-accessdenied": "Không cho phép truy cập",
        "img-auth-nopathinfo": "Thiếu PATH_INFO.\nMáy chủ của bạn không được thiết lập để truyền thông tin này.\nCó thể do nó dựa trên CGI và không hỗ trợ img_auth.\nXem [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization hướng dẫn điều khiển truy cập hình ảnh].",
index bc98445..19b3bec 100644 (file)
@@ -15,7 +15,8 @@
                        "아라",
                        "Silovan",
                        "David1010",
-                       "Macofe"
+                       "Macofe",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "რცხუეფიშ ათოღაზუა:",
        "recentchangeslinked-page": "ხასილაშ ჯოხო:",
        "recentchangeslinked-to": "მანგიერო ქაძირე ათე ხასილაშა მერცხილ ხასილეფშა მიშაღალირ თირაფეფ",
        "recentchanges-page-added-to-category": "[[:$1]] გეძინელჷ რე კატეგორიას",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] დო {{PLURAL:$2|ართ ხასჷლა|$2 ხასჷლა}} გეძინელ რე კატეგორიას",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] დო [[Special:WhatLinksHere/$1|{{PLURAL:$2|ართ ხასჷლა|$2 ხასჷლა}}]] გეძინელ რე კატეგორიას",
        "recentchanges-page-removed-from-category": "[[:$1]] ლასირი რე კატეგორიაშე",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] დო {{PLURAL:$2|ართ ხასჷლა|$2 ხასჷლა}} ლასირი რე კატეგორიაშე",
        "upload": "ფაილიშ ეხარგუა",
index d5f5776..8a69603 100644 (file)
@@ -16,7 +16,8 @@
                        "Amire80",
                        "පසිඳු කාවින්ද",
                        "Matma Rex",
-                       "Macofe"
+                       "Macofe",
+                       "Nemo bis"
                ]
        },
        "tog-underline": "שטרייכט אונטער לינקען",
        "recentchangeslinked-page": "בלאַט נאָמען:",
        "recentchangeslinked-to": "צייג ענדערונגען צו בלעטער פארבינדן צו דעם בלאט אנשטאט",
        "recentchanges-page-added-to-category": "[[:$1]] צוגעלייגט צו קאטעגאריע",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] און {{PLURAL:$2|איין בלאט|$2 בלעטער}} צוגעלייגט צו קאטעגאריע",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] און [[Special:WhatLinksHere/$1|{{PLURAL:$2]]|איין בלאט|$2 בלעטער}} צוגעלייגט צו קאטעגאריע",
        "recentchanges-page-removed-from-category": "[[:$1]] אראפגענומען פון קאטעגאריע",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] און {{PLURAL:$2|איין בלאט|$2 בלעטער}} אראפגענומען פון קאטעגאריע",
        "autochange-username": "מעדיעוויקי אויטאמאטישער טויש",
        "special-characters-group-khmer": "כמער",
        "special-characters-title-endash": "ען טירע",
        "special-characters-title-emdash": "עם טירע",
-       "special-characters-title-minus": "מינוס"
+       "special-characters-title-minus": "מינוס",
+       "log-action-filter-upload": "טיפ ארויפֿלאד:",
+       "log-action-filter-all": "אַלע",
+       "log-action-filter-delete-delete": "אויסמעקן בלאט",
+       "log-action-filter-protect-unprotect": "אראפנעמען שיץ"
 }
index 6d63e20..8f01a17 100644 (file)
        "recentchangeslinked-page": "頁名:",
        "recentchangeslinked-to": "顯示連到所畀到嘅版",
        "recentchanges-page-added-to-category": "[[:$1]] 加咗落分類",
-       "recentchanges-page-added-to-category-bundled": "[[:$1]] 同另外 {{PLURAL:$2|1 版|$2 版}}加咗落分類",
+       "recentchanges-page-added-to-category-bundled": "[[:$1]] 同另外 [[Special:WhatLinksHere/$1|{{PLURAL:$2|1 版|$2 版}}]]加咗落分類",
        "recentchanges-page-removed-from-category": "[[:$1]] 拎走咗分類",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] 同另外 {{PLURAL:$2|1 版|$2 版}}拎走咗分類",
        "autochange-username": "MediaWiki 自動改動",
index ea51fc9..7aa6dc8 100644 (file)
        "uploadstash-badtoken": "执行对应操作失败。可能是因为您的编辑凭证已过期。请重试。",
        "uploadstash-errclear": "清除文件失败。",
        "uploadstash-refresh": "更新文件列表",
+       "uploadstash-thumbnail": "显示缩略图",
        "invalid-chunk-offset": "无效区块偏移量",
        "img-auth-accessdenied": "拒绝访问",
        "img-auth-nopathinfo": "PATH_INFO缺失。\n您的服务器尚未设置传送该信息。\n它可能基于CGI,因而不支持img_auth。\n请参见https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization。",
        "sessionprovider-generic": "$1会话",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "基于cookie的会话",
        "sessionprovider-nocookies": "Cookie可能已被禁用。确保您已启用cookie,并重试。",
-       "randomrootpage": "随机根页面"
+       "randomrootpage": "随机根页面",
+       "log-action-filter-block": "封禁类型:",
+       "log-action-filter-delete": "删除类型:",
+       "log-action-filter-patrol": "巡查类型:",
+       "log-action-filter-protect": "保护类型:",
+       "log-action-filter-upload": "上传类型:",
+       "log-action-filter-all": "全部",
+       "log-action-filter-block-block": "封禁",
+       "log-action-filter-block-reblock": "封禁修改",
+       "log-action-filter-block-unblock": "解封",
+       "log-action-filter-delete-delete": "页面删除",
+       "log-action-filter-delete-restore": "页面还原",
+       "log-action-filter-delete-event": "日志删除",
+       "log-action-filter-delete-revision": "修订版本删除",
+       "log-action-filter-patrol-patrol": "手动巡查",
+       "log-action-filter-patrol-autopatrol": "自动巡查",
+       "log-action-filter-protect-protect": "保护",
+       "log-action-filter-protect-modify": "保护修改",
+       "log-action-filter-protect-unprotect": "解除保护",
+       "log-action-filter-upload-upload": "新上传",
+       "log-action-filter-upload-overwrite": "重新上传"
 }
index 0916c97..79e71af 100644 (file)
        "feedlinks": "訂閱:",
        "feed-invalid": "無效的訂閱 Feed 類型。",
        "feed-unavailable": "目前未提供 RSS 或 Atom",
-       "site-rss-feed": "$1 的 RSS 摘要",
-       "site-atom-feed": "$1 的 Atom 摘要",
-       "page-rss-feed": "\"$1\" 的 RSS 摘要",
-       "page-atom-feed": "\"$1\" 的 Atom 摘要",
+       "site-rss-feed": "$1 的 RSS 來源",
+       "site-atom-feed": "$1 的 Atom 來源",
+       "page-rss-feed": "\"$1\" 的 RSS 來源",
+       "page-atom-feed": "\"$1\" 的 Atom 來源",
        "red-link-title": "$1 (頁面不存在)",
        "sort-descending": "降冪排序",
        "sort-ascending": "昇冪排序",
        "createaccount": "建立帳號",
        "gotaccount": "您已經擁有帳號了嗎? $1。",
        "gotaccountlink": "登入",
-       "userlogin-resetlink": "您忘記了登入的詳細資料?",
+       "userlogin-resetlink": "忘了您登入的詳細資料?",
        "userlogin-resetpassword-link": "忘記密碼?",
        "userlogin-helplink2": "登入協助",
        "userlogin-loggedin": "您目前已登入 {{GENDER:$1|$1}} 使用者,\n請使用下列表單改登入另一位使用者。",
        "nosuchsectiontext": "您嘗試編輯的章節並不存在。\n可能在您檢視頁面時已經移動或刪除。",
        "loginreqtitle": "需要登入",
        "loginreqlink": "登入",
-       "loginreqpagetext": "æ\82¨å¿\85é \88 $1 æ\96¹å\8f¯æª¢è¦\96å\85¶ä»\96é \81é\9d¢ã\80\82",
+       "loginreqpagetext": "è«\8bå\85\88 $1 æ\96¹å\8f¯æª¢è¦\96å\85¶ä»\96é \81é\9d¢ã\80\82",
        "accmailtitle": "密碼已寄出",
        "accmailtext": "[[User talk:$1|$1]] 的隨機密碼已經寄送至 $2,可登入後至 <em>[[Special:ChangePassword|變更密碼]] 頁面更改</em>。",
        "newarticle": "(新)",
        "recentchanges-label-bot": "該編輯由機器人執行",
        "recentchanges-label-unpatrolled": "該編輯尚未巡查",
        "recentchanges-label-plusminus": "該頁面變更的大小 (位元組)",
-       "recentchanges-legend-heading": "<strong>說明:</strong>",
+       "recentchanges-legend-heading": "<strong>圖例:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (請參考[[Special:NewPages|新頁面]])",
        "recentchanges-legend-plusminus": "(<em>±123</em>)",
        "recentchanges-submit": "顯示",
        "rcshowhidecategorization": "$1 頁面分類",
        "rcshowhidecategorization-show": "顯示",
        "rcshowhidecategorization-hide": "隱藏",
-       "rclinks": "顯示最近 $2 天內的 $1 次更改。<br />$3",
+       "rclinks": "顯示最近 $2 天內的 $1 次變更。<br />$3",
        "diff": "差異",
        "hist": "歷史",
        "hide": "隱藏",
        "uploadstash-badtoken": "執行動作失敗。您的編輯資訊可能已經過期,請重新再試。",
        "uploadstash-errclear": "清除檔案失敗。",
        "uploadstash-refresh": "更新檔案清單",
+       "uploadstash-thumbnail": "檢視縮圖",
        "invalid-chunk-offset": "無效區塊位置",
        "img-auth-accessdenied": "拒絕存取",
        "img-auth-nopathinfo": "缺少 PATH_INFO 參數。\n您安裝的伺服器未傳遞此資訊,\n您可能使用 CGI 為基礎的伺服器,且不支援 img_auth 功能。\n請參考 https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization。",
        "tooltip-n-help": "尋求協助的地方",
        "tooltip-t-whatlinkshere": "列出所有連結此頁面的頁面",
        "tooltip-t-recentchangeslinked": "此頁面連結至其他頁面的最近變更",
-       "tooltip-feed-rss": "此頁面的 RSS 摘要",
-       "tooltip-feed-atom": "此頁面的 Atom 摘要",
+       "tooltip-feed-rss": "此頁面的 RSS 來源",
+       "tooltip-feed-atom": "此頁面的 Atom 來源",
        "tooltip-t-contributions": "{{GENDER:$1|此使用者}}的貢獻清單",
        "tooltip-t-emailuser": "傳送電子郵件聯絡{{GENDER:$1|這位使用者}}",
        "tooltip-t-info": "更多關於此頁面的資訊",
        "sessionprovider-generic": "$1 連線階段",
        "sessionprovider-mediawiki-session-cookiesessionprovider": "以 cookie 為基礎的連線階段",
        "sessionprovider-nocookies": "Cookie 功能可能已被關閉,請確認您改開啟 Cookie 功能並重新啟動。",
-       "randomrootpage": "隨機根頁面"
+       "randomrootpage": "隨機根頁面",
+       "log-action-filter-block": "封鎖類型:",
+       "log-action-filter-delete": "刪除類型:",
+       "log-action-filter-patrol": "巡查類型:",
+       "log-action-filter-protect": "保護類型:",
+       "log-action-filter-upload": "上傳類型:",
+       "log-action-filter-all": "全部",
+       "log-action-filter-block-block": "封鎖",
+       "log-action-filter-block-reblock": "封鎖修改",
+       "log-action-filter-block-unblock": "解除封鎖",
+       "log-action-filter-delete-delete": "頁面刪除",
+       "log-action-filter-delete-restore": "頁面取消刪除",
+       "log-action-filter-delete-event": "日誌刪除",
+       "log-action-filter-delete-revision": "修訂刪除",
+       "log-action-filter-patrol-patrol": "手動巡查",
+       "log-action-filter-patrol-autopatrol": "自動巡查",
+       "log-action-filter-protect-protect": "保護",
+       "log-action-filter-protect-modify": "保護修改",
+       "log-action-filter-protect-unprotect": "解除保護",
+       "log-action-filter-upload-upload": "新上傳",
+       "log-action-filter-upload-overwrite": "重新上傳"
 }
index 6d5472e..914336f 100644 (file)
@@ -538,7 +538,6 @@ asctime
 asdf
 aspx
 assert
-astriks
 asymp
 async
 at
index eddfa26..46616db 100644 (file)
@@ -32,12 +32,12 @@ class Digit2Html extends Maintenance {
 
        # A list of unicode numerals is available at:
        # http://www.fileformat.info/info/unicode/category/Nd/list.htm
-       private $mLangs = array(
+       private $mLangs = [
                'Ar', 'As', 'Bh', 'Bo', 'Dz',
                'Fa', 'Gu', 'Hi', 'Km', 'Kn',
                'Ks', 'Lo', 'Ml', 'Mr', 'Ne',
                'New', 'Or', 'Pa', 'Pi', 'Sa'
-       );
+       ];
 
        public function __construct() {
                parent::__construct();
index 15a1cb9..abe08e4 100755 (executable)
@@ -248,7 +248,8 @@ def translate(text, conv_table):
 
 def manualWordsTable(path, conv_table, reconv_table):
     fp = open(path, 'r', encoding='U8')
-    reconv_table = {}
+    reconv_table = reconv_table.copy()
+    out_table = {}
     wordlist = [line.split('#')[0].strip() for line in fp]
     wordlist = list(set(wordlist))
     wordlist.sort(key=lambda w: (len(w), w), reverse=True)
@@ -257,9 +258,9 @@ def manualWordsTable(path, conv_table, reconv_table):
         new_word = translate(word, conv_table)
         rcv_word = translate(word, reconv_table)
         if word != rcv_word:
-            reconv_table[word] = word
-        reconv_table[new_word] = word
-    return reconv_table
+            reconv_table[word] = out_table[word] = word
+        reconv_table[new_word] = out_table[new_word] = word
+    return out_table
 
 
 def defaultWordsTable(src_wordlist, src_tomany, char_conv_table,
index 88767de..bdbb347 100644 (file)
@@ -68,9 +68,16 @@ class RefreshImageMetadata extends Maintenance {
                $this->addOption( 'start', 'Name of file to start with', false, true );
                $this->addOption( 'end', 'Name of file to end with', false, true );
 
+               $this->addOption(
+                       'mediatype',
+                       'Only refresh files with this media type, e.g. BITMAP, UNKNOWN etc.',
+                       false,
+                       true
+               );
                $this->addOption(
                        'mime',
-                       '(Inefficient!) Only refresh files with this MIME type. Can accept wild-card image/*',
+                       "Only refresh files with this MIME type. Can accept wild-card 'image/*'. "
+                               . "Potentially inefficient unless 'mediatype' is also specified",
                        false,
                        true
                );
@@ -197,6 +204,7 @@ class RefreshImageMetadata extends Maintenance {
 
                $end = $this->getOption( 'end', false );
                $mime = $this->getOption( 'mime', false );
+               $mediatype = $this->getOption( 'mediatype', false );
                $like = $this->getOption( 'metadata-contains', false );
 
                if ( $end !== false ) {
@@ -209,6 +217,9 @@ class RefreshImageMetadata extends Maintenance {
                                $conds['img_minor_mime'] = $minor;
                        }
                }
+               if ( $mediatype !== false ) {
+                       $conds['img_media_type'] = $mediatype;
+               }
                if ( $like ) {
                        $conds[] = 'img_metadata ' . $dbw->buildLike( $dbw->anyString(), $like, $dbw->anyString() );
                }
index 9ea6c7b..8bfb94d 100644 (file)
@@ -8,7 +8,7 @@
   "devDependencies": {
     "grunt": "0.4.5",
     "grunt-cli": "0.1.13",
-    "grunt-banana-checker": "0.4.0",
+    "grunt-banana-checker": "0.5.0",
     "grunt-contrib-copy": "1.0.0",
     "grunt-contrib-jshint": "1.0.0",
     "grunt-contrib-watch": "1.0.0",
index 07cd7b5..0f3d70b 100644 (file)
@@ -482,8 +482,8 @@ return [
                        'sk' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-sk.js',
                        'sl' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-sl.js',
                        'sq' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-sq.js',
-                       'sr-sr' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-sr-SR.js',
-                       'sr' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-sr.js',
+                       'sr-ec' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-sr.js',
+                       'sr-el' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-sr-SR.js',
                        'sv' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-sv.js',
                        'ta' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-ta.js',
                        'th' => 'resources/lib/jquery.ui/i18n/jquery.ui.datepicker-th.js',
@@ -797,8 +797,8 @@ return [
                        'sk' => 'resources/lib/moment/locale/sk.js',
                        'sl' => 'resources/lib/moment/locale/sl.js',
                        'sq' => 'resources/lib/moment/locale/sq.js',
-                       'sr' => 'resources/lib/moment/locale/sr.js',
                        'sr-ec' => 'resources/lib/moment/locale/sr-cyrl.js',
+                       'sr-el' => 'resources/lib/moment/locale/sr.js',
                        'sv' => 'resources/lib/moment/locale/sv.js',
                        'ta' => 'resources/lib/moment/locale/ta.js',
                        'th' => 'resources/lib/moment/locale/th.js',
@@ -811,6 +811,8 @@ return [
                        'vi' => 'resources/lib/moment/locale/vi.js',
                        'zh-cn' => 'resources/lib/moment/locale/zh-cn.js',
                        'zh-tw' => 'resources/lib/moment/locale/zh-tw.js',
+                       'zh-hans' => 'resources/lib/moment/locale/zh-cn.js',
+                       'zh-hant' => 'resources/lib/moment/locale/zh-tw.js',
                ],
                'targets' => [ 'desktop', 'mobile' ],
        ],
index d4446ab..0dffd7d 100644 (file)
@@ -90,6 +90,9 @@
        "greek": [
                "Α", "Ά", "α", "ά", "Β", "β", "Γ", "γ", "Δ", "δ", "Ε", "Έ", "ε", "έ", "Ζ", "ζ", "Η", "Ή", "η", "ή", "Θ", "θ", "Ι", "Ί", "ι", "ί", "Κ", "κ", "Λ", "λ", "Μ", "μ", "Ν", "ν", "Ξ", "ξ", "Ο", "Ό", "ο", "ό", "Π", "π", "Ρ", "ρ", "Σ", "σ", "ς", "Τ", "τ", "Υ", "Ύ", "υ", "ύ", "Φ", "φ", "Χ", "χ", "Ψ", "ψ", "Ω", "Ώ", "ω", "ώ"
        ],
+       "greekextended": [
+               "ἀ", "ἁ", "ἂ", "ἃ", "ἄ", "ἅ", "ἆ", "ἇ", "Ἀ", "Ἁ", "Ἂ", "Ἃ", "Ἄ", "Ἅ", "Ἆ", "Ἇ", "ἐ", "ἑ", "ἒ", "ἓ", "ἔ", "ἕ", "Ἐ", "Ἑ", "Ἒ", "Ἓ", "Ἔ", "Ἕ", "ἠ", "ἡ", "ἢ", "ἣ", "ἤ", "ἥ", "ἦ", "ἧ", "Ἠ", "Ἡ", "Ἢ", "Ἣ", "Ἤ", "Ἥ", "Ἦ", "Ἧ", "ἰ", "ἱ", "ἲ", "ἳ", "ἴ", "ἵ", "ἶ", "ἷ", "Ἰ", "Ἱ", "Ἲ", "Ἳ", "Ἴ", "Ἵ", "Ἶ", "Ἷ", "ὀ", "ὁ", "ὂ", "ὃ", "ὄ", "ὅ", "Ὀ", "Ὁ", "Ὂ", "Ὃ", "Ὄ", "Ὅ", "ὐ", "ὑ", "ὒ", "ὓ", "ὔ", "ὕ", "ὖ", "ὗ", "Ὑ", "Ὓ", "Ὕ", "Ὗ", "ὠ", "ὡ", "ὢ", "ὣ", "ὤ", "ὥ", "ὦ", "ὧ", "Ὠ", "Ὡ", "Ὢ", "Ὣ", "Ὤ", "Ὥ", "Ὦ", "Ὧ", "ὰ", "ά", "ὲ", "έ", "ὴ", "ή", "ὶ", "ί", "ὸ", "ό", "ὺ", "ύ", "ὼ", "ώ", "ᾀ", "ᾁ", "ᾂ", "ᾃ", "ᾄ", "ᾅ", "ᾆ", "ᾇ", "ᾈ", "ᾉ", "ᾊ", "ᾋ", "ᾌ", "ᾍ", "ᾎ", "ᾏ", "ᾐ", "ᾑ", "ᾒ", "ᾓ", "ᾔ", "ᾕ", "ᾖ", "ᾗ", "ᾘ", "ᾙ", "ᾚ", "ᾛ", "ᾜ", "ᾝ", "ᾞ", "ᾟ", "ᾠ", "ᾡ", "ᾢ", "ᾣ", "ᾤ", "ᾥ", "ᾦ", "ᾧ", "ᾨ", "ᾩ", "ᾪ", "ᾫ", "ᾬ", "ᾭ", "ᾮ", "ᾯ", "ᾰ", "ᾱ", "ᾲ", "ᾳ", "ᾴ", "ᾶ", "ᾷ", "Ᾰ", "Ᾱ", "Ὰ", "Ά", "ᾼ", "᾽", "ι", "᾿", "῀", "῁", "ῂ", "ῃ", "ῄ", "ῆ", "ῇ", "Ὲ", "Έ", "Ὴ", "Ή", "ῌ", "῍", "῎", "῏", "ῐ", "ῑ", "ῒ", "ΐ", "ῖ", "ῗ", "Ῐ", "Ῑ", "Ὶ", "Ί", "῝", "῞", "῟", "ῠ", "ῡ", "ῢ", "ΰ", "ῤ", "ῥ", "ῦ", "ῧ", "Ῠ", "Ῡ", "Ὺ", "Ύ", "Ῥ", "῭", "΅", "`", "ῲ", "ῳ", "ῴ", "ῶ", "ῷ", "Ὸ", "Ό", "Ὼ", "Ώ", "ῼ", "´", "῾"
+       ],
        "cyrillic": [
                "А", "а", "Ӑ", "ӑ", "Ӓ", "ӓ", "Ә", "ә", "Ӛ", "ӛ", "Б", "б", "В", "в", "Г", "г", "Ґ", "ґ", "Ӷ", "ӷ", "Ѓ", "ѓ", "Ӻ", "ӻ", "Ғ", "ғ", "Ҕ", "ҕ", "Д", "д", "Ԁ", "ԁ", "Ԃ", "ԃ", "Ђ", "ђ", "Е", "е", "Ѐ", "ѐ", "Є", "є", "Ё", "ё", "Ӗ", "ӗ", "Ҽ", "ҽ", "Ҿ", "ҿ", "Ж", "ж", "Җ", "җ", "Ӂ", "ӂ", "Ӝ", "ӝ", "З", "з", "Ҙ", "ҙ", "Ӟ", "ӟ", "Ԑ", "ԑ", "Ӡ", "ӡ", "Ѕ", "ѕ", "Ԅ", "ԅ", "Ԇ", "ԇ", "И", "и", "І", "і", "Ї", "ї",
                [
index a2d106d..3cfc52c 100644 (file)
                                                return xhr;
                                        }
                                } )
+                                       .then( null, function ( code, data, result, jqXHR ) {
+                                               if ( code !== 'http' ) {
+                                                       // Not really an error, work around mw.Api thinking it is.
+                                                       return $.Deferred()
+                                                               .resolve( result, jqXHR )
+                                                               .promise();
+                                               }
+                                               return this;
+                                       } )
                                        .fail( function ( code, data ) {
                                                var details = 'HTTP error: ' + data.exception;
                                                $result.empty()
index 5369d35..58115c3 100644 (file)
         * @private
         */
        PageExistenceCache.prototype.processExistenceCheckQueue = function () {
-               var queue, titles;
+               var queue, titles,
+                       cache = this;
                if ( this.currentRequest ) {
                        // Don't fire off a million requests at the same time
                        this.currentRequest.always( function () {
-                               this.currentRequest = null;
-                               this.processExistenceCheckQueueDebounced();
-                       }.bind( this ) );
+                               cache.currentRequest = null;
+                               cache.processExistenceCheckQueueDebounced();
+                       } );
                        return;
                }
                queue = this.existenceCheckQueue;
                this.existenceCheckQueue = {};
                titles = Object.keys( queue ).filter( function ( title ) {
-                       if ( this.existenceCache.hasOwnProperty( title ) ) {
-                               queue[ title ].resolve( this.existenceCache[ title ] );
+                       if ( cache.existenceCache.hasOwnProperty( title ) ) {
+                               queue[ title ].resolve( cache.existenceCache[ title ] );
                        }
-                       return !this.existenceCache.hasOwnProperty( title );
-               }.bind( this ) );
+                       return !cache.existenceCache.hasOwnProperty( title );
+               } );
                if ( !titles.length ) {
                        return;
                }
                } ).done( function ( response ) {
                        $.each( response.query.pages, function ( index, page ) {
                                var title = new ForeignTitle( page.title ).getPrefixedText();
-                               this.existenceCache[ title ] = !page.missing;
-                               queue[ title ].resolve( this.existenceCache[ title ] );
-                       }.bind( this ) );
-               }.bind( this ) );
+                               cache.existenceCache[ title ] = !page.missing;
+                               queue[ title ].resolve( cache.existenceCache[ title ] );
+                       } );
+               } );
        };
 
        /**
         * @cfg {string} [apiUrl] API URL, if not the current wiki's API
         */
        mw.widgets.CategoryCapsuleItemWidget = function MWWCategoryCapsuleItemWidget( config ) {
+               var widget = this;
                // Parent constructor
                mw.widgets.CategoryCapsuleItemWidget.parent.call( this, $.extend( {
                        data: config.title.getMainText(),
                this.constructor.static.pageExistenceCaches[ this.apiUrl ]
                        .checkPageExistence( new ForeignTitle( this.title.getPrefixedText() ) )
                        .done( function ( exists ) {
-                               this.setMissing( !exists );
-                       }.bind( this ) );
+                               widget.setMissing( !exists );
+                       } );
                /*jshint +W024*/
        };
 
index b805e65..3d97711 100644 (file)
@@ -6,6 +6,16 @@
  */
 ( function ( $, mw ) {
 
+       var interwikiPrefixesPromise = new mw.Api().get( {
+                       action: 'query',
+                       meta: 'siteinfo',
+                       siprop: 'interwikimap'
+               } ).then( function ( data ) {
+                       return $.map( data.query.interwikimap, function ( interwiki ) {
+                               return interwiki.prefix;
+                       } );
+               } );
+
        /**
         * Mixin for title widgets
         *
@@ -28,8 +38,6 @@
         * @cfg {Object} [cache] Result cache which implements a 'set' method, taking keyed values as an argument
         */
        mw.widgets.TitleWidget = function MwWidgetsTitleWidget( config ) {
-               var widget = this;
-
                // Config initialization
                config = $.extend( {
                        maxLength: 255,
 
                // Initialization
                this.$element.addClass( 'mw-widget-titleWidget' );
-               this.interwikiPrefixes = [];
-               this.interwikiPrefixesPromise = new mw.Api().get( {
-                       action: 'query',
-                       meta: 'siteinfo',
-                       siprop: 'interwikimap'
-               } ).done( function ( data ) {
-                       $.each( data.query.interwikimap, function ( index, interwiki ) {
-                               widget.interwikiPrefixes.push( interwiki.prefix );
-                       } );
-               } );
        };
 
        /* Setup */
                        } };
 
                if ( mw.Title.newFromText( query ) ) {
-                       return this.interwikiPrefixesPromise.then( function () {
+                       return interwikiPrefixesPromise.then( function ( interwikiPrefixes ) {
                                var params,
                                        interwiki = query.substring( 0, query.indexOf( ':' ) );
                                if (
                                        interwiki && interwiki !== '' &&
-                                       widget.interwikiPrefixes.indexOf( interwiki ) !== -1
+                                       interwikiPrefixes.indexOf( interwiki ) !== -1
                                ) {
                                        return $.Deferred().resolve( { query: {
                                                pages: [ {
index 10e0c56..64e5976 100644 (file)
                                .done( function ( result, textStatus, jqXHR ) {
                                        if ( result === undefined || result === null || result === '' ) {
                                                apiDeferred.reject( 'ok-but-empty',
-                                                       'OK response but empty result (check HTTP headers?)'
+                                                       'OK response but empty result (check HTTP headers?)',
+                                                       result,
+                                                       jqXHR
                                                );
                                        } else if ( result.error ) {
                                                var code = result.error.code === undefined ? 'unknown' : result.error.code;
-                                               apiDeferred.reject( code, result );
+                                               apiDeferred.reject( code, result, result, jqXHR );
                                        } else {
                                                apiDeferred.resolve( result, jqXHR );
                                        }
index d0e21ae..dfc98ad 100644 (file)
@@ -28,4 +28,4 @@
                // Bind because it throws TypeError if context is not window
                ? window.requestIdleCallback.bind( window )
                : mw.requestIdleCallbackInternal;
-}( mediaWiki, jQuery ) );
+}( mediaWiki ) );
index 76a6335..c8b4661 100644 (file)
@@ -105,6 +105,7 @@ $wgAutoloadClasses += [
 
        # tests/phpunit/includes/specials
        'SpecialPageTestBase' => "$testDir/phpunit/includes/specials/SpecialPageTestBase.php",
+       'SpecialPageExecutor' => "$testDir/phpunit/includes/specials/SpecialPageExecutor.php",
 
        # tests/phpunit/languages
        'LanguageClassesTestCase' => "$testDir/phpunit/languages/LanguageClassesTestCase.php",
index bef8f50..a48087e 100644 (file)
Binary files a/tests/parser/extraParserTests.txt and b/tests/parser/extraParserTests.txt differ
index 15f2dcf..56108c9 100644 (file)
@@ -619,6 +619,7 @@ class ParserTest {
                        $titleText = 'Parser test';
                }
 
+               ObjectCache::getMainWANInstance()->clearProcessCache();
                $local = isset( $opts['local'] );
                $preprocessor = isset( $opts['preprocessor'] ) ? $opts['preprocessor'] : null;
                $parser = $this->getParser( $preprocessor );
index 260e0f0..c6eebe4 100644 (file)
@@ -18,7 +18,6 @@
 # ill           add inter-language links
 #               (ignored by Parsoid, since it emits <link>s)
 # subpage       enable subpages (disabled by default)
-# noxml         don't check for XML well-formedness
 # title=[[XXX]] run test using article title XXX
 # language=XXX  set content language to XXX for this test
 # variant=XXX   set the variant of language for this test (eg zh-tw)
@@ -6567,6 +6566,8 @@ Table with empty line following the start tag
 
 !! test
 Table attributes with empty value
+!! options
+parsoid=wt2html,html2html
 !! wikitext
 {|
 | style=| hello
@@ -6579,11 +6580,8 @@ Table attributes with empty value
 
 !! html/parsoid
 <table>
-<tbody>
-<tr>
-<td style=""> hello
-</td></tr></tbody></table>
-
+<tbody><tr><td style=""> hello</td></tr>
+</tbody></table>
 !! end
 
 !! test
@@ -10509,6 +10507,7 @@ Abort table cell attribute parsing on wikilink
 {|
 | testing [[one|two]] | three || four
 | testing one two | three || four
+| testing="[[one|two]]" | three || four
 |}
 !! html/php
 <table>
@@ -10518,12 +10517,16 @@ Abort table cell attribute parsing on wikilink
 </td>
 <td> three </td>
 <td> four
+</td>
+<td> testing="<a href="/index.php?title=One&amp;action=edit&amp;redlink=1" class="new" title="One (page does not exist)">two</a>" | three </td>
+<td> four
 </td></tr></table>
 
 !! html/parsoid
 <table>
 <tbody><tr data-parsoid='{"autoInsertedEnd":true,"autoInsertedStart":true}'><td data-parsoid='{"autoInsertedEnd":true}'> testing <a rel="mw:WikiLink" href="./One" title="One" data-parsoid='{"stx":"piped","a":{"href":"./One"},"sa":{"href":"one"}}'>two</a> | three </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> four</td>
-<td data-parsoid='{"a":{"testing":null,"one":null,"two":null},"sa":{"testing":"","one":"","two":""},"autoInsertedEnd":true}'> three </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> four</td></tr>
+<td data-parsoid='{"a":{"testing":null,"one":null,"two":null},"sa":{"testing":"","one":"","two":""},"autoInsertedEnd":true}'> three </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> four</td>
+<td> testing="<a rel="mw:WikiLink" href="./One" title="One" data-parsoid='{"stx":"piped","a":{"href":"./One"},"sa":{"href":"one"}}'>two</a>" | three </td><td data-parsoid='{"stx_v":"row","autoInsertedEnd":true}'> four</td></tr>
 </tbody></table>
 !! end
 
@@ -12163,7 +12166,7 @@ This template has <!-- a comment --> in it.
 !! test
 pre-save transform: unclosed tag
 !! options
-pst noxml
+pst
 !! wikitext
 <nowiki>'''not wiki'''
 !! html/php
@@ -12173,7 +12176,7 @@ pst noxml
 !! test
 pre-save transform: mixed tag case
 !! options
-pst noxml
+pst
 !! wikitext
 <NOwiki>'''not wiki'''</noWIKI>
 !! html/php
@@ -12183,7 +12186,7 @@ pst noxml
 !! test
 pre-save transform: unclosed comment in <nowiki>
 !! options
-pst noxml
+pst
 !! wikitext
 wiki<nowiki>nowiki<!--nowiki</nowiki>wiki
 !! html/php
@@ -15471,14 +15474,17 @@ div with illegal double attributes
 
 !! test
 div with empty attribute value, space before equals
+!! options
+parsoid=wt2html,html2html
 !! wikitext
 <div class =>HTML rocks</div>
-!! html
+!! html/php
 <div class="">HTML rocks</div>
 
+!! html/parsoid
+<div class="" data-parsoid='{"stx":"html"}'>HTML rocks</div>
 !! end
 
-# FIXME: Parsoid doesn't match the html5 spec
 !! test
 div with multiple empty attribute values
 !! options
@@ -15489,10 +15495,9 @@ parsoid=wt2html,html2html
 <div id="title.3D">HTML rocks</div>
 
 !! html/parsoid
-<div id="" title="">HTML rocks</div>
+<div id="title=" data-parsoid='{"stx":"html"}'>HTML rocks</div>
 !! end
 
-# FIXME: Parsoid doesn't match the html5 spec
 !! test
 table with multiple empty attribute values
 !! options
@@ -15508,7 +15513,7 @@ parsoid=wt2html,html2html
 </td></tr></table>
 
 !! html/parsoid
-<table title="" id="">
+<table title="id=">
 <tbody><tr><td> hi</td></tr>
 </tbody></table>
 !! end
@@ -15850,20 +15855,28 @@ Empty attribute crash test single-quotes (bug 2067)
 
 !! test
 Attribute test: equals, then nothing
+!! options
+parsoid=wt2html,html2html
 !! wikitext
 <font color=>foo</font>
-!! html
+!! html/php
 <p><font color="">foo</font>
 </p>
+!! html/parsoid
+<p><font color="" data-parsoid='{"stx":"html"}'>foo</font></p>
 !! end
 
 !! test
 Attribute test: unquoted value
+!! options
+parsoid=wt2html,html2html
 !! wikitext
 <font color=x>foo</font>
-!! html
+!! html/php
 <p><font color="x">foo</font>
 </p>
+!! html/parsoid
+<p><font color="x" data-parsoid='{"stx":"html"}'>foo</font></p>
 !! end
 
 !! test
@@ -16414,8 +16427,6 @@ array (
 
 !! test
 Parser hook: nested tags
-!! options
-noxml
 !! wikitext
 <tag><tag></tag></tag>
 !! html/php
@@ -17049,6 +17060,8 @@ http://<div id="toc" class="toc"><div id="toctitle"><h2>Contents</h2></div>
 
 !! test
 Fuzz testing: Parser14-table
+!! options
+parsoid=wt2html,html2html
 !! wikitext
 ==a==
 {| STYLE=__TOC__
@@ -17065,13 +17078,14 @@ Fuzz testing: Parser14-table
 <td></td>
 </tr>
 </table>
+!! html/parsoid
+<h2>a</h2>
+<table style="__TOC__"></table>
 !! end
 
 # Known to produce bogus xml (extra </td>)
 !! test
 Fuzz testing: Parser16
-!! options
-noxml
 !! wikitext
 {|
 !https://||||||
@@ -17133,8 +17147,6 @@ http://===r:::https://b
 # Known to produce bad XML for now
 !! test
 Fuzz testing: Parser24
-!! options
-noxml
 !! wikitext
 {|
 {{{|
@@ -18199,7 +18211,7 @@ section=1
 !! test
 Section extraction, <pre> around bogus header (bug 10309)
 !! options
-noxml section=2
+section=2
 !! wikitext
 == Section One ==
 <pre>
@@ -18216,7 +18228,7 @@ stuff
 !! test
 Section replacement, <pre> around bogus header (bug 10309)
 !! options
-noxml replace=2,"xxx"
+replace=2,"xxx"
 !! wikitext
 == Section One ==
 <pre>
index 4d0e39c..a99b4b9 100644 (file)
@@ -247,6 +247,7 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                }
 
                DeferredUpdates::clearPendingUpdates();
+               ObjectCache::getMainWANInstance()->clearProcessCache();
 
                ob_start( 'MediaWikiTestCase::wfResetOutputBuffersBarrier' );
        }
index 98eb0c5..6c92b8c 100644 (file)
@@ -8,6 +8,7 @@ class HtmlTest extends MediaWikiTestCase {
 
                $this->setMwGlobals( [
                        'wgWellFormedXml' => false,
+                       'wgUseMediaWikiUIEverywhere' => false,
                ] );
 
                $langObj = Language::factory( 'en' );
index f380696..4c2e02b 100644 (file)
@@ -62,6 +62,17 @@ class HttpTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers Http::getProxy
+        */
+       public function testGetProxy() {
+               $this->setMwGlobals( 'wgHTTPProxy', 'proxy.domain.tld' );
+               $this->assertEquals(
+                       'proxy.domain.tld',
+                       Http::getProxy()
+               );
+       }
+
        /**
         * Feeds URI to test a long regular expression in Http::isValidURI
         */
index 8248257..e50b4f1 100644 (file)
@@ -132,129 +132,129 @@ class LinkerTest extends MediaWikiLangTestCase {
                $wikiId = 'enwiki'; // $wgConf has a fake entry for this
 
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
+               return [
                        // Linker::formatComment
-                       array(
+                       [
                                'a&lt;script&gt;b',
                                'a<script>b',
-                       ),
-                       array(
+                       ],
+                       [
                                'a—b',
                                'a&mdash;b',
-                       ),
-                       array(
+                       ],
+                       [
                                "&#039;&#039;&#039;not bolded&#039;&#039;&#039;",
                                "'''not bolded'''",
-                       ),
-                       array(
+                       ],
+                       [
                                "try &lt;script&gt;evil&lt;/scipt&gt; things",
                                "try <script>evil</scipt> things",
-                       ),
+                       ],
                        // Linker::formatAutocomments
-                       array(
+                       [
                                '<a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
                                "/* autocomment */",
-                       ),
-                       array(
+                       ],
+                       [
                                '<a href="/wiki/Special:BlankPage#linkie.3F" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment"><a href="/wiki/index.php?title=Linkie%3F&amp;action=edit&amp;redlink=1" class="new" title="Linkie? (page does not exist)">linkie?</a></span></span>',
                                "/* [[linkie?]] */",
-                       ),
-                       array(
+                       ],
+                       [
                                '<a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment: </span> post</span>',
                                "/* autocomment */ post",
-                       ),
-                       array(
+                       ],
+                       [
                                'pre <a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
                                "pre /* autocomment */",
-                       ),
-                       array(
+                       ],
+                       [
                                'pre <a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment: </span> post</span>',
                                "pre /* autocomment */ post",
-                       ),
-                       array(
+                       ],
+                       [
                                '<a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment: </span> multiple? <a href="/wiki/Special:BlankPage#autocomment2" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment2: </span> </span></span>',
                                "/* autocomment */ multiple? /* autocomment2 */ ",
-                       ),
-                       array(
+                       ],
+                       [
                                '<a href="/wiki/Special:BlankPage#autocomment_containing_.2F.2A" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment containing /*: </span> T70361</span>',
                                "/* autocomment containing /* */ T70361"
-                       ),
-                       array(
+                       ],
+                       [
                                '<a href="/wiki/Special:BlankPage#autocomment_containing_.22quotes.22" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment containing &quot;quotes&quot;</span></span>',
                                "/* autocomment containing \"quotes\" */"
-                       ),
-                       array(
+                       ],
+                       [
                                '<a href="/wiki/Special:BlankPage#autocomment_containing_.3Cscript.3Etags.3C.2Fscript.3E" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment containing &lt;script&gt;tags&lt;/script&gt;</span></span>',
                                "/* autocomment containing <script>tags</script> */"
-                       ),
-                       array(
+                       ],
+                       [
                                '<a href="#autocomment">→</a>‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
                                "/* autocomment */",
                                false, true
-                       ),
-                       array(
+                       ],
+                       [
                                '‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
                                "/* autocomment */",
                                null
-                       ),
-                       array(
+                       ],
+                       [
                                '<a href="/wiki/Special:BlankPage#autocomment" title="Special:BlankPage">→</a>‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
                                "/* autocomment */",
                                false, false
-                       ),
-                       array(
+                       ],
+                       [
                                '<a class="external" rel="nofollow" href="//en.example.org/w/Special:BlankPage#autocomment">→</a>‎<span dir="auto"><span class="autocomment">autocomment</span></span>',
                                "/* autocomment */",
                                false, false, $wikiId
-                       ),
+                       ],
                        // Linker::formatLinksInComment
-                       array(
+                       [
                                'abc <a href="/wiki/index.php?title=Link&amp;action=edit&amp;redlink=1" class="new" title="Link (page does not exist)">link</a> def',
                                "abc [[link]] def",
-                       ),
-                       array(
+                       ],
+                       [
                                'abc <a href="/wiki/index.php?title=Link&amp;action=edit&amp;redlink=1" class="new" title="Link (page does not exist)">text</a> def',
                                "abc [[link|text]] def",
-                       ),
-                       array(
+                       ],
+                       [
                                'abc <a href="/wiki/Special:BlankPage" title="Special:BlankPage">Special:BlankPage</a> def',
                                "abc [[Special:BlankPage|]] def",
-                       ),
-                       array(
+                       ],
+                       [
                                'abc <a href="/wiki/index.php?title=%C4%84%C5%9B%C5%BC&amp;action=edit&amp;redlink=1" class="new" title="Ąśż (page does not exist)">ąśż</a> def',
                                "abc [[%C4%85%C5%9B%C5%BC]] def",
-                       ),
-                       array(
+                       ],
+                       [
                                'abc <a href="/wiki/Special:BlankPage#section" title="Special:BlankPage">#section</a> def',
                                "abc [[#section]] def",
-                       ),
-                       array(
+                       ],
+                       [
                                'abc <a href="/wiki/index.php?title=/subpage&amp;action=edit&amp;redlink=1" class="new" title="/subpage (page does not exist)">/subpage</a> def',
                                "abc [[/subpage]] def",
-                       ),
-                       array(
+                       ],
+                       [
                                'abc <a href="/wiki/index.php?title=%22evil!%22&amp;action=edit&amp;redlink=1" class="new" title="&quot;evil!&quot; (page does not exist)">&quot;evil!&quot;</a> def',
                                "abc [[\"evil!\"]] def",
-                       ),
-                       array(
+                       ],
+                       [
                                'abc [[&lt;script&gt;very evil&lt;/script&gt;]] def',
                                "abc [[<script>very evil</script>]] def",
-                       ),
-                       array(
+                       ],
+                       [
                                'abc [[|]] def',
                                "abc [[|]] def",
-                       ),
-                       array(
+                       ],
+                       [
                                'abc <a href="/wiki/index.php?title=Link&amp;action=edit&amp;redlink=1" class="new" title="Link (page does not exist)">link</a> def',
                                "abc [[link]] def",
                                false, false
-                       ),
-                       array(
+                       ],
+                       [
                                'abc <a class="external" rel="nofollow" href="//en.example.org/w/Link">link</a> def',
                                "abc [[link]] def",
                                false, false, $wikiId
-                       )
-               );
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 
@@ -290,23 +290,23 @@ class LinkerTest extends MediaWikiLangTestCase {
 
        public static function provideCasesForFormatLinksInComment() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
-                       array(
+               return [
+                       [
                                'foo bar <a href="/wiki/Special:BlankPage" title="Special:BlankPage">Special:BlankPage</a>',
                                'foo bar [[Special:BlankPage]]',
                                null,
-                       ),
-                       array(
+                       ],
+                       [
                                '<a class="external" rel="nofollow" href="//en.example.org/w/Foo%27bar">Foo\'bar</a>',
                                "[[Foo'bar]]",
                                'enwiki',
-                       ),
-                       array(
+                       ],
+                       [
                                'foo bar <a class="external" rel="nofollow" href="//en.example.org/w/Special:BlankPage">Special:BlankPage</a>',
                                'foo bar [[Special:BlankPage]]',
                                'enwiki',
-                       ),
-               );
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 }
index 9bef038..2f63ca8 100644 (file)
@@ -138,62 +138,62 @@ class OutputPageTest extends MediaWikiTestCase {
 
        public static function provideMakeResourceLoaderLink() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
+               return [
                        // Load module script only
-                       array(
-                               array( 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS ),
+                       [
+                               [ 'test.foo', ResourceLoaderModule::TYPE_SCRIPTS ],
                                "<script>(window.RLQ=window.RLQ||[]).push(function(){"
                                        . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.foo\u0026only=scripts\u0026skin=fallback");'
                                        . "});</script>"
-                       ),
-                       array(
+                       ],
+                       [
                                // Don't condition wrap raw modules (like the startup module)
-                               array( 'test.raw', ResourceLoaderModule::TYPE_SCRIPTS ),
+                               [ 'test.raw', ResourceLoaderModule::TYPE_SCRIPTS ],
                                '<script async src="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.raw&amp;only=scripts&amp;skin=fallback"></script>'
-                       ),
+                       ],
                        // Load module styles only
                        // This also tests the order the modules are put into the url
-                       array(
-                               array( array( 'test.baz', 'test.foo', 'test.bar' ), ResourceLoaderModule::TYPE_STYLES ),
+                       [
+                               [ [ 'test.baz', 'test.foo', 'test.bar' ], ResourceLoaderModule::TYPE_STYLES ],
 
                                '<link rel=stylesheet href="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.bar%2Cbaz%2Cfoo&amp;only=styles&amp;skin=fallback">'
-                       ),
+                       ],
                        // Load private module (only=scripts)
-                       array(
-                               array( 'test.quux', ResourceLoaderModule::TYPE_SCRIPTS ),
+                       [
+                               [ 'test.quux', ResourceLoaderModule::TYPE_SCRIPTS ],
                                "<script>(window.RLQ=window.RLQ||[]).push(function(){"
                                        . "mw.test.baz({token:123});mw.loader.state({\"test.quux\":\"ready\"});"
                                        . "});</script>"
-                       ),
+                       ],
                        // Load private module (combined)
-                       array(
-                               array( 'test.quux', ResourceLoaderModule::TYPE_COMBINED ),
+                       [
+                               [ 'test.quux', ResourceLoaderModule::TYPE_COMBINED ],
                                "<script>(window.RLQ=window.RLQ||[]).push(function(){"
                                        . "mw.loader.implement(\"test.quux\",function($,jQuery){"
                                        . "mw.test.baz({token:123});},{\"css\":[\".mw-icon{transition:none}"
                                        . "\"]});});</script>"
-                       ),
+                       ],
                        // Load no modules
-                       array(
-                               array( array(), ResourceLoaderModule::TYPE_COMBINED ),
+                       [
+                               [ [], ResourceLoaderModule::TYPE_COMBINED ],
                                '',
-                       ),
+                       ],
                        // noscript group
-                       array(
-                               array( 'test.noscript', ResourceLoaderModule::TYPE_STYLES ),
+                       [
+                               [ 'test.noscript', ResourceLoaderModule::TYPE_STYLES ],
                                '<noscript><link rel=stylesheet href="http://127.0.0.1:8080/w/load.php?debug=false&amp;lang=en&amp;modules=test.noscript&amp;only=styles&amp;skin=fallback"></noscript>'
-                       ),
+                       ],
                        // Load two modules in separate groups
-                       array(
-                               array( array( 'test.group.foo', 'test.group.bar' ), ResourceLoaderModule::TYPE_COMBINED ),
+                       [
+                               [ [ 'test.group.foo', 'test.group.bar' ], ResourceLoaderModule::TYPE_COMBINED ],
                                "<script>(window.RLQ=window.RLQ||[]).push(function(){"
                                        . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.bar\u0026skin=fallback");'
                                        . "});</script>\n"
                                        . "<script>(window.RLQ=window.RLQ||[]).push(function(){"
                                        . 'mw.loader.load("http://127.0.0.1:8080/w/load.php?debug=false\u0026lang=en\u0026modules=test.group.foo\u0026skin=fallback");'
                                        . "});</script>"
-                       ),
-               );
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 
index d5f5420..67364cb 100644 (file)
@@ -237,8 +237,13 @@ class PathRouterTest extends MediaWikiTestCase {
         */
        public function testLength() {
                // @codingStandardsIgnoreStart Ignore long line warnings
-               $matches = $this->basicRouter->parse( "/wiki/Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum." );
-               $this->assertEquals( $matches, array( 'title' => "Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum." ) );
+               $matches = $this->basicRouter->parse(
+                       "/wiki/Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum."
+               );
+               $this->assertEquals(
+                       $matches,
+                       [ 'title' => "Lorem_ipsum_dolor_sit_amet,_consectetur_adipisicing_elit,_sed_do_eiusmod_tempor_incididunt_ut_labore_et_dolore_magna_aliqua._Ut_enim_ad_minim_veniam,_quis_nostrud_exercitation_ullamco_laboris_nisi_ut_aliquip_ex_ea_commodo_consequat._Duis_aute_irure_dolor_in_reprehenderit_in_voluptate_velit_esse_cillum_dolore_eu_fugiat_nulla_pariatur._Excepteur_sint_occaecat_cupidatat_non_proident,_sunt_in_culpa_qui_officia_deserunt_mollit_anim_id_est_laborum." ]
+               );
                // @codingStandardsIgnoreEnd
        }
 
index afde88c..5f07dbf 100644 (file)
@@ -934,7 +934,7 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
                );
        }
 
-       public function testAddWatchBatch_nonAnonymousUser() {
+       public function testAddWatchBatchForUser_nonAnonymousUser() {
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->once() )
                        ->method( 'insert' )
@@ -974,52 +974,14 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
                $mockUser = $this->getMockNonAnonUserWithId( 1 );
 
                $this->assertTrue(
-                       $store->addWatchBatch(
-                               [
-                                       [ $mockUser, new TitleValue( 0, 'Some_Page' ) ],
-                                       [ $mockUser, new TitleValue( 1, 'Some_Page' ) ],
-                               ]
-                       )
-               );
-       }
-
-       public function testAddWatchBatch_anonymousUserCombinationsAreSkipped() {
-               $mockDb = $this->getMockDb();
-               $mockDb->expects( $this->once() )
-                       ->method( 'insert' )
-                       ->with(
-                               'watchlist',
-                               [
-                                       [
-                                               'wl_user' => 1,
-                                               'wl_namespace' => 0,
-                                               'wl_title' => 'Some_Page',
-                                               'wl_notificationtimestamp' => null,
-                                       ]
-                               ]
-                       );
-
-               $mockCache = $this->getMockCache();
-               $mockCache->expects( $this->once() )
-                       ->method( 'delete' )
-                       ->with( '0:Some_Page:1' );
-
-               $store = new WatchedItemStore(
-                       $this->getMockLoadBalancer( $mockDb ),
-                       $mockCache
-               );
-
-               $this->assertTrue(
-                       $store->addWatchBatch(
-                               [
-                                       [ $this->getMockNonAnonUserWithId( 1 ), new TitleValue( 0, 'Some_Page' ) ],
-                                       [ $this->getAnonUser(), new TitleValue( 0, 'Other_Page' ) ],
-                               ]
+                       $store->addWatchBatchForUser(
+                               $mockUser,
+                               [ new TitleValue( 0, 'Some_Page' ), new TitleValue( 1, 'Some_Page' ) ]
                        )
                );
        }
 
-       public function testAddWatchBatchReturnsFalse_whenOnlyGivenAnonymousUserCombinations() {
+       public function testAddWatchBatchForUser_anonymousUsersAreSkipped() {
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->never() )
                        ->method( 'insert' );
@@ -1033,18 +995,16 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
                        $mockCache
                );
 
-               $anonUser = $this->getAnonUser();
                $this->assertFalse(
-                       $store->addWatchBatch(
-                               [
-                                       [ $anonUser, new TitleValue( 0, 'Some_Page' ) ],
-                                       [ $anonUser, new TitleValue( 1, 'Other_Page' ) ],
-                               ]
+                       $store->addWatchBatchForUser(
+                               $this->getAnonUser(),
+                               [ new TitleValue( 0, 'Other_Page' ) ]
                        )
                );
        }
 
-       public function testAddWatchBatchReturnsFalse_whenGivenEmptyList() {
+       public function testAddWatchBatchReturnsTrue_whenGivenEmptyList() {
+               $user = $this->getMockNonAnonUserWithId( 1 );
                $mockDb = $this->getMockDb();
                $mockDb->expects( $this->never() )
                        ->method( 'insert' );
@@ -1058,8 +1018,8 @@ class WatchedItemStoreUnitTest extends PHPUnit_Framework_TestCase {
                        $mockCache
                );
 
-               $this->assertFalse(
-                       $store->addWatchBatch( [] )
+               $this->assertTrue(
+                       $store->addWatchBatchForUser( $user, [] )
                );
        }
 
index 58984cf..b4eaa76 100644 (file)
@@ -165,25 +165,37 @@ class WatchedItemUnitTest extends PHPUnit_Framework_TestCase {
        }
 
        public function testBatchAddWatch() {
-               /** @var WatchedItem[] $items */
-               $items = [
-                       new WatchedItem( User::newFromId( 1 ), new TitleValue( 0, 'Title1' ), null ),
-                       new WatchedItem( User::newFromId( 3 ), Title::newFromText( 'Title2' ), '20150101010101' ),
-               ];
-
-               $userTargetCombinations = [];
-               foreach ( $items as $item ) {
-                       $userTargetCombinations[] = [ $item->getUser(), $item->getTitle()->getSubjectPage() ];
-                       $userTargetCombinations[] = [ $item->getUser(), $item->getTitle()->getTalkPage() ];
-               }
+               $itemOne = new WatchedItem( User::newFromId( 1 ), new TitleValue( 0, 'Title1' ), null );
+               $itemTwo = new WatchedItem(
+                       User::newFromId( 3 ),
+                       Title::newFromText( 'Title2' ),
+                       '20150101010101'
+               );
 
                $store = $this->getMockWatchedItemStore();
-               $store->expects( $this->once() )
-                       ->method( 'addWatchBatch' )
-                       ->with( $userTargetCombinations );
+               $store->expects( $this->exactly( 2 ) )
+                       ->method( 'addWatchBatchForUser' );
+               $store->expects( $this->at( 0 ) )
+                       ->method( 'addWatchBatchForUser' )
+                       ->with(
+                               $itemOne->getUser(),
+                               [
+                                       $itemOne->getTitle()->getSubjectPage(),
+                                       $itemOne->getTitle()->getTalkPage(),
+                               ]
+                       );
+               $store->expects( $this->at( 1 ) )
+                       ->method( 'addWatchBatchForUser' )
+                       ->with(
+                               $itemTwo->getUser(),
+                               [
+                                       $itemTwo->getTitle()->getSubjectPage(),
+                                       $itemTwo->getTitle()->getTalkPage(),
+                               ]
+                       );
                $scopedOverride = WatchedItemStore::overrideDefaultInstance( $store );
 
-               WatchedItem::batchAddWatch( $items );
+               WatchedItem::batchAddWatch( [ $itemOne, $itemTwo ] );
 
                ScopedCallback::consume( $scopedOverride );
        }
index 7b82d68..00d429e 100644 (file)
@@ -31,6 +31,7 @@ class XmlTest extends MediaWikiTestCase {
                $this->setMwGlobals( [
                        'wgLang' => $langObj,
                        'wgWellFormedXml' => true,
+                       'wgUseMediaWikiUIEverywhere' => false,
                ] );
        }
 
index 3052915..bcd884e 100644 (file)
@@ -193,7 +193,7 @@ class ApiLoginTest extends ApiTestCase {
                $this->setMwGlobals( [
                        'wgSessionProviders' => array_merge( $wgSessionProviders, [
                                [
-                                       'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider',
+                                       'class' => MediaWiki\Session\BotPasswordSessionProvider::class,
                                        'args' => [ [ 'priority' => 40 ] ],
                                ]
                        ] ),
@@ -207,14 +207,14 @@ class ApiLoginTest extends ApiTestCase {
 
                // Make sure our session provider is present
                $manager = TestingAccessWrapper::newFromObject( MediaWiki\Session\SessionManager::singleton() );
-               if ( !isset( $manager->sessionProviders['MediaWiki\\Session\\BotPasswordSessionProvider'] ) ) {
+               if ( !isset( $manager->sessionProviders[MediaWiki\Session\BotPasswordSessionProvider::class] ) ) {
                        $tmp = $manager->sessionProviders;
                        $manager->sessionProviders = null;
                        $manager->sessionProviders = $tmp + $manager->getProviders();
                }
                $this->assertNotNull(
                        MediaWiki\Session\SessionManager::singleton()->getProvider(
-                               'MediaWiki\\Session\\BotPasswordSessionProvider'
+                               MediaWiki\Session\BotPasswordSessionProvider::class
                        ),
                        'sanity check'
                );
index 690ba3a..0028bbb 100644 (file)
@@ -22,80 +22,80 @@ class ApiFormatPhpTest extends ApiFormatTestBase {
        public static function provideGeneralEncoding() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
                return array_merge(
-                       self::addFormatVersion( 1, array(
+                       self::addFormatVersion( 1, [
                                // Basic types
-                               array( array( null ), 'a:1:{i:0;N;}' ),
-                               array( array( true ), 'a:1:{i:0;s:0:"";}' ),
-                               array( array( false ), 'a:0:{}' ),
-                               array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ),
-                                       'a:1:{i:0;b:1;}' ),
-                               array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ),
-                                       'a:1:{i:0;b:0;}' ),
-                               array( array( 42 ), 'a:1:{i:0;i:42;}' ),
-                               array( array( 42.5 ), 'a:1:{i:0;d:42.5;}' ),
-                               array( array( 1e42 ), 'a:1:{i:0;d:1.0E+42;}' ),
-                               array( array( 'foo' ), 'a:1:{i:0;s:3:"foo";}' ),
-                               array( array( 'fóo' ), 'a:1:{i:0;s:4:"fóo";}' ),
+                               [ [ null ], 'a:1:{i:0;N;}' ],
+                               [ [ true ], 'a:1:{i:0;s:0:"";}' ],
+                               [ [ false ], 'a:0:{}' ],
+                               [ [ true, ApiResult::META_BC_BOOLS => [ 0 ] ],
+                                       'a:1:{i:0;b:1;}' ],
+                               [ [ false, ApiResult::META_BC_BOOLS => [ 0 ] ],
+                                       'a:1:{i:0;b:0;}' ],
+                               [ [ 42 ], 'a:1:{i:0;i:42;}' ],
+                               [ [ 42.5 ], 'a:1:{i:0;d:42.5;}' ],
+                               [ [ 1e42 ], 'a:1:{i:0;d:1.0E+42;}' ],
+                               [ [ 'foo' ], 'a:1:{i:0;s:3:"foo";}' ],
+                               [ [ 'fóo' ], 'a:1:{i:0;s:4:"fóo";}' ],
 
                                // Arrays and objects
-                               array( array( array() ), 'a:1:{i:0;a:0:{}}' ),
-                               array( array( array( 1 ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
-                               array( array( array( 'x' => 1 ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
-                               array( array( array( 2 => 1 ) ), 'a:1:{i:0;a:1:{i:2;i:1;}}' ),
-                               array( array( (object)array() ), 'a:1:{i:0;a:0:{}}' ),
-                               array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
-                               array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
-                               array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
-                               array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
-                                       'a:1:{i:0;a:1:{i:0;a:2:{s:3:"key";s:1:"x";s:1:"*";i:1;}}}' ),
-                               array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
-                               array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), 'a:1:{i:0;a:2:{i:0;s:1:"a";i:1;s:1:"b";}}' ),
+                               [ [ [] ], 'a:1:{i:0;a:0:{}}' ],
+                               [ [ [ 1 ] ], 'a:1:{i:0;a:1:{i:0;i:1;}}' ],
+                               [ [ [ 'x' => 1 ] ], 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ],
+                               [ [ [ 2 => 1 ] ], 'a:1:{i:0;a:1:{i:2;i:1;}}' ],
+                               [ [ (object)[] ], 'a:1:{i:0;a:0:{}}' ],
+                               [ [ [ 1, ApiResult::META_TYPE => 'assoc' ] ], 'a:1:{i:0;a:1:{i:0;i:1;}}' ],
+                               [ [ [ 'x' => 1, ApiResult::META_TYPE => 'array' ] ], 'a:1:{i:0;a:1:{i:0;i:1;}}' ],
+                               [ [ [ 'x' => 1, ApiResult::META_TYPE => 'kvp' ] ], 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ],
+                               [ [ [ 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ] ],
+                                       'a:1:{i:0;a:1:{i:0;a:2:{s:3:"key";s:1:"x";s:1:"*";i:1;}}}' ],
+                               [ [ [ 'x' => 1, ApiResult::META_TYPE => 'BCarray' ] ], 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ],
+                               [ [ [ 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ] ], 'a:1:{i:0;a:2:{i:0;s:1:"a";i:1;s:1:"b";}}' ],
 
                                // Content
-                               array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
-                                       'a:1:{s:1:"*";s:3:"foo";}' ),
+                               [ [ 'content' => 'foo', ApiResult::META_CONTENT => 'content' ],
+                                       'a:1:{s:1:"*";s:3:"foo";}' ],
 
                                // BC Subelements
-                               array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
-                                       'a:1:{s:3:"foo";a:1:{s:1:"*";s:3:"foo";}}' ),
-                       ) ),
-                       self::addFormatVersion( 2, array(
+                               [ [ 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => [ 'foo' ] ],
+                                       'a:1:{s:3:"foo";a:1:{s:1:"*";s:3:"foo";}}' ],
+                       ] ),
+                       self::addFormatVersion( 2, [
                                // Basic types
-                               array( array( null ), 'a:1:{i:0;N;}' ),
-                               array( array( true ), 'a:1:{i:0;b:1;}' ),
-                               array( array( false ), 'a:1:{i:0;b:0;}' ),
-                               array( array( true, ApiResult::META_BC_BOOLS => array( 0 ) ),
-                                       'a:1:{i:0;b:1;}' ),
-                               array( array( false, ApiResult::META_BC_BOOLS => array( 0 ) ),
-                                       'a:1:{i:0;b:0;}' ),
-                               array( array( 42 ), 'a:1:{i:0;i:42;}' ),
-                               array( array( 42.5 ), 'a:1:{i:0;d:42.5;}' ),
-                               array( array( 1e42 ), 'a:1:{i:0;d:1.0E+42;}' ),
-                               array( array( 'foo' ), 'a:1:{i:0;s:3:"foo";}' ),
-                               array( array( 'fóo' ), 'a:1:{i:0;s:4:"fóo";}' ),
+                               [ [ null ], 'a:1:{i:0;N;}' ],
+                               [ [ true ], 'a:1:{i:0;b:1;}' ],
+                               [ [ false ], 'a:1:{i:0;b:0;}' ],
+                               [ [ true, ApiResult::META_BC_BOOLS => [ 0 ] ],
+                                       'a:1:{i:0;b:1;}' ],
+                               [ [ false, ApiResult::META_BC_BOOLS => [ 0 ] ],
+                                       'a:1:{i:0;b:0;}' ],
+                               [ [ 42 ], 'a:1:{i:0;i:42;}' ],
+                               [ [ 42.5 ], 'a:1:{i:0;d:42.5;}' ],
+                               [ [ 1e42 ], 'a:1:{i:0;d:1.0E+42;}' ],
+                               [ [ 'foo' ], 'a:1:{i:0;s:3:"foo";}' ],
+                               [ [ 'fóo' ], 'a:1:{i:0;s:4:"fóo";}' ],
 
                                // Arrays and objects
-                               array( array( array() ), 'a:1:{i:0;a:0:{}}' ),
-                               array( array( array( 1 ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
-                               array( array( array( 'x' => 1 ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
-                               array( array( array( 2 => 1 ) ), 'a:1:{i:0;a:1:{i:2;i:1;}}' ),
-                               array( array( (object)array() ), 'a:1:{i:0;a:0:{}}' ),
-                               array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
-                               array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
-                               array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp' ) ), 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
-                               array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
-                                       'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ),
-                               array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), 'a:1:{i:0;a:1:{i:0;i:1;}}' ),
-                               array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), 'a:1:{i:0;a:2:{i:0;s:1:"a";i:1;s:1:"b";}}' ),
+                               [ [ [] ], 'a:1:{i:0;a:0:{}}' ],
+                               [ [ [ 1 ] ], 'a:1:{i:0;a:1:{i:0;i:1;}}' ],
+                               [ [ [ 'x' => 1 ] ], 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ],
+                               [ [ [ 2 => 1 ] ], 'a:1:{i:0;a:1:{i:2;i:1;}}' ],
+                               [ [ (object)[] ], 'a:1:{i:0;a:0:{}}' ],
+                               [ [ [ 1, ApiResult::META_TYPE => 'assoc' ] ], 'a:1:{i:0;a:1:{i:0;i:1;}}' ],
+                               [ [ [ 'x' => 1, ApiResult::META_TYPE => 'array' ] ], 'a:1:{i:0;a:1:{i:0;i:1;}}' ],
+                               [ [ [ 'x' => 1, ApiResult::META_TYPE => 'kvp' ] ], 'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ],
+                               [ [ [ 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ] ],
+                                       'a:1:{i:0;a:1:{s:1:"x";i:1;}}' ],
+                               [ [ [ 'x' => 1, ApiResult::META_TYPE => 'BCarray' ] ], 'a:1:{i:0;a:1:{i:0;i:1;}}' ],
+                               [ [ [ 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ] ], 'a:1:{i:0;a:2:{i:0;s:1:"a";i:1;s:1:"b";}}' ],
 
                                // Content
-                               array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
-                                       'a:1:{s:7:"content";s:3:"foo";}' ),
+                               [ [ 'content' => 'foo', ApiResult::META_CONTENT => 'content' ],
+                                       'a:1:{s:7:"content";s:3:"foo";}' ],
 
                                // BC Subelements
-                               array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
-                                       'a:1:{s:3:"foo";s:3:"foo";}' ),
-                       ) )
+                               [ [ 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => [ 'foo' ] ],
+                                       'a:1:{s:3:"foo";s:3:"foo";}' ],
+                       ] )
                );
                // @codingStandardsIgnoreEnd
        }
index 0b7ae35..3fef0b0 100644 (file)
@@ -25,98 +25,98 @@ class ApiFormatXmlTest extends ApiFormatTestBase {
 
        public static function provideGeneralEncoding() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
+               return [
                        // Basic types
-                       array( array( null, 'a' => null ), '<?xml version="1.0"?><api><_v _idx="0" /></api>' ),
-                       array( array( true, 'a' => true ), '<?xml version="1.0"?><api a=""><_v _idx="0">true</_v></api>' ),
-                       array( array( false, 'a' => false ), '<?xml version="1.0"?><api><_v _idx="0">false</_v></api>' ),
-                       array( array( true, 'a' => true, ApiResult::META_BC_BOOLS => array( 0, 'a' ) ),
-                               '<?xml version="1.0"?><api a=""><_v _idx="0">1</_v></api>' ),
-                       array( array( false, 'a' => false, ApiResult::META_BC_BOOLS => array( 0, 'a' ) ),
-                               '<?xml version="1.0"?><api><_v _idx="0"></_v></api>' ),
-                       array( array( 42, 'a' => 42 ), '<?xml version="1.0"?><api a="42"><_v _idx="0">42</_v></api>' ),
-                       array( array( 42.5, 'a' => 42.5 ), '<?xml version="1.0"?><api a="42.5"><_v _idx="0">42.5</_v></api>' ),
-                       array( array( 1e42, 'a' => 1e42 ), '<?xml version="1.0"?><api a="1.0E+42"><_v _idx="0">1.0E+42</_v></api>' ),
-                       array( array( 'foo', 'a' => 'foo' ), '<?xml version="1.0"?><api a="foo"><_v _idx="0">foo</_v></api>' ),
-                       array( array( 'fóo', 'a' => 'fóo' ), '<?xml version="1.0"?><api a="fóo"><_v _idx="0">fóo</_v></api>' ),
+                       [ [ null, 'a' => null ], '<?xml version="1.0"?><api><_v _idx="0" /></api>' ],
+                       [ [ true, 'a' => true ], '<?xml version="1.0"?><api a=""><_v _idx="0">true</_v></api>' ],
+                       [ [ false, 'a' => false ], '<?xml version="1.0"?><api><_v _idx="0">false</_v></api>' ],
+                       [ [ true, 'a' => true, ApiResult::META_BC_BOOLS => [ 0, 'a' ] ],
+                               '<?xml version="1.0"?><api a=""><_v _idx="0">1</_v></api>' ],
+                       [ [ false, 'a' => false, ApiResult::META_BC_BOOLS => [ 0, 'a' ] ],
+                               '<?xml version="1.0"?><api><_v _idx="0"></_v></api>' ],
+                       [ [ 42, 'a' => 42 ], '<?xml version="1.0"?><api a="42"><_v _idx="0">42</_v></api>' ],
+                       [ [ 42.5, 'a' => 42.5 ], '<?xml version="1.0"?><api a="42.5"><_v _idx="0">42.5</_v></api>' ],
+                       [ [ 1e42, 'a' => 1e42 ], '<?xml version="1.0"?><api a="1.0E+42"><_v _idx="0">1.0E+42</_v></api>' ],
+                       [ [ 'foo', 'a' => 'foo' ], '<?xml version="1.0"?><api a="foo"><_v _idx="0">foo</_v></api>' ],
+                       [ [ 'fóo', 'a' => 'fóo' ], '<?xml version="1.0"?><api a="fóo"><_v _idx="0">fóo</_v></api>' ],
 
                        // Arrays and objects
-                       array( array( array() ), '<?xml version="1.0"?><api><_v /></api>' ),
-                       array( array( array( 'x' => 1 ) ), '<?xml version="1.0"?><api><_v x="1" /></api>' ),
-                       array( array( array( 2 => 1 ) ), '<?xml version="1.0"?><api><_v><_v _idx="2">1</_v></_v></api>' ),
-                       array( array( (object)array() ), '<?xml version="1.0"?><api><_v /></api>' ),
-                       array( array( array( 1, ApiResult::META_TYPE => 'assoc' ) ), '<?xml version="1.0"?><api><_v><_v _idx="0">1</_v></_v></api>' ),
-                       array( array( array( 'x' => 1, ApiResult::META_TYPE => 'array' ) ), '<?xml version="1.0"?><api><_v><_v>1</_v></_v></api>' ),
-                       array( array( array( 'x' => 1, 'y' => array( 'z' => 1 ), ApiResult::META_TYPE => 'kvp' ) ),
-                               '<?xml version="1.0"?><api><_v><_v _name="x" xml:space="preserve">1</_v><_v _name="y"><z xml:space="preserve">1</z></_v></_v></api>' ),
-                       array( array( array( 'x' => 1, ApiResult::META_TYPE => 'kvp', ApiResult::META_INDEXED_TAG_NAME => 'i', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
-                               '<?xml version="1.0"?><api><_v><i key="x" xml:space="preserve">1</i></_v></api>' ),
-                       array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ) ),
-                               '<?xml version="1.0"?><api><_v><_v key="x" xml:space="preserve">1</_v></_v></api>' ),
-                       array( array( array( 'x' => 1, ApiResult::META_TYPE => 'BCarray' ) ), '<?xml version="1.0"?><api><_v x="1" /></api>' ),
-                       array( array( array( 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ) ), '<?xml version="1.0"?><api><_v><_v _idx="0">a</_v><_v _idx="1">b</_v></_v></api>' ),
+                       [ [ [] ], '<?xml version="1.0"?><api><_v /></api>' ],
+                       [ [ [ 'x' => 1 ] ], '<?xml version="1.0"?><api><_v x="1" /></api>' ],
+                       [ [ [ 2 => 1 ] ], '<?xml version="1.0"?><api><_v><_v _idx="2">1</_v></_v></api>' ],
+                       [ [ (object)[] ], '<?xml version="1.0"?><api><_v /></api>' ],
+                       [ [ [ 1, ApiResult::META_TYPE => 'assoc' ] ], '<?xml version="1.0"?><api><_v><_v _idx="0">1</_v></_v></api>' ],
+                       [ [ [ 'x' => 1, ApiResult::META_TYPE => 'array' ] ], '<?xml version="1.0"?><api><_v><_v>1</_v></_v></api>' ],
+                       [ [ [ 'x' => 1, 'y' => [ 'z' => 1 ], ApiResult::META_TYPE => 'kvp' ] ],
+                               '<?xml version="1.0"?><api><_v><_v _name="x" xml:space="preserve">1</_v><_v _name="y"><z xml:space="preserve">1</z></_v></_v></api>' ],
+                       [ [ [ 'x' => 1, ApiResult::META_TYPE => 'kvp', ApiResult::META_INDEXED_TAG_NAME => 'i', ApiResult::META_KVP_KEY_NAME => 'key' ] ],
+                               '<?xml version="1.0"?><api><_v><i key="x" xml:space="preserve">1</i></_v></api>' ],
+                       [ [ [ 'x' => 1, ApiResult::META_TYPE => 'BCkvp', ApiResult::META_KVP_KEY_NAME => 'key' ] ],
+                               '<?xml version="1.0"?><api><_v><_v key="x" xml:space="preserve">1</_v></_v></api>' ],
+                       [ [ [ 'x' => 1, ApiResult::META_TYPE => 'BCarray' ] ], '<?xml version="1.0"?><api><_v x="1" /></api>' ],
+                       [ [ [ 'a', 'b', ApiResult::META_TYPE => 'BCassoc' ] ], '<?xml version="1.0"?><api><_v><_v _idx="0">a</_v><_v _idx="1">b</_v></_v></api>' ],
 
                        // Content
-                       array( array( 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
-                               '<?xml version="1.0"?><api xml:space="preserve">foo</api>' ),
+                       [ [ 'content' => 'foo', ApiResult::META_CONTENT => 'content' ],
+                               '<?xml version="1.0"?><api xml:space="preserve">foo</api>' ],
 
                        // Specified element name
-                       array( array( 'foo', 'bar', ApiResult::META_INDEXED_TAG_NAME => 'itn' ),
-                               '<?xml version="1.0"?><api><itn>foo</itn><itn>bar</itn></api>' ),
+                       [ [ 'foo', 'bar', ApiResult::META_INDEXED_TAG_NAME => 'itn' ],
+                               '<?xml version="1.0"?><api><itn>foo</itn><itn>bar</itn></api>' ],
 
                        // Subelements
-                       array( array( 'a' => 1, 's' => 1, '_subelements' => array( 's' ) ),
-                               '<?xml version="1.0"?><api a="1"><s xml:space="preserve">1</s></api>' ),
+                       [ [ 'a' => 1, 's' => 1, '_subelements' => [ 's' ] ],
+                               '<?xml version="1.0"?><api a="1"><s xml:space="preserve">1</s></api>' ],
 
                        // Content and subelement
-                       array( array( 'a' => 1, 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
-                               '<?xml version="1.0"?><api a="1" xml:space="preserve">foo</api>' ),
-                       array( array( 's' => array(), 'content' => 'foo', ApiResult::META_CONTENT => 'content' ),
-                               '<?xml version="1.0"?><api><s /><content xml:space="preserve">foo</content></api>' ),
-                       array(
-                               array(
+                       [ [ 'a' => 1, 'content' => 'foo', ApiResult::META_CONTENT => 'content' ],
+                               '<?xml version="1.0"?><api a="1" xml:space="preserve">foo</api>' ],
+                       [ [ 's' => [], 'content' => 'foo', ApiResult::META_CONTENT => 'content' ],
+                               '<?xml version="1.0"?><api><s /><content xml:space="preserve">foo</content></api>' ],
+                       [
+                               [
                                        's' => 1,
                                        'content' => 'foo',
                                        ApiResult::META_CONTENT => 'content',
-                                       ApiResult::META_SUBELEMENTS => array( 's' )
-                               ),
+                                       ApiResult::META_SUBELEMENTS => [ 's' ]
+                               ],
                                '<?xml version="1.0"?><api><s xml:space="preserve">1</s><content xml:space="preserve">foo</content></api>'
-                       ),
+                       ],
 
                        // BC Subelements
-                       array( array( 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => array( 'foo' ) ),
-                               '<?xml version="1.0"?><api><foo xml:space="preserve">foo</foo></api>' ),
+                       [ [ 'foo' => 'foo', ApiResult::META_BC_SUBELEMENTS => [ 'foo' ] ],
+                               '<?xml version="1.0"?><api><foo xml:space="preserve">foo</foo></api>' ],
 
                        // Name mangling
-                       array( array( 'foo.bar' => 1 ), '<?xml version="1.0"?><api foo.bar="1" />' ),
-                       array( array( '' => 1 ), '<?xml version="1.0"?><api _="1" />' ),
-                       array( array( 'foo bar' => 1 ), '<?xml version="1.0"?><api _foo.20.bar="1" />' ),
-                       array( array( 'foo:bar' => 1 ), '<?xml version="1.0"?><api _foo.3A.bar="1" />' ),
-                       array( array( 'foo%.bar' => 1 ), '<?xml version="1.0"?><api _foo.25..2E.bar="1" />' ),
-                       array( array( '4foo' => 1, 'foo4' => 1 ), '<?xml version="1.0"?><api _4foo="1" foo4="1" />' ),
-                       array( array( "foo\xe3\x80\x80bar" => 1 ), '<?xml version="1.0"?><api _foo.3000.bar="1" />' ),
-                       array( array( 'foo:bar' => 1, ApiResult::META_PRESERVE_KEYS => array( 'foo:bar' ) ),
-                               '<?xml version="1.0"?><api foo:bar="1" />' ),
-                       array( array( 'a', 'b', ApiResult::META_INDEXED_TAG_NAME => 'foo bar' ),
-                               '<?xml version="1.0"?><api><_foo.20.bar>a</_foo.20.bar><_foo.20.bar>b</_foo.20.bar></api>' ),
+                       [ [ 'foo.bar' => 1 ], '<?xml version="1.0"?><api foo.bar="1" />' ],
+                       [ [ '' => 1 ], '<?xml version="1.0"?><api _="1" />' ],
+                       [ [ 'foo bar' => 1 ], '<?xml version="1.0"?><api _foo.20.bar="1" />' ],
+                       [ [ 'foo:bar' => 1 ], '<?xml version="1.0"?><api _foo.3A.bar="1" />' ],
+                       [ [ 'foo%.bar' => 1 ], '<?xml version="1.0"?><api _foo.25..2E.bar="1" />' ],
+                       [ [ '4foo' => 1, 'foo4' => 1 ], '<?xml version="1.0"?><api _4foo="1" foo4="1" />' ],
+                       [ [ "foo\xe3\x80\x80bar" => 1 ], '<?xml version="1.0"?><api _foo.3000.bar="1" />' ],
+                       [ [ 'foo:bar' => 1, ApiResult::META_PRESERVE_KEYS => [ 'foo:bar' ] ],
+                               '<?xml version="1.0"?><api foo:bar="1" />' ],
+                       [ [ 'a', 'b', ApiResult::META_INDEXED_TAG_NAME => 'foo bar' ],
+                               '<?xml version="1.0"?><api><_foo.20.bar>a</_foo.20.bar><_foo.20.bar>b</_foo.20.bar></api>' ],
 
                        // includenamespace param
-                       array( array( 'x' => 'foo' ), '<?xml version="1.0"?><api x="foo" xmlns="http://www.mediawiki.org/xml/api/" />',
-                               array( 'includexmlnamespace' => 1 ) ),
+                       [ [ 'x' => 'foo' ], '<?xml version="1.0"?><api x="foo" xmlns="http://www.mediawiki.org/xml/api/" />',
+                               [ 'includexmlnamespace' => 1 ] ],
 
                        // xslt param
-                       array( array(), '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Invalid or non-existent stylesheet specified</xml></warnings></api>',
-                               array( 'xslt' => 'DoesNotExist' ) ),
-                       array( array(), '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Stylesheet should be in the MediaWiki namespace.</xml></warnings></api>',
-                               array( 'xslt' => 'ApiFormatXmlTest' ) ),
-                       array( array(), '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Stylesheet should have .xsl extension.</xml></warnings></api>',
-                               array( 'xslt' => 'MediaWiki:ApiFormatXmlTest' ) ),
-                       array( array(),
+                       [ [], '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Invalid or non-existent stylesheet specified</xml></warnings></api>',
+                               [ 'xslt' => 'DoesNotExist' ] ],
+                       [ [], '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Stylesheet should be in the MediaWiki namespace.</xml></warnings></api>',
+                               [ 'xslt' => 'ApiFormatXmlTest' ] ],
+                       [ [], '<?xml version="1.0"?><api><warnings><xml xml:space="preserve">Stylesheet should have .xsl extension.</xml></warnings></api>',
+                               [ 'xslt' => 'MediaWiki:ApiFormatXmlTest' ] ],
+                       [ [],
                                '<?xml version="1.0"?><?xml-stylesheet href="' .
                                        htmlspecialchars( Title::newFromText( 'MediaWiki:ApiFormatXmlTest.xsl' )->getLocalURL( 'action=raw' ) ) .
                                        '" type="text/xsl" ?><api />',
-                               array( 'xslt' => 'MediaWiki:ApiFormatXmlTest.xsl' ) ),
-               );
+                               [ 'xslt' => 'MediaWiki:ApiFormatXmlTest.xsl' ] ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 
index 9643d13..d92fb8f 100644 (file)
@@ -22,11 +22,20 @@ class CssContentHandlerTest extends MediaWikiLangTestCase {
         */
        public static function provideMakeRedirectContent() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
-                       array( 'MediaWiki:MonoBook.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=MediaWiki:MonoBook.css&action=raw&ctype=text/css);" ),
-                       array( 'User:FooBar/common.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=User:FooBar/common.css&action=raw&ctype=text/css);" ),
-                       array( 'Gadget:FooBaz.css', "/* #REDIRECT */@import url(//example.org/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);" ),
-               );
+               return [
+                       [
+                               'MediaWiki:MonoBook.css',
+                               "/* #REDIRECT */@import url(//example.org/w/index.php?title=MediaWiki:MonoBook.css&action=raw&ctype=text/css);"
+                       ],
+                       [
+                               'User:FooBar/common.css',
+                               "/* #REDIRECT */@import url(//example.org/w/index.php?title=User:FooBar/common.css&action=raw&ctype=text/css);"
+                       ],
+                       [
+                               'Gadget:FooBaz.css',
+                               "/* #REDIRECT */@import url(//example.org/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);"
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 }
index 17f653c..d229623 100644 (file)
@@ -22,11 +22,20 @@ class JavaScriptContentHandlerTest extends MediaWikiLangTestCase {
         */
        public static function provideMakeRedirectContent() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
-                       array( 'MediaWiki:MonoBook.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");' ),
-                       array( 'User:FooBar/common.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=User:FooBar/common.js\u0026action=raw\u0026ctype=text/javascript");' ),
-                       array( 'Gadget:FooBaz.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=Gadget:FooBaz.js\u0026action=raw\u0026ctype=text/javascript");' ),
-               );
+               return [
+                       [
+                               'MediaWiki:MonoBook.js',
+                               '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");'
+                       ],
+                       [
+                               'User:FooBar/common.js',
+                               '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=User:FooBar/common.js\u0026action=raw\u0026ctype=text/javascript");'
+                       ],
+                       [
+                               'Gadget:FooBaz.js',
+                               '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=Gadget:FooBaz.js\u0026action=raw\u0026ctype=text/javascript");'
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 }
index abe352a..8cbbfb8 100644 (file)
@@ -278,10 +278,10 @@ class JavaScriptContentTest extends TextContentTest {
                        ],
 
                        // @codingStandardsIgnoreStart Generic.Files.LineLength
-                       array(
+                       [
                                '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");',
                                '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=TestUpdateRedirect_target\u0026action=raw\u0026ctype=text/javascript");'
-                       )
+                       ]
                        // @codingStandardsIgnoreEnd
                ];
        }
@@ -333,15 +333,30 @@ class JavaScriptContentTest extends TextContentTest {
         */
        public static function provideGetRedirectTarget() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
-                       array( 'MediaWiki:MonoBook.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");' ),
-                       array( 'User:FooBar/common.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=User:FooBar/common.js\u0026action=raw\u0026ctype=text/javascript");' ),
-                       array( 'Gadget:FooBaz.js', '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=Gadget:FooBaz.js\u0026action=raw\u0026ctype=text/javascript");' ),
+               return [
+                       [
+                               'MediaWiki:MonoBook.js',
+                               '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=MediaWiki:MonoBook.js\u0026action=raw\u0026ctype=text/javascript");'
+                       ],
+                       [
+                               'User:FooBar/common.js',
+                               '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=User:FooBar/common.js\u0026action=raw\u0026ctype=text/javascript");'
+                       ],
+                       [
+                               'Gadget:FooBaz.js',
+                               '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=Gadget:FooBaz.js\u0026action=raw\u0026ctype=text/javascript");'
+                       ],
                        // No #REDIRECT comment
-                       array( null, 'mw.loader.load("//example.org/w/index.php?title=MediaWiki:NoRedirect.js\u0026action=raw\u0026ctype=text/javascript");' ),
+                       [
+                               null,
+                               'mw.loader.load("//example.org/w/index.php?title=MediaWiki:NoRedirect.js\u0026action=raw\u0026ctype=text/javascript");'
+                       ],
                        // Different domain
-                       array( null, '/* #REDIRECT */mw.loader.load("//example.com/w/index.php?title=MediaWiki:OtherWiki.js\u0026action=raw\u0026ctype=text/javascript");' ),
-               );
+                       [
+                               null,
+                               '/* #REDIRECT */mw.loader.load("//example.com/w/index.php?title=MediaWiki:OtherWiki.js\u0026action=raw\u0026ctype=text/javascript");'
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 }
index f4aac23..9d05d15 100644 (file)
@@ -37,8 +37,8 @@ class ImportTest extends MediaWikiLangTestCase {
 
        public function getUnknownTagsXML() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
-                       array(
+               return [
+                       [
                                <<< EOF
 <mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en">
   <page unknown="123" dontknow="533">
@@ -68,8 +68,8 @@ EOF
                                ,
                                'noitazinagro tseb eht si ikiWaideM',
                                'TestImportPage'
-                       )
-               );
+                       ]
+               ];
                // @codingStandardsIgnoreEnd
        }
 
@@ -102,8 +102,8 @@ EOF
 
        public function getRedirectXML() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
-                       array(
+               return [
+                       [
                                <<< EOF
 <mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en">
        <page>
@@ -129,8 +129,8 @@ EOF
 EOF
                        ,
                                'Test22'
-                       ),
-                       array(
+                       ],
+                       [
                                <<< EOF
 <mediawiki xmlns="http://www.mediawiki.org/xml/export-0.9/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.9/ http://www.mediawiki.org/xml/export-0.9.xsd" version="0.9" xml:lang="en">
        <page>
@@ -154,8 +154,8 @@ EOF
 EOF
                        ,
                                null
-                       ),
-               );
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 
@@ -185,8 +185,8 @@ EOF
 
        public function getSiteInfoXML() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
-                       array(
+               return [
+                       [
                                <<< EOF
 <mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="en">
   <siteinfo>
@@ -204,7 +204,7 @@ EOF
 </mediawiki>
 EOF
                        ,
-                               array(
+                               [
                                        '-2' => 'Media',
                                        '-1' => 'Special',
                                        '0' => '',
@@ -213,9 +213,9 @@ EOF
                                        '3' => 'User talk',
                                        '100' => 'Portal',
                                        '101' => 'Portal talk',
-                               )
-                       ),
-               );
+                               ]
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 
index 8902ecd..5f5a1e8 100644 (file)
@@ -189,192 +189,192 @@ class CSSMinTest extends MediaWikiTestCase {
                        . '%228%22%3E%0A%3Ccircle%20cx%3D%224%22%20cy%3D%224%22%20r%3D%222%22%2F%3E%0A%3C%2Fsvg%3E%0A';
 
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
-                       array(
+               return [
+                       [
                                'Regular file',
                                'foo { background: url(red.gif); }',
                                'foo { background: url(http://localhost/w/red.gif?34ac6); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Regular file (missing)',
                                'foo { background: url(theColorOfHerHair.gif); }',
                                'foo { background: url(http://localhost/w/theColorOfHerHair.gif); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Remote URL',
                                'foo { background: url(http://example.org/w/foo.png); }',
                                'foo { background: url(http://example.org/w/foo.png); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Protocol-relative remote URL',
                                'foo { background: url(//example.org/w/foo.png); }',
                                'foo { background: url(//example.org/w/foo.png); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Remote URL with query',
                                'foo { background: url(http://example.org/w/foo.png?query=yes); }',
                                'foo { background: url(http://example.org/w/foo.png?query=yes); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Protocol-relative remote URL with query',
                                'foo { background: url(//example.org/w/foo.png?query=yes); }',
                                'foo { background: url(//example.org/w/foo.png?query=yes); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Domain-relative URL',
                                'foo { background: url(/static/foo.png); }',
                                'foo { background: url(http://doc.example.org/static/foo.png); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Domain-relative URL with query',
                                'foo { background: url(/static/foo.png?query=yes); }',
                                'foo { background: url(http://doc.example.org/static/foo.png?query=yes); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Remote URL (unnecessary quotes not preserved)',
                                'foo { background: url("http://example.org/w/foo.png"); }',
                                'foo { background: url(http://example.org/w/foo.png); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Embedded file',
                                'foo { /* @embed */ background: url(red.gif); }',
                                "foo { background: url($red); background: url(http://localhost/w/red.gif?34ac6)!ie; }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Embedded file, other comments before the rule',
                                "foo { /* Bar. */ /* @embed */ background: url(red.gif); }",
                                "foo { /* Bar. */ background: url($red); /* Bar. */ background: url(http://localhost/w/red.gif?34ac6)!ie; }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Can not re-embed data: URIs',
                                "foo { /* @embed */ background: url($red); }",
                                "foo { background: url($red); }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Can not remap data: URIs',
                                "foo { background: url($red); }",
                                "foo { background: url($red); }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Can not embed remote URLs',
                                'foo { /* @embed */ background: url(http://example.org/w/foo.png); }',
                                'foo { background: url(http://example.org/w/foo.png); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Embedded file (inline @embed)',
                                'foo { background: /* @embed */ url(red.gif); }',
                                "foo { background: url($red); "
                                        . "background: url(http://localhost/w/red.gif?34ac6)!ie; }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Can not embed large files',
                                'foo { /* @embed */ background: url(large.png); }',
                                "foo { background: url(http://localhost/w/large.png?e3d1f); }",
-                       ),
-                       array(
+                       ],
+                       [
                                'SVG files are embedded without base64 encoding and unnecessary IE 6 and 7 fallback',
                                'foo { /* @embed */ background: url(circle.svg); }',
                                "foo { background: url($svg); }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Two regular files in one rule',
                                'foo { background: url(red.gif), url(green.gif); }',
                                'foo { background: url(http://localhost/w/red.gif?34ac6), '
                                        . 'url(http://localhost/w/green.gif?13651); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Two embedded files in one rule',
                                'foo { /* @embed */ background: url(red.gif), url(green.gif); }',
                                "foo { background: url($red), url($green); "
                                        . "background: url(http://localhost/w/red.gif?34ac6), "
                                        . "url(http://localhost/w/green.gif?13651)!ie; }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Two embedded files in one rule (inline @embed)',
                                'foo { background: /* @embed */ url(red.gif), /* @embed */ url(green.gif); }',
                                "foo { background: url($red), url($green); "
                                        . "background: url(http://localhost/w/red.gif?34ac6), "
                                        . "url(http://localhost/w/green.gif?13651)!ie; }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Two embedded files in one rule (inline @embed), one too large',
                                'foo { background: /* @embed */ url(red.gif), /* @embed */ url(large.png); }',
                                "foo { background: url($red), url(http://localhost/w/large.png?e3d1f); "
                                        . "background: url(http://localhost/w/red.gif?34ac6), "
                                        . "url(http://localhost/w/large.png?e3d1f)!ie; }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Practical example with some noise',
                                'foo { /* @embed */ background: #f9f9f9 url(red.gif) 0 0 no-repeat; }',
                                "foo { background: #f9f9f9 url($red) 0 0 no-repeat; "
                                        . "background: #f9f9f9 url(http://localhost/w/red.gif?34ac6) 0 0 no-repeat!ie; }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Does not mess with other properties',
                                'foo { color: red; background: url(red.gif); font-size: small; }',
                                'foo { color: red; background: url(http://localhost/w/red.gif?34ac6); font-size: small; }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Spacing and miscellanea not changed (1)',
                                'foo {   background:    url(red.gif);  }',
                                'foo {   background:    url(http://localhost/w/red.gif?34ac6);  }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Spacing and miscellanea not changed (2)',
                                'foo {background:url(red.gif)}',
                                'foo {background:url(http://localhost/w/red.gif?34ac6)}',
-                       ),
-                       array(
+                       ],
+                       [
                                'Spaces within url() parentheses are ignored',
                                'foo { background: url( red.gif ); }',
                                'foo { background: url(http://localhost/w/red.gif?34ac6); }',
-                       ),
-                       array(
+                       ],
+                       [
                                '@import rule to local file (should we remap this?)',
                                '@import url(/styles.css)',
                                '@import url(http://doc.example.org/styles.css)',
-                       ),
-                       array(
+                       ],
+                       [
                                '@import rule to URL (should we remap this?)',
                                '@import url(//localhost/styles.css?query=yes)',
                                '@import url(//localhost/styles.css?query=yes)',
-                       ),
-                       array(
+                       ],
+                       [
                                'Simple case with comments before url',
                                'foo { prop: /* some {funny;} comment */ url(bar.png); }',
                                'foo { prop: /* some {funny;} comment */ url(http://localhost/w/bar.png); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Simple case with comments after url',
                                'foo { prop: url(red.gif)/* some {funny;} comment */ ; }',
                                'foo { prop: url(http://localhost/w/red.gif?34ac6)/* some {funny;} comment */ ; }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Embedded file with comment before url',
                                'foo { /* @embed */ background: /* some {funny;} comment */ url(red.gif); }',
                                "foo { background: /* some {funny;} comment */ url($red); background: /* some {funny;} comment */ url(http://localhost/w/red.gif?34ac6)!ie; }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Embedded file with comments inside and outside the rule',
                                'foo { /* @embed */ background: url(red.gif) /* some {foo;} comment */; /* some {bar;} comment */ }',
                                "foo { background: url($red) /* some {foo;} comment */; background: url(http://localhost/w/red.gif?34ac6) /* some {foo;} comment */!ie; /* some {bar;} comment */ }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Embedded file with comment outside the rule',
                                'foo { /* @embed */ background: url(red.gif); /* some {funny;} comment */ }',
                                "foo { background: url($red); background: url(http://localhost/w/red.gif?34ac6)!ie; /* some {funny;} comment */ }",
-                       ),
-                       array(
+                       ],
+                       [
                                'Rule with two urls, each with comments',
                                '{ background: /*asd*/ url(something.png); background: /*jkl*/ url(something.png); }',
                                '{ background: /*asd*/ url(http://localhost/w/something.png); background: /*jkl*/ url(http://localhost/w/something.png); }',
-                       ),
-                       array(
+                       ],
+                       [
                                'Sanity check for offending line from jquery.ui.theme.css (bug 60077)',
                                '.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }',
                                '.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(http://localhost/w/images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }',
-                       ),
-               );
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 
index bf23890..f24b68b 100644 (file)
@@ -78,7 +78,10 @@ class GIFHandlerTest extends MediaWikiMediaTestCase {
                        [ null, GIFHandler::METADATA_BAD ],
                        [ 'Something invalid!', GIFHandler::METADATA_BAD ],
                        // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
-                       array( 'a:4:{s:10:"frameCount";i:1;s:6:"looped";b:0;s:8:"duration";d:0.1000000000000000055511151231257827021181583404541015625;s:8:"metadata";a:2:{s:14:"GIFFileComment";a:1:{i:0;s:35:"GIF test file ⁕ Created with GIMP";}s:15:"_MW_GIF_VERSION";i:1;}}', GIFHandler::METADATA_GOOD ),
+                       [
+                               'a:4:{s:10:"frameCount";i:1;s:6:"looped";b:0;s:8:"duration";d:0.1000000000000000055511151231257827021181583404541015625;s:8:"metadata";a:2:{s:14:"GIFFileComment";a:1:{i:0;s:35:"GIF test file ⁕ Created with GIMP";}s:15:"_MW_GIF_VERSION";i:1;}}',
+                               GIFHandler::METADATA_GOOD
+                       ],
                        // @codingStandardsIgnoreEnd
                ];
        }
@@ -98,8 +101,14 @@ class GIFHandlerTest extends MediaWikiMediaTestCase {
        public static function provideGetMetadata() {
                return [
                        // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
-                       array( 'nonanimated.gif', 'a:4:{s:10:"frameCount";i:1;s:6:"looped";b:0;s:8:"duration";d:0.1000000000000000055511151231257827021181583404541015625;s:8:"metadata";a:2:{s:14:"GIFFileComment";a:1:{i:0;s:35:"GIF test file ⁕ Created with GIMP";}s:15:"_MW_GIF_VERSION";i:1;}}' ),
-                       array( 'animated-xmp.gif', 'a:4:{s:10:"frameCount";i:4;s:6:"looped";b:1;s:8:"duration";d:2.399999999999999911182158029987476766109466552734375;s:8:"metadata";a:5:{s:6:"Artist";s:7:"Bawolff";s:16:"ImageDescription";a:2:{s:9:"x-default";s:18:"A file to test GIF";s:5:"_type";s:4:"lang";}s:15:"SublocationDest";s:13:"The interwebs";s:14:"GIFFileComment";a:1:{i:0;s:16:"GIƒ·test·file";}s:15:"_MW_GIF_VERSION";i:1;}}' ),
+                       [
+                               'nonanimated.gif',
+                               'a:4:{s:10:"frameCount";i:1;s:6:"looped";b:0;s:8:"duration";d:0.1000000000000000055511151231257827021181583404541015625;s:8:"metadata";a:2:{s:14:"GIFFileComment";a:1:{i:0;s:35:"GIF test file ⁕ Created with GIMP";}s:15:"_MW_GIF_VERSION";i:1;}}'
+                       ],
+                       [
+                               'animated-xmp.gif',
+                               'a:4:{s:10:"frameCount";i:4;s:6:"looped";b:1;s:8:"duration";d:2.399999999999999911182158029987476766109466552734375;s:8:"metadata";a:5:{s:6:"Artist";s:7:"Bawolff";s:16:"ImageDescription";a:2:{s:9:"x-default";s:18:"A file to test GIF";s:5:"_type";s:4:"lang";}s:15:"SublocationDest";s:13:"The interwebs";s:14:"GIFFileComment";a:1:{i:0;s:16:"GIƒ·test·file";}s:15:"_MW_GIF_VERSION";i:1;}}'
+                       ],
                        // @codingStandardsIgnoreEnd
                ];
        }
index 4417c4f..afc338e 100644 (file)
@@ -79,7 +79,10 @@ class PNGHandlerTest extends MediaWikiMediaTestCase {
                        [ null, PNGHandler::METADATA_BAD ],
                        [ 'Something invalid!', PNGHandler::METADATA_BAD ],
                        // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
-                       array( 'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:8;s:9:"colorType";s:10:"truecolour";s:8:"metadata";a:1:{s:15:"_MW_PNG_VERSION";i:1;}}', PNGHandler::METADATA_GOOD ),
+                       [
+                               'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:8;s:9:"colorType";s:10:"truecolour";s:8:"metadata";a:1:{s:15:"_MW_PNG_VERSION";i:1;}}',
+                               PNGHandler::METADATA_GOOD
+                       ],
                        // @codingStandardsIgnoreEnd
                ];
        }
@@ -100,8 +103,14 @@ class PNGHandlerTest extends MediaWikiMediaTestCase {
        public static function provideGetMetadata() {
                return [
                        // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
-                       array( 'rgb-na-png.png', 'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:8;s:9:"colorType";s:10:"truecolour";s:8:"metadata";a:1:{s:15:"_MW_PNG_VERSION";i:1;}}' ),
-                       array( 'xmp.png', 'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:1;s:9:"colorType";s:14:"index-coloured";s:8:"metadata";a:2:{s:12:"SerialNumber";s:9:"123456789";s:15:"_MW_PNG_VERSION";i:1;}}' ),
+                       [
+                               'rgb-na-png.png',
+                               'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:8;s:9:"colorType";s:10:"truecolour";s:8:"metadata";a:1:{s:15:"_MW_PNG_VERSION";i:1;}}'
+                       ],
+                       [
+                               'xmp.png',
+                               'a:6:{s:10:"frameCount";i:0;s:9:"loopCount";i:1;s:8:"duration";d:0;s:8:"bitDepth";i:1;s:9:"colorType";s:14:"index-coloured";s:8:"metadata";a:2:{s:12:"SerialNumber";s:9:"123456789";s:15:"_MW_PNG_VERSION";i:1;}}'
+                       ],
                        // @codingStandardsIgnoreEnd
                ];
        }
index dfa92f1..f51693d 100644 (file)
@@ -20,53 +20,53 @@ class WebPHandlerTest extends MediaWikiTestCase {
        }
        public function provideTestExtractMetaData() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
+               return [
                        // Files from https://developers.google.com/speed/webp/gallery2
-                       array( "\x52\x49\x46\x46\x90\x68\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x83\x68\x01\x00\x2F\x8F\x01\x4B\x10\x8D\x38\x6C\xDB\x46\x92\xE0\xE0\x82\x7B\x6C",
-                               array( 'compression' => 'lossless', 'width' => 400, 'height' => 301 ) ),
-                       array( "\x52\x49\x46\x46\x64\x5B\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x8F\x01\x00\x2C\x01\x00\x41\x4C\x50\x48\xE5\x0E",
-                               array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 400, 'height' => 301 ) ),
-                       array( "\x52\x49\x46\x46\xA8\x72\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x9B\x72\x00\x00\x2F\x81\x81\x62\x10\x8D\x40\x8C\x24\x39\x6E\x73\x73\x38\x01\x96",
-                               array( 'compression' => 'lossless', 'width' => 386, 'height' => 395 ) ),
-                       array( "\x52\x49\x46\x46\xE0\x42\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x81\x01\x00\x8A\x01\x00\x41\x4C\x50\x48\x56\x10",
-                               array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 386, 'height' => 395 ) ),
-                       array( "\x52\x49\x46\x46\x70\x61\x02\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x63\x61\x02\x00\x2F\x1F\xC3\x95\x10\x8D\xC8\x72\xDB\xC8\x92\x24\xD8\x91\xD9\x91",
-                               array( 'compression' => 'lossless', 'width' => 800, 'height' => 600 ) ),
-                       array( "\x52\x49\x46\x46\x1C\x1D\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x1F\x03\x00\x57\x02\x00\x41\x4C\x50\x48\x25\x8B",
-                               array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 800, 'height' => 600 ) ),
-                       array( "\x52\x49\x46\x46\xFA\xC5\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xEE\xC5\x00\x00\x2F\xA4\x81\x28\x10\x8D\x40\x68\x24\xC9\x91\xA4\xAE\xF3\x97\x75",
-                               array( 'compression' => 'lossless', 'width' => 421, 'height' => 163 ) ),
-                       array( "\x52\x49\x46\x46\xF6\x5D\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\xA4\x01\x00\xA2\x00\x00\x41\x4C\x50\x48\x38\x1A",
-                               array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 421, 'height' => 163 ) ),
-                       array( "\x52\x49\x46\x46\xC4\x96\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xB8\x96\x01\x00\x2F\x2B\xC1\x4A\x10\x11\x87\x6D\xDB\x48\x12\xFC\x60\xB0\x83\x24",
-                               array( 'compression' => 'lossless', 'width' => 300, 'height' => 300 ) ),
-                       array( "\x52\x49\x46\x46\x0A\x11\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x2B\x01\x00\x2B\x01\x00\x41\x4C\x50\x48\x67\x6E",
-                               array( 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 300, 'height' => 300 ) ),
+                       [ "\x52\x49\x46\x46\x90\x68\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x83\x68\x01\x00\x2F\x8F\x01\x4B\x10\x8D\x38\x6C\xDB\x46\x92\xE0\xE0\x82\x7B\x6C",
+                               [ 'compression' => 'lossless', 'width' => 400, 'height' => 301 ] ],
+                       [ "\x52\x49\x46\x46\x64\x5B\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x8F\x01\x00\x2C\x01\x00\x41\x4C\x50\x48\xE5\x0E",
+                               [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 400, 'height' => 301 ] ],
+                       [ "\x52\x49\x46\x46\xA8\x72\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x9B\x72\x00\x00\x2F\x81\x81\x62\x10\x8D\x40\x8C\x24\x39\x6E\x73\x73\x38\x01\x96",
+                               [ 'compression' => 'lossless', 'width' => 386, 'height' => 395 ] ],
+                       [ "\x52\x49\x46\x46\xE0\x42\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x81\x01\x00\x8A\x01\x00\x41\x4C\x50\x48\x56\x10",
+                               [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 386, 'height' => 395 ] ],
+                       [ "\x52\x49\x46\x46\x70\x61\x02\x00\x57\x45\x42\x50\x56\x50\x38\x4C\x63\x61\x02\x00\x2F\x1F\xC3\x95\x10\x8D\xC8\x72\xDB\xC8\x92\x24\xD8\x91\xD9\x91",
+                               [ 'compression' => 'lossless', 'width' => 800, 'height' => 600 ] ],
+                       [ "\x52\x49\x46\x46\x1C\x1D\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x1F\x03\x00\x57\x02\x00\x41\x4C\x50\x48\x25\x8B",
+                               [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 800, 'height' => 600 ] ],
+                       [ "\x52\x49\x46\x46\xFA\xC5\x00\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xEE\xC5\x00\x00\x2F\xA4\x81\x28\x10\x8D\x40\x68\x24\xC9\x91\xA4\xAE\xF3\x97\x75",
+                               [ 'compression' => 'lossless', 'width' => 421, 'height' => 163 ] ],
+                       [ "\x52\x49\x46\x46\xF6\x5D\x00\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\xA4\x01\x00\xA2\x00\x00\x41\x4C\x50\x48\x38\x1A",
+                               [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 421, 'height' => 163 ] ],
+                       [ "\x52\x49\x46\x46\xC4\x96\x01\x00\x57\x45\x42\x50\x56\x50\x38\x4C\xB8\x96\x01\x00\x2F\x2B\xC1\x4A\x10\x11\x87\x6D\xDB\x48\x12\xFC\x60\xB0\x83\x24",
+                               [ 'compression' => 'lossless', 'width' => 300, 'height' => 300 ] ],
+                       [ "\x52\x49\x46\x46\x0A\x11\x01\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x10\x00\x00\x00\x2B\x01\x00\x2B\x01\x00\x41\x4C\x50\x48\x67\x6E",
+                               [ 'compression' => 'unknown', 'animated' => false, 'transparency' => true, 'width' => 300, 'height' => 300 ] ],
 
                        // Lossy files from https://developers.google.com/speed/webp/gallery1
-                       array( "\x52\x49\x46\x46\x68\x76\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\x5C\x76\x00\x00\xD2\xBE\x01\x9D\x01\x2A\x26\x02\x70\x01\x3E\xD5\x4E\x97\x43\xA2",
-                               array( 'compression' => 'lossy', 'width' => 550, 'height' => 368 ) ),
-                       array( "\x52\x49\x46\x46\xB0\xEC\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\xA4\xEC\x00\x00\xB2\x4B\x02\x9D\x01\x2A\x26\x02\x94\x01\x3E\xD1\x50\x96\x46\x26",
-                               array( 'compression' => 'lossy', 'width' => 550, 'height' => 404 ) ),
-                       array( "\x52\x49\x46\x46\x7A\x19\x03\x00\x57\x45\x42\x50\x56\x50\x38\x20\x6E\x19\x03\x00\xB2\xF8\x09\x9D\x01\x2A\x00\x05\xD0\x02\x3E\xAD\x46\x99\x4A\xA5",
-                               array( 'compression' => 'lossy', 'width' => 1280, 'height' => 720 ) ),
-                       array( "\x52\x49\x46\x46\x44\xB3\x02\x00\x57\x45\x42\x50\x56\x50\x38\x20\x38\xB3\x02\x00\x52\x57\x06\x9D\x01\x2A\x00\x04\x04\x03\x3E\xA5\x44\x96\x49\x26",
-                               array( 'compression' => 'lossy', 'width' => 1024, 'height' => 772 ) ),
-                       array( "\x52\x49\x46\x46\x02\x43\x01\x00\x57\x45\x42\x50\x56\x50\x38\x20\xF6\x42\x01\x00\x12\xC0\x05\x9D\x01\x2A\x00\x04\xF0\x02\x3E\x79\x34\x93\x47\xA4",
-                               array( 'compression' => 'lossy', 'width' => 1024, 'height' => 752 ) ),
+                       [ "\x52\x49\x46\x46\x68\x76\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\x5C\x76\x00\x00\xD2\xBE\x01\x9D\x01\x2A\x26\x02\x70\x01\x3E\xD5\x4E\x97\x43\xA2",
+                               [ 'compression' => 'lossy', 'width' => 550, 'height' => 368 ] ],
+                       [ "\x52\x49\x46\x46\xB0\xEC\x00\x00\x57\x45\x42\x50\x56\x50\x38\x20\xA4\xEC\x00\x00\xB2\x4B\x02\x9D\x01\x2A\x26\x02\x94\x01\x3E\xD1\x50\x96\x46\x26",
+                               [ 'compression' => 'lossy', 'width' => 550, 'height' => 404 ] ],
+                       [ "\x52\x49\x46\x46\x7A\x19\x03\x00\x57\x45\x42\x50\x56\x50\x38\x20\x6E\x19\x03\x00\xB2\xF8\x09\x9D\x01\x2A\x00\x05\xD0\x02\x3E\xAD\x46\x99\x4A\xA5",
+                               [ 'compression' => 'lossy', 'width' => 1280, 'height' => 720 ] ],
+                       [ "\x52\x49\x46\x46\x44\xB3\x02\x00\x57\x45\x42\x50\x56\x50\x38\x20\x38\xB3\x02\x00\x52\x57\x06\x9D\x01\x2A\x00\x04\x04\x03\x3E\xA5\x44\x96\x49\x26",
+                               [ 'compression' => 'lossy', 'width' => 1024, 'height' => 772 ] ],
+                       [ "\x52\x49\x46\x46\x02\x43\x01\x00\x57\x45\x42\x50\x56\x50\x38\x20\xF6\x42\x01\x00\x12\xC0\x05\x9D\x01\x2A\x00\x04\xF0\x02\x3E\x79\x34\x93\x47\xA4",
+                               [ 'compression' => 'lossy', 'width' => 1024, 'height' => 752 ] ],
 
                        // Animated file from https://groups.google.com/a/chromium.org/d/topic/blink-dev/Y8tRC4mdQz8/discussion
-                       array( "\x52\x49\x46\x46\xD0\x0B\x02\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x12\x00\x00\x00\x3F\x01\x00\x3F\x01\x00\x41\x4E",
-                               array( 'compression' => 'unknown', 'animated' => true, 'transparency' => true, 'width' => 320, 'height' => 320 ) ),
+                       [ "\x52\x49\x46\x46\xD0\x0B\x02\x00\x57\x45\x42\x50\x56\x50\x38\x58\x0A\x00\x00\x00\x12\x00\x00\x00\x3F\x01\x00\x3F\x01\x00\x41\x4E",
+                               [ 'compression' => 'unknown', 'animated' => true, 'transparency' => true, 'width' => 320, 'height' => 320 ] ],
 
                        // Error cases
-                       array( '', false ),
-                       array( '                                    ', false ),
-                       array( 'RIFF                                ', false ),
-                       array( 'RIFF1234WEBP                        ', false ),
-                       array( 'RIFF1234WEBPVP8                     ', false ),
-                       array( 'RIFF1234WEBPVP8L                    ', false ),
-               );
+                       [ '', false ],
+                       [ '                                    ', false ],
+                       [ 'RIFF                                ', false ],
+                       [ 'RIFF1234WEBP                        ', false ],
+                       [ 'RIFF1234WEBPVP8                     ', false ],
+                       [ 'RIFF1234WEBPVP8L                    ', false ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 
index b0c1525..b1119a1 100644 (file)
@@ -433,6 +433,7 @@ class NewParserTest extends MediaWikiTestCase {
                        'wgThumbLimits' => [ self::getOptionValue( 'thumbsize', $opts, 180 ) ],
                        'wgMaxTocLevel' => $maxtoclevel,
                        'wgUseTeX' => isset( $opts['math'] ) || isset( $opts['texvc'] ),
+                       'wgWellFormedXml' => true,
                        'wgMathDirectory' => $uploadDir . '/math',
                        'wgDefaultLanguageVariant' => $variant,
                        'wgLinkHolderBatchSize' => $linkHolderBatchSize,
index e55b9e5..4204601 100644 (file)
@@ -29,93 +29,93 @@ class PreprocessorTest extends MediaWikiTestCase {
 
        public static function provideCases() {
                // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
-               return array(
-                       array( "Foo", "<root>Foo</root>" ),
-                       array( "<!-- Foo -->", "<root><comment>&lt;!-- Foo --&gt;</comment></root>" ),
-                       array( "<!-- Foo --><!-- Bar -->", "<root><comment>&lt;!-- Foo --&gt;</comment><comment>&lt;!-- Bar --&gt;</comment></root>" ),
-                       array( "<!-- Foo -->  <!-- Bar -->", "<root><comment>&lt;!-- Foo --&gt;</comment>  <comment>&lt;!-- Bar --&gt;</comment></root>" ),
-                       array( "<!-- Foo --> \n <!-- Bar -->", "<root><comment>&lt;!-- Foo --&gt;</comment> \n <comment>&lt;!-- Bar --&gt;</comment></root>" ),
-                       array( "<!-- Foo --> \n <!-- Bar -->\n", "<root><comment>&lt;!-- Foo --&gt;</comment> \n<comment> &lt;!-- Bar --&gt;\n</comment></root>" ),
-                       array( "<!-- Foo -->  <!-- Bar -->\n", "<root><comment>&lt;!-- Foo --&gt;</comment>  <comment>&lt;!-- Bar --&gt;</comment>\n</root>" ),
-                       array( "<!-->Bar", "<root><comment>&lt;!--&gt;Bar</comment></root>" ),
-                       array( "<!-- Comment -- comment", "<root><comment>&lt;!-- Comment -- comment</comment></root>" ),
-                       array( "== Foo ==\n  <!-- Bar -->\n== Baz ==\n", "<root><h level=\"2\" i=\"1\">== Foo ==</h>\n<comment>  &lt;!-- Bar --&gt;\n</comment><h level=\"2\" i=\"2\">== Baz ==</h>\n</root>" ),
-                       array( "<gallery/>", "<root><ext><name>gallery</name><attr></attr></ext></root>" ),
-                       array( "Foo <gallery/> Bar", "<root>Foo <ext><name>gallery</name><attr></attr></ext> Bar</root>" ),
-                       array( "<gallery></gallery>", "<root><ext><name>gallery</name><attr></attr><inner></inner><close>&lt;/gallery&gt;</close></ext></root>" ),
-                       array( "<foo> <gallery></gallery>", "<root>&lt;foo&gt; <ext><name>gallery</name><attr></attr><inner></inner><close>&lt;/gallery&gt;</close></ext></root>" ),
-                       array( "<foo> <gallery><gallery></gallery>", "<root>&lt;foo&gt; <ext><name>gallery</name><attr></attr><inner>&lt;gallery&gt;</inner><close>&lt;/gallery&gt;</close></ext></root>" ),
-                       array( "<noinclude> Foo bar </noinclude>", "<root><ignore>&lt;noinclude&gt;</ignore> Foo bar <ignore>&lt;/noinclude&gt;</ignore></root>" ),
-                       array( "<noinclude>\n{{Foo}}\n</noinclude>", "<root><ignore>&lt;noinclude&gt;</ignore>\n<template lineStart=\"1\"><title>Foo</title></template>\n<ignore>&lt;/noinclude&gt;</ignore></root>" ),
-                       array( "<noinclude>\n{{Foo}}\n</noinclude>\n", "<root><ignore>&lt;noinclude&gt;</ignore>\n<template lineStart=\"1\"><title>Foo</title></template>\n<ignore>&lt;/noinclude&gt;</ignore>\n</root>" ),
-                       array( "<gallery>foo bar", "<root><ext><name>gallery</name><attr></attr><inner>foo bar</inner></ext></root>" ),
-                       array( "<{{foo}}>", "<root>&lt;<template><title>foo</title></template>&gt;</root>" ),
-                       array( "<{{{foo}}}>", "<root>&lt;<tplarg><title>foo</title></tplarg>&gt;</root>" ),
-                       array( "<gallery></gallery</gallery>", "<root><ext><name>gallery</name><attr></attr><inner>&lt;/gallery</inner><close>&lt;/gallery&gt;</close></ext></root>" ),
-                       array( "=== Foo === ", "<root><h level=\"3\" i=\"1\">=== Foo === </h></root>" ),
-                       array( "==<!-- -->= Foo === ", "<root><h level=\"2\" i=\"1\">==<comment>&lt;!-- --&gt;</comment>= Foo === </h></root>" ),
-                       array( "=== Foo ==<!-- -->= ", "<root><h level=\"1\" i=\"1\">=== Foo ==<comment>&lt;!-- --&gt;</comment>= </h></root>" ),
-                       array( "=== Foo ===<!-- -->\n", "<root><h level=\"3\" i=\"1\">=== Foo ===<comment>&lt;!-- --&gt;</comment></h>\n</root>" ),
-                       array( "=== Foo ===<!-- --> <!-- -->\n", "<root><h level=\"3\" i=\"1\">=== Foo ===<comment>&lt;!-- --&gt;</comment> <comment>&lt;!-- --&gt;</comment></h>\n</root>" ),
-                       array( "== Foo ==\n== Bar == \n", "<root><h level=\"2\" i=\"1\">== Foo ==</h>\n<h level=\"2\" i=\"2\">== Bar == </h>\n</root>" ),
-                       array( "===========", "<root><h level=\"5\" i=\"1\">===========</h></root>" ),
-                       array( "Foo\n=\n==\n=\n", "<root>Foo\n=\n==\n=\n</root>" ),
-                       array( "{{Foo}}", "<root><template><title>Foo</title></template></root>" ),
-                       array( "\n{{Foo}}", "<root>\n<template lineStart=\"1\"><title>Foo</title></template></root>" ),
-                       array( "{{Foo|bar}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template></root>" ),
-                       array( "{{Foo|bar}}a", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template>a</root>" ),
-                       array( "{{Foo|bar|baz}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></template></root>" ),
-                       array( "{{Foo|1=bar}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part></template></root>" ),
-                       array( "{{Foo|=bar}}", "<root><template><title>Foo</title><part><name></name>=<value>bar</value></part></template></root>" ),
-                       array( "{{Foo|bar=baz}}", "<root><template><title>Foo</title><part><name>bar</name>=<value>baz</value></part></template></root>" ),
-                       array( "{{Foo|{{bar}}=baz}}", "<root><template><title>Foo</title><part><name><template><title>bar</title></template></name>=<value>baz</value></part></template></root>" ),
-                       array( "{{Foo|1=bar|baz}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name index=\"1\" /><value>baz</value></part></template></root>" ),
-                       array( "{{Foo|1=bar|2=baz}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name>2</name>=<value>baz</value></part></template></root>" ),
-                       array( "{{Foo|bar|foo=baz}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name>foo</name>=<value>baz</value></part></template></root>" ),
-                       array( "{{{1}}}", "<root><tplarg><title>1</title></tplarg></root>" ),
-                       array( "{{{1|}}}", "<root><tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ),
-                       array( "{{{Foo}}}", "<root><tplarg><title>Foo</title></tplarg></root>" ),
-                       array( "{{{Foo|}}}", "<root><tplarg><title>Foo</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ),
-                       array( "{{{Foo|bar|baz}}}", "<root><tplarg><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></tplarg></root>" ),
-                       array( "{<!-- -->{Foo}}", "<root>{<comment>&lt;!-- --&gt;</comment>{Foo}}</root>" ),
-                       array( "{{{{Foobar}}}}", "<root>{<tplarg><title>Foobar</title></tplarg>}</root>" ),
-                       array( "{{{ {{Foo}} }}}", "<root><tplarg><title> <template><title>Foo</title></template> </title></tplarg></root>" ),
-                       array( "{{ {{{Foo}}} }}", "<root><template><title> <tplarg><title>Foo</title></tplarg> </title></template></root>" ),
-                       array( "{{{{{Foo}}}}}", "<root><template><title><tplarg><title>Foo</title></tplarg></title></template></root>" ),
-                       array( "{{{{{Foo}} }}}", "<root><tplarg><title><template><title>Foo</title></template> </title></tplarg></root>" ),
-                       array( "{{{{{{Foo}}}}}}", "<root><tplarg><title><tplarg><title>Foo</title></tplarg></title></tplarg></root>" ),
-                       array( "{{{{{{Foo}}}}}", "<root>{<template><title><tplarg><title>Foo</title></tplarg></title></template></root>" ),
-                       array( "[[[Foo]]", "<root>[[[Foo]]</root>" ),
-                       array( "{{Foo|[[[[bar]]|baz]]}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>[[[[bar]]|baz]]</value></part></template></root>" ), // This test is important, since it means the difference between having the [[ rule stacked or not
-                       array( "{{Foo|[[[[bar]|baz]]}}", "<root>{{Foo|[[[[bar]|baz]]}}</root>" ),
-                       array( "{{Foo|Foo [[[[bar]|baz]]}}", "<root>{{Foo|Foo [[[[bar]|baz]]}}</root>" ),
-                       array( "Foo <display map>Bar</display map             >Baz", "<root>Foo <ext><name>display map</name><attr></attr><inner>Bar</inner><close>&lt;/display map             &gt;</close></ext>Baz</root>" ),
-                       array( "Foo <display map foo>Bar</display map             >Baz", "<root>Foo <ext><name>display map</name><attr> foo</attr><inner>Bar</inner><close>&lt;/display map             &gt;</close></ext>Baz</root>" ),
-                       array( "Foo <gallery bar=\"baz\" />", "<root>Foo <ext><name>gallery</name><attr> bar=&quot;baz&quot; </attr></ext></root>" ),
-                       array( "Foo <gallery bar=\"1\" baz=2 />", "<root>Foo <ext><name>gallery</name><attr> bar=&quot;1&quot; baz=2 </attr></ext></root>" ),
-                       array( "</foo>Foo<//foo>", "<root><ext><name>/foo</name><attr></attr><inner>Foo</inner><close>&lt;//foo&gt;</close></ext></root>" ), # Worth blacklisting IMHO
-                       array( "{{#ifexpr: ({{{1|1}}} = 2) | Foo | Bar }}", "<root><template><title>#ifexpr: (<tplarg><title>1</title><part><name index=\"1\" /><value>1</value></part></tplarg> = 2) </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>" ),
-                       array( "{{#if: {{{1|}}} | Foo | {{Bar}} }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> <template><title>Bar</title></template> </value></part></template></root>" ),
-                       array( "{{#if: {{{1|}}} | Foo | [[Bar]] }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> [[Bar]] </value></part></template></root>" ),
-                       array( "{{#if: {{{1|}}} | [[Foo]] | Bar }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> [[Foo]] </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>" ),
-                       array( "{{#if: {{{1|}}} | 1 | {{#if: {{{1|}}} | 2 | 3 }} }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 1 </value></part><part><name index=\"2\" /><value> <template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 2 </value></part><part><name index=\"2\" /><value> 3 </value></part></template> </value></part></template></root>" ),
-                       array( "{{ {{Foo}}", "<root>{{ <template><title>Foo</title></template></root>" ),
-                       array( "{{Foobar {{Foo}} {{Bar}} {{Baz}} ", "<root>{{Foobar <template><title>Foo</title></template> <template><title>Bar</title></template> <template><title>Baz</title></template> </root>" ),
-                       array( "[[Foo]] |", "<root>[[Foo]] |</root>" ),
-                       array( "{{Foo|Bar|", "<root>{{Foo|Bar|</root>" ),
-                       array( "[[Foo]", "<root>[[Foo]</root>" ),
-                       array( "[[Foo|Bar]", "<root>[[Foo|Bar]</root>" ),
-                       array( "{{Foo| [[Bar] }}", "<root>{{Foo| [[Bar] }}</root>" ),
-                       array( "{{Foo| [[Bar|Baz] }}", "<root>{{Foo| [[Bar|Baz] }}</root>" ),
-                       array( "{{Foo|bar=[[baz]}}", "<root>{{Foo|bar=[[baz]}}</root>" ),
-                       array( "{{foo|", "<root>{{foo|</root>" ),
-                       array( "{{foo|}", "<root>{{foo|}</root>" ),
-                       array( "{{foo|} }}", "<root><template><title>foo</title><part><name index=\"1\" /><value>} </value></part></template></root>" ),
-                       array( "{{foo|bar=|}", "<root>{{foo|bar=|}</root>" ),
-                       array( "{{Foo|} Bar=", "<root>{{Foo|} Bar=</root>" ),
-                       array( "{{Foo|} Bar=}}", "<root><template><title>Foo</title><part><name>} Bar</name>=<value></value></part></template></root>" ),
-                       /* array( file_get_contents( __DIR__ . '/QuoteQuran.txt' ), file_get_contents( __DIR__ . '/QuoteQuranExpanded.txt' ) ), */
-               );
+               return [
+                       [ "Foo", "<root>Foo</root>" ],
+                       [ "<!-- Foo -->", "<root><comment>&lt;!-- Foo --&gt;</comment></root>" ],
+                       [ "<!-- Foo --><!-- Bar -->", "<root><comment>&lt;!-- Foo --&gt;</comment><comment>&lt;!-- Bar --&gt;</comment></root>" ],
+                       [ "<!-- Foo -->  <!-- Bar -->", "<root><comment>&lt;!-- Foo --&gt;</comment>  <comment>&lt;!-- Bar --&gt;</comment></root>" ],
+                       [ "<!-- Foo --> \n <!-- Bar -->", "<root><comment>&lt;!-- Foo --&gt;</comment> \n <comment>&lt;!-- Bar --&gt;</comment></root>" ],
+                       [ "<!-- Foo --> \n <!-- Bar -->\n", "<root><comment>&lt;!-- Foo --&gt;</comment> \n<comment> &lt;!-- Bar --&gt;\n</comment></root>" ],
+                       [ "<!-- Foo -->  <!-- Bar -->\n", "<root><comment>&lt;!-- Foo --&gt;</comment>  <comment>&lt;!-- Bar --&gt;</comment>\n</root>" ],
+                       [ "<!-->Bar", "<root><comment>&lt;!--&gt;Bar</comment></root>" ],
+                       [ "<!-- Comment -- comment", "<root><comment>&lt;!-- Comment -- comment</comment></root>" ],
+                       [ "== Foo ==\n  <!-- Bar -->\n== Baz ==\n", "<root><h level=\"2\" i=\"1\">== Foo ==</h>\n<comment>  &lt;!-- Bar --&gt;\n</comment><h level=\"2\" i=\"2\">== Baz ==</h>\n</root>" ],
+                       [ "<gallery/>", "<root><ext><name>gallery</name><attr></attr></ext></root>" ],
+                       [ "Foo <gallery/> Bar", "<root>Foo <ext><name>gallery</name><attr></attr></ext> Bar</root>" ],
+                       [ "<gallery></gallery>", "<root><ext><name>gallery</name><attr></attr><inner></inner><close>&lt;/gallery&gt;</close></ext></root>" ],
+                       [ "<foo> <gallery></gallery>", "<root>&lt;foo&gt; <ext><name>gallery</name><attr></attr><inner></inner><close>&lt;/gallery&gt;</close></ext></root>" ],
+                       [ "<foo> <gallery><gallery></gallery>", "<root>&lt;foo&gt; <ext><name>gallery</name><attr></attr><inner>&lt;gallery&gt;</inner><close>&lt;/gallery&gt;</close></ext></root>" ],
+                       [ "<noinclude> Foo bar </noinclude>", "<root><ignore>&lt;noinclude&gt;</ignore> Foo bar <ignore>&lt;/noinclude&gt;</ignore></root>" ],
+                       [ "<noinclude>\n{{Foo}}\n</noinclude>", "<root><ignore>&lt;noinclude&gt;</ignore>\n<template lineStart=\"1\"><title>Foo</title></template>\n<ignore>&lt;/noinclude&gt;</ignore></root>" ],
+                       [ "<noinclude>\n{{Foo}}\n</noinclude>\n", "<root><ignore>&lt;noinclude&gt;</ignore>\n<template lineStart=\"1\"><title>Foo</title></template>\n<ignore>&lt;/noinclude&gt;</ignore>\n</root>" ],
+                       [ "<gallery>foo bar", "<root><ext><name>gallery</name><attr></attr><inner>foo bar</inner></ext></root>" ],
+                       [ "<{{foo}}>", "<root>&lt;<template><title>foo</title></template>&gt;</root>" ],
+                       [ "<{{{foo}}}>", "<root>&lt;<tplarg><title>foo</title></tplarg>&gt;</root>" ],
+                       [ "<gallery></gallery</gallery>", "<root><ext><name>gallery</name><attr></attr><inner>&lt;/gallery</inner><close>&lt;/gallery&gt;</close></ext></root>" ],
+                       [ "=== Foo === ", "<root><h level=\"3\" i=\"1\">=== Foo === </h></root>" ],
+                       [ "==<!-- -->= Foo === ", "<root><h level=\"2\" i=\"1\">==<comment>&lt;!-- --&gt;</comment>= Foo === </h></root>" ],
+                       [ "=== Foo ==<!-- -->= ", "<root><h level=\"1\" i=\"1\">=== Foo ==<comment>&lt;!-- --&gt;</comment>= </h></root>" ],
+                       [ "=== Foo ===<!-- -->\n", "<root><h level=\"3\" i=\"1\">=== Foo ===<comment>&lt;!-- --&gt;</comment></h>\n</root>" ],
+                       [ "=== Foo ===<!-- --> <!-- -->\n", "<root><h level=\"3\" i=\"1\">=== Foo ===<comment>&lt;!-- --&gt;</comment> <comment>&lt;!-- --&gt;</comment></h>\n</root>" ],
+                       [ "== Foo ==\n== Bar == \n", "<root><h level=\"2\" i=\"1\">== Foo ==</h>\n<h level=\"2\" i=\"2\">== Bar == </h>\n</root>" ],
+                       [ "===========", "<root><h level=\"5\" i=\"1\">===========</h></root>" ],
+                       [ "Foo\n=\n==\n=\n", "<root>Foo\n=\n==\n=\n</root>" ],
+                       [ "{{Foo}}", "<root><template><title>Foo</title></template></root>" ],
+                       [ "\n{{Foo}}", "<root>\n<template lineStart=\"1\"><title>Foo</title></template></root>" ],
+                       [ "{{Foo|bar}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template></root>" ],
+                       [ "{{Foo|bar}}a", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part></template>a</root>" ],
+                       [ "{{Foo|bar|baz}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></template></root>" ],
+                       [ "{{Foo|1=bar}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part></template></root>" ],
+                       [ "{{Foo|=bar}}", "<root><template><title>Foo</title><part><name></name>=<value>bar</value></part></template></root>" ],
+                       [ "{{Foo|bar=baz}}", "<root><template><title>Foo</title><part><name>bar</name>=<value>baz</value></part></template></root>" ],
+                       [ "{{Foo|{{bar}}=baz}}", "<root><template><title>Foo</title><part><name><template><title>bar</title></template></name>=<value>baz</value></part></template></root>" ],
+                       [ "{{Foo|1=bar|baz}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name index=\"1\" /><value>baz</value></part></template></root>" ],
+                       [ "{{Foo|1=bar|2=baz}}", "<root><template><title>Foo</title><part><name>1</name>=<value>bar</value></part><part><name>2</name>=<value>baz</value></part></template></root>" ],
+                       [ "{{Foo|bar|foo=baz}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name>foo</name>=<value>baz</value></part></template></root>" ],
+                       [ "{{{1}}}", "<root><tplarg><title>1</title></tplarg></root>" ],
+                       [ "{{{1|}}}", "<root><tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ],
+                       [ "{{{Foo}}}", "<root><tplarg><title>Foo</title></tplarg></root>" ],
+                       [ "{{{Foo|}}}", "<root><tplarg><title>Foo</title><part><name index=\"1\" /><value></value></part></tplarg></root>" ],
+                       [ "{{{Foo|bar|baz}}}", "<root><tplarg><title>Foo</title><part><name index=\"1\" /><value>bar</value></part><part><name index=\"2\" /><value>baz</value></part></tplarg></root>" ],
+                       [ "{<!-- -->{Foo}}", "<root>{<comment>&lt;!-- --&gt;</comment>{Foo}}</root>" ],
+                       [ "{{{{Foobar}}}}", "<root>{<tplarg><title>Foobar</title></tplarg>}</root>" ],
+                       [ "{{{ {{Foo}} }}}", "<root><tplarg><title> <template><title>Foo</title></template> </title></tplarg></root>" ],
+                       [ "{{ {{{Foo}}} }}", "<root><template><title> <tplarg><title>Foo</title></tplarg> </title></template></root>" ],
+                       [ "{{{{{Foo}}}}}", "<root><template><title><tplarg><title>Foo</title></tplarg></title></template></root>" ],
+                       [ "{{{{{Foo}} }}}", "<root><tplarg><title><template><title>Foo</title></template> </title></tplarg></root>" ],
+                       [ "{{{{{{Foo}}}}}}", "<root><tplarg><title><tplarg><title>Foo</title></tplarg></title></tplarg></root>" ],
+                       [ "{{{{{{Foo}}}}}", "<root>{<template><title><tplarg><title>Foo</title></tplarg></title></template></root>" ],
+                       [ "[[[Foo]]", "<root>[[[Foo]]</root>" ],
+                       [ "{{Foo|[[[[bar]]|baz]]}}", "<root><template><title>Foo</title><part><name index=\"1\" /><value>[[[[bar]]|baz]]</value></part></template></root>" ], // This test is important, since it means the difference between having the [[ rule stacked or not
+                       [ "{{Foo|[[[[bar]|baz]]}}", "<root>{{Foo|[[[[bar]|baz]]}}</root>" ],
+                       [ "{{Foo|Foo [[[[bar]|baz]]}}", "<root>{{Foo|Foo [[[[bar]|baz]]}}</root>" ],
+                       [ "Foo <display map>Bar</display map             >Baz", "<root>Foo <ext><name>display map</name><attr></attr><inner>Bar</inner><close>&lt;/display map             &gt;</close></ext>Baz</root>" ],
+                       [ "Foo <display map foo>Bar</display map             >Baz", "<root>Foo <ext><name>display map</name><attr> foo</attr><inner>Bar</inner><close>&lt;/display map             &gt;</close></ext>Baz</root>" ],
+                       [ "Foo <gallery bar=\"baz\" />", "<root>Foo <ext><name>gallery</name><attr> bar=&quot;baz&quot; </attr></ext></root>" ],
+                       [ "Foo <gallery bar=\"1\" baz=2 />", "<root>Foo <ext><name>gallery</name><attr> bar=&quot;1&quot; baz=2 </attr></ext></root>" ],
+                       [ "</foo>Foo<//foo>", "<root><ext><name>/foo</name><attr></attr><inner>Foo</inner><close>&lt;//foo&gt;</close></ext></root>" ], # Worth blacklisting IMHO
+                       [ "{{#ifexpr: ({{{1|1}}} = 2) | Foo | Bar }}", "<root><template><title>#ifexpr: (<tplarg><title>1</title><part><name index=\"1\" /><value>1</value></part></tplarg> = 2) </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>" ],
+                       [ "{{#if: {{{1|}}} | Foo | {{Bar}} }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> <template><title>Bar</title></template> </value></part></template></root>" ],
+                       [ "{{#if: {{{1|}}} | Foo | [[Bar]] }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> Foo </value></part><part><name index=\"2\" /><value> [[Bar]] </value></part></template></root>" ],
+                       [ "{{#if: {{{1|}}} | [[Foo]] | Bar }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> [[Foo]] </value></part><part><name index=\"2\" /><value> Bar </value></part></template></root>" ],
+                       [ "{{#if: {{{1|}}} | 1 | {{#if: {{{1|}}} | 2 | 3 }} }}", "<root><template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 1 </value></part><part><name index=\"2\" /><value> <template><title>#if: <tplarg><title>1</title><part><name index=\"1\" /><value></value></part></tplarg> </title><part><name index=\"1\" /><value> 2 </value></part><part><name index=\"2\" /><value> 3 </value></part></template> </value></part></template></root>" ],
+                       [ "{{ {{Foo}}", "<root>{{ <template><title>Foo</title></template></root>" ],
+                       [ "{{Foobar {{Foo}} {{Bar}} {{Baz}} ", "<root>{{Foobar <template><title>Foo</title></template> <template><title>Bar</title></template> <template><title>Baz</title></template> </root>" ],
+                       [ "[[Foo]] |", "<root>[[Foo]] |</root>" ],
+                       [ "{{Foo|Bar|", "<root>{{Foo|Bar|</root>" ],
+                       [ "[[Foo]", "<root>[[Foo]</root>" ],
+                       [ "[[Foo|Bar]", "<root>[[Foo|Bar]</root>" ],
+                       [ "{{Foo| [[Bar] }}", "<root>{{Foo| [[Bar] }}</root>" ],
+                       [ "{{Foo| [[Bar|Baz] }}", "<root>{{Foo| [[Bar|Baz] }}</root>" ],
+                       [ "{{Foo|bar=[[baz]}}", "<root>{{Foo|bar=[[baz]}}</root>" ],
+                       [ "{{foo|", "<root>{{foo|</root>" ],
+                       [ "{{foo|}", "<root>{{foo|}</root>" ],
+                       [ "{{foo|} }}", "<root><template><title>foo</title><part><name index=\"1\" /><value>} </value></part></template></root>" ],
+                       [ "{{foo|bar=|}", "<root>{{foo|bar=|}</root>" ],
+                       [ "{{Foo|} Bar=", "<root>{{Foo|} Bar=</root>" ],
+                       [ "{{Foo|} Bar=}}", "<root><template><title>Foo</title><part><name>} Bar</name>=<value></value></part></template></root>" ],
+                       /* [ file_get_contents( __DIR__ . '/QuoteQuran.txt' ], file_get_contents( __DIR__ . '/QuoteQuranExpanded.txt' ) ], */
+               ];
                // @codingStandardsIgnoreEnd
        }
 
@@ -162,13 +162,13 @@ class PreprocessorTest extends MediaWikiTestCase {
         */
        public static function provideFiles() {
                // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
-               return array(
-                       array( "QuoteQuran" ), # http://en.wikipedia.org/w/index.php?title=Template:QuoteQuran/sandbox&oldid=237348988 GFDL + CC BY-SA by Striver
-                       array( "Factorial" ), # http://en.wikipedia.org/w/index.php?title=Template:Factorial&oldid=98548758 GFDL + CC BY-SA by Polonium
-                       array( "All_system_messages" ), # http://tl.wiktionary.org/w/index.php?title=Suleras:All_system_messages&oldid=2765 GPL text generated by MediaWiki
-                       array( "Fundraising" ), # http://tl.wiktionary.org/w/index.php?title=MediaWiki:Sitenotice&oldid=5716 GFDL + CC BY-SA, copied there by Sky Harbor.
-                       array( "NestedTemplates" ), # bug 27936
-               );
+               return [
+                       [ "QuoteQuran" ], # http://en.wikipedia.org/w/index.php?title=Template:QuoteQuran/sandbox&oldid=237348988 GFDL + CC BY-SA by Striver
+                       [ "Factorial" ], # http://en.wikipedia.org/w/index.php?title=Template:Factorial&oldid=98548758 GFDL + CC BY-SA by Polonium
+                       [ "All_system_messages" ], # http://tl.wiktionary.org/w/index.php?title=Suleras:All_system_messages&oldid=2765 GPL text generated by MediaWiki
+                       [ "Fundraising" ], # http://tl.wiktionary.org/w/index.php?title=MediaWiki:Sitenotice&oldid=5716 GFDL + CC BY-SA, copied there by Sky Harbor.
+                       [ "NestedTemplates" ], # bug 27936
+               ];
                // @codingStandardsIgnoreEnd
        }
 
@@ -197,43 +197,43 @@ class PreprocessorTest extends MediaWikiTestCase {
         */
        public static function provideHeadings() {
                // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
-               return array( /* These should become headings: */
-                       array( "== h ==<!--c1-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment></h></root>" ),
-                       array( "== h ==         <!--c1-->", "<root><h level=\"2\" i=\"1\">== h ==       <comment>&lt;!--c1--&gt;</comment></h></root>" ),
-                       array( "== h ==<!--c1-->        ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>      </h></root>" ),
-                       array( "== h ==         <!--c1-->       ", "<root><h level=\"2\" i=\"1\">== h ==        <comment>&lt;!--c1--&gt;</comment>      </h></root>" ),
-                       array( "== h ==<!--c1--><!--c2-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment></h></root>" ),
-                       array( "== h ==         <!--c1--><!--c2-->", "<root><h level=\"2\" i=\"1\">== h ==      <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment></h></root>" ),
-                       array( "== h ==<!--c1--><!--c2-->       ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>    </h></root>" ),
-                       array( "== h ==         <!--c1--><!--c2-->      ", "<root><h level=\"2\" i=\"1\">== h ==        <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>    </h></root>" ),
-                       array( "== h ==         <!--c1-->  <!--c2-->", "<root><h level=\"2\" i=\"1\">== h ==    <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment></h></root>" ),
-                       array( "== h ==<!--c1-->  <!--c2-->     ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  </h></root>" ),
-                       array( "== h ==         <!--c1-->  <!--c2-->    ", "<root><h level=\"2\" i=\"1\">== h ==        <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  </h></root>" ),
-                       array( "== h ==<!--c1--><!--c2--><!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment></h></root>" ),
-                       array( "== h ==<!--c1-->  <!--c2--><!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment></h></root>" ),
-                       array( "== h ==<!--c1--><!--c2-->  <!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment></h></root>" ),
-                       array( "== h ==<!--c1-->  <!--c2-->  <!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment></h></root>" ),
-                       array( "== h ==  <!--c1--><!--c2--><!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment></h></root>" ),
-                       array( "== h ==  <!--c1-->  <!--c2--><!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment></h></root>" ),
-                       array( "== h ==  <!--c1--><!--c2-->  <!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment></h></root>" ),
-                       array( "== h ==  <!--c1-->  <!--c2-->  <!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment></h></root>" ),
-                       array( "== h ==<!--c1--><!--c2--><!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </h></root>" ),
-                       array( "== h ==<!--c1-->  <!--c2--><!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </h></root>" ),
-                       array( "== h ==<!--c1--><!--c2-->  <!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment>  </h></root>" ),
-                       array( "== h ==<!--c1-->  <!--c2-->  <!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment>  </h></root>" ),
-                       array( "== h ==  <!--c1--><!--c2--><!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </h></root>" ),
-                       array( "== h ==  <!--c1-->  <!--c2--><!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </h></root>" ),
-                       array( "== h ==  <!--c1--><!--c2-->  <!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment>  </h></root>" ),
-                       array( "== h ==  <!--c1-->  <!--c2-->  <!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment>  </h></root>" ),
-                       array( "== h ==<!--c1-->        <!--c2-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>     <comment>&lt;!--c2--&gt;</comment></h></root>" ),
-                       array( "== h ==         <!--c1-->       <!--c2-->", "<root><h level=\"2\" i=\"1\">== h ==       <comment>&lt;!--c1--&gt;</comment>      <comment>&lt;!--c2--&gt;</comment></h></root>" ),
-                       array( "== h ==<!--c1-->        <!--c2-->       ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>      <comment>&lt;!--c2--&gt;</comment>      </h></root>" ),
+               return [ /* These should become headings: */
+                       [ "== h ==<!--c1-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment></h></root>" ],
+                       [ "== h ==      <!--c1-->", "<root><h level=\"2\" i=\"1\">== h ==       <comment>&lt;!--c1--&gt;</comment></h></root>" ],
+                       [ "== h ==<!--c1-->     ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>      </h></root>" ],
+                       [ "== h ==      <!--c1-->       ", "<root><h level=\"2\" i=\"1\">== h ==        <comment>&lt;!--c1--&gt;</comment>      </h></root>" ],
+                       [ "== h ==<!--c1--><!--c2-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment></h></root>" ],
+                       [ "== h ==      <!--c1--><!--c2-->", "<root><h level=\"2\" i=\"1\">== h ==      <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment></h></root>" ],
+                       [ "== h ==<!--c1--><!--c2-->    ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>    </h></root>" ],
+                       [ "== h ==      <!--c1--><!--c2-->      ", "<root><h level=\"2\" i=\"1\">== h ==        <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>    </h></root>" ],
+                       [ "== h ==      <!--c1-->  <!--c2-->", "<root><h level=\"2\" i=\"1\">== h ==    <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment></h></root>" ],
+                       [ "== h ==<!--c1-->  <!--c2-->  ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  </h></root>" ],
+                       [ "== h ==      <!--c1-->  <!--c2-->    ", "<root><h level=\"2\" i=\"1\">== h ==        <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  </h></root>" ],
+                       [ "== h ==<!--c1--><!--c2--><!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment></h></root>" ],
+                       [ "== h ==<!--c1-->  <!--c2--><!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment></h></root>" ],
+                       [ "== h ==<!--c1--><!--c2-->  <!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment></h></root>" ],
+                       [ "== h ==<!--c1-->  <!--c2-->  <!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment></h></root>" ],
+                       [ "== h ==  <!--c1--><!--c2--><!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment></h></root>" ],
+                       [ "== h ==  <!--c1-->  <!--c2--><!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment></h></root>" ],
+                       [ "== h ==  <!--c1--><!--c2-->  <!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment></h></root>" ],
+                       [ "== h ==  <!--c1-->  <!--c2-->  <!--c3-->", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment></h></root>" ],
+                       [ "== h ==<!--c1--><!--c2--><!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </h></root>" ],
+                       [ "== h ==<!--c1-->  <!--c2--><!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </h></root>" ],
+                       [ "== h ==<!--c1--><!--c2-->  <!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment>  </h></root>" ],
+                       [ "== h ==<!--c1-->  <!--c2-->  <!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment>  </h></root>" ],
+                       [ "== h ==  <!--c1--><!--c2--><!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </h></root>" ],
+                       [ "== h ==  <!--c1-->  <!--c2--><!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </h></root>" ],
+                       [ "== h ==  <!--c1--><!--c2-->  <!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment>  </h></root>" ],
+                       [ "== h ==  <!--c1-->  <!--c2-->  <!--c3-->  ", "<root><h level=\"2\" i=\"1\">== h ==  <comment>&lt;!--c1--&gt;</comment>  <comment>&lt;!--c2--&gt;</comment>  <comment>&lt;!--c3--&gt;</comment>  </h></root>" ],
+                       [ "== h ==<!--c1-->     <!--c2-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>     <comment>&lt;!--c2--&gt;</comment></h></root>" ],
+                       [ "== h ==      <!--c1-->       <!--c2-->", "<root><h level=\"2\" i=\"1\">== h ==       <comment>&lt;!--c1--&gt;</comment>      <comment>&lt;!--c2--&gt;</comment></h></root>" ],
+                       [ "== h ==<!--c1-->     <!--c2-->       ", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment>      <comment>&lt;!--c2--&gt;</comment>      </h></root>" ],
 
                        /* These are not working: */
-                       array( "== h == x <!--c1--><!--c2--><!--c3-->  ", "<root>== h == x <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </root>" ),
-                       array( "== h ==<!--c1--> x <!--c2--><!--c3-->  ", "<root>== h ==<comment>&lt;!--c1--&gt;</comment> x <comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </root>" ),
-                       array( "== h ==<!--c1--><!--c2--><!--c3--> x ", "<root>== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment> x </root>" ),
-               );
+                       [ "== h == x <!--c1--><!--c2--><!--c3-->  ", "<root>== h == x <comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </root>" ],
+                       [ "== h ==<!--c1--> x <!--c2--><!--c3-->  ", "<root>== h ==<comment>&lt;!--c1--&gt;</comment> x <comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment>  </root>" ],
+                       [ "== h ==<!--c1--><!--c2--><!--c3--> x ", "<root>== h ==<comment>&lt;!--c1--&gt;</comment><comment>&lt;!--c2--&gt;</comment><comment>&lt;!--c3--&gt;</comment> x </root>" ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 
index d6940b5..8f80362 100644 (file)
@@ -13,28 +13,28 @@ class BcryptPasswordTest extends PasswordTestCase {
 
        public static function providePasswordTests() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
+               return [
                        // Tests from glibc bcrypt implementation
-                       array( true, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "U*U" ),
-                       array( true, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$VGOzA784oUp/Z0DY336zx7pLYAy0lwK', "U*U*" ),
-                       array( true, ':bcrypt:5$XXXXXXXXXXXXXXXXXXXXXO$AcXxm9kjPGEMsLznoKqmqw7tc8WCx4a', "U*U*U" ),
-                       array( true, ':bcrypt:5$abcdefghijklmnopqrstuu$5s2v8.iXieOjg/.AySBTTZIIVFJeBui', "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789chars after 72 are ignored" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$CE5elHaaO4EbggVDjb8P19RukzXSM3e', "\xff\xff\xa3" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq', "\xa3" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq', "\xa3" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$o./n25XVfn6oAPaUvHe.Csk4zRfsYPi', "\xff\xa334\xff\xff\xff\xa3345" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$nRht2l/HRhr6zmCp9vYUvvsqynflf9e', "\xff\xa3345" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$nRht2l/HRhr6zmCp9vYUvvsqynflf9e', "\xff\xa3345" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$6IflQkJytoRVc1yuaNtHfiuq.FRlSIS', "\xa3ab" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$6IflQkJytoRVc1yuaNtHfiuq.FRlSIS', "\xa3ab" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6', "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaachars after 72 are ignored as usual" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy', "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" ),
-                       array( true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe', "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" ),
-                       array( true, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy', "" ),
+                       [ true, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "U*U" ],
+                       [ true, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$VGOzA784oUp/Z0DY336zx7pLYAy0lwK', "U*U*" ],
+                       [ true, ':bcrypt:5$XXXXXXXXXXXXXXXXXXXXXO$AcXxm9kjPGEMsLznoKqmqw7tc8WCx4a', "U*U*U" ],
+                       [ true, ':bcrypt:5$abcdefghijklmnopqrstuu$5s2v8.iXieOjg/.AySBTTZIIVFJeBui', "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789chars after 72 are ignored" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$CE5elHaaO4EbggVDjb8P19RukzXSM3e', "\xff\xff\xa3" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq', "\xa3" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$Sa7shbm4.OzKpvFnX1pQLmQW96oUlCq', "\xa3" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$o./n25XVfn6oAPaUvHe.Csk4zRfsYPi', "\xff\xa334\xff\xff\xff\xa3345" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$nRht2l/HRhr6zmCp9vYUvvsqynflf9e', "\xff\xa3345" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$nRht2l/HRhr6zmCp9vYUvvsqynflf9e', "\xff\xa3345" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$6IflQkJytoRVc1yuaNtHfiuq.FRlSIS', "\xa3ab" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$6IflQkJytoRVc1yuaNtHfiuq.FRlSIS', "\xa3ab" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$swQOIzjOiJ9GHEPuhEkvqrUyvWhEMx6', "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaachars after 72 are ignored as usual" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$R9xrDjiycxMbQE2bp.vgqlYpW5wx2yy', "\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55\xaa\x55" ],
+                       [ true, ':bcrypt:5$/OK.fbVrR/bpIqNJ5ianF.$9tQZzcJfm3uj2NvJ/n5xkhpqLrMpWCe', "\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff\x55\xaa\xff" ],
+                       [ true, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy', "" ],
                        // One or two false sanity tests
-                       array( false, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "UXU" ),
-                       array( false, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "" ),
-               );
+                       [ false, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "UXU" ],
+                       [ false, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "" ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 }
index cccec5f..773f033 100644 (file)
@@ -28,9 +28,13 @@ class LayeredParameterizedPasswordTest extends PasswordTestCase {
 
        public static function providePasswordTests() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
-               return array(
-                       array( true, ':testLargeLayeredTop:sha512:1024:512!sha512:1024:512!sha512:1024:512!sha512:1024:512!5!vnRy+2SrSA0fHt3dwhTP5g==!AVnwfZsAQjn+gULv7FSGjA==!xvHUX3WcpkeSn1lvjWcvBg==!It+OC/N9tu+d3ByHhuB0BQ==!Tb.gqUOiD.aWktVwHM.Q/O!7CcyMfXUPky5ptyATJsR2nq3vUqtnBC', 'testPassword123' ),
-               );
+               return [
+                       [
+                               true,
+                               ':testLargeLayeredTop:sha512:1024:512!sha512:1024:512!sha512:1024:512!sha512:1024:512!5!vnRy+2SrSA0fHt3dwhTP5g==!AVnwfZsAQjn+gULv7FSGjA==!xvHUX3WcpkeSn1lvjWcvBg==!It+OC/N9tu+d3ByHhuB0BQ==!Tb.gqUOiD.aWktVwHM.Q/O!7CcyMfXUPky5ptyATJsR2nq3vUqtnBC',
+                               'testPassword123' 
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 
index d76d9df..edab0dc 100644 (file)
@@ -33,8 +33,8 @@ class BotPasswordSessionProviderTest extends MediaWikiTestCase {
                                'EnableBotPasswords' => true,
                                'BotPasswordsDatabase' => false,
                                'SessionProviders' => $wgSessionProviders + [
-                                       'MediaWiki\\Session\\BotPasswordSessionProvider' => [
-                                               'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider',
+                                       BotPasswordSessionProvider::class => [
+                                               'class' => BotPasswordSessionProvider::class,
                                                'args' => [ $params ],
                                        ]
                                ],
@@ -46,7 +46,7 @@ class BotPasswordSessionProviderTest extends MediaWikiTestCase {
                        'store' => new TestBagOStuff,
                ] );
 
-               return $manager->getProvider( 'MediaWiki\\Session\\BotPasswordSessionProvider' );
+               return $manager->getProvider( BotPasswordSessionProvider::class );
        }
 
        protected function setUp() {
@@ -172,7 +172,7 @@ class BotPasswordSessionProviderTest extends MediaWikiTestCase {
                }
 
                $info = $provider->provideSessionInfo( $request );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\SessionInfo', $info );
+               $this->assertInstanceOf( SessionInfo::class, $info );
                $this->assertSame( 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', $info->getId() );
 
                $this->config->set( 'EnableBotPasswords', false );
@@ -191,7 +191,7 @@ class BotPasswordSessionProviderTest extends MediaWikiTestCase {
                $bp = \BotPassword::newFromUser( $user, 'BotPasswordSessionProvider' );
 
                $session = $provider->newSessionForRequest( $user, $bp, $request );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
 
                $this->assertEquals( $session->getId(), $request->getSession()->getId() );
                $this->assertEquals( $user->getName(), $session->getUser()->getName() );
index 2412a3b..d705fc0 100644 (file)
@@ -24,7 +24,7 @@ class ImmutableSessionProviderWithCookieTest extends MediaWikiTestCase {
                        $params['sessionCookieOptions']['prefix'] = $prefix;
                }
 
-               $provider = $this->getMockBuilder( 'MediaWiki\\Session\\ImmutableSessionProviderWithCookie' )
+               $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
                        ->setConstructorArgs( [ $params ] )
                        ->getMockForAbstractClass();
                $provider->setLogger( new \TestLogger() );
@@ -35,13 +35,13 @@ class ImmutableSessionProviderWithCookieTest extends MediaWikiTestCase {
        }
 
        public function testConstructor() {
-               $provider = $this->getMockBuilder( 'MediaWiki\\Session\\ImmutableSessionProviderWithCookie' )
+               $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
                        ->getMockForAbstractClass();
                $priv = \TestingAccessWrapper::newFromObject( $provider );
                $this->assertNull( $priv->sessionCookieName );
                $this->assertSame( [], $priv->sessionCookieOptions );
 
-               $provider = $this->getMockBuilder( 'MediaWiki\\Session\\ImmutableSessionProviderWithCookie' )
+               $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
                        ->setConstructorArgs( [ [
                                'sessionCookieName' => 'Foo',
                                'sessionCookieOptions' => [ 'Bar' ],
@@ -52,7 +52,7 @@ class ImmutableSessionProviderWithCookieTest extends MediaWikiTestCase {
                $this->assertSame( [ 'Bar' ], $priv->sessionCookieOptions );
 
                try {
-                       $provider = $this->getMockBuilder( 'MediaWiki\\Session\\ImmutableSessionProviderWithCookie' )
+                       $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
                                ->setConstructorArgs( [ [
                                        'sessionCookieName' => false,
                                ] ] )
@@ -66,7 +66,7 @@ class ImmutableSessionProviderWithCookieTest extends MediaWikiTestCase {
                }
 
                try {
-                       $provider = $this->getMockBuilder( 'MediaWiki\\Session\\ImmutableSessionProviderWithCookie' )
+                       $provider = $this->getMockBuilder( ImmutableSessionProviderWithCookie::class )
                                ->setConstructorArgs( [ [
                                        'sessionCookieOptions' => 'x',
                                ] ] )
index 05773a9..ce0f1b0 100644 (file)
@@ -23,7 +23,7 @@ class PHPSessionHandlerTest extends MediaWikiTestCase {
                } );
                $reset[] = new \ScopedCallback( 'restore_error_handler' );
 
-               $rProp = new \ReflectionProperty( 'MediaWiki\\Session\\PHPSessionHandler', 'instance' );
+               $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                $rProp->setAccessible( true );
                if ( $rProp->getValue() ) {
                        $old = \TestingAccessWrapper::newFromObject( $rProp->getValue() );
@@ -31,7 +31,7 @@ class PHPSessionHandlerTest extends MediaWikiTestCase {
                        $oldStore = $old->store;
                        $oldLogger = $old->logger;
                        $reset[] = new \ScopedCallback(
-                               [ 'MediaWiki\\Session\\PHPSessionHandler', 'install' ],
+                               [ PHPSessionHandler::class, 'install' ],
                                [ $oldManager, $oldStore, $oldLogger ]
                        );
                }
@@ -41,13 +41,13 @@ class PHPSessionHandlerTest extends MediaWikiTestCase {
 
        public function testEnableFlags() {
                $handler = \TestingAccessWrapper::newFromObject(
-                       $this->getMockBuilder( 'MediaWiki\\Session\\PHPSessionHandler' )
+                       $this->getMockBuilder( PHPSessionHandler::class )
                                ->setMethods( null )
                                ->disableOriginalConstructor()
                                ->getMock()
                );
 
-               $rProp = new \ReflectionProperty( 'MediaWiki\\Session\\PHPSessionHandler', 'instance' );
+               $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                $rProp->setAccessible( true );
                $reset = new \ScopedCallback( [ $rProp, 'setValue' ], [ $rProp->getValue() ] );
                $rProp->setValue( $handler );
@@ -325,9 +325,9 @@ class PHPSessionHandlerTest extends MediaWikiTestCase {
         * @expectedExceptionMessage Attempt to use PHP session management
         */
        public function testDisabled( $method, $args ) {
-               $rProp = new \ReflectionProperty( 'MediaWiki\\Session\\PHPSessionHandler', 'instance' );
+               $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                $rProp->setAccessible( true );
-               $handler = $this->getMockBuilder( 'MediaWiki\\Session\\PHPSessionHandler' )
+               $handler = $this->getMockBuilder( PHPSessionHandler::class )
                        ->setMethods( null )
                        ->disableOriginalConstructor()
                        ->getMock();
@@ -354,7 +354,7 @@ class PHPSessionHandlerTest extends MediaWikiTestCase {
         * @expectedExceptionMessageRegExp /: Wrong instance called!$/
         */
        public function testWrongInstance( $method, $args ) {
-               $handler = $this->getMockBuilder( 'MediaWiki\\Session\\PHPSessionHandler' )
+               $handler = $this->getMockBuilder( PHPSessionHandler::class )
                        ->setMethods( null )
                        ->disableOriginalConstructor()
                        ->getMock();
index 7459ed2..0b5f4c2 100644 (file)
@@ -184,8 +184,8 @@ class SessionBackendTest extends MediaWikiTestCase {
                $request2 = new \FauxRequest();
                $session2 = $backend->getSession( $request2 );
 
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session1 );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session2 );
+               $this->assertInstanceOf( Session::class, $session1 );
+               $this->assertInstanceOf( Session::class, $session2 );
                $this->assertSame( 2, count( $priv->requests ) );
 
                $index = \TestingAccessWrapper::newFromObject( $session1 )->index;
@@ -819,7 +819,7 @@ class SessionBackendTest extends MediaWikiTestCase {
                        PHPSessionHandler::install( SessionManager::singleton() );
                }
                if ( !PHPSessionHandler::isEnabled() ) {
-                       $rProp = new \ReflectionProperty( 'MediaWiki\\Session\\PHPSessionHandler', 'instance' );
+                       $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                        $rProp->setAccessible( true );
                        $handler = \TestingAccessWrapper::newFromObject( $rProp->getValue() );
                        $resetHandler = new \ScopedCallback( function () use ( $handler ) {
@@ -859,7 +859,7 @@ class SessionBackendTest extends MediaWikiTestCase {
                        PHPSessionHandler::install( SessionManager::singleton() );
                }
                if ( !PHPSessionHandler::isEnabled() ) {
-                       $rProp = new \ReflectionProperty( 'MediaWiki\\Session\\PHPSessionHandler', 'instance' );
+                       $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                        $rProp->setAccessible( true );
                        $handler = \TestingAccessWrapper::newFromObject( $rProp->getValue() );
                        $resetHandler = new \ScopedCallback( function () use ( $handler ) {
@@ -895,7 +895,7 @@ class SessionBackendTest extends MediaWikiTestCase {
                        PHPSessionHandler::install( SessionManager::singleton() );
                }
                if ( !PHPSessionHandler::isEnabled() ) {
-                       $rProp = new \ReflectionProperty( 'MediaWiki\\Session\\PHPSessionHandler', 'instance' );
+                       $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                        $rProp->setAccessible( true );
                        $handler = \TestingAccessWrapper::newFromObject( $rProp->getValue() );
                        $resetHandler = new \ScopedCallback( function () use ( $handler ) {
index e702125..ff22bfa 100644 (file)
@@ -61,7 +61,7 @@ class SessionInfoTest extends MediaWikiTestCase {
                }
 
                $manager = new SessionManager();
-               $provider = $this->getMockBuilder( 'MediaWiki\\Session\\SessionProvider' )
+               $provider = $this->getMockBuilder( SessionProvider::class )
                        ->setMethods( [ 'persistsSessionId', 'canChangeUser', '__toString' ] )
                        ->getMockForAbstractClass();
                $provider->setManager( $manager );
@@ -72,7 +72,7 @@ class SessionInfoTest extends MediaWikiTestCase {
                $provider->expects( $this->any() )->method( '__toString' )
                        ->will( $this->returnValue( 'Mock' ) );
 
-               $provider2 = $this->getMockBuilder( 'MediaWiki\\Session\\SessionProvider' )
+               $provider2 = $this->getMockBuilder( SessionProvider::class )
                        ->setMethods( [ 'persistsSessionId', 'canChangeUser', '__toString' ] )
                        ->getMockForAbstractClass();
                $provider2->setManager( $manager );
index b0f84fc..6218f0a 100644 (file)
@@ -48,7 +48,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                $reset = TestUtils::setSessionManagerSingleton( null );
 
                $singleton = SessionManager::singleton();
-               $this->assertInstanceOf( 'MediaWiki\\Session\\SessionManager', $singleton );
+               $this->assertInstanceOf( SessionManager::class, $singleton );
                $this->assertSame( $singleton, SessionManager::singleton() );
        }
 
@@ -58,7 +58,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                if ( !PHPSessionHandler::isInstalled() ) {
                        PHPSessionHandler::install( SessionManager::singleton() );
                }
-               $rProp = new \ReflectionProperty( 'MediaWiki\\Session\\PHPSessionHandler', 'instance' );
+               $rProp = new \ReflectionProperty( PHPSessionHandler::class, 'instance' );
                $rProp->setAccessible( true );
                $handler = \TestingAccessWrapper::newFromObject( $rProp->getValue() );
                $oldEnable = $handler->enable;
@@ -191,7 +191,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                $request->info1 = null;
                $request->info2 = null;
                $session = $manager->getSessionForRequest( $request );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( $idEmpty, $session->getId() );
                $this->assertFalse( $request->unpersist1 );
                $this->assertFalse( $request->unpersist2 );
@@ -210,7 +210,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                        'idIsSafe' => true,
                ] );
                $session = $manager->getSessionForRequest( $request );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( $id2, $session->getId() );
                $this->assertFalse( $request->unpersist1 );
                $this->assertFalse( $request->unpersist2 );
@@ -228,7 +228,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                        'idIsSafe' => true,
                ] );
                $session = $manager->getSessionForRequest( $request );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( $id1, $session->getId() );
                $this->assertFalse( $request->unpersist1 );
                $this->assertFalse( $request->unpersist2 );
@@ -299,7 +299,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                        'idIsSafe' => true,
                ] );
                $session = $manager->getSessionForRequest( $request );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( $id2, $session->getId() );
                $this->logger->setCollect( false );
                $this->assertTrue( $request->unpersist1 );
@@ -321,7 +321,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                        'idIsSafe' => true,
                ] );
                $session = $manager->getSessionForRequest( $request );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( $id1, $session->getId() );
                $this->logger->setCollect( false );
                $this->assertFalse( $request->unpersist1 );
@@ -338,7 +338,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                ] );
                $request->info2 = null;
                $session = $manager->getSessionForRequest( $request );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( $id1, $session->getId() );
                $this->assertTrue( $request->unpersist1 ); // The saving of the session does it
                $this->assertFalse( $request->unpersist2 );
@@ -358,7 +358,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                // Unknown session ID
                $id = $manager->generateSessionId();
                $session = $manager->getSessionById( $id, true );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( $id, $session->getId() );
 
                $id = $manager->generateSessionId();
@@ -379,7 +379,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                // Known session ID
                $this->store->setSession( $id, [] );
                $session = $manager->getSessionById( $id, false );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( $id, $session->getId() );
 
                // Store isn't checked if the session is already loaded
@@ -388,7 +388,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                        'userToken' => 'bad',
                ] ] );
                $session2 = $manager->getSessionById( $id, false );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session2 );
+               $this->assertInstanceOf( Session::class, $session2 );
                $this->assertSame( $id, $session2->getId() );
                unset( $session, $session2 );
                $this->logger->setCollect( true );
@@ -484,7 +484,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                ] );
                $info2 = null;
                $session = $manager->getEmptySession();
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( 'empty---------------------------', $session->getId() );
 
                // Info, explicitly
@@ -497,7 +497,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                ] );
                $info2 = null;
                $session = $pmanager->getEmptySessionInternal( null, $expectId );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( $expectId, $session->getId() );
 
                // Wrong ID
@@ -572,7 +572,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                        'idIsSafe' => true,
                ] );
                $session = $manager->getEmptySession();
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( 'empty1--------------------------', $session->getId() );
 
                $expectId = null;
@@ -589,7 +589,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                        'idIsSafe' => true,
                ] );
                $session = $manager->getEmptySession();
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( Session::class, $session );
                $this->assertSame( 'empty2--------------------------', $session->getId() );
 
                // Tied priorities throw an exception
@@ -1177,7 +1177,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                        'provider' => 'Mock',
                ];
 
-               $builder = $this->getMockBuilder( 'MediaWiki\\Session\\SessionProvider' )
+               $builder = $this->getMockBuilder( SessionProvider::class )
                        ->setMethods( [ '__toString', 'mergeMetadata', 'refreshSessionInfo' ] );
 
                $provider = $builder->getMockForAbstractClass();
@@ -1292,7 +1292,7 @@ class SessionManagerTest extends MediaWikiTestCase {
                ] );
                $this->assertFalse( $info->isIdSafe(), 'sanity check' );
                $this->assertTrue( $loadSessionInfoFromStore( $info ) );
-               $this->assertInstanceOf( 'MediaWiki\\Session\\UserInfo', $info->getUserInfo() );
+               $this->assertInstanceOf( UserInfo::class, $info->getUserInfo() );
                $this->assertTrue( $info->getUserInfo()->isVerified() );
                $this->assertTrue( $info->getUserInfo()->isAnon() );
                $this->assertFalse( $info->isIdSafe() );
index e92eb09..18b1efd 100644 (file)
@@ -16,7 +16,7 @@ class SessionProviderTest extends MediaWikiTestCase {
                $logger = new \TestLogger();
                $config = new \HashConfig();
 
-               $provider = $this->getMockForAbstractClass( 'MediaWiki\\Session\\SessionProvider' );
+               $provider = $this->getMockForAbstractClass( SessionProvider::class );
                $priv = \TestingAccessWrapper::newFromObject( $provider );
 
                $provider->setConfig( $config );
@@ -53,7 +53,7 @@ class SessionProviderTest extends MediaWikiTestCase {
        public function testNewSessionInfo( $persistId, $persistUser, $ok ) {
                $manager = new SessionManager();
 
-               $provider = $this->getMockBuilder( 'MediaWiki\\Session\\SessionProvider' )
+               $provider = $this->getMockBuilder( SessionProvider::class )
                        ->setMethods( [ 'canChangeUser', 'persistsSessionId' ] )
                        ->getMockForAbstractClass();
                $provider->expects( $this->any() )->method( 'persistsSessionId' )
@@ -80,7 +80,7 @@ class SessionProviderTest extends MediaWikiTestCase {
        }
 
        public function testMergeMetadata() {
-               $provider = $this->getMockBuilder( 'MediaWiki\\Session\\SessionProvider' )
+               $provider = $this->getMockBuilder( SessionProvider::class )
                        ->getMockForAbstractClass();
 
                try {
@@ -112,14 +112,14 @@ class SessionProviderTest extends MediaWikiTestCase {
        }
 
        public function testImmutableSessions() {
-               $provider = $this->getMockBuilder( 'MediaWiki\\Session\\SessionProvider' )
+               $provider = $this->getMockBuilder( SessionProvider::class )
                        ->setMethods( [ 'canChangeUser', 'persistsSessionId' ] )
                        ->getMockForAbstractClass();
                $provider->expects( $this->any() )->method( 'canChangeUser' )
                        ->will( $this->returnValue( true ) );
                $provider->preventSessionsForUser( 'Foo' );
 
-               $provider = $this->getMockBuilder( 'MediaWiki\\Session\\SessionProvider' )
+               $provider = $this->getMockBuilder( SessionProvider::class )
                        ->setMethods( [ 'canChangeUser', 'persistsSessionId' ] )
                        ->getMockForAbstractClass();
                $provider->expects( $this->any() )->method( 'canChangeUser' )
@@ -142,7 +142,7 @@ class SessionProviderTest extends MediaWikiTestCase {
                        'SecretKey' => 'Shhh!',
                ] );
 
-               $provider = $this->getMockForAbstractClass( 'MediaWiki\\Session\\SessionProvider',
+               $provider = $this->getMockForAbstractClass( SessionProvider::class,
                        [], 'MockSessionProvider' );
                $provider->setConfig( $config );
                $priv = \TestingAccessWrapper::newFromObject( $provider );
@@ -172,7 +172,7 @@ class SessionProviderTest extends MediaWikiTestCase {
        }
 
        public function testDescribe() {
-               $provider = $this->getMockForAbstractClass( 'MediaWiki\\Session\\SessionProvider',
+               $provider = $this->getMockForAbstractClass( SessionProvider::class,
                        [], 'MockSessionProvider' );
 
                $this->assertSame(
@@ -182,7 +182,7 @@ class SessionProviderTest extends MediaWikiTestCase {
        }
 
        public function testGetAllowedUserRights() {
-               $provider = $this->getMockForAbstractClass( 'MediaWiki\\Session\\SessionProvider' );
+               $provider = $this->getMockForAbstractClass( SessionProvider::class );
                $backend = TestUtils::getDummySessionBackend();
 
                try {
index a4727c4..e87f41d 100644 (file)
@@ -37,7 +37,7 @@ class SessionTest extends MediaWikiTestCase {
         * @param bool $ret Whether the method returns a value
         */
        public function testMethods( $m, $args, $index, $ret ) {
-               $mock = $this->getMock( 'MediaWiki\\Session\\DummySessionBackend',
+               $mock = $this->getMock( DummySessionBackend::class,
                        [ $m, 'deregisterSession' ] );
                $mock->expects( $this->once() )->method( 'deregisterSession' )
                        ->with( $this->identicalTo( 42 ) );
@@ -224,7 +224,7 @@ class SessionTest extends MediaWikiTestCase {
                $priv = \TestingAccessWrapper::newFromObject( $session );
 
                $backend = $this->getMock(
-                       'MediaWiki\\Session\\DummySessionBackend', [ 'canSetUser', 'setUser', 'save' ]
+                       DummySessionBackend::class, [ 'canSetUser', 'setUser', 'save' ]
                );
                $backend->expects( $this->once() )->method( 'canSetUser' )
                        ->will( $this->returnValue( true ) );
@@ -239,7 +239,7 @@ class SessionTest extends MediaWikiTestCase {
                $this->assertTrue( $backend->dirty );
 
                $backend = $this->getMock(
-                       'MediaWiki\\Session\\DummySessionBackend', [ 'canSetUser', 'setUser', 'save' ]
+                       DummySessionBackend::class, [ 'canSetUser', 'setUser', 'save' ]
                );
                $backend->data = [];
                $backend->expects( $this->once() )->method( 'canSetUser' )
@@ -254,7 +254,7 @@ class SessionTest extends MediaWikiTestCase {
                $this->assertFalse( $backend->dirty );
 
                $backend = $this->getMock(
-                       'MediaWiki\\Session\\DummySessionBackend', [ 'canSetUser', 'setUser', 'save' ]
+                       DummySessionBackend::class, [ 'canSetUser', 'setUser', 'save' ]
                );
                $backend->expects( $this->once() )->method( 'canSetUser' )
                        ->will( $this->returnValue( false ) );
@@ -267,7 +267,7 @@ class SessionTest extends MediaWikiTestCase {
        }
 
        public function testTokens() {
-               $rc = new \ReflectionClass( 'MediaWiki\\Session\\Session' );
+               $rc = new \ReflectionClass( Session::class );
                if ( !method_exists( $rc, 'newInstanceWithoutConstructor' ) ) {
                        $this->markTestSkipped(
                                'ReflectionClass::newInstanceWithoutConstructor isn\'t available'
index 36175af..f1dc9e9 100644 (file)
@@ -18,15 +18,15 @@ class TestUtils {
                session_write_close();
 
                $rInstance = new \ReflectionProperty(
-                       'MediaWiki\\Session\\SessionManager', 'instance'
+                       SessionManager::class, 'instance'
                );
                $rInstance->setAccessible( true );
                $rGlobalSession = new \ReflectionProperty(
-                       'MediaWiki\\Session\\SessionManager', 'globalSession'
+                       SessionManager::class, 'globalSession'
                );
                $rGlobalSession->setAccessible( true );
                $rGlobalSessionRequest = new \ReflectionProperty(
-                       'MediaWiki\\Session\\SessionManager', 'globalSessionRequest'
+                       SessionManager::class, 'globalSessionRequest'
                );
                $rGlobalSessionRequest->setAccessible( true );
 
@@ -62,7 +62,7 @@ class TestUtils {
         *  fields necessary.
         */
        public static function getDummySessionBackend() {
-               $rc = new \ReflectionClass( 'MediaWiki\\Session\\SessionBackend' );
+               $rc = new \ReflectionClass( SessionBackend::class );
                if ( !method_exists( $rc, 'newInstanceWithoutConstructor' ) ) {
                        \PHPUnit_Framework_Assert::markTestSkipped(
                                'ReflectionClass::newInstanceWithoutConstructor isn\'t available'
@@ -83,7 +83,7 @@ class TestUtils {
         * @return Session
         */
        public static function getDummySession( $backend = null, $index = -1, $logger = null ) {
-               $rc = new \ReflectionClass( 'MediaWiki\\Session\\Session' );
+               $rc = new \ReflectionClass( Session::class );
                if ( !method_exists( $rc, 'newInstanceWithoutConstructor' ) ) {
                        \PHPUnit_Framework_Assert::markTestSkipped(
                                'ReflectionClass::newInstanceWithoutConstructor isn\'t available'
index 47b70af..ca001f3 100644 (file)
@@ -11,7 +11,7 @@ use MediaWikiTestCase;
 class TokenTest extends MediaWikiTestCase {
 
        public function testBasics() {
-               $token = $this->getMockBuilder( 'MediaWiki\\Session\\Token' )
+               $token = $this->getMockBuilder( Token::class )
                        ->setMethods( [ 'toStringAtTimestamp' ] )
                        ->setConstructorArgs( [ 'sekret', 'salty', true ] )
                        ->getMock();
diff --git a/tests/phpunit/includes/specials/SpecialPageExecutor.php b/tests/phpunit/includes/specials/SpecialPageExecutor.php
new file mode 100644 (file)
index 0000000..2f7b767
--- /dev/null
@@ -0,0 +1,129 @@
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @since 1.27
+ */
+class SpecialPageExecutor {
+
+       /**
+        * @param SpecialPage $page The special page to execute
+        * @param string $subPage The subpage parameter to call the page with
+        * @param WebRequest|null $request Web request that may contain URL parameters, etc
+        * @param Language|string|null $language The language which should be used in the context
+        * @param User|null $user The user which should be used in the context of this special page
+        *
+        * @throws Exception
+        * @return array( string, WebResponse ) A two-elements array containing the HTML output
+        * generated by the special page as well as the response object.
+        */
+       public function executeSpecialPage(
+               SpecialPage $page,
+               $subPage = '',
+               WebRequest $request = null,
+               $language = null,
+               User $user = null
+       ) {
+               $context = $this->newContext( $request, $language, $user );
+
+               $output = new OutputPage( $context );
+               $context->setOutput( $output );
+
+               $page->setContext( $context );
+               $output->setTitle( $page->getPageTitle() );
+
+               $html = $this->getHTMLFromSpecialPage( $page, $subPage );
+               $response = $context->getRequest()->response();
+
+               if ( $response instanceof FauxResponse ) {
+                       $code = $response->getStatusCode();
+
+                       if ( $code > 0 ) {
+                               $response->header( 'Status: ' . $code . ' ' . HttpStatus::getMessage( $code ) );
+                       }
+               }
+
+               return [ $html, $response ];
+       }
+
+       /**
+        * @param WebRequest|null $request
+        * @param Language|string|null $language
+        * @param User|null $user
+        *
+        * @return DerivativeContext
+        */
+       private function newContext(
+               WebRequest $request = null,
+               $language = null,
+               User $user = null
+       ) {
+               $context = new DerivativeContext( RequestContext::getMain() );
+
+               $context->setRequest( $request ?: new FauxRequest() );
+
+               if ( $language !== null ) {
+                       $context->setLanguage( $language );
+               }
+
+               if ( $user !== null ) {
+                       $context->setUser( $user );
+               }
+
+               $this->setEditTokenFromUser( $context );
+
+               return $context;
+       }
+
+       /**
+        * If we are trying to edit and no token is set, supply one.
+        *
+        * @param DerivativeContext $context
+        */
+       private function setEditTokenFromUser( DerivativeContext $context ) {
+               $request = $context->getRequest();
+
+               // Edits via GET are a security issue and should not succeed. On the other hand, not all
+               // POST requests are edits, but should ignore unused parameters.
+               if ( !$request->getCheck( 'wpEditToken' ) && $request->wasPosted() ) {
+                       $request->setVal( 'wpEditToken', $context->getUser()->getEditToken() );
+               }
+       }
+
+       /**
+        * @param SpecialPage $page
+        * @param string $subPage
+        *
+        * @throws Exception
+        * @return string HTML
+        */
+       private function getHTMLFromSpecialPage( SpecialPage $page, $subPage ) {
+               ob_start();
+
+               try {
+                       $page->execute( $subPage );
+
+                       $output = $page->getOutput();
+
+                       if ( $output->getRedirect() !== '' ) {
+                               $output->output();
+                               $html = ob_get_contents();
+                       } elseif ( $output->isDisabled() ) {
+                               $html = ob_get_contents();
+                       } else {
+                               $html = $output->getHTML();
+                       }
+               } catch ( Exception $ex ) {
+                       ob_end_clean();
+
+                       // Re-throw exception after "finally" handling because PHP 5.3 doesn't have "finally".
+                       throw $ex;
+               }
+
+               ob_end_clean();
+
+               return $html;
+       }
+
+}
index 48baa8e..2f091d5 100644 (file)
@@ -60,106 +60,13 @@ abstract class SpecialPageTestBase extends MediaWikiTestCase {
                $language = null,
                User $user = null
        ) {
-               $context = $this->newContext( $request, $language, $user );
-
-               $output = new OutputPage( $context );
-               $context->setOutput( $output );
-
-               $page = $this->newSpecialPage();
-               $page->setContext( $context );
-               $output->setTitle( $page->getPageTitle() );
-
-               $html = $this->getHTMLFromSpecialPage( $page, $subPage );
-               $response = $context->getRequest()->response();
-
-               if ( $response instanceof FauxResponse ) {
-                       $code = $response->getStatusCode();
-
-                       if ( $code > 0 ) {
-                               $response->header( 'Status: ' . $code . ' ' . HttpStatus::getMessage( $code ) );
-                       }
-               }
-
-               return [ $html, $response ];
-       }
-
-       /**
-        * @param WebRequest|null $request
-        * @param Language|string|null $language
-        * @param User|null $user
-        *
-        * @return DerivativeContext
-        */
-       private function newContext(
-               WebRequest $request = null,
-               $language = null,
-               User $user = null
-       ) {
-               $context = new DerivativeContext( RequestContext::getMain() );
-
-               $context->setRequest( $request ?: new FauxRequest() );
-
-               if ( $language !== null ) {
-                       $context->setLanguage( $language );
-               }
-
-               if ( $user !== null ) {
-                       $context->setUser( $user );
-               }
-
-               $this->setEditTokenFromUser( $context );
-
-               return $context;
-       }
-
-       /**
-        * If we are trying to edit and no token is set, supply one.
-        *
-        * @param DerivativeContext $context
-        */
-       private function setEditTokenFromUser( DerivativeContext $context ) {
-               $request = $context->getRequest();
-
-               // Edits via GET are a security issue and should not succeed. On the other hand, not all
-               // POST requests are edits, but should ignore unused parameters.
-               if ( !$request->getCheck( 'wpEditToken' ) && $request->wasPosted() ) {
-                       $request->setVal( 'wpEditToken', $context->getUser()->getEditToken() );
-               }
-       }
-
-       /**
-        * @param SpecialPage $page
-        * @param string $subPage
-        *
-        * @throws Exception
-        * @return string HTML
-        */
-       private function getHTMLFromSpecialPage( SpecialPage $page, $subPage ) {
-               ob_start();
-
-               try {
-                       $page->execute( $subPage );
-
-                       $output = $page->getOutput();
-
-                       if ( $output->getRedirect() !== '' ) {
-                               $output->output();
-                               $html = ob_get_contents();
-                       } elseif ( $output->isDisabled() ) {
-                               $html = ob_get_contents();
-                       } else {
-                               $html = $output->getHTML();
-                       }
-               } catch ( Exception $ex ) {
-                       ob_end_clean();
-
-                       // Re-throw exception after "finally" handling because PHP 5.3 doesn't have "finally".
-                       throw $ex;
-               }
-
-               ob_end_clean();
-
-               return $html;
+               return ( new SpecialPageExecutor() )->executeSpecialPage(
+                       $this->newSpecialPage(),
+                       $subPage,
+                       $request,
+                       $language,
+                       $user
+               );
        }
 
 }
index a274b84..ee74957 100644 (file)
@@ -136,259 +136,259 @@ class UploadBaseTest extends MediaWikiTestCase {
 
        public static function provideCheckSvgScriptCallback() {
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
+               return [
                        // html5sec SVG vectors
-                       array(
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>',
                                true,
                                true,
                                'Script tag in svg (http://html5sec.org/#47)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"><g onload="javascript:alert(1)"></g></svg>',
                                true,
                                true,
                                'SVG with onload property (http://html5sec.org/#11)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg onload="javascript:alert(1)" xmlns="http://www.w3.org/2000/svg"></svg>',
                                true,
                                true,
                                'SVG with onload property (http://html5sec.org/#65)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="javascript:alert(1)"><rect width="1000" height="1000" fill="white"/></a> </svg>',
                                true,
                                true,
                                'SVG with javascript xlink (http://html5sec.org/#87)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><use xlink:href="data:application/xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj4KPGRlZnM+CjxjaXJjbGUgaWQ9InRlc3QiIHI9IjUwIiBjeD0iMTAwIiBjeT0iMTAwIiBzdHlsZT0iZmlsbDogI0YwMCI+CjxzZXQgYXR0cmlidXRlTmFtZT0iZmlsbCIgYXR0cmlidXRlVHlwZT0iQ1NTIiBvbmJlZ2luPSdhbGVydChkb2N1bWVudC5jb29raWUpJwpvbmVuZD0nYWxlcnQoIm9uZW5kIiknIHRvPSIjMDBGIiBiZWdpbj0iMXMiIGR1cj0iNXMiIC8+CjwvY2lyY2xlPgo8L2RlZnM+Cjx1c2UgeGxpbms6aHJlZj0iI3Rlc3QiLz4KPC9zdmc+#test"/> </svg>',
                                true,
                                true,
                                'SVG with Opera image xlink (http://html5sec.org/#88 - c)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  <animation xlink:href="javascript:alert(1)"/> </svg>',
                                true,
                                true,
                                'SVG with Opera animation xlink (http://html5sec.org/#88 - a)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  <animation xlink:href="data:text/xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' onload=\'alert(1)\'%3E%3C/svg%3E"/> </svg>',
                                true,
                                true,
                                'SVG with Opera animation xlink (http://html5sec.org/#88 - b)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  <image xlink:href="data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' onload=\'alert(1)\'%3E%3C/svg%3E"/> </svg>',
                                true,
                                true,
                                'SVG with Opera image xlink (http://html5sec.org/#88 - c)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  <foreignObject xlink:href="javascript:alert(1)"/> </svg>',
                                true,
                                true,
                                'SVG with Opera foreignObject xlink (http://html5sec.org/#88 - d)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">  <foreignObject xlink:href="data:text/xml,%3Cscript xmlns=\'http://www.w3.org/1999/xhtml\'%3Ealert(1)%3C/script%3E"/> </svg>',
                                true,
                                true,
                                'SVG with Opera foreignObject xlink (http://html5sec.org/#88 - e)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <set attributeName="onmouseover" to="alert(1)"/> </svg>',
                                true,
                                true,
                                'SVG with event handler set (http://html5sec.org/#89 - a)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <animate attributeName="onunload" to="alert(1)"/> </svg>',
                                true,
                                true,
                                'SVG with event handler animate (http://html5sec.org/#89 - a)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <handler xmlns:ev="http://www.w3.org/2001/xml-events" ev:event="load">alert(1)</handler> </svg>',
                                true,
                                true,
                                'SVG with element handler (http://html5sec.org/#94)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <feImage> <set attributeName="xlink:href" to="data:image/svg+xml;charset=utf-8;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxzY3JpcHQ%2BYWxlcnQoMSk8L3NjcmlwdD48L3N2Zz4NCg%3D%3D"/> </feImage> </svg>',
                                true,
                                true,
                                'SVG with href to data: url (http://html5sec.org/#95)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" id="foo"> <x xmlns="http://www.w3.org/2001/xml-events" event="load" observer="foo" handler="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Chandler%20xml%3Aid%3D%22bar%22%20type%3D%22application%2Fecmascript%22%3E alert(1) %3C%2Fhandler%3E%0A%3C%2Fsvg%3E%0A#bar"/> </svg>',
                                true,
                                true,
                                'SVG with Tiny handler (http://html5sec.org/#104)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <a id="x"><rect fill="white" width="1000" height="1000"/></a> <rect fill="white" style="clip-path:url(test3.svg#a);fill:url(#b);filter:url(#c);marker:url(#d);mask:url(#e);stroke:url(#f);"/> </svg>',
                                true,
                                true,
                                'SVG with new CSS styles properties (http://html5sec.org/#109)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <a id="x"><rect fill="white" width="1000" height="1000"/></a> <rect clip-path="url(test3.svg#a)" /> </svg>',
                                true,
                                true,
                                'SVG with new CSS styles properties as attributes'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <a id="x"> <rect fill="white" width="1000" height="1000"/> </a> <rect fill="url(http://html5sec.org/test3.svg#a)" /> </svg>',
                                true,
                                true,
                                'SVG with new CSS styles properties as attributes (2)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <path d="M0,0" style="marker-start:url(test4.svg#a)"/> </svg>',
                                true,
                                true,
                                'SVG with path marker-start (http://html5sec.org/#110)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<?xml version="1.0"?> <?xml-stylesheet type="text/xml" href="#stylesheet"?> <!DOCTYPE doc [ <!ATTLIST xsl:stylesheet id ID #REQUIRED>]> <svg xmlns="http://www.w3.org/2000/svg"> <xsl:stylesheet id="stylesheet" version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <iframe xmlns="http://www.w3.org/1999/xhtml" src="javascript:alert(1)"></iframe> </xsl:template> </xsl:stylesheet> <circle fill="red" r="40"></circle> </svg>',
                                true,
                                true,
                                'SVG with embedded stylesheet (http://html5sec.org/#125)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" id="x"> <listener event="load" handler="#y" xmlns="http://www.w3.org/2001/xml-events" observer="x"/> <handler id="y">alert(1)</handler> </svg>',
                                true,
                                true,
                                'SVG with handler attribute (http://html5sec.org/#127)'
-                       ),
-                       array(
+                       ],
+                       [
                                // Haven't found a browser that accepts this particular example, but we
                                // don't want to allow embeded svgs, ever
                                '<svg> <image style=\'filter:url("data:image/svg+xml;charset=utf-8;base64, PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxzY3JpcHQ/YWxlcnQoMSk8L3NjcmlwdD48L3N2Zz4NCg==")\' /> </svg>',
                                true,
                                true,
                                'SVG with image filter via style (http://html5sec.org/#129)'
-                       ),
-                       array(
+                       ],
+                       [
                                // This doesn't seem possible without embedding the svg, but just in case
                                '<svg> <a xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="?"> <circle r="400"></circle> <animate attributeName="xlink:href" begin="0" from="javascript:alert(1)" to="" /> </a></svg>',
                                true,
                                true,
                                'SVG with animate from (http://html5sec.org/#137)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <a><text y="1em">Click me</text> <animate attributeName="xlink:href" values="javascript:alert(\'Bang!\')" begin="0s" dur="0.1s" fill="freeze" /> </a></svg>',
                                true,
                                true,
                                'SVG with animate xlink:href (http://html5sec.org/#137)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:y="http://www.w3.org/1999/xlink"> <a y:href="#"> <text y="1em">Click me</text> <animate attributeName="y:href" values="javascript:alert(\'Bang!\')" begin="0s" dur="0.1s" fill="freeze" /> </a> </svg>',
                                true,
                                true,
                                'SVG with animate y:href (http://html5sec.org/#137)'
-                       ),
+                       ],
 
                        // Other hostile SVG's
-                       array(
+                       [
                                '<?xml version="1.0" encoding="UTF-8" standalone="no"?> <svg xmlns:xlink="http://www.w3.org/1999/xlink"> <image xlink:href="https://upload.wikimedia.org/wikipedia/commons/3/34/Bahnstrecke_Zeitz-Camburg_1930.png" /> </svg>',
                                true,
                                true,
                                'SVG with non-local image href (bug 65839)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<?xml version="1.0" ?> <?xml-stylesheet type="text/xsl" href="/w/index.php?title=User:Jeeves/test.xsl&amp;action=raw&amp;format=xml" ?> <svg> <height>50</height> <width>100</width> </svg>',
                                true,
                                true,
                                'SVG with remote stylesheet (bug 57550)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" viewbox="-1 -1 15 15"> <rect y="0" height="13" width="12" stroke="#179" rx="1" fill="#2ac"/> <text x="1.5" y="11" font-family="courier" stroke="white" font-size="16"><![CDATA[B]]></text> <iframe xmlns="http://www.w3.org/1999/xhtml" srcdoc="&#x3C;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3E;&#x61;&#x6C;&#x65;&#x72;&#x74;&#x28;&#x27;&#x58;&#x53;&#x53;&#x45;&#x44;&#x20;&#x3D;&#x3E;&#x20;&#x44;&#x6F;&#x6D;&#x61;&#x69;&#x6E;&#x28;&#x27;&#x2B;&#x74;&#x6F;&#x70;&#x2E;&#x64;&#x6F;&#x63;&#x75;&#x6D;&#x65;&#x6E;&#x74;&#x2E;&#x64;&#x6F;&#x6D;&#x61;&#x69;&#x6E;&#x2B;&#x27;&#x29;&#x27;&#x29;&#x3B;&#x3C;&#x2F;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3E;"></iframe> </svg>',
                                true,
                                true,
                                'SVG with rembeded iframe (bug 60771)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" viewBox="6 3 177 153" xmlns:xlink="http://www.w3.org/1999/xlink"> <style>@import url("https://fonts.googleapis.com/css?family=Bitter:700&amp;text=WebPlatform.org");</style> <g transform="translate(-.5,-.5)"> <text fill="#474747" x="95" y="150" text-anchor="middle" font-family="Bitter" font-size="20" font-weight="bold">WebPlatform.org</text> </g> </svg>',
                                true,
                                true,
                                'SVG with @import in style element (bug 69008)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" viewBox="6 3 177 153" xmlns:xlink="http://www.w3.org/1999/xlink"> <style>@import url("https://fonts.googleapis.com/css?family=Bitter:700&amp;text=WebPlatform.org");<foo/></style> <g transform="translate(-.5,-.5)"> <text fill="#474747" x="95" y="150" text-anchor="middle" font-family="Bitter" font-size="20" font-weight="bold">WebPlatform.org</text> </g> </svg>',
                                true,
                                true,
                                'SVG with @import in style element and child element (bug 69008#c11)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" viewBox="6 3 177 153" xmlns:xlink="http://www.w3.org/1999/xlink"> <style>@imporT "https://fonts.googleapis.com/css?family=Bitter:700&amp;text=WebPlatform.org";</style> <g transform="translate(-.5,-.5)"> <text fill="#474747" x="95" y="150" text-anchor="middle" font-family="Bitter" font-size="20" font-weight="bold">WebPlatform.org</text> </g> </svg>',
                                true,
                                true,
                                'SVG with case-insensitive @import in style element (bug T85349)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <rect width="100" height="100" style="background-image:url(https://www.google.com/images/srpr/logo11w.png)"/> </svg>',
                                true,
                                true,
                                'SVG with remote background image (bug 69008)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <rect width="100" height="100" style="background-image:\55rl(https://www.google.com/images/srpr/logo11w.png)"/> </svg>',
                                true,
                                true,
                                'SVG with remote background image, encoded (bug 69008)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg"> <style> #a { background-image:\55rl(\'https://www.google.com/images/srpr/logo11w.png\'); } </style> <rect width="100" height="100" id="a"/> </svg>',
                                true,
                                true,
                                'SVG with remote background image, in style element (bug 69008)'
-                       ),
-                       array(
+                       ],
+                       [
                                // This currently doesn't seem to work in any browsers, but in case
                                // http://www.w3.org/TR/css3-images/ is implemented for SVG files
                                '<svg xmlns="http://www.w3.org/2000/svg"> <rect width="100" height="100" style="background-image:image(\'sprites.svg#xywh=40,0,20,20\')"/> </svg>',
                                true,
                                true,
                                'SVG with remote background image using image() (bug 69008)'
-                       ),
-                       array(
+                       ],
+                       [
                                // As reported by Cure53
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <a xlink:href="data:text/html;charset=utf-8;base64, PHNjcmlwdD5hbGVydChkb2N1bWVudC5kb21haW4pPC9zY3JpcHQ%2BDQo%3D"> <circle r="400" fill="red"></circle> </a> </svg>',
                                true,
                                true,
                                'SVG with data:text/html link target (firefox only)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ <!ENTITY lol "lol"> <!ENTITY lol2 "&#x3C;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3E;&#x61;&#x6C;&#x65;&#x72;&#x74;&#x28;&#x27;&#x58;&#x53;&#x53;&#x45;&#x44;&#x20;&#x3D;&#x3E;&#x20;&#x27;&#x2B;&#x64;&#x6F;&#x63;&#x75;&#x6D;&#x65;&#x6E;&#x74;&#x2E;&#x64;&#x6F;&#x6D;&#x61;&#x69;&#x6E;&#x29;&#x3B;&#x3C;&#x2F;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3E;"> ]> <svg xmlns="http://www.w3.org/2000/svg" width="68" height="68" viewBox="-34 -34 68 68" version="1.1"> <circle cx="0" cy="0" r="24" fill="#c8c8c8"/> <text x="0" y="0" fill="black">&lol2;</text> </svg>',
                                true,
                                true,
                                'SVG with encoded script tag in internal entity (reported by Beyond Security)'
-                       ),
-                       array(
+                       ],
+                       [
                                '<?xml version="1.0"?> <!DOCTYPE svg [ <!ENTITY foo SYSTEM "file:///etc/passwd"> ]> <svg xmlns="http://www.w3.org/2000/svg" version="1.1"> <desc>&foo;</desc> <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:1;stroke:rgb(0,0,2)" /> </svg>',
                                false,
                                false,
                                'SVG with external entity'
-                       ),
+                       ],
 
                        // Test good, but strange files that we want to allow
-                       array(
+                       [
                                '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <g> <a xlink:href="http://en.wikipedia.org/wiki/Main_Page"> <path transform="translate(0,496)" id="path6706" d="m 112.09375,107.6875 -5.0625,3.625 -4.3125,5.03125 -0.46875,0.5 -4.09375,3.34375 -9.125,5.28125 -8.625,-3.375 z" style="fill:#cccccc;fill-opacity:1;stroke:#6e6e6e;stroke-width:0.69999999;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;display:inline" /> </a> </g> </svg>',
                                true,
                                false,
                                'SVG with <a> link to a remote site'
-                       ),
-                       array(
+                       ],
+                       [
                                '<svg> <defs> <filter id="filter6226" x="-0.93243687" width="2.8648737" y="-0.24250539" height="1.4850108"> <feGaussianBlur stdDeviation="3.2344681" id="feGaussianBlur6228" /> </filter> <clipPath id="clipPath2436"> <path d="M 0,0 L 0,0 L 0,0 L 0,0 z" id="path2438" /> </clipPath> </defs> <g clip-path="url(#clipPath2436)" id="g2460"> <text id="text2466"> <tspan>12345</tspan> </text> </g> <path style="fill:#346733;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:bevel;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;filter:url(\'#filter6226\');fill-opacity:1;opacity:0.79807692" d="M 236.82371,332.63732 C 236.92217,332.63732 z" id="path5618" /> </svg>',
                                true,
                                false,
                                'SVG with local urls, including filter: in style'
-                       ),
-               );
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 }
index d3a5791..27ce287 100644 (file)
@@ -234,7 +234,7 @@ class BotPasswordTest extends MediaWikiTestCase {
                ] );
                $reset = MediaWiki\Session\TestUtils::setSessionManagerSingleton( $manager );
                $this->assertNull(
-                       $manager->getProvider( 'MediaWiki\\Session\\BotPasswordSessionProvider' ),
+                       $manager->getProvider( MediaWiki\Session\BotPasswordSessionProvider::class ),
                        'sanity check'
                );
                $status = BotPassword::login( 'UTSysop@BotPassword', 'foobaz', new FauxRequest );
@@ -245,8 +245,8 @@ class BotPasswordTest extends MediaWikiTestCase {
                $mainConfig = RequestContext::getMain()->getConfig();
                $config = new HashConfig( [
                        'SessionProviders' => $mainConfig->get( 'SessionProviders' ) + [
-                               'MediaWiki\\Session\\BotPasswordSessionProvider' => [
-                                       'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider',
+                               MediaWiki\Session\BotPasswordSessionProvider::class => [
+                                       'class' => MediaWiki\Session\BotPasswordSessionProvider::class,
                                        'args' => [ [ 'priority' => 40 ] ],
                                ]
                        ],
@@ -287,7 +287,7 @@ class BotPasswordTest extends MediaWikiTestCase {
                // Success!
                $request = new FauxRequest;
                $this->assertNotInstanceOf(
-                       'MediaWiki\\Session\\BotPasswordSessionProvider',
+                       MediaWiki\Session\BotPasswordSessionProvider::class,
                        $request->getSession()->getProvider(),
                        'sanity check'
                );
@@ -295,9 +295,9 @@ class BotPasswordTest extends MediaWikiTestCase {
                $this->assertInstanceOf( 'Status', $status );
                $this->assertTrue( $status->isGood() );
                $session = $status->getValue();
-               $this->assertInstanceOf( 'MediaWiki\\Session\\Session', $session );
+               $this->assertInstanceOf( MediaWiki\Session\Session::class, $session );
                $this->assertInstanceOf(
-                       'MediaWiki\\Session\\BotPasswordSessionProvider', $session->getProvider()
+                       MediaWiki\Session\BotPasswordSessionProvider::class, $session->getProvider()
                );
                $this->assertSame( $session->getId(), $request->getSession()->getId() );
 
index 17442b8..fafd4fa 100644 (file)
@@ -42,53 +42,58 @@ class MWCryptHKDFTest extends MediaWikiTestCase {
        public static function providerRfc5869() {
 
                // @codingStandardsIgnoreStart Generic.Files.LineLength
-               return array(
+               return [
                        // A.1
-                       array( 'sha256',
+                       [
+                               'sha256',
                                '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', // ikm
                                '000102030405060708090a0b0c', // salt
                                'f0f1f2f3f4f5f6f7f8f9', // context
                                42, // bytes
                                '077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5', // prk
                                '3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865' // okm
-                       ),
+                       ],
                        // A.2
-                       array( 'sha256',
+                       [
+                               'sha256',
                                '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f',
                                '606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf',
                                'b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff',
                                82,
                                '06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244',
                                'b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87'
-                       ),
+                       ],
                        // A.3
-                       array( 'sha256',
+                       [
+                               'sha256',
                                '0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', // ikm
                                '', // salt
                                '', // context
                                42, // bytes
                                '19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04', // prk
                                '8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8' // okm
-                       ),
+                       ],
                        // A.4
-                       array( 'sha1',
+                       [
+                               'sha1',
                                '0b0b0b0b0b0b0b0b0b0b0b', // ikm
                                '000102030405060708090a0b0c', // salt
                                'f0f1f2f3f4f5f6f7f8f9', // context
                                42, // bytes
                                '9b6c18c432a7bf8f0e71c8eb88f4b30baa2ba243', // prk
                                '085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896' // okm
-                       ),
+                       ],
                        // A.5
-                       array( 'sha1',
+                       [
+                               'sha1',
                                '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f', // ikm
                                '606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf', // salt
                                'b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', // context
                                82, // bytes
                                '8adae09a2a307059478d309b26c4115a224cfaf6', // prk
                                '0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4' // okm
-                       ),
-               );
+                       ],
+               ];
                // @codingStandardsIgnoreEnd
        }
 }
index 3f80b90..0cf2d0f 100644 (file)
@@ -1310,19 +1310,19 @@ class LanguageTest extends LanguageClassesTestCase {
 
        public static function provideCheckTitleEncodingData() {
                // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
-               return array(
-                       array( "" ),
-                       array( "United States of America" ), // 7bit ASCII
-                       array( rawurldecode( "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e" ) ),
-                       array(
+               return [
+                       [ "" ],
+                       [ "United States of America" ], // 7bit ASCII
+                       [ rawurldecode( "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e" ) ],
+                       [
                                rawurldecode(
                                        "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn"
                                )
-                       ),
+                       ],
                        // The following two data sets come from bug 36839. They fail if checkTitleEncoding uses a regexp to test for
                        // valid UTF-8 encoding and the pcre.recursion_limit is low (like, say, 1024). They succeed if checkTitleEncoding
                        // uses mb_check_encoding for its test.
-                       array(
+                       [
                                rawurldecode(
                                        "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C"
                                                . "Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C"
@@ -1339,8 +1339,8 @@ class LanguageTest extends LanguageClassesTestCase {
                                                . "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
                                                . "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
                                ),
-                       ),
-                       array(
+                       ],
+                       [
                                rawurldecode(
                                        "Mod%C3%A8le%3AArrondissements%20homonymes%7CMod%C3%A8le%3ABandeau%20standard%20pour%20page%20d'homonymie%7C"
                                                . "Mod%C3%A8le%3ABatailles%20homonymes%7CMod%C3%A8le%3ACantons%20homonymes%7C"
@@ -1358,8 +1358,8 @@ class LanguageTest extends LanguageClassesTestCase {
                                                . "Mod%C3%A8le%3ATitres%20homonymes%7CMod%C3%A8le%3AToponymie%7CMod%C3%A8le%3AUnit%C3%A9s%20homonymes%7C"
                                                . "Mod%C3%A8le%3AVilles%20homonymes%7CMod%C3%A8le%3A%C3%89difices%20religieux%20homonymes"
                                )
-                       )
-               );
+                       ]
+               ];
                // @codingStandardsIgnoreEnd
        }
 
index 4d060e4..77690cd 100755 (executable)
@@ -116,7 +116,7 @@ class PHPUnitMaintClass extends Maintenance {
                // cookies to show up in a FauxRequest somewhere.
                $wgSessionProviders = [
                        [
-                               'class' => 'MediaWiki\\Session\\CookieSessionProvider',
+                               'class' => MediaWiki\Session\CookieSessionProvider::class,
                                'args' => [ [
                                        'priority' => 30,
                                        'callUserSetCookiesHook' => true,