Merge "MCR database schema"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 2 Jan 2018 19:17:04 +0000 (19:17 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 2 Jan 2018 19:17:04 +0000 (19:17 +0000)
518 files changed:
.phpcs.xml
.travis.yml
RELEASE-NOTES-1.31
autoload.php
composer.json
docs/hooks.txt
includes/DefaultSettings.php
includes/DeprecatedGlobal.php
includes/GlobalFunctions.php
includes/HistoryBlob.php
includes/Linker.php
includes/MediaWiki.php
includes/MediaWikiServices.php
includes/OutputPage.php
includes/PHPVersionCheck.php
includes/Revision.php
includes/ServiceWiring.php
includes/Setup.php
includes/Storage/BlobStoreFactory.php [new file with mode: 0644]
includes/Storage/RevisionLookup.php
includes/Storage/RevisionStore.php
includes/Storage/RevisionStoreRecord.php
includes/Storage/SqlBlobStore.php
includes/Title.php
includes/actions/HistoryAction.php
includes/actions/WatchAction.php
includes/api/ApiBlock.php
includes/api/ApiEmailUser.php
includes/api/ApiErrorFormatter.php
includes/api/ApiFormatNone.php
includes/api/ApiRevisionDelete.php
includes/api/ApiTag.php
includes/api/i18n/ar.json
includes/api/i18n/gl.json
includes/api/i18n/lb.json
includes/api/i18n/nb.json
includes/api/i18n/pl.json
includes/api/i18n/pt-br.json
includes/api/i18n/pt.json
includes/api/i18n/ru.json
includes/cache/CacheDependency.php
includes/cache/CacheHelper.php
includes/cache/MessageCache.php
includes/cache/localisation/LocalisationCache.php
includes/changetags/ChangeTagsLogList.php
includes/changetags/ChangeTagsRevisionList.php
includes/config/ConfigFactory.php
includes/content/Content.php
includes/content/TextContentHandler.php
includes/context/MutableContext.php
includes/context/RequestContext.php
includes/exception/MWExceptionHandler.php
includes/filebackend/FileBackendGroup.php
includes/htmlform/HTMLForm.php
includes/htmlform/HTMLFormElement.php
includes/htmlform/fields/HTMLEditTools.php
includes/import/WikiImporter.php
includes/installer/DatabaseUpdater.php
includes/installer/Installer.php
includes/installer/OracleInstaller.php
includes/installer/i18n/ca.json
includes/installer/i18n/nl.json
includes/installer/i18n/pl.json
includes/installer/i18n/pt.json
includes/interwiki/ClassicInterwikiLookup.php
includes/jobqueue/JobQueueFederated.php
includes/jobqueue/jobs/DeleteLinksJob.php
includes/libs/CSSMin.php
includes/libs/JavaScriptMinifier.php
includes/libs/jsminplus.php
includes/libs/lockmanager/ScopedLock.php
includes/libs/objectcache/MemcachedClient.php
includes/libs/objectcache/WANObjectCache.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
includes/libs/stats/BufferingStatsdDataFactory.php
includes/libs/stats/IBufferingStatsdDataFactory.php
includes/libs/stats/NullStatsdDataFactory.php
includes/libs/xmp/XMP.php
includes/libs/xmp/XMPValidate.php
includes/media/Bitmap_ClientOnly.php
includes/objectcache/SqlBagOStuff.php
includes/page/ImagePage.php
includes/page/PageArchive.php
includes/page/WikiPage.php
includes/parser/Parser.php
includes/parser/Preprocessor_DOM.php
includes/parser/Preprocessor_Hash.php
includes/parser/Sanitizer.php
includes/password/PasswordPolicyChecks.php
includes/poolcounter/PoolCounter.php
includes/poolcounter/PoolCounterRedis.php
includes/resourceloader/ResourceLoader.php
includes/resourceloader/ResourceLoaderFileModule.php
includes/resourceloader/ResourceLoaderFilePath.php
includes/resourceloader/ResourceLoaderModule.php
includes/resourceloader/ResourceLoaderUserTokensModule.php
includes/resourceloader/ResourceLoaderWikiModule.php
includes/search/SearchExactMatchRescorer.php
includes/shell/Command.php
includes/shell/FirejailCommand.php
includes/shell/Shell.php
includes/skins/SkinFallbackTemplate.php
includes/specialpage/ChangesListSpecialPage.php
includes/specialpage/QueryPage.php
includes/specials/SpecialEditTags.php
includes/specials/SpecialExpandTemplates.php
includes/specials/SpecialExport.php
includes/specials/SpecialNewpages.php
includes/specials/SpecialProtectedpages.php
includes/specials/SpecialRecentchanges.php
includes/specials/SpecialRecentchangeslinked.php
includes/specials/SpecialRevisiondelete.php
includes/specials/SpecialUncategorizedcategories.php
includes/specials/SpecialUserrights.php
includes/specials/pagers/ContribsPager.php
includes/specials/pagers/ImageListPager.php
includes/specials/pagers/ProtectedPagesPager.php
includes/specials/pagers/UsersPager.php
includes/tidy/Balancer.php
includes/upload/UploadBase.php
includes/user/User.php
includes/user/UserGroupMembership.php
includes/utils/AutoloadGenerator.php
includes/utils/BatchRowWriter.php
includes/widget/ComplexNamespaceInputWidget.php
includes/widget/ComplexTitleInputWidget.php
includes/widget/DateInputWidget.php
includes/widget/DateTimeInputWidget.php
includes/widget/NamespaceInputWidget.php
includes/widget/SearchInputWidget.php
includes/widget/SelectWithInputWidget.php
includes/widget/TitleInputWidget.php
includes/widget/UserInputWidget.php
includes/widget/search/BasicSearchResultSetWidget.php
includes/widget/search/SearchFormWidget.php
includes/widget/search/SimpleSearchResultSetWidget.php
index.php
languages/Language.php
languages/LanguageConverter.php
languages/classes/LanguageBe_tarask.php
languages/classes/LanguageBg.php [deleted file]
languages/classes/LanguageEs.php [deleted file]
languages/classes/LanguageEt.php [deleted file]
languages/classes/LanguageHy.php
languages/classes/LanguageKaa.php
languages/classes/LanguageKk_cyrl.php
languages/classes/LanguageKsh.php
languages/classes/LanguageKu.php
languages/classes/LanguageKu_ku.php [deleted file]
languages/classes/LanguagePl.php [deleted file]
languages/classes/LanguageRu.php [deleted file]
languages/classes/LanguageUk.php [deleted file]
languages/classes/LanguageZh_hans.php
languages/data/CrhExceptions.php
languages/data/ZhConversion.php
languages/i18n/ar.json
languages/i18n/ast.json
languages/i18n/az.json
languages/i18n/be-tarask.json
languages/i18n/bg.json
languages/i18n/bho.json
languages/i18n/bn.json
languages/i18n/bs.json
languages/i18n/ca.json
languages/i18n/ce.json
languages/i18n/cs.json
languages/i18n/da.json
languages/i18n/de.json
languages/i18n/en.json
languages/i18n/es.json
languages/i18n/et.json
languages/i18n/eu.json
languages/i18n/fa.json
languages/i18n/fi.json
languages/i18n/fr.json
languages/i18n/frr.json
languages/i18n/gl.json
languages/i18n/he.json
languages/i18n/hi.json
languages/i18n/hr.json
languages/i18n/hu.json
languages/i18n/ia.json
languages/i18n/is.json
languages/i18n/it.json
languages/i18n/ja.json
languages/i18n/kk-cyrl.json
languages/i18n/ko.json
languages/i18n/lad.json
languages/i18n/lb.json
languages/i18n/lt.json
languages/i18n/lzh.json
languages/i18n/mk.json
languages/i18n/ml.json
languages/i18n/ms.json
languages/i18n/mwl.json
languages/i18n/nb.json
languages/i18n/nl.json
languages/i18n/pl.json
languages/i18n/ps.json
languages/i18n/pt-br.json
languages/i18n/pt.json
languages/i18n/ru.json
languages/i18n/sd.json
languages/i18n/skr-arab.json
languages/i18n/sl.json
languages/i18n/sr-ec.json
languages/i18n/sv.json
languages/i18n/th.json
languages/i18n/tr.json
languages/i18n/uk.json
languages/i18n/ur.json
languages/i18n/zh-hans.json
languages/messages/MessagesBe_tarask.php
languages/messages/MessagesBg.php
languages/messages/MessagesEs.php
languages/messages/MessagesEt.php
languages/messages/MessagesHy.php
languages/messages/MessagesKaa.php
languages/messages/MessagesKk_cyrl.php
languages/messages/MessagesKsh.php
languages/messages/MessagesKu_latn.php
languages/messages/MessagesPl.php
languages/messages/MessagesRu.php
languages/messages/MessagesUk.php
maintenance/Maintenance.php
maintenance/benchmarks/Benchmarker.php
maintenance/benchmarks/bench_utf8_title_check.php
maintenance/cdb.php
maintenance/commandLine.inc
maintenance/deleteBatch.php
maintenance/doMaintenance.php
maintenance/dumpIterator.php
maintenance/dumpTextPass.php
maintenance/generateSitemap.php
maintenance/importDump.php
maintenance/language/checkLanguage.inc
maintenance/language/zhtable/simp2trad.manual
maintenance/language/zhtable/toCN.manual
maintenance/language/zhtable/toHK.manual
maintenance/language/zhtable/toSimp.manual
maintenance/language/zhtable/toTW.manual
maintenance/language/zhtable/toTrad.manual
maintenance/language/zhtable/trad2simp.manual
maintenance/language/zhtable/tradphrases.manual
maintenance/language/zhtable/tradphrases_exclude.manual
maintenance/mergeMessageFileList.php
maintenance/moveBatch.php
maintenance/renderDump.php
maintenance/storage/checkStorage.php
maintenance/storage/compressOld.php
maintenance/update.php
maintenance/userOptions.php
mw-config/index.php
profileinfo.php
resources/Resources.php
resources/lib/jquery.chosen/LICENSE
resources/lib/jquery.chosen/README.md [new file with mode: 0644]
resources/lib/jquery.chosen/chosen-sprite.png
resources/lib/jquery.chosen/chosen-sprite@2x.png
resources/lib/jquery.chosen/chosen.css
resources/lib/jquery.chosen/chosen.jquery.js
resources/src/jquery/jquery.tablesorter.less
resources/src/mediawiki.action/mediawiki.action.edit.styles.less
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterGroup.js
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FilterItem.js
resources/src/mediawiki.rcfilters/dm/mw.rcfilters.dm.FiltersViewModel.js
resources/src/mediawiki.rcfilters/mw.rcfilters.Controller.js
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.MenuSelectWidget.less
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.Overlay.vector.less [new file with mode: 0644]
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTargetPageWidget.less [new file with mode: 0644]
resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclToOrFromWidget.less
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterMenuHeaderWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterMenuSectionOptionWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.FilterTagMultiselectWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.ItemMenuOptionWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.MenuSelectWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.RclTargetPageWidget.js
resources/src/mediawiki.rcfilters/ui/mw.rcfilters.ui.SaveFiltersPopupButtonWidget.js
resources/src/mediawiki.skinning/interface.css
tests/common/TestsAutoLoader.php
tests/parser/ParserTestParserHook.php
tests/parser/editTests.php
tests/parser/parserTests.txt
tests/phan/stubs/hhvm.php
tests/phan/stubs/mail.php
tests/phan/stubs/memcached.php
tests/phan/stubs/tideways.php
tests/phan/stubs/wikidiff.php
tests/phpunit/MediaWikiCoversValidator.php [new file with mode: 0644]
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/includes/AutopromoteTest.php
tests/phpunit/includes/BlockTest.php
tests/phpunit/includes/FauxRequestTest.php
tests/phpunit/includes/GlobalFunctions/GlobalTest.php
tests/phpunit/includes/HooksTest.php
tests/phpunit/includes/HtmlTest.php
tests/phpunit/includes/LinkFilterTest.php
tests/phpunit/includes/LinkerTest.php
tests/phpunit/includes/MWNamespaceTest.php
tests/phpunit/includes/MediaWikiServicesTest.php
tests/phpunit/includes/MediaWikiVersionFetcherTest.php
tests/phpunit/includes/OutputPageTest.php
tests/phpunit/includes/PageArchiveTest.php
tests/phpunit/includes/PagePropsTest.php
tests/phpunit/includes/PathRouterTest.php
tests/phpunit/includes/RevisionDbTestBase.php
tests/phpunit/includes/RevisionTest.php
tests/phpunit/includes/SampleTest.php
tests/phpunit/includes/SanitizerValidateEmailTest.php
tests/phpunit/includes/Services/ServiceContainerTest.php [deleted file]
tests/phpunit/includes/Services/TestWiring1.php [deleted file]
tests/phpunit/includes/Services/TestWiring2.php [deleted file]
tests/phpunit/includes/StatusTest.php
tests/phpunit/includes/Storage/BlobStoreFactoryTest.php [new file with mode: 0644]
tests/phpunit/includes/Storage/RevisionStoreDbTest.php
tests/phpunit/includes/Storage/RevisionStoreTest.php
tests/phpunit/includes/TemplateParserTest.php
tests/phpunit/includes/TitleArrayFromResultTest.php
tests/phpunit/includes/TitleMethodsTest.php
tests/phpunit/includes/TitleTest.php
tests/phpunit/includes/WikiReferenceTest.php
tests/phpunit/includes/XmlJsTest.php
tests/phpunit/includes/XmlTest.php
tests/phpunit/includes/api/ApiBaseTest.php
tests/phpunit/includes/api/ApiCheckTokenTest.php [new file with mode: 0644]
tests/phpunit/includes/api/ApiClearHasMsgTest.php [new file with mode: 0644]
tests/phpunit/includes/api/ApiComparePagesTest.php
tests/phpunit/includes/api/ApiOpenSearchTest.php
tests/phpunit/includes/api/ApiPageSetTest.php
tests/phpunit/includes/api/ApiParseTest.php
tests/phpunit/includes/api/ApiQueryAllPagesTest.php
tests/phpunit/includes/api/ApiQueryRecentChangesIntegrationTest.php [new file with mode: 0644]
tests/phpunit/includes/api/ApiTestCase.php
tests/phpunit/includes/api/ApiUploadTest.php
tests/phpunit/includes/api/ApiUsageExceptionTest.php
tests/phpunit/includes/api/ApiWatchTest.php
tests/phpunit/includes/api/format/ApiFormatPhpTest.php
tests/phpunit/includes/api/format/ApiFormatXmlTest.php
tests/phpunit/includes/changes/ChangesListFilterGroupTest.php
tests/phpunit/includes/changes/ChangesListFilterTest.php
tests/phpunit/includes/collation/CollationFaTest.php
tests/phpunit/includes/collation/CustomUppercaseCollationTest.php
tests/phpunit/includes/composer/ComposerVersionNormalizerTest.php
tests/phpunit/includes/config/EtcdConfigTest.php
tests/phpunit/includes/content/ContentHandlerTest.php
tests/phpunit/includes/content/CssContentHandlerTest.php
tests/phpunit/includes/content/CssContentTest.php
tests/phpunit/includes/content/FileContentHandlerTest.php
tests/phpunit/includes/content/JavaScriptContentHandlerTest.php
tests/phpunit/includes/content/JavaScriptContentTest.php
tests/phpunit/includes/content/TextContentHandlerTest.php
tests/phpunit/includes/content/WikitextContentHandlerTest.php
tests/phpunit/includes/content/WikitextStructureTest.php
tests/phpunit/includes/db/DatabaseSqliteTest.php
tests/phpunit/includes/db/LBFactoryTest.php
tests/phpunit/includes/db/LoadBalancerTest.php
tests/phpunit/includes/debug/logger/monolog/AvroFormatterTest.php
tests/phpunit/includes/debug/logger/monolog/KafkaHandlerTest.php
tests/phpunit/includes/deferred/LinksUpdateTest.php
tests/phpunit/includes/deferred/MWCallableUpdateTest.php
tests/phpunit/includes/deferred/TransactionRoundDefiningUpdateTest.php
tests/phpunit/includes/editpage/TextboxBuilderTest.php [new file with mode: 0644]
tests/phpunit/includes/exception/MWExceptionTest.php
tests/phpunit/includes/externalstore/ExternalStoreFactoryTest.php
tests/phpunit/includes/filerepo/MigrateFileRepoLayoutTest.php
tests/phpunit/includes/filerepo/RepoGroupTest.php
tests/phpunit/includes/filerepo/file/FileTest.php
tests/phpunit/includes/htmlform/HTMLFormTest.php
tests/phpunit/includes/htmlform/HTMLRestrictionsFieldTest.php
tests/phpunit/includes/http/HttpTest.php
tests/phpunit/includes/import/ImportTest.php
tests/phpunit/includes/jobqueue/JobQueueMemoryTest.php
tests/phpunit/includes/jobqueue/RefreshLinksPartitionTest.php
tests/phpunit/includes/libs/ArrayUtilsTest.php
tests/phpunit/includes/libs/CSSMinTest.php
tests/phpunit/includes/libs/DeferredStringifierTest.php
tests/phpunit/includes/libs/DnsSrvDiscovererTest.php
tests/phpunit/includes/libs/GenericArrayObjectTest.php
tests/phpunit/includes/libs/HashRingTest.php
tests/phpunit/includes/libs/HtmlArmorTest.php
tests/phpunit/includes/libs/IEUrlExtensionTest.php
tests/phpunit/includes/libs/IPTest.php
tests/phpunit/includes/libs/JavaScriptMinifierTest.php
tests/phpunit/includes/libs/MWMessagePackTest.php
tests/phpunit/includes/libs/MapCacheLRUTest.php
tests/phpunit/includes/libs/MemoizedCallableTest.php
tests/phpunit/includes/libs/ObjectFactoryTest.php
tests/phpunit/includes/libs/ProcessCacheLRUTest.php
tests/phpunit/includes/libs/SamplingStatsdClientTest.php
tests/phpunit/includes/libs/StringUtilsTest.php
tests/phpunit/includes/libs/TimingTest.php
tests/phpunit/includes/libs/XhprofDataTest.php
tests/phpunit/includes/libs/XhprofTest.php
tests/phpunit/includes/libs/XmlTypeCheckTest.php
tests/phpunit/includes/libs/mime/MimeAnalyzerTest.php
tests/phpunit/includes/libs/objectcache/BagOStuffTest.php
tests/phpunit/includes/libs/objectcache/CachedBagOStuffTest.php
tests/phpunit/includes/libs/objectcache/HashBagOStuffTest.php
tests/phpunit/includes/libs/objectcache/WANObjectCacheTest.php
tests/phpunit/includes/libs/rdbms/TransactionProfilerTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseDomainTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseSQLTest.php
tests/phpunit/includes/libs/rdbms/database/DatabaseTest.php
tests/phpunit/includes/libs/xmp/XMPTest.php
tests/phpunit/includes/libs/xmp/XMPValidateTest.php
tests/phpunit/includes/logging/BlockLogFormatterTest.php
tests/phpunit/includes/logging/DeleteLogFormatterTest.php
tests/phpunit/includes/logging/ImportLogFormatterTest.php
tests/phpunit/includes/logging/MergeLogFormatterTest.php
tests/phpunit/includes/logging/MoveLogFormatterTest.php
tests/phpunit/includes/logging/NewUsersLogFormatterTest.php
tests/phpunit/includes/logging/PageLangLogFormatterTest.php
tests/phpunit/includes/logging/PatrolLogFormatterTest.php
tests/phpunit/includes/logging/ProtectLogFormatterTest.php
tests/phpunit/includes/logging/RightsLogFormatterTest.php
tests/phpunit/includes/logging/UploadLogFormatterTest.php
tests/phpunit/includes/media/ExifBitmapTest.php
tests/phpunit/includes/media/ExifRotationTest.php
tests/phpunit/includes/media/GIFTest.php
tests/phpunit/includes/media/JpegTest.php
tests/phpunit/includes/media/PNGTest.php
tests/phpunit/includes/media/SVGMetadataExtractorTest.php
tests/phpunit/includes/media/TiffTest.php
tests/phpunit/includes/media/WebPTest.php
tests/phpunit/includes/objectcache/MemcachedBagOStuffTest.php
tests/phpunit/includes/objectcache/RESTBagOStuffTest.php
tests/phpunit/includes/objectcache/RedisBagOStuffTest.php
tests/phpunit/includes/page/ImagePage404Test.php
tests/phpunit/includes/page/ImagePageTest.php
tests/phpunit/includes/page/WikiPageDbTestBase.php
tests/phpunit/includes/parser/MagicVariableTest.php
tests/phpunit/includes/parser/ParserIntegrationTest.php
tests/phpunit/includes/parser/ParserOptionsTest.php
tests/phpunit/includes/parser/ParserOutputTest.php
tests/phpunit/includes/parser/PreprocessorTest.php
tests/phpunit/includes/parser/SanitizerTest.php
tests/phpunit/includes/password/BcryptPasswordTest.php
tests/phpunit/includes/password/EncryptedPasswordTest.php
tests/phpunit/includes/password/LayeredParameterizedPasswordTest.php
tests/phpunit/includes/poolcounter/PoolCounterTest.php
tests/phpunit/includes/registration/ExtensionProcessorTest.php
tests/phpunit/includes/registration/VersionCheckerTest.php
tests/phpunit/includes/resourceloader/DerivativeResourceLoaderContextTest.php
tests/phpunit/includes/resourceloader/MessageBlobStoreTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderClientHtmlTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderContextTest.php
tests/phpunit/includes/resourceloader/ResourceLoaderSkinModuleTest.php
tests/phpunit/includes/services/ServiceContainerTest.php [new file with mode: 0644]
tests/phpunit/includes/services/TestWiring1.php [new file with mode: 0644]
tests/phpunit/includes/services/TestWiring2.php [new file with mode: 0644]
tests/phpunit/includes/shell/CommandFactoryTest.php
tests/phpunit/includes/shell/CommandTest.php
tests/phpunit/includes/shell/FirejailCommandTest.php
tests/phpunit/includes/shell/ShellTest.php
tests/phpunit/includes/site/DBSiteStoreTest.php
tests/phpunit/includes/site/FileBasedSiteLookupTest.php
tests/phpunit/includes/site/MediaWikiPageNameNormalizerTest.php
tests/phpunit/includes/site/SiteExporterTest.php
tests/phpunit/includes/site/SiteImporterTest.php
tests/phpunit/includes/site/SiteListTest.php
tests/phpunit/includes/site/SitesCacheFileBuilderTest.php
tests/phpunit/includes/specials/ContribsPagerTest.php
tests/phpunit/includes/specials/SpecialMIMESearchTest.php
tests/phpunit/includes/specials/SpecialUncategorizedcategoriesTest.php
tests/phpunit/includes/tidy/RemexDriverTest.php
tests/phpunit/includes/upload/UploadBaseTest.php
tests/phpunit/includes/user/PasswordResetTest.php
tests/phpunit/includes/user/UserTest.php
tests/phpunit/includes/utils/AvroValidatorTest.php
tests/phpunit/includes/utils/BatchRowUpdateTest.php
tests/phpunit/includes/utils/ClassCollectorTest.php
tests/phpunit/includes/utils/FileContentsHasherTest.php
tests/phpunit/includes/utils/MWCryptHKDFTest.php
tests/phpunit/includes/utils/MWCryptHashTest.php
tests/phpunit/includes/utils/MWRestrictionsTest.php
tests/phpunit/includes/utils/UIDGeneratorTest.php
tests/phpunit/includes/utils/ZipDirectoryReaderTest.php
tests/phpunit/includes/watcheditem/WatchedItemQueryServiceUnitTest.php
tests/phpunit/languages/LanguageCodeTest.php
tests/phpunit/languages/LanguageConverterTest.php
tests/phpunit/languages/LanguageTest.php
tests/phpunit/languages/classes/LanguageArTest.php
tests/phpunit/languages/classes/LanguageBe_taraskTest.php
tests/phpunit/languages/classes/LanguageBsTest.php
tests/phpunit/languages/classes/LanguageCrhTest.php
tests/phpunit/languages/classes/LanguageCuTest.php
tests/phpunit/languages/classes/LanguageDsbTest.php
tests/phpunit/languages/classes/LanguageGanTest.php
tests/phpunit/languages/classes/LanguageHsbTest.php
tests/phpunit/languages/classes/LanguageHuTest.php
tests/phpunit/languages/classes/LanguageHyTest.php
tests/phpunit/languages/classes/LanguageIuTest.php
tests/phpunit/languages/classes/LanguageKkTest.php
tests/phpunit/languages/classes/LanguageKshTest.php
tests/phpunit/languages/classes/LanguageKuTest.php
tests/phpunit/languages/classes/LanguageMlTest.php
tests/phpunit/languages/classes/LanguagePlTest.php
tests/phpunit/languages/classes/LanguageRuTest.php
tests/phpunit/languages/classes/LanguageShiTest.php
tests/phpunit/languages/classes/LanguageSlTest.php
tests/phpunit/languages/classes/LanguageSrTest.php
tests/phpunit/languages/classes/LanguageTgTest.php
tests/phpunit/languages/classes/LanguageTrTest.php
tests/phpunit/languages/classes/LanguageUkTest.php
tests/phpunit/languages/classes/LanguageUzTest.php
tests/phpunit/languages/classes/LanguageWaTest.php
tests/phpunit/languages/classes/LanguageZhTest.php
tests/phpunit/maintenance/BenchmarkerTest.php [new file with mode: 0644]
tests/phpunit/maintenance/backupPrefetchTest.php
tests/phpunit/maintenance/categoriesRdfTest.php
tests/phpunit/skins/SideBarTest.php
tests/phpunit/structure/AvailableRightsTest.php
tests/phpunit/structure/ExtensionJsonValidationTest.php
tests/qunit/suites/resources/mediawiki/mediawiki.toc.test.js
tests/qunit/suites/resources/mediawiki/mediawiki.util.test.js
tests/selenium/wdio.conf.jenkins.js
tests/selenium/wdio.conf.js

index 3170381..7f90f27 100644 (file)
                <exclude name="MediaWiki.Usage.SuperGlobalsUsage.SuperGlobals" />
                <exclude name="MediaWiki.Files.ClassMatchesFilename.WrongCase" />
                <exclude name="MediaWiki.Files.ClassMatchesFilename.NotMatch" />
-               <exclude name="MediaWiki.Files.OneClassPerFile.MultipleFound" />
+               <exclude name="Generic.Files.OneObjectStructurePerFile.MultipleFound" />
                <exclude name="MediaWiki.VariableAnalysis.ForbiddenGlobalVariables.ForbiddenGlobal$wgTitle" />
                <exclude name="MediaWiki.Usage.DeprecatedConstantUsage.NS_IMAGE" />
                <exclude name="MediaWiki.Usage.DeprecatedConstantUsage.NS_IMAGE_TALK" />
                <exclude name="MediaWiki.Commenting.FunctionComment.SpacingDocStar" />
                <exclude name="MediaWiki.Commenting.FunctionComment.SpacingDocTag" />
+               <exclude name="Squiz.Scope.MethodScope.Missing" />
+               <exclude name="Squiz.Scope.MemberVarScope.Missing" />
        </rule>
        <rule ref="MediaWiki.NamingConventions.PrefixedGlobalFunctions">
                <properties>
index 64414b5..32763b5 100644 (file)
@@ -27,8 +27,6 @@ matrix:
     - env: dbtype=postgres dbuser=travis
       php: 5.5
     # https://docs.travis-ci.com/user/languages/php#HHVM-versions
-    - env: dbtype=mysql dbuser=root
-      php: hhvm-3.12
     - env: dbtype=mysql dbuser=root
       php: hhvm-3.18
     - env: dbtype=mysql dbuser=root
index 1a1a9f7..a496b02 100644 (file)
@@ -19,6 +19,8 @@ production.
   maintenance/cleanupUsersWithNoId.php.
 * $wgResourceLoaderMinifierStatementsOnOwnLine and $wgResourceLoaderMinifierMaxLineLength
   were removed (deprecated since 1.27).
+* (T180921) $wgReferrerPolicy now supports having fallbacks for browsers that are not
+  using the latest version of the Referrer Policy specification.
 
 === New features in 1.31 ===
 * Wikimedia\Rdbms\IDatabase->select() and similar methods now support
@@ -39,6 +41,7 @@ production.
 === External library changes in 1.31 ===
 
 ==== Upgraded external libraries ====
+* Updated jquery.chosen from v0.9.14 to v1.8.2.
 * …
 
 ==== New external libraries ====
@@ -71,6 +74,10 @@ changes to languages because of Phabricator reports.
 * (T180052) Mirandese (mwl) now supports gendered NS_USER/NS_USER_TALK namespaces.
 
 === Other changes in 1.31 ===
+* Introducing multi-content-revision capability into the storage layer. For details,
+  see <https://www.mediawiki.org/wiki/Requests_for_comment/Multi-Content_Revisions>.
+* The Revision class was deprecated in favor of RevisionStore, BlobStore, and
+  RevisionRecord and its subclasses.
 * MessageBlobStore::insertMessageBlob() (deprecated in 1.27) was removed.
 * The global function wfBCP47 was renamed to LanguageCode::bcp47.
 * The global function wfBCP47 is now deprecated.
@@ -123,6 +130,9 @@ changes to languages because of Phabricator reports.
 * The Block class will no longer accept usable-but-missing usernames for
   'byText' or ->setBlocker(). Callers should either ensure the blocker exists
   locally or use a new interwiki-format username like "iw>Example".
+* The RevisionInsertComplete hook is now deprecated, use RevisionRecordInserted instead.
+  RevisionInsertComplete is still called, but the second and third parameter will always be null.
+  Hard deprecation is scheduled for 1.32.
 * The following methods that get and set ParserOutput state are deprecated.
   Callers should use the new stateless $options parameter to
   ParserOutput::getText() instead.
@@ -146,6 +156,9 @@ changes to languages because of Phabricator reports.
   * WatchedItem::IGNORE_USER_RIGHTS
   * WatchedItem::CHECK_USER_RIGHTS
   * WatchedItem::DEPRECATED_USAGE_TIMESTAMP
+* The $statementsOnOwnLine parameter of JavaScriptMinifier::minify was removed.
+  The corresponding configuration variable ($wgResourceLoaderMinifierStatementsOnOwnLine)
+  has been deprecated since 1.27 and was removed as well.
 
 == Compatibility ==
 MediaWiki 1.31 requires PHP 5.5.9 or later. There is experimental support for
index 6b8387b..4a8e18d 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 // This file is generated by maintenance/generateLocalAutoload.php, do not adjust manually
-// @codingStandardsIgnoreFile
+// phpcs:ignoreFile Generic.Files.LineLength
 global $wgAutoloadLocalClasses;
 
 $wgAutoloadLocalClasses = [
@@ -705,7 +705,6 @@ $wgAutoloadLocalClasses = [
        'LanguageAr' => __DIR__ . '/languages/classes/LanguageAr.php',
        'LanguageAz' => __DIR__ . '/languages/classes/LanguageAz.php',
        'LanguageBe_tarask' => __DIR__ . '/languages/classes/LanguageBe_tarask.php',
-       'LanguageBg' => __DIR__ . '/languages/classes/LanguageBg.php',
        'LanguageBs' => __DIR__ . '/languages/classes/LanguageBs.php',
        'LanguageCode' => __DIR__ . '/languages/LanguageCode.php',
        'LanguageConverter' => __DIR__ . '/languages/LanguageConverter.php',
@@ -713,8 +712,6 @@ $wgAutoloadLocalClasses = [
        'LanguageCu' => __DIR__ . '/languages/classes/LanguageCu.php',
        'LanguageDsb' => __DIR__ . '/languages/classes/LanguageDsb.php',
        'LanguageEn' => __DIR__ . '/languages/classes/LanguageEn.php',
-       'LanguageEs' => __DIR__ . '/languages/classes/LanguageEs.php',
-       'LanguageEt' => __DIR__ . '/languages/classes/LanguageEt.php',
        'LanguageFi' => __DIR__ . '/languages/classes/LanguageFi.php',
        'LanguageGa' => __DIR__ . '/languages/classes/LanguageGa.php',
        'LanguageGan' => __DIR__ . '/languages/classes/LanguageGan.php',
@@ -729,21 +726,17 @@ $wgAutoloadLocalClasses = [
        'LanguageKm' => __DIR__ . '/languages/classes/LanguageKm.php',
        'LanguageKsh' => __DIR__ . '/languages/classes/LanguageKsh.php',
        'LanguageKu' => __DIR__ . '/languages/classes/LanguageKu.php',
-       'LanguageKu_ku' => __DIR__ . '/languages/classes/LanguageKu_ku.php',
        'LanguageLa' => __DIR__ . '/languages/classes/LanguageLa.php',
        'LanguageMl' => __DIR__ . '/languages/classes/LanguageMl.php',
        'LanguageMy' => __DIR__ . '/languages/classes/LanguageMy.php',
        'LanguageOs' => __DIR__ . '/languages/classes/LanguageOs.php',
-       'LanguagePl' => __DIR__ . '/languages/classes/LanguagePl.php',
        'LanguageQqx' => __DIR__ . '/languages/classes/LanguageQqx.php',
-       'LanguageRu' => __DIR__ . '/languages/classes/LanguageRu.php',
        'LanguageShi' => __DIR__ . '/languages/classes/LanguageShi.php',
        'LanguageSl' => __DIR__ . '/languages/classes/LanguageSl.php',
        'LanguageSr' => __DIR__ . '/languages/classes/LanguageSr.php',
        'LanguageTg' => __DIR__ . '/languages/classes/LanguageTg.php',
        'LanguageTr' => __DIR__ . '/languages/classes/LanguageTr.php',
        'LanguageTyv' => __DIR__ . '/languages/classes/LanguageTyv.php',
-       'LanguageUk' => __DIR__ . '/languages/classes/LanguageUk.php',
        'LanguageUz' => __DIR__ . '/languages/classes/LanguageUz.php',
        'LanguageWa' => __DIR__ . '/languages/classes/LanguageWa.php',
        'LanguageYue' => __DIR__ . '/languages/classes/LanguageYue.php',
@@ -944,6 +937,7 @@ $wgAutoloadLocalClasses = [
        'MediaWiki\\Site\\MediaWikiPageNameNormalizer' => __DIR__ . '/includes/site/MediaWikiPageNameNormalizer.php',
        'MediaWiki\\Storage\\BlobAccessException' => __DIR__ . '/includes/Storage/BlobAccessException.php',
        'MediaWiki\\Storage\\BlobStore' => __DIR__ . '/includes/Storage/BlobStore.php',
+       'MediaWiki\\Storage\\BlobStoreFactory' => __DIR__ . '/includes/Storage/BlobStoreFactory.php',
        'MediaWiki\\Storage\\IncompleteRevisionException' => __DIR__ . '/includes/Storage/IncompleteRevisionException.php',
        'MediaWiki\\Storage\\MutableRevisionRecord' => __DIR__ . '/includes/Storage/MutableRevisionRecord.php',
        'MediaWiki\\Storage\\MutableRevisionSlots' => __DIR__ . '/includes/Storage/MutableRevisionSlots.php',
index 35783f2..cc29165 100644 (file)
@@ -39,7 +39,7 @@
                "wikimedia/php-session-serializer": "1.0.4",
                "wikimedia/purtle": "1.0.6",
                "wikimedia/relpath": "2.0.0",
-               "wikimedia/remex-html": "1.0.1",
+               "wikimedia/remex-html": "1.0.2",
                "wikimedia/running-stat": "1.1.0",
                "wikimedia/scoped-callback": "1.0.0",
                "wikimedia/utfnormal": "1.1.0",
@@ -54,7 +54,7 @@
                "jakub-onderka/php-parallel-lint": "0.9.2",
                "jetbrains/phpstorm-stubs": "dev-master#1b9906084d6635456fcf3f3a01f0d7d5b99a578a",
                "justinrainbow/json-schema": "~5.2",
-               "mediawiki/mediawiki-codesniffer": "14.1.0",
+               "mediawiki/mediawiki-codesniffer": "15.0.0",
                "monolog/monolog": "~1.22.1",
                "nikic/php-parser": "2.1.0",
                "nmred/kafka-php": "0.1.5",
index ee38ea9..45387a3 100644 (file)
@@ -951,7 +951,7 @@ $id: the page ID (original ID in case of page deletions)
 in a Category page. Gives extensions the opportunity to batch load any
 related data about the pages.
 $type: The category type. Either 'page', 'file' or 'subcat'
-$res: Query result from DatabaseBase::select()
+$res: Query result from Wikimedia\Rdbms\IDatabase::select()
 
 'CategoryViewer::generateLink': Before generating an output link allow
 extensions opportunity to generate a more specific or relevant link.
@@ -2810,14 +2810,14 @@ called after the addition of 'qunit' and MediaWiki testing resources.
   added to any module.
 &$ResourceLoader: object
 
-'RevisionInsertComplete': Called after a revision is inserted into the database.
-&$revision: the Revision
-$data: the data stored in old_text.  The meaning depends on $flags: if external
-  is set, it's the URL of the revision text in external storage; otherwise,
-  it's the revision text itself.  In either case, if gzip is set, the revision
-  text is gzipped.
-$flags: a comma-delimited list of strings representing the options used.  May
-  include: utf8 (this will always be set for new revisions); gzip; external.
+'RevisionRecordInserted': Called after a revision is inserted into the database.
+$revisionRecord: the RevisionRecord that has just been inserted.
+
+'RevisionInsertComplete': DEPRECATED! Use RevisionRecordInserted hook instead.
+Called after a revision is inserted into the database.
+$revision: the Revision
+$data: DEPRECATED! Always null!
+$flags: DEPRECATED! Always null!
 
 'SearchableNamespaces': An option to modify which namespaces are searchable.
 &$arr: Array of namespaces ($nsId => $name) which will be used.
index b707174..8091428 100644 (file)
@@ -316,10 +316,20 @@ $wgAppleTouchIcon = false;
 
 /**
  * Value for the referrer policy meta tag.
- * One of 'never', 'default', 'origin', 'always'. Setting it to false just
- * prevents the meta tag from being output.
- * See https://www.w3.org/TR/referrer-policy/ for details.
- *
+ * One or more of the values defined in the Referrer Policy specification:
+ * https://w3c.github.io/webappsec-referrer-policy/
+ * ('no-referrer', 'no-referrer-when-downgrade', 'same-origin',
+ * 'origin', 'strict-origin', 'origin-when-cross-origin',
+ * 'strict-origin-when-cross-origin', or 'unsafe-url')
+ * Setting it to false prevents the meta tag from being output
+ * (which results in falling back to the Referrer-Policy header,
+ * or 'no-referrer-when-downgrade' if that's not set either.)
+ * Setting it to an array (supported since 1.31) will create a meta tag for
+ * each value, in the reverse of the order (meaning that the first array element
+ * will be the default and the others used as fallbacks for browsers which do not
+ * understand it).
+ *
+ * @var array|string|bool
  * @since 1.25
  */
 $wgReferrerPolicy = false;
index 60dde40..242cecf 100644 (file)
@@ -37,9 +37,7 @@ class DeprecatedGlobal extends StubObject {
                $this->version = $version;
        }
 
-       // @codingStandardsIgnoreStart
-       // PSR2.Methods.MethodDeclaration.Underscore
-       // PSR2.Classes.PropertyDeclaration.ScopeMissing
+       // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore,PSR2.Classes.PropertyDeclaration.ScopeMissing
        function _newObject() {
                /* Put the caller offset for wfDeprecated as 6, as
                 * that gives the function that uses this object, since:
@@ -56,5 +54,4 @@ class DeprecatedGlobal extends StubObject {
                wfDeprecated( '$' . $this->global, $this->version, false, 6 );
                return parent::_newObject();
        }
-       // @codingStandardsIgnoreEnd
 }
index 1a33b76..523a0f9 100644 (file)
@@ -24,7 +24,6 @@ if ( !defined( 'MEDIAWIKI' ) ) {
        die( "This file is part of MediaWiki, it is not a valid entry point" );
 }
 
-use Liuggio\StatsdClient\Sender\SocketSender;
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\ProcOpenError;
 use MediaWiki\Session\SessionManager;
@@ -1231,6 +1230,7 @@ function wfErrorLog( $text, $file, array $context = [] ) {
 
 /**
  * @todo document
+ * @todo Move logic to MediaWiki.php
  */
 function wfLogProfilingData() {
        global $wgDebugLogGroups, $wgDebugRawPage;
@@ -1242,23 +1242,13 @@ function wfLogProfilingData() {
        $profiler->setContext( $context );
        $profiler->logData();
 
-       $config = $context->getConfig();
-       $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
-       if ( $config->get( 'StatsdServer' ) && $stats->hasData() ) {
-               try {
-                       $statsdServer = explode( ':', $config->get( 'StatsdServer' ) );
-                       $statsdHost = $statsdServer[0];
-                       $statsdPort = isset( $statsdServer[1] ) ? $statsdServer[1] : 8125;
-                       $statsdSender = new SocketSender( $statsdHost, $statsdPort );
-                       $statsdClient = new SamplingStatsdClient( $statsdSender, true, false );
-                       $statsdClient->setSamplingRates( $config->get( 'StatsdSamplingRates' ) );
-                       $statsdClient->send( $stats->getData() );
-               } catch ( Exception $ex ) {
-                       MWExceptionHandler::logException( $ex );
-               }
-       }
+       // Send out any buffered statsd metrics as needed
+       MediaWiki::emitBufferedStatsdData(
+               MediaWikiServices::getInstance()->getStatsdDataFactory(),
+               $context->getConfig()
+       );
 
-       # Profiling must actually be enabled...
+       // Profiling must actually be enabled...
        if ( $profiler instanceof ProfilerStub ) {
                return;
        }
index 5193168..075b48d 100644 (file)
@@ -700,7 +700,7 @@ class DiffHistoryBlob implements HistoryBlob {
 
 }
 
-// @codingStandardsIgnoreStart
+// phpcs:ignore Generic.CodeAnalysis.UnconditionalIfStatement.Found
 if ( false ) {
        // Blobs generated by MediaWiki < 1.5 on PHP 4 were serialized with the
        // class name coerced to lowercase. We can improve efficiency by adding
@@ -711,4 +711,3 @@ if ( false ) {
        class_alias( 'HistoryBlobCurStub', 'historyblobcurstub' );
        class_alias( 'HistoryBlobStub', 'historyblobstub' );
 }
-// @codingStandardsIgnoreEnd
index 48be3bf..c0255ac 100644 (file)
@@ -1595,7 +1595,12 @@ class Linker {
                $title = wfMessage( 'toc' )->inLanguage( $lang )->escaped();
 
                return '<div id="toc" class="toc">'
-                       . '<div class="toctitle"><h2>' . $title . "</h2></div>\n"
+                       . Html::openElement( 'div', [
+                               'class' => 'toctitle',
+                               'lang' => $lang->getHtmlCode(),
+                               'dir' => $lang->getDir(),
+                       ] )
+                       . '<h2>' . $title . "</h2></div>\n"
                        . $toc
                        . "</ul>\n</div>\n";
        }
@@ -2119,8 +2124,6 @@ class Linker {
                return Xml::tags( 'span', [ 'class' => 'mw-revdelundel-link' ], $htmlParentheses );
        }
 
-       /* Deprecated methods */
-
        /**
         * Returns the attributes for the tooltip and access key.
         *
index 9e3bc10..beb9de5 100644 (file)
@@ -26,6 +26,7 @@ use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\ChronologyProtector;
 use Wikimedia\Rdbms\LBFactory;
 use Wikimedia\Rdbms\DBConnectionError;
+use Liuggio\StatsdClient\Sender\SocketSender;
 
 /**
  * The MediaWiki class is the helper class for the index.php entry point.
@@ -912,6 +913,34 @@ class MediaWiki {
                wfDebug( "Request ended normally\n" );
        }
 
+       /**
+        * Send out any buffered statsd data according to sampling rules
+        *
+        * @param IBufferingStatsdDataFactory $stats
+        * @param Config $config
+        * @throws ConfigException
+        * @since 1.31
+        */
+       public static function emitBufferedStatsdData(
+               IBufferingStatsdDataFactory $stats, Config $config
+       ) {
+               if ( $config->get( 'StatsdServer' ) && $stats->hasData() ) {
+                       try {
+                               $statsdServer = explode( ':', $config->get( 'StatsdServer' ) );
+                               $statsdHost = $statsdServer[0];
+                               $statsdPort = isset( $statsdServer[1] ) ? $statsdServer[1] : 8125;
+                               $statsdSender = new SocketSender( $statsdHost, $statsdPort );
+                               $statsdClient = new SamplingStatsdClient( $statsdSender, true, false );
+                               $statsdClient->setSamplingRates( $config->get( 'StatsdSamplingRates' ) );
+                               $statsdClient->send( $stats->getData() );
+
+                               $stats->clearData(); // empty buffer for the next round
+                       } catch ( Exception $ex ) {
+                               MWExceptionHandler::logException( $ex );
+                       }
+               }
+       }
+
        /**
         * Potentially open a socket and sent an HTTP request back to the server
         * to run a specified number of jobs. This registers a callback to cleanup
index 33d0fd4..04c67fb 100644 (file)
@@ -12,6 +12,7 @@ use Hooks;
 use IBufferingStatsdDataFactory;
 use MediaWiki\Shell\CommandFactory;
 use MediaWiki\Storage\BlobStore;
+use MediaWiki\Storage\BlobStoreFactory;
 use MediaWiki\Storage\RevisionStore;
 use Wikimedia\Rdbms\LBFactory;
 use LinkCache;
@@ -700,12 +701,20 @@ class MediaWikiServices extends ServiceContainer {
                return $this->getService( 'ExternalStoreFactory' );
        }
 
+       /**
+        * @since 1.31
+        * @return BlobStoreFactory
+        */
+       public function getBlobStoreFactory() {
+               return $this->getService( 'BlobStoreFactory' );
+       }
+
        /**
         * @since 1.31
         * @return BlobStore
         */
        public function getBlobStore() {
-               return $this->getService( 'BlobStore' );
+               return $this->getService( '_SqlBlobStore' );
        }
 
        /**
index 92963fd..a2d445f 100644 (file)
@@ -366,8 +366,8 @@ class OutputPage extends ContextSource {
         * Add a new "<meta>" tag
         * To add an http-equiv meta tag, precede the name with "http:"
         *
-        * @param string $name Tag name
-        * @param string $val Tag value
+        * @param string $name Name of the meta tag
+        * @param string $val Value of the meta tag
         */
        function addMeta( $name, $val ) {
                array_push( $this->mMetatags, [ $name, $val ] );
@@ -3243,6 +3243,8 @@ class OutputPage extends ContextSource {
                        && ( $relevantTitle->exists() || $relevantTitle->quickUserCan( 'create', $user ) );
 
                foreach ( $title->getRestrictionTypes() as $type ) {
+                       // Following keys are set in $vars:
+                       // wgRestrictionCreate, wgRestrictionEdit, wgRestrictionMove, wgRestrictionUpload
                        $vars['wgRestriction' . ucfirst( $type )] = $title->getRestrictions( $type );
                }
 
@@ -3331,10 +3333,14 @@ class OutputPage extends ContextSource {
                ] );
 
                if ( $config->get( 'ReferrerPolicy' ) !== false ) {
-                       $tags['meta-referrer'] = Html::element( 'meta', [
-                               'name' => 'referrer',
-                               'content' => $config->get( 'ReferrerPolicy' )
-                       ] );
+                       // Per https://w3c.github.io/webappsec-referrer-policy/#unknown-policy-values
+                       // fallbacks should come before the primary value so we need to reverse the array.
+                       foreach ( array_reverse( (array)$config->get( 'ReferrerPolicy' ) ) as $i => $policy ) {
+                               $tags["meta-referrer-$i"] = Html::element( 'meta', [
+                                       'name' => 'referrer',
+                                       'content' => $policy,
+                               ] );
+                       }
                }
 
                $p = "{$this->mIndexPolicy},{$this->mFollowPolicy}";
index a862903..0a9bba8 100644 (file)
@@ -1,7 +1,5 @@
 <?php
-// @codingStandardsIgnoreFile Generic.Arrays.DisallowLongArraySyntax
-// @codingStandardsIgnoreFile Generic.Files.LineLength
-// @codingStandardsIgnoreFile MediaWiki.Usage.DirUsage.FunctionFound
+// phpcs:ignoreFile Generic.Arrays.DisallowLongArraySyntax,MediaWiki.Usage.DirUsage.FunctionFound
 /**
  * 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
@@ -126,6 +124,7 @@ class PHPVersionCheck {
                                . "{$otherInfo['minSupported']}.\n\nCheck if you have a"
                                . " newer php executable with a different name, such as php5.\n\n";
 
+                       // phpcs:ignore Generic.Files.LineLength
                        $longHtml = <<<HTML
                        Please consider <a href="{$phpInfo['upgradeURL']}">upgrading your copy of
                        {$phpInfo['implementation']}</a>.
@@ -140,6 +139,7 @@ class PHPVersionCheck {
                        See our<a href="https://www.mediawiki.org/wiki/Compatibility#PHP">compatibility page</a>
                        for details of which versions are compatible with prior versions of {$phpInfo['implementation']}.
 HTML;
+                       // phpcs:enable
                        $this->triggerError(
                                "Supported {$phpInfo['implementation']} versions",
                                $shortText,
@@ -164,12 +164,14 @@ HTML;
                                . "https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries\n"
                                . "for help on installing the required components.";
 
+                       // phpcs:ignore Generic.Files.LineLength
                        $longHtml = <<<HTML
                MediaWiki now also has some external dependencies that need to be installed via
                composer or from a separate git repo. Please see
                <a href="https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries">mediawiki.org</a>
                for help on installing the required components.
 HTML;
+                       // phpcs:enable
 
                        $this->triggerError( 'External dependencies', $shortText, $longText, $longHtml );
                }
index 25c89c2..54c6de0 100644 (file)
  * @file
  */
 
-use Wikimedia\Rdbms\Database;
+use MediaWiki\Storage\MutableRevisionRecord;
+use MediaWiki\Storage\RevisionAccessException;
+use MediaWiki\Storage\RevisionRecord;
+use MediaWiki\Storage\RevisionStore;
+use MediaWiki\Storage\RevisionStoreRecord;
+use MediaWiki\Storage\SlotRecord;
+use MediaWiki\Storage\SqlBlobStore;
+use MediaWiki\User\UserIdentityValue;
 use Wikimedia\Rdbms\IDatabase;
 use MediaWiki\Linker\LinkTarget;
 use MediaWiki\MediaWikiServices;
@@ -28,78 +35,54 @@ use Wikimedia\Rdbms\ResultWrapper;
 use Wikimedia\Rdbms\FakeResultWrapper;
 
 /**
- * @todo document
+ * @deprecated since 1.31, use RevisionRecord, RevisionStore, and BlobStore instead.
  */
 class Revision implements IDBAccessObject {
-       /** @var int|null */
-       protected $mId;
-       /** @var int|null */
-       protected $mPage;
-       /** @var string */
-       protected $mUserText;
-       /** @var string */
-       protected $mOrigUserText;
-       /** @var int */
-       protected $mUser;
-       /** @var bool */
-       protected $mMinorEdit;
-       /** @var string */
-       protected $mTimestamp;
-       /** @var int */
-       protected $mDeleted;
-       /** @var int */
-       protected $mSize;
-       /** @var string */
-       protected $mSha1;
-       /** @var int */
-       protected $mParentId;
-       /** @var string */
-       protected $mComment;
-       /** @var string */
-       protected $mText;
-       /** @var int */
-       protected $mTextId;
-       /** @var int */
-       protected $mUnpatrolled;
-
-       /** @var stdClass|null */
-       protected $mTextRow;
-
-       /**  @var null|Title */
-       protected $mTitle;
-       /** @var bool */
-       protected $mCurrent;
-       /** @var string */
-       protected $mContentModel;
-       /** @var string */
-       protected $mContentFormat;
-
-       /** @var Content|null|bool */
-       protected $mContent;
-       /** @var null|ContentHandler */
-       protected $mContentHandler;
-
-       /** @var int */
-       protected $mQueryFlags = 0;
-       /** @var bool Used for cached values to reload user text and rev_deleted */
-       protected $mRefreshMutableFields = false;
-       /** @var string Wiki ID; false means the current wiki */
-       protected $mWiki = false;
+
+       /** @var RevisionRecord */
+       protected $mRecord;
 
        // Revision deletion constants
-       const DELETED_TEXT = 1;
-       const DELETED_COMMENT = 2;
-       const DELETED_USER = 4;
-       const DELETED_RESTRICTED = 8;
-       const SUPPRESSED_USER = 12; // convenience
-       const SUPPRESSED_ALL = 15; // convenience
+       const DELETED_TEXT = RevisionRecord::DELETED_TEXT;
+       const DELETED_COMMENT = RevisionRecord::DELETED_COMMENT;
+       const DELETED_USER = RevisionRecord::DELETED_USER;
+       const DELETED_RESTRICTED = RevisionRecord::DELETED_RESTRICTED;
+       const SUPPRESSED_USER = RevisionRecord::SUPPRESSED_USER;
+       const SUPPRESSED_ALL = RevisionRecord::SUPPRESSED_ALL;
 
        // Audience options for accessors
-       const FOR_PUBLIC = 1;
-       const FOR_THIS_USER = 2;
-       const RAW = 3;
+       const FOR_PUBLIC = RevisionRecord::FOR_PUBLIC;
+       const FOR_THIS_USER = RevisionRecord::FOR_THIS_USER;
+       const RAW = RevisionRecord::RAW;
 
-       const TEXT_CACHE_GROUP = 'revisiontext:10'; // process cache name and max key count
+       const TEXT_CACHE_GROUP = SqlBlobStore::TEXT_CACHE_GROUP;
+
+       /**
+        * @return RevisionStore
+        */
+       protected static function getRevisionStore() {
+               return MediaWikiServices::getInstance()->getRevisionStore();
+       }
+
+       /**
+        * @param bool|string $wikiId The ID of the target wiki database. Use false for the local wiki.
+        *
+        * @return SqlBlobStore
+        */
+       protected static function getBlobStore( $wiki = false ) {
+               $store = MediaWikiServices::getInstance()
+                       ->getBlobStoreFactory()
+                       ->newSqlBlobStore( $wiki );
+
+               if ( !$store instanceof SqlBlobStore ) {
+                       throw new RuntimeException(
+                               'The backwards compatibility code in Revision currently requires the BlobStore '
+                               . 'service to be an SqlBlobStore instance, but it is a ' . get_class( $store )
+                       );
+               }
+
+               return $store;
+       }
 
        /**
         * Load a page revision from a given revision ID number.
@@ -114,7 +97,8 @@ class Revision implements IDBAccessObject {
         * @return Revision|null
         */
        public static function newFromId( $id, $flags = 0 ) {
-               return self::newFromConds( [ 'rev_id' => intval( $id ) ], $flags );
+               $rec = self::getRevisionStore()->getRevisionById( $id, $flags );
+               return $rec === null ? null : new Revision( $rec, $flags );
        }
 
        /**
@@ -132,20 +116,8 @@ class Revision implements IDBAccessObject {
         * @return Revision|null
         */
        public static function newFromTitle( LinkTarget $linkTarget, $id = 0, $flags = 0 ) {
-               $conds = [
-                       'page_namespace' => $linkTarget->getNamespace(),
-                       'page_title' => $linkTarget->getDBkey()
-               ];
-               if ( $id ) {
-                       // Use the specified ID
-                       $conds['rev_id'] = $id;
-                       return self::newFromConds( $conds, $flags );
-               } else {
-                       // Use a join to get the latest revision
-                       $conds[] = 'rev_id=page_latest';
-                       $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_REPLICA );
-                       return self::loadFromConds( $db, $conds, $flags );
-               }
+               $rec = self::getRevisionStore()->getRevisionByTitle( $linkTarget, $id, $flags );
+               return $rec === null ? null : new Revision( $rec, $flags );
        }
 
        /**
@@ -163,22 +135,13 @@ class Revision implements IDBAccessObject {
         * @return Revision|null
         */
        public static function newFromPageId( $pageId, $revId = 0, $flags = 0 ) {
-               $conds = [ 'page_id' => $pageId ];
-               if ( $revId ) {
-                       $conds['rev_id'] = $revId;
-                       return self::newFromConds( $conds, $flags );
-               } else {
-                       // Use a join to get the latest revision
-                       $conds[] = 'rev_id = page_latest';
-                       $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_REPLICA );
-                       return self::loadFromConds( $db, $conds, $flags );
-               }
+               $rec = self::getRevisionStore()->getRevisionByPageId( $pageId, $revId, $flags );
+               return $rec === null ? null : new Revision( $rec, $flags );
        }
 
        /**
         * Make a fake revision object from an archive table row. This is queried
         * for permissions or even inserted (as in Special:Undelete)
-        * @todo FIXME: Should be a subclass for RevisionDelete. [TS]
         *
         * @param object $row
         * @param array $overrides
@@ -187,68 +150,79 @@ class Revision implements IDBAccessObject {
         * @return Revision
         */
        public static function newFromArchiveRow( $row, $overrides = [] ) {
-               global $wgContentHandlerUseDB;
-
-               $attribs = $overrides + [
-                       'page'       => isset( $row->ar_page_id ) ? $row->ar_page_id : null,
-                       'id'         => isset( $row->ar_rev_id ) ? $row->ar_rev_id : null,
-                       'comment'    => CommentStore::newKey( 'ar_comment' )
-                               // Legacy because $row may have come from self::selectArchiveFields()
-                               ->getCommentLegacy( wfGetDB( DB_REPLICA ), $row, true )->text,
-                       'user'       => $row->ar_user,
-                       'user_text'  => $row->ar_user_text,
-                       'timestamp'  => $row->ar_timestamp,
-                       'minor_edit' => $row->ar_minor_edit,
-                       'text_id'    => isset( $row->ar_text_id ) ? $row->ar_text_id : null,
-                       'deleted'    => $row->ar_deleted,
-                       'len'        => $row->ar_len,
-                       'sha1'       => isset( $row->ar_sha1 ) ? $row->ar_sha1 : null,
-                       'content_model'   => isset( $row->ar_content_model ) ? $row->ar_content_model : null,
-                       'content_format'  => isset( $row->ar_content_format ) ? $row->ar_content_format : null,
-               ];
-
-               if ( !$wgContentHandlerUseDB ) {
-                       unset( $attribs['content_model'] );
-                       unset( $attribs['content_format'] );
-               }
+               /**
+                * MCR Migration: https://phabricator.wikimedia.org/T183564
+                * This method used to overwrite attributes, then passed to Revision::__construct
+                * RevisionStore::newRevisionFromArchiveRow instead overrides row field names
+                * So do a conversion here.
+                */
+               if ( array_key_exists( 'page', $overrides ) ) {
+                       $overrides['page_id'] = $overrides['page'];
+                       unset( $overrides['page'] );
+               }
+
+               /**
+                * We require a Title for both the Revision object and the RevisionRecord.
+                * Below is duplicated logic from RevisionStore::newRevisionFromArchiveRow
+                * to fetch a title in order pass it into the Revision object.
+                */
+               $title = null;
+               if ( isset( $overrides['title'] ) ) {
+                       if ( !( $overrides['title'] instanceof Title ) ) {
+                               throw new MWException( 'title field override must contain a Title object.' );
+                       }
 
-               if ( !isset( $attribs['title'] )
-                       && isset( $row->ar_namespace )
-                       && isset( $row->ar_title )
-               ) {
-                       $attribs['title'] = Title::makeTitle( $row->ar_namespace, $row->ar_title );
+                       $title = $overrides['title'];
                }
-
-               if ( isset( $row->ar_text ) && !$row->ar_text_id ) {
-                       // Pre-1.5 ar_text row
-                       $attribs['text'] = self::getRevisionText( $row, 'ar_' );
-                       if ( $attribs['text'] === false ) {
-                               throw new MWException( 'Unable to load text from archive row (possibly T24624)' );
+               if ( $title !== null ) {
+                       if ( isset( $row->ar_namespace ) && isset( $row->ar_title ) ) {
+                               $title = Title::makeTitle( $row->ar_namespace, $row->ar_title );
+                       } else {
+                               throw new InvalidArgumentException(
+                                       'A Title or ar_namespace and ar_title must be given'
+                               );
                        }
                }
-               return new self( $attribs );
+
+               $rec = self::getRevisionStore()->newRevisionFromArchiveRow( $row, 0, $title, $overrides );
+               return new Revision( $rec, self::READ_NORMAL, $title );
        }
 
        /**
         * @since 1.19
         *
-        * @param object $row
+        * MCR migration note: replaced by RevisionStore::newRevisionFromRow(). Note that
+        * newFromRow() also accepts arrays, while newRevisionFromRow() does not. Instead,
+        * a MutableRevisionRecord should be constructed directly. RevisionStore::newRevisionFromArray()
+        * can be used as a temporary replacement, but should be avoided.
+        *
+        * @param object|array $row
         * @return Revision
         */
        public static function newFromRow( $row ) {
-               return new self( $row );
+               if ( is_array( $row ) ) {
+                       $rec = self::getRevisionStore()->newMutableRevisionFromArray( $row );
+               } else {
+                       $rec = self::getRevisionStore()->newRevisionFromRow( $row );
+               }
+
+               return new Revision( $rec );
        }
 
        /**
         * Load a page revision from a given revision ID number.
         * Returns null if no such revision can be found.
         *
+        * @deprecated since 1.31, use RevisionStore::getRevisionById() instead.
+        *
         * @param IDatabase $db
         * @param int $id
         * @return Revision|null
         */
        public static function loadFromId( $db, $id ) {
-               return self::loadFromConds( $db, [ 'rev_id' => intval( $id ) ] );
+               wfDeprecated( __METHOD__, '1.31' ); // no known callers
+               $rec = self::getRevisionStore()->loadRevisionFromId( $db, $id );
+               return $rec === null ? null : new Revision( $rec );
        }
 
        /**
@@ -256,19 +230,16 @@ class Revision implements IDBAccessObject {
         * that's attached to a given page. If not attached
         * to that page, will return null.
         *
+        * @deprecated since 1.31, use RevisionStore::getRevisionByPageId() instead.
+        *
         * @param IDatabase $db
         * @param int $pageid
         * @param int $id
         * @return Revision|null
         */
        public static function loadFromPageId( $db, $pageid, $id = 0 ) {
-               $conds = [ 'rev_page' => intval( $pageid ), 'page_id' => intval( $pageid ) ];
-               if ( $id ) {
-                       $conds['rev_id'] = intval( $id );
-               } else {
-                       $conds[] = 'rev_id=page_latest';
-               }
-               return self::loadFromConds( $db, $conds );
+               $rec = self::getRevisionStore()->loadRevisionFromPageId( $db, $pageid, $id );
+               return $rec === null ? null : new Revision( $rec );
        }
 
        /**
@@ -276,24 +247,16 @@ class Revision implements IDBAccessObject {
         * that's attached to a given page. If not attached
         * to that page, will return null.
         *
+        * @deprecated since 1.31, use RevisionStore::getRevisionByTitle() instead.
+        *
         * @param IDatabase $db
         * @param Title $title
         * @param int $id
         * @return Revision|null
         */
        public static function loadFromTitle( $db, $title, $id = 0 ) {
-               if ( $id ) {
-                       $matchId = intval( $id );
-               } else {
-                       $matchId = 'page_latest';
-               }
-               return self::loadFromConds( $db,
-                       [
-                               "rev_id=$matchId",
-                               'page_namespace' => $title->getNamespace(),
-                               'page_title' => $title->getDBkey()
-                       ]
-               );
+               $rec = self::getRevisionStore()->loadRevisionFromTitle( $db, $title, $id );
+               return $rec === null ? null : new Revision( $rec );
        }
 
        /**
@@ -301,73 +264,17 @@ class Revision implements IDBAccessObject {
         * WARNING: Timestamps may in some circumstances not be unique,
         * so this isn't the best key to use.
         *
+        * @deprecated since 1.31, use RevisionStore::loadRevisionFromTimestamp() instead.
+        *
         * @param IDatabase $db
         * @param Title $title
         * @param string $timestamp
         * @return Revision|null
         */
        public static function loadFromTimestamp( $db, $title, $timestamp ) {
-               return self::loadFromConds( $db,
-                       [
-                               'rev_timestamp' => $db->timestamp( $timestamp ),
-                               'page_namespace' => $title->getNamespace(),
-                               'page_title' => $title->getDBkey()
-                       ]
-               );
-       }
-
-       /**
-        * Given a set of conditions, fetch a revision
-        *
-        * This method is used then a revision ID is qualified and
-        * will incorporate some basic replica DB/master fallback logic
-        *
-        * @param array $conditions
-        * @param int $flags (optional)
-        * @return Revision|null
-        */
-       private static function newFromConds( $conditions, $flags = 0 ) {
-               $db = wfGetDB( ( $flags & self::READ_LATEST ) ? DB_MASTER : DB_REPLICA );
-
-               $rev = self::loadFromConds( $db, $conditions, $flags );
-               // Make sure new pending/committed revision are visibile later on
-               // within web requests to certain avoid bugs like T93866 and T94407.
-               if ( !$rev
-                       && !( $flags & self::READ_LATEST )
-                       && wfGetLB()->getServerCount() > 1
-                       && wfGetLB()->hasOrMadeRecentMasterChanges()
-               ) {
-                       $flags = self::READ_LATEST;
-                       $db = wfGetDB( DB_MASTER );
-                       $rev = self::loadFromConds( $db, $conditions, $flags );
-               }
-
-               if ( $rev ) {
-                       $rev->mQueryFlags = $flags;
-               }
-
-               return $rev;
-       }
-
-       /**
-        * Given a set of conditions, fetch a revision from
-        * the given database connection.
-        *
-        * @param IDatabase $db
-        * @param array $conditions
-        * @param int $flags (optional)
-        * @return Revision|null
-        */
-       private static function loadFromConds( $db, $conditions, $flags = 0 ) {
-               $row = self::fetchFromConds( $db, $conditions, $flags );
-               if ( $row ) {
-                       $rev = new Revision( $row );
-                       $rev->mWiki = $db->getDomainID();
-
-                       return $rev;
-               }
-
-               return null;
+               // XXX: replace loadRevisionFromTimestamp by getRevisionByTimestamp?
+               $rec = self::getRevisionStore()->loadRevisionFromTimestamp( $db, $title, $timestamp );
+               return $rec === null ? null : new Revision( $rec );
        }
 
        /**
@@ -377,52 +284,18 @@ class Revision implements IDBAccessObject {
         *
         * @param LinkTarget $title
         * @return ResultWrapper
-        * @deprecated Since 1.28
+        * @deprecated Since 1.28, no callers in core nor in known extensions. No-op since 1.31.
         */
        public static function fetchRevision( LinkTarget $title ) {
-               $row = self::fetchFromConds(
-                       wfGetDB( DB_REPLICA ),
-                       [
-                               'rev_id=page_latest',
-                               'page_namespace' => $title->getNamespace(),
-                               'page_title' => $title->getDBkey()
-                       ]
-               );
-
-               return new FakeResultWrapper( $row ? [ $row ] : [] );
-       }
-
-       /**
-        * Given a set of conditions, return a ResultWrapper
-        * which will return matching database rows with the
-        * fields necessary to build Revision objects.
-        *
-        * @param IDatabase $db
-        * @param array $conditions
-        * @param int $flags (optional)
-        * @return stdClass
-        */
-       private static function fetchFromConds( $db, $conditions, $flags = 0 ) {
-               $revQuery = self::getQueryInfo( [ 'page', 'user' ] );
-               $options = [];
-               if ( ( $flags & self::READ_LOCKING ) == self::READ_LOCKING ) {
-                       $options[] = 'FOR UPDATE';
-               }
-               return $db->selectRow(
-                       $revQuery['tables'],
-                       $revQuery['fields'],
-                       $conditions,
-                       __METHOD__,
-                       $options,
-                       $revQuery['joins']
-               );
+               wfDeprecated( __METHOD__, '1.31' );
+               return new FakeResultWrapper( [] );
        }
 
        /**
         * Return the value of a select() JOIN conds array for the user table.
         * This will get user table rows for logged-in users.
         * @since 1.19
-        * @deprecated since 1.31, use self::getQueryInfo( [ 'user' ] ) instead.
+        * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'user' ] ) instead.
         * @return array
         */
        public static function userJoinCond() {
@@ -434,7 +307,7 @@ class Revision implements IDBAccessObject {
         * Return the value of a select() page conds array for the page table.
         * This will assure that the revision(s) are not orphaned from live pages.
         * @since 1.19
-        * @deprecated since 1.31, use self::getQueryInfo( [ 'page' ] ) instead.
+        * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'page' ] ) instead.
         * @return array
         */
        public static function pageJoinCond() {
@@ -445,7 +318,7 @@ class Revision implements IDBAccessObject {
        /**
         * Return the list of revision fields that should be selected to create
         * a new revision.
-        * @deprecated since 1.31, use self::getQueryInfo() instead.
+        * @deprecated since 1.31, use RevisionStore::getQueryInfo() instead.
         * @return array
         */
        public static function selectFields() {
@@ -480,7 +353,7 @@ class Revision implements IDBAccessObject {
        /**
         * Return the list of revision fields that should be selected to create
         * a new revision from an archive row.
-        * @deprecated since 1.31, use self::getArchiveQueryInfo() instead.
+        * @deprecated since 1.31, use RevisionStore::getArchiveQueryInfo() instead.
         * @return array
         */
        public static function selectArchiveFields() {
@@ -516,7 +389,7 @@ class Revision implements IDBAccessObject {
        /**
         * Return the list of text fields that should be selected to read the
         * revision text
-        * @deprecated since 1.31, use self::getQueryInfo( [ 'text' ] ) instead.
+        * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'text' ] ) instead.
         * @return array
         */
        public static function selectTextFields() {
@@ -529,7 +402,7 @@ class Revision implements IDBAccessObject {
 
        /**
         * Return the list of page fields that should be selected from page table
-        * @deprecated since 1.31, use self::getQueryInfo( [ 'page' ] ) instead.
+        * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'page' ] ) instead.
         * @return array
         */
        public static function selectPageFields() {
@@ -546,7 +419,7 @@ class Revision implements IDBAccessObject {
 
        /**
         * Return the list of user fields that should be selected from user table
-        * @deprecated since 1.31, use self::getQueryInfo( [ 'user' ] ) instead.
+        * @deprecated since 1.31, use RevisionStore::getQueryInfo( [ 'user' ] ) instead.
         * @return array
         */
        public static function selectUserFields() {
@@ -558,6 +431,7 @@ class Revision implements IDBAccessObject {
         * Return the tables, fields, and join conditions to be selected to create
         * a new revision object.
         * @since 1.31
+        * @deprecated since 1.31, use RevisionStore::getQueryInfo() instead.
         * @param array $options Any combination of the following strings
         *  - 'page': Join with the page table, and select fields to identify the page
         *  - 'user': Join with the user table, and select the user name
@@ -568,104 +442,21 @@ class Revision implements IDBAccessObject {
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         */
        public static function getQueryInfo( $options = [] ) {
-               global $wgContentHandlerUseDB;
-
-               $commentQuery = CommentStore::newKey( 'rev_comment' )->getJoin();
-               $ret = [
-                       'tables' => [ 'revision' ] + $commentQuery['tables'],
-                       'fields' => [
-                               'rev_id',
-                               'rev_page',
-                               'rev_text_id',
-                               'rev_timestamp',
-                               'rev_user_text',
-                               'rev_user',
-                               'rev_minor_edit',
-                               'rev_deleted',
-                               'rev_len',
-                               'rev_parent_id',
-                               'rev_sha1',
-                       ] + $commentQuery['fields'],
-                       'joins' => $commentQuery['joins'],
-               ];
-
-               if ( $wgContentHandlerUseDB ) {
-                       $ret['fields'][] = 'rev_content_format';
-                       $ret['fields'][] = 'rev_content_model';
-               }
-
-               if ( in_array( 'page', $options, true ) ) {
-                       $ret['tables'][] = 'page';
-                       $ret['fields'] = array_merge( $ret['fields'], [
-                               'page_namespace',
-                               'page_title',
-                               'page_id',
-                               'page_latest',
-                               'page_is_redirect',
-                               'page_len',
-                       ] );
-                       $ret['joins']['page'] = [ 'INNER JOIN', [ 'page_id = rev_page' ] ];
-               }
-
-               if ( in_array( 'user', $options, true ) ) {
-                       $ret['tables'][] = 'user';
-                       $ret['fields'] = array_merge( $ret['fields'], [
-                               'user_name',
-                       ] );
-                       $ret['joins']['user'] = [ 'LEFT JOIN', [ 'rev_user != 0', 'user_id = rev_user' ] ];
-               }
-
-               if ( in_array( 'text', $options, true ) ) {
-                       $ret['tables'][] = 'text';
-                       $ret['fields'] = array_merge( $ret['fields'], [
-                               'old_text',
-                               'old_flags'
-                       ] );
-                       $ret['joins']['text'] = [ 'INNER JOIN', [ 'rev_text_id=old_id' ] ];
-               }
-
-               return $ret;
+               return self::getRevisionStore()->getQueryInfo( $options );
        }
 
        /**
         * Return the tables, fields, and join conditions to be selected to create
         * a new archived revision object.
         * @since 1.31
+        * @deprecated since 1.31, use RevisionStore::getArchiveQueryInfo() instead.
         * @return array With three keys:
         *   - tables: (string[]) to include in the `$table` to `IDatabase->select()`
         *   - fields: (string[]) to include in the `$vars` to `IDatabase->select()`
         *   - joins: (array) to include in the `$join_conds` to `IDatabase->select()`
         */
        public static function getArchiveQueryInfo() {
-               global $wgContentHandlerUseDB;
-
-               $commentQuery = CommentStore::newKey( 'ar_comment' )->getJoin();
-               $ret = [
-                       'tables' => [ 'archive' ] + $commentQuery['tables'],
-                       'fields' => [
-                               'ar_id',
-                               'ar_page_id',
-                               'ar_rev_id',
-                               'ar_text',
-                               'ar_text_id',
-                               'ar_timestamp',
-                               'ar_user_text',
-                               'ar_user',
-                               'ar_minor_edit',
-                               'ar_deleted',
-                               'ar_len',
-                               'ar_parent_id',
-                               'ar_sha1',
-                       ] + $commentQuery['fields'],
-                       'joins' => $commentQuery['joins'],
-               ];
-
-               if ( $wgContentHandlerUseDB ) {
-                       $ret['fields'][] = 'ar_content_format';
-                       $ret['fields'][] = 'ar_content_model';
-               }
-
-               return $ret;
+               return self::getRevisionStore()->getArchiveQueryInfo();
        }
 
        /**
@@ -675,203 +466,49 @@ class Revision implements IDBAccessObject {
         * @return array
         */
        public static function getParentLengths( $db, array $revIds ) {
-               $revLens = [];
-               if ( !$revIds ) {
-                       return $revLens; // empty
-               }
-               $res = $db->select( 'revision',
-                       [ 'rev_id', 'rev_len' ],
-                       [ 'rev_id' => $revIds ],
-                       __METHOD__ );
-               foreach ( $res as $row ) {
-                       $revLens[$row->rev_id] = $row->rev_len;
-               }
-               return $revLens;
+               return self::getRevisionStore()->listRevisionSizes( $db, $revIds );
        }
 
        /**
-        * @param object|array $row Either a database row or an array
-        * @throws MWException
+        * @param object|array|RevisionRecord $row Either a database row or an array
+        * @param int $queryFlags
+        * @param Title|null $title
+        *
         * @access private
         */
-       public function __construct( $row ) {
-               if ( is_object( $row ) ) {
-                       $this->constructFromDbRowObject( $row );
-               } elseif ( is_array( $row ) ) {
-                       $this->constructFromRowArray( $row );
-               } else {
-                       throw new MWException( 'Revision constructor passed invalid row format.' );
-               }
-               $this->mUnpatrolled = null;
-       }
+       function __construct( $row, $queryFlags = 0, Title $title = null ) {
+               global $wgUser;
 
-       /**
-        * @param object $row
-        */
-       private function constructFromDbRowObject( $row ) {
-               $this->mId = intval( $row->rev_id );
-               $this->mPage = intval( $row->rev_page );
-               $this->mTextId = intval( $row->rev_text_id );
-               $this->mComment = CommentStore::newKey( 'rev_comment' )
-                       // Legacy because $row may have come from self::selectFields()
-                       ->getCommentLegacy( wfGetDB( DB_REPLICA ), $row, true )->text;
-               $this->mUser = intval( $row->rev_user );
-               $this->mMinorEdit = intval( $row->rev_minor_edit );
-               $this->mTimestamp = $row->rev_timestamp;
-               $this->mDeleted = intval( $row->rev_deleted );
-
-               if ( !isset( $row->rev_parent_id ) ) {
-                       $this->mParentId = null;
-               } else {
-                       $this->mParentId = intval( $row->rev_parent_id );
-               }
-
-               if ( !isset( $row->rev_len ) ) {
-                       $this->mSize = null;
-               } else {
-                       $this->mSize = intval( $row->rev_len );
-               }
-
-               if ( !isset( $row->rev_sha1 ) ) {
-                       $this->mSha1 = null;
-               } else {
-                       $this->mSha1 = $row->rev_sha1;
-               }
-
-               if ( isset( $row->page_latest ) ) {
-                       $this->mCurrent = ( $row->rev_id == $row->page_latest );
-                       $this->mTitle = Title::newFromRow( $row );
-               } else {
-                       $this->mCurrent = false;
-                       $this->mTitle = null;
-               }
-
-               if ( !isset( $row->rev_content_model ) ) {
-                       $this->mContentModel = null; # determine on demand if needed
-               } else {
-                       $this->mContentModel = strval( $row->rev_content_model );
-               }
-
-               if ( !isset( $row->rev_content_format ) ) {
-                       $this->mContentFormat = null; # determine on demand if needed
-               } else {
-                       $this->mContentFormat = strval( $row->rev_content_format );
-               }
+               if ( $row instanceof RevisionRecord ) {
+                       $this->mRecord = $row;
+               } elseif ( is_array( $row ) ) {
+                       if ( !isset( $row['user'] ) && !isset( $row['user_text'] ) ) {
+                               $row['user'] = $wgUser;
+                       }
 
-               // Lazy extraction...
-               $this->mText = null;
-               if ( isset( $row->old_text ) ) {
-                       $this->mTextRow = $row;
+                       $this->mRecord = self::getRevisionStore()->newMutableRevisionFromArray(
+                               $row,
+                               $queryFlags,
+                               $title
+                       );
+               } elseif ( is_object( $row ) ) {
+                       $this->mRecord = self::getRevisionStore()->newRevisionFromRow(
+                               $row,
+                               $queryFlags,
+                               $title
+                       );
                } else {
-                       // 'text' table row entry will be lazy-loaded
-                       $this->mTextRow = null;
-               }
-
-               // Use user_name for users and rev_user_text for IPs...
-               $this->mUserText = null; // lazy load if left null
-               if ( $this->mUser == 0 ) {
-                       $this->mUserText = $row->rev_user_text; // IP user
-               } elseif ( isset( $row->user_name ) ) {
-                       $this->mUserText = $row->user_name; // logged-in user
+                       throw new InvalidArgumentException(
+                               '$row must be a row object, an associative array, or a RevisionRecord'
+                       );
                }
-               $this->mOrigUserText = $row->rev_user_text;
        }
 
        /**
-        * @param array $row
-        *
-        * @throws MWException
+        * @return RevisionRecord
         */
-       private function constructFromRowArray( array $row ) {
-               // Build a new revision to be saved...
-               global $wgUser; // ugh
-
-               # if we have a content object, use it to set the model and type
-               if ( !empty( $row['content'] ) ) {
-                       if ( !( $row['content'] instanceof Content ) ) {
-                               throw new MWException( '`content` field must contain a Content object.' );
-                       }
-
-                       // @todo when is that set? test with external store setup! check out insertOn() [dk]
-                       if ( !empty( $row['text_id'] ) ) {
-                               throw new MWException( "Text already stored in external store (id {$row['text_id']}), " .
-                                       "can't serialize content object" );
-                       }
-
-                       $row['content_model'] = $row['content']->getModel();
-                       # note: mContentFormat is initializes later accordingly
-                       # note: content is serialized later in this method!
-                       # also set text to null?
-               }
-
-               $this->mId = isset( $row['id'] ) ? intval( $row['id'] ) : null;
-               $this->mPage = isset( $row['page'] ) ? intval( $row['page'] ) : null;
-               $this->mTextId = isset( $row['text_id'] ) ? intval( $row['text_id'] ) : null;
-               $this->mUserText = isset( $row['user_text'] )
-                       ? strval( $row['user_text'] ) : $wgUser->getName();
-               $this->mUser = isset( $row['user'] ) ? intval( $row['user'] ) : $wgUser->getId();
-               $this->mMinorEdit = isset( $row['minor_edit'] ) ? intval( $row['minor_edit'] ) : 0;
-               $this->mTimestamp = isset( $row['timestamp'] )
-                       ? strval( $row['timestamp'] ) : wfTimestampNow();
-               $this->mDeleted = isset( $row['deleted'] ) ? intval( $row['deleted'] ) : 0;
-               $this->mSize = isset( $row['len'] ) ? intval( $row['len'] ) : null;
-               $this->mParentId = isset( $row['parent_id'] ) ? intval( $row['parent_id'] ) : null;
-               $this->mSha1 = isset( $row['sha1'] ) ? strval( $row['sha1'] ) : null;
-
-               $this->mContentModel = isset( $row['content_model'] )
-                       ? strval( $row['content_model'] ) : null;
-               $this->mContentFormat = isset( $row['content_format'] )
-                       ? strval( $row['content_format'] ) : null;
-
-               // Enforce spacing trimming on supplied text
-               $this->mComment = isset( $row['comment'] ) ? trim( strval( $row['comment'] ) ) : null;
-               $this->mText = isset( $row['text'] ) ? rtrim( strval( $row['text'] ) ) : null;
-               $this->mTextRow = null;
-
-               $this->mTitle = isset( $row['title'] ) ? $row['title'] : null;
-
-               // if we have a Content object, override mText and mContentModel
-               if ( !empty( $row['content'] ) ) {
-                       $handler = $this->getContentHandler();
-                       $this->mContent = $row['content'];
-
-                       $this->mContentModel = $this->mContent->getModel();
-                       $this->mContentHandler = null;
-
-                       $this->mText = $handler->serializeContent( $row['content'], $this->getContentFormat() );
-               } elseif ( $this->mText !== null ) {
-                       $handler = $this->getContentHandler();
-                       $this->mContent = $handler->unserializeContent( $this->mText );
-               }
-
-               // If we have a Title object, make sure it is consistent with mPage.
-               if ( $this->mTitle && $this->mTitle->exists() ) {
-                       if ( $this->mPage === null ) {
-                               // if the page ID wasn't known, set it now
-                               $this->mPage = $this->mTitle->getArticleID();
-                       } elseif ( $this->mTitle->getArticleID() !== $this->mPage ) {
-                               // Got different page IDs. This may be legit (e.g. during undeletion),
-                               // but it seems worth mentioning it in the log.
-                               wfDebug( "Page ID " . $this->mPage . " mismatches the ID " .
-                                       $this->mTitle->getArticleID() . " provided by the Title object." );
-                       }
-               }
-
-               $this->mCurrent = false;
-
-               // If we still have no length, see it we have the text to figure it out
-               if ( !$this->mSize && $this->mContent !== null ) {
-                       $this->mSize = $this->mContent->getSize();
-               }
-
-               // Same for sha1
-               if ( $this->mSha1 === null ) {
-                       $this->mSha1 = $this->mText === null ? null : self::base36Sha1( $this->mText );
-               }
-
-               // force lazy init
-               $this->getContentModel();
-               $this->getContentFormat();
+       public function getRevisionRecord() {
+               return $this->mRecord;
        }
 
        /**
@@ -880,19 +517,27 @@ class Revision implements IDBAccessObject {
         * @return int|null
         */
        public function getId() {
-               return $this->mId;
+               return $this->mRecord->getId();
        }
 
        /**
         * Set the revision ID
         *
-        * This should only be used for proposed revisions that turn out to be null edits
+        * This should only be used for proposed revisions that turn out to be null edits.
+        *
+        * @note Only supported on Revisions that were constructed based on associative arrays,
+        *       since they are mutable.
         *
         * @since 1.19
-        * @param int $id
+        * @param int|string $id
+        * @throws MWException
         */
        public function setId( $id ) {
-               $this->mId = (int)$id;
+               if ( $this->mRecord instanceof MutableRevisionRecord ) {
+                       $this->mRecord->setId( intval( $id ) );
+               } else {
+                       throw new MWException( __METHOD__ . ' is not supported on this instance' );
+               }
        }
 
        /**
@@ -900,106 +545,107 @@ class Revision implements IDBAccessObject {
         *
         * This should only be used for proposed revisions that turn out to be null edits
         *
+        * @note Only supported on Revisions that were constructed based on associative arrays,
+        *       since they are mutable.
+        *
         * @since 1.28
         * @deprecated since 1.31, please reuse old Revision object
         * @param int $id User ID
         * @param string $name User name
+        * @throws MWException
         */
        public function setUserIdAndName( $id, $name ) {
-               $this->mUser = (int)$id;
-               $this->mUserText = $name;
-               $this->mOrigUserText = $name;
+               if ( $this->mRecord instanceof MutableRevisionRecord ) {
+                       $user = new UserIdentityValue( intval( $id ), $name );
+                       $this->mRecord->setUser( $user );
+               } else {
+                       throw new MWException( __METHOD__ . ' is not supported on this instance' );
+               }
+       }
+
+       /**
+        * @return SlotRecord
+        */
+       private function getMainSlotRaw() {
+               return $this->mRecord->getSlot( 'main', RevisionRecord::RAW );
        }
 
        /**
-        * Get text row ID
+        * Get the ID of the row of the text table that contains the content of the
+        * revision's main slot, if that content is stored in the text table.
+        *
+        * If the content is stored elsewhere, this returns null.
+        *
+        * @deprecated since 1.31, use RevisionRecord()->getSlot()->getContentAddress() to
+        * get that actual address that can be used with BlobStore::getBlob(); or use
+        * RevisionRecord::hasSameContent() to check if two revisions have the same content.
         *
         * @return int|null
         */
        public function getTextId() {
-               return $this->mTextId;
+               $slot = $this->getMainSlotRaw();
+               return $slot->hasAddress()
+                       ? self::getBlobStore()->getTextIdFromAddress( $slot->getAddress() )
+                       : null;
        }
 
        /**
         * Get parent revision ID (the original previous page revision)
         *
-        * @return int|null
+        * @return int|null The ID of the parent revision. 0 indicates that there is no
+        * parent revision. Null indicates that the parent revision is not known.
         */
        public function getParentId() {
-               return $this->mParentId;
+               return $this->mRecord->getParentId();
        }
 
        /**
         * Returns the length of the text in this revision, or null if unknown.
         *
-        * @return int|null
+        * @return int
         */
        public function getSize() {
-               return $this->mSize;
+               return $this->mRecord->getSize();
        }
 
        /**
-        * Returns the base36 sha1 of the text in this revision, or null if unknown.
+        * Returns the base36 sha1 of the content in this revision, or null if unknown.
         *
-        * @return string|null
+        * @return string
         */
        public function getSha1() {
-               return $this->mSha1;
+               // XXX: we may want to drop all the hashing logic, it's not worth the overhead.
+               return $this->mRecord->getSha1();
        }
 
        /**
-        * Returns the title of the page associated with this entry or null.
+        * Returns the title of the page associated with this entry.
+        * Since 1.31, this will never return null.
         *
         * Will do a query, when title is not set and id is given.
         *
-        * @return Title|null
+        * @return Title
         */
        public function getTitle() {
-               if ( $this->mTitle !== null ) {
-                       return $this->mTitle;
-               }
-               // rev_id is defined as NOT NULL, but this revision may not yet have been inserted.
-               if ( $this->mId !== null ) {
-                       $dbr = wfGetLB( $this->mWiki )->getConnectionRef( DB_REPLICA, [], $this->mWiki );
-                       // @todo: Title::getSelectFields(), or Title::getQueryInfo(), or something like that
-                       $row = $dbr->selectRow(
-                               [ 'revision', 'page' ],
-                               [
-                                       'page_namespace',
-                                       'page_title',
-                                       'page_id',
-                                       'page_latest',
-                                       'page_is_redirect',
-                                       'page_len',
-                               ],
-                               [ 'rev_id' => $this->mId ],
-                               __METHOD__,
-                               [],
-                               [ 'page' => [ 'JOIN', 'page_id=rev_page' ] ]
-                       );
-                       if ( $row ) {
-                               // @TODO: better foreign title handling
-                               $this->mTitle = Title::newFromRow( $row );
-                       }
-               }
-
-               if ( $this->mWiki === false || $this->mWiki === wfWikiID() ) {
-                       // Loading by ID is best, though not possible for foreign titles
-                       if ( !$this->mTitle && $this->mPage !== null && $this->mPage > 0 ) {
-                               $this->mTitle = Title::newFromID( $this->mPage );
-                       }
-               }
-
-               return $this->mTitle;
+               $linkTarget = $this->mRecord->getPageAsLinkTarget();
+               return Title::newFromLinkTarget( $linkTarget );
        }
 
        /**
         * Set the title of the revision
         *
+        * @deprecated: since 1.31, this is now a noop. Pass the Title to the constructor instead.
+        *
         * @param Title $title
         */
        public function setTitle( $title ) {
-               $this->mTitle = $title;
+               if ( !$title->equals( $this->getTitle() ) ) {
+                       throw new InvalidArgumentException(
+                               $title->getPrefixedText()
+                                       . ' is not the same as '
+                                       . $this->mRecord->getPageAsLinkTarget()->__toString()
+                       );
+               }
        }
 
        /**
@@ -1008,7 +654,7 @@ class Revision implements IDBAccessObject {
         * @return int|null
         */
        public function getPage() {
-               return $this->mPage;
+               return $this->mRecord->getPageId();
        }
 
        /**
@@ -1025,13 +671,14 @@ class Revision implements IDBAccessObject {
         * @return int
         */
        public function getUser( $audience = self::FOR_PUBLIC, User $user = null ) {
-               if ( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_USER ) ) {
-                       return 0;
-               } elseif ( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_USER, $user ) ) {
-                       return 0;
-               } else {
-                       return $this->mUser;
+               global $wgUser;
+
+               if ( $audience === self::FOR_THIS_USER && !$user ) {
+                       $user = $wgUser;
                }
+
+               $user = $this->mRecord->getUser( $audience, $user );
+               return $user ? $user->getId() : 0;
        }
 
        /**
@@ -1059,23 +706,14 @@ class Revision implements IDBAccessObject {
         * @return string
         */
        public function getUserText( $audience = self::FOR_PUBLIC, User $user = null ) {
-               $this->loadMutableFields();
+               global $wgUser;
 
-               if ( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_USER ) ) {
-                       return '';
-               } elseif ( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_USER, $user ) ) {
-                       return '';
-               } else {
-                       if ( $this->mUserText === null ) {
-                               $this->mUserText = User::whoIs( $this->mUser ); // load on demand
-                               if ( $this->mUserText === false ) {
-                                       # This shouldn't happen, but it can if the wiki was recovered
-                                       # via importing revs and there is no user table entry yet.
-                                       $this->mUserText = $this->mOrigUserText;
-                               }
-                       }
-                       return $this->mUserText;
+               if ( $audience === self::FOR_THIS_USER && !$user ) {
+                       $user = $wgUser;
                }
+
+               $user = $this->mRecord->getUser( $audience, $user );
+               return $user ? $user->getName() : '';
        }
 
        /**
@@ -1103,13 +741,14 @@ class Revision implements IDBAccessObject {
         * @return string
         */
        function getComment( $audience = self::FOR_PUBLIC, User $user = null ) {
-               if ( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_COMMENT ) ) {
-                       return '';
-               } elseif ( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_COMMENT, $user ) ) {
-                       return '';
-               } else {
-                       return $this->mComment;
+               global $wgUser;
+
+               if ( $audience === self::FOR_THIS_USER && !$user ) {
+                       $user = $wgUser;
                }
+
+               $comment = $this->mRecord->getComment( $audience, $user );
+               return $comment === null ? null : $comment->text;
        }
 
        /**
@@ -1127,23 +766,14 @@ class Revision implements IDBAccessObject {
         * @return bool
         */
        public function isMinor() {
-               return (bool)$this->mMinorEdit;
+               return $this->mRecord->isMinor();
        }
 
        /**
         * @return int Rcid of the unpatrolled row, zero if there isn't one
         */
        public function isUnpatrolled() {
-               if ( $this->mUnpatrolled !== null ) {
-                       return $this->mUnpatrolled;
-               }
-               $rc = $this->getRecentChange();
-               if ( $rc && $rc->getAttribute( 'rc_patrolled' ) == 0 ) {
-                       $this->mUnpatrolled = $rc->getAttribute( 'rc_id' );
-               } else {
-                       $this->mUnpatrolled = 0;
-               }
-               return $this->mUnpatrolled;
+               return self::getRevisionStore()->isUnpatrolled( $this->mRecord );
        }
 
        /**
@@ -1156,19 +786,7 @@ class Revision implements IDBAccessObject {
         * @return RecentChange|null
         */
        public function getRecentChange( $flags = 0 ) {
-               $dbr = wfGetDB( DB_REPLICA );
-
-               list( $dbType, ) = DBAccessObjectUtils::getDBOptions( $flags );
-
-               return RecentChange::newFromConds(
-                       [
-                               'rc_user_text' => $this->getUserText( self::RAW ),
-                               'rc_timestamp' => $dbr->timestamp( $this->getTimestamp() ),
-                               'rc_this_oldid' => $this->getId()
-                       ],
-                       __METHOD__,
-                       $dbType
-               );
+               return self::getRevisionStore()->getRecentChange( $this->mRecord, $flags );
        }
 
        /**
@@ -1177,14 +795,7 @@ class Revision implements IDBAccessObject {
         * @return bool
         */
        public function isDeleted( $field ) {
-               if ( $this->isCurrent() && $field === self::DELETED_TEXT ) {
-                       // Current revisions of pages cannot have the content hidden. Skipping this
-                       // check is very useful for Parser as it fetches templates using newKnownCurrent().
-                       // Calling getVisibility() in that case triggers a verification database query.
-                       return false; // no need to check
-               }
-
-               return ( $this->getVisibility() & $field ) == $field;
+               return $this->mRecord->isDeleted( $field );
        }
 
        /**
@@ -1193,19 +804,17 @@ class Revision implements IDBAccessObject {
         * @return int
         */
        public function getVisibility() {
-               $this->loadMutableFields();
-
-               return (int)$this->mDeleted;
+               return $this->mRecord->getVisibility();
        }
 
        /**
         * Fetch revision content if it's available to the specified audience.
         * If the specified audience does not have the ability to view this
-        * revision, null will be returned.
+        * revision, or the content could not be loaded, null will be returned.
         *
         * @param int $audience One of:
         *   Revision::FOR_PUBLIC       to be displayed to all users
-        *   Revision::FOR_THIS_USER    to be displayed to $wgUser
+        *   Revision::FOR_THIS_USER    to be displayed to $user
         *   Revision::RAW              get the text regardless of permissions
         * @param User $user User object to check for, only if FOR_THIS_USER is passed
         *   to the $audience parameter
@@ -1213,12 +822,17 @@ class Revision implements IDBAccessObject {
         * @return Content|null
         */
        public function getContent( $audience = self::FOR_PUBLIC, User $user = null ) {
-               if ( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_TEXT ) ) {
-                       return null;
-               } elseif ( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_TEXT, $user ) ) {
+               global $wgUser;
+
+               if ( $audience === self::FOR_THIS_USER && !$user ) {
+                       $user = $wgUser;
+               }
+
+               try {
+                       return $this->mRecord->getContent( 'main', $audience, $user );
+               }
+               catch ( RevisionAccessException $e ) {
                        return null;
-               } else {
-                       return $this->getContentInternal();
                }
        }
 
@@ -1226,86 +840,51 @@ class Revision implements IDBAccessObject {
         * Get original serialized data (without checking view restrictions)
         *
         * @since 1.21
+        * @deprecated since 1.31, use BlobStore::getBlob instead.
+        *
         * @return string
         */
        public function getSerializedData() {
-               if ( $this->mText === null ) {
-                       // Revision is immutable. Load on demand.
-                       $this->mText = $this->loadText();
-               }
-
-               return $this->mText;
+               $slot = $this->getMainSlotRaw();
+               return $slot->getContent()->serialize();
        }
 
        /**
-        * Gets the content object for the revision (or null on failure).
-        *
-        * Note that for mutable Content objects, each call to this method will return a
-        * fresh clone.
-        *
-        * @since 1.21
-        * @return Content|null The Revision's content, or null on failure.
-        */
-       protected function getContentInternal() {
-               if ( $this->mContent === null ) {
-                       $text = $this->getSerializedData();
-
-                       if ( $text !== null && $text !== false ) {
-                               // Unserialize content
-                               $handler = $this->getContentHandler();
-                               $format = $this->getContentFormat();
-
-                               $this->mContent = $handler->unserializeContent( $text, $format );
-                       }
-               }
-
-               // NOTE: copy() will return $this for immutable content objects
-               return $this->mContent ? $this->mContent->copy() : null;
-       }
-
-       /**
-        * Returns the content model for this revision.
+        * Returns the content model for the main slot of this revision.
         *
         * If no content model was stored in the database, the default content model for the title is
         * used to determine the content model to use. If no title is know, CONTENT_MODEL_WIKITEXT
         * is used as a last resort.
         *
+        * @todo: drop this, with MCR, there no longer is a single model associated with a revision.
+        *
         * @return string The content model id associated with this revision,
         *     see the CONTENT_MODEL_XXX constants.
         */
        public function getContentModel() {
-               if ( !$this->mContentModel ) {
-                       $title = $this->getTitle();
-                       if ( $title ) {
-                               $this->mContentModel = ContentHandler::getDefaultModelFor( $title );
-                       } else {
-                               $this->mContentModel = CONTENT_MODEL_WIKITEXT;
-                       }
-
-                       assert( !empty( $this->mContentModel ) );
-               }
-
-               return $this->mContentModel;
+               return $this->getMainSlotRaw()->getModel();
        }
 
        /**
-        * Returns the content format for this revision.
+        * Returns the content format for the main slot of this revision.
         *
         * If no content format was stored in the database, the default format for this
         * revision's content model is returned.
         *
+        * @todo: drop this, the format is irrelevant to the revision!
+        *
         * @return string The content format id associated with this revision,
         *     see the CONTENT_FORMAT_XXX constants.
         */
        public function getContentFormat() {
-               if ( !$this->mContentFormat ) {
-                       $handler = $this->getContentHandler();
-                       $this->mContentFormat = $handler->getDefaultFormat();
+               $format = $this->getMainSlotRaw()->getFormat();
 
-                       assert( !empty( $this->mContentFormat ) );
+               if ( $format === null ) {
+                       // if no format was stored along with the blob, fall back to default format
+                       $format = $this->getContentHandler()->getDefaultFormat();
                }
 
-               return $this->mContentFormat;
+               return $format;
        }
 
        /**
@@ -1315,33 +894,21 @@ class Revision implements IDBAccessObject {
         * @return ContentHandler
         */
        public function getContentHandler() {
-               if ( !$this->mContentHandler ) {
-                       $model = $this->getContentModel();
-                       $this->mContentHandler = ContentHandler::getForModelID( $model );
-
-                       $format = $this->getContentFormat();
-
-                       if ( !$this->mContentHandler->isSupportedFormat( $format ) ) {
-                               throw new MWException( "Oops, the content format $format is not supported for "
-                                       . "this content model, $model" );
-                       }
-               }
-
-               return $this->mContentHandler;
+               return ContentHandler::getForModelID( $this->getContentModel() );
        }
 
        /**
         * @return string
         */
        public function getTimestamp() {
-               return wfTimestamp( TS_MW, $this->mTimestamp );
+               return $this->mRecord->getTimestamp();
        }
 
        /**
         * @return bool
         */
        public function isCurrent() {
-               return $this->mCurrent;
+               return ( $this->mRecord instanceof RevisionStoreRecord ) && $this->mRecord->isCurrent();
        }
 
        /**
@@ -1350,13 +917,8 @@ class Revision implements IDBAccessObject {
         * @return Revision|null
         */
        public function getPrevious() {
-               if ( $this->getTitle() ) {
-                       $prev = $this->getTitle()->getPreviousRevisionID( $this->getId() );
-                       if ( $prev ) {
-                               return self::newFromTitle( $this->getTitle(), $prev );
-                       }
-               }
-               return null;
+               $rec = self::getRevisionStore()->getPreviousRevision( $this->mRecord );
+               return $rec === null ? null : new Revision( $rec );
        }
 
        /**
@@ -1365,38 +927,8 @@ class Revision implements IDBAccessObject {
         * @return Revision|null
         */
        public function getNext() {
-               if ( $this->getTitle() ) {
-                       $next = $this->getTitle()->getNextRevisionID( $this->getId() );
-                       if ( $next ) {
-                               return self::newFromTitle( $this->getTitle(), $next );
-                       }
-               }
-               return null;
-       }
-
-       /**
-        * Get previous revision Id for this page_id
-        * This is used to populate rev_parent_id on save
-        *
-        * @param IDatabase $db
-        * @return int
-        */
-       private function getPreviousRevisionId( $db ) {
-               if ( $this->mPage === null ) {
-                       return 0;
-               }
-               # Use page_latest if ID is not given
-               if ( !$this->mId ) {
-                       $prevId = $db->selectField( 'page', 'page_latest',
-                               [ 'page_id' => $this->mPage ],
-                               __METHOD__ );
-               } else {
-                       $prevId = $db->selectField( 'revision', 'rev_id',
-                               [ 'rev_page' => $this->mPage, 'rev_id < ' . $this->mId ],
-                               __METHOD__,
-                               [ 'ORDER BY' => 'rev_id DESC' ] );
-               }
-               return intval( $prevId );
+               $rec = self::getRevisionStore()->getNextRevision( $this->mRecord );
+               return $rec === null ? null : new Revision( $rec );
        }
 
        /**
@@ -1429,35 +961,9 @@ class Revision implements IDBAccessObject {
                        return false;
                }
 
-               // Use external methods for external objects, text in table is URL-only then
-               if ( in_array( 'external', $flags ) ) {
-                       $url = $text;
-                       $parts = explode( '://', $url, 2 );
-                       if ( count( $parts ) == 1 || $parts[1] == '' ) {
-                               return false;
-                       }
-
-                       if ( isset( $row->old_id ) && $wiki === false ) {
-                               // Make use of the wiki-local revision text cache
-                               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
-                               // The cached value should be decompressed, so handle that and return here
-                               return $cache->getWithSetCallback(
-                                       $cache->makeKey( 'revisiontext', 'textid', $row->old_id ),
-                                       self::getCacheTTL( $cache ),
-                                       function () use ( $url, $wiki, $flags ) {
-                                               // No negative caching per Revision::loadText()
-                                               $text = ExternalStore::fetchFromURL( $url, [ 'wiki' => $wiki ] );
-
-                                               return self::decompressRevisionText( $text, $flags );
-                                       },
-                                       [ 'pcGroup' => self::TEXT_CACHE_GROUP, 'pcTTL' => $cache::TTL_PROC_LONG ]
-                               );
-                       } else {
-                               $text = ExternalStore::fetchFromURL( $url, [ 'wiki' => $wiki ] );
-                       }
-               }
+               $cacheKey = isset( $row->old_id ) ? ( 'tt:' . $row->old_id ) : null;
 
-               return self::decompressRevisionText( $text, $flags );
+               return self::getBlobStore( $wiki )->expandBlob( $text, $flags, $cacheKey );
        }
 
        /**
@@ -1471,28 +977,7 @@ class Revision implements IDBAccessObject {
         * @return string
         */
        public static function compressRevisionText( &$text ) {
-               global $wgCompressRevisions;
-               $flags = [];
-
-               # Revisions not marked this way will be converted
-               # on load if $wgLegacyCharset is set in the future.
-               $flags[] = 'utf-8';
-
-               if ( $wgCompressRevisions ) {
-                       if ( function_exists( 'gzdeflate' ) ) {
-                               $deflated = gzdeflate( $text );
-
-                               if ( $deflated === false ) {
-                                       wfLogWarning( __METHOD__ . ': gzdeflate() failed' );
-                               } else {
-                                       $text = $deflated;
-                                       $flags[] = 'gzip';
-                               }
-                       } else {
-                               wfDebug( __METHOD__ . " -- no zlib support, not compressing\n" );
-                       }
-               }
-               return implode( ',', $flags );
+               return self::getBlobStore()->compressData( $text );
        }
 
        /**
@@ -1503,46 +988,7 @@ class Revision implements IDBAccessObject {
         * @return string|bool Decompressed text, or false on failure
         */
        public static function decompressRevisionText( $text, $flags ) {
-               global $wgLegacyEncoding, $wgContLang;
-
-               if ( $text === false ) {
-                       // Text failed to be fetched; nothing to do
-                       return false;
-               }
-
-               if ( in_array( 'gzip', $flags ) ) {
-                       # Deal with optional compression of archived pages.
-                       # This can be done periodically via maintenance/compressOld.php, and
-                       # as pages are saved if $wgCompressRevisions is set.
-                       $text = gzinflate( $text );
-
-                       if ( $text === false ) {
-                               wfLogWarning( __METHOD__ . ': gzinflate() failed' );
-                               return false;
-                       }
-               }
-
-               if ( in_array( 'object', $flags ) ) {
-                       # Generic compressed storage
-                       $obj = unserialize( $text );
-                       if ( !is_object( $obj ) ) {
-                               // Invalid object
-                               return false;
-                       }
-                       $text = $obj->getText();
-               }
-
-               if ( $text !== false && $wgLegacyEncoding
-                       && !in_array( 'utf-8', $flags ) && !in_array( 'utf8', $flags )
-               ) {
-                       # Old revisions kept around in a legacy encoding?
-                       # Upconvert on demand.
-                       # ("utf8" checked for compatibility with some broken
-                       #  conversion scripts 2008-12-30)
-                       $text = $wgContLang->iconv( $wgLegacyEncoding, 'UTF-8', $text );
-               }
-
-               return $text;
+               return self::getBlobStore()->decompressData( $text, $flags );
        }
 
        /**
@@ -1554,192 +1000,29 @@ class Revision implements IDBAccessObject {
         * @return int The revision ID
         */
        public function insertOn( $dbw ) {
-               global $wgDefaultExternalStore, $wgContentHandlerUseDB;
-
-               // We're inserting a new revision, so we have to use master anyway.
-               // If it's a null revision, it may have references to rows that
-               // are not in the replica yet (the text row).
-               $this->mQueryFlags |= self::READ_LATEST;
-
-               // Not allowed to have rev_page equal to 0, false, etc.
-               if ( !$this->mPage ) {
-                       $title = $this->getTitle();
-                       if ( $title instanceof Title ) {
-                               $titleText = ' for page ' . $title->getPrefixedText();
-                       } else {
-                               $titleText = '';
-                       }
-                       throw new MWException( "Cannot insert revision$titleText: page ID must be nonzero" );
-               }
-
-               $this->checkContentModel();
-
-               $data = $this->mText;
-               $flags = self::compressRevisionText( $data );
-
-               # Write to external storage if required
-               if ( $wgDefaultExternalStore ) {
-                       // Store and get the URL
-                       $data = ExternalStore::insertToDefault( $data );
-                       if ( !$data ) {
-                               throw new MWException( "Unable to store text to external storage" );
-                       }
-                       if ( $flags ) {
-                               $flags .= ',';
-                       }
-                       $flags .= 'external';
-               }
-
-               # Record the text (or external storage URL) to the text table
-               if ( $this->mTextId === null ) {
-                       $dbw->insert( 'text',
-                               [
-                                       'old_text' => $data,
-                                       'old_flags' => $flags,
-                               ], __METHOD__
-                       );
-                       $this->mTextId = $dbw->insertId();
-               }
-
-               if ( $this->mComment === null ) {
-                       $this->mComment = "";
-               }
-
-               # Record the edit in revisions
-               $row = [
-                       'rev_page'       => $this->mPage,
-                       'rev_text_id'    => $this->mTextId,
-                       'rev_minor_edit' => $this->mMinorEdit ? 1 : 0,
-                       'rev_user'       => $this->mUser,
-                       'rev_user_text'  => $this->mUserText,
-                       'rev_timestamp'  => $dbw->timestamp( $this->mTimestamp ),
-                       'rev_deleted'    => $this->mDeleted,
-                       'rev_len'        => $this->mSize,
-                       'rev_parent_id'  => $this->mParentId === null
-                               ? $this->getPreviousRevisionId( $dbw )
-                               : $this->mParentId,
-                       'rev_sha1'       => $this->mSha1 === null
-                               ? self::base36Sha1( $this->mText )
-                               : $this->mSha1,
-               ];
-               if ( $this->mId !== null ) {
-                       $row['rev_id'] = $this->mId;
-               }
-
-               list( $commentFields, $commentCallback ) =
-                       CommentStore::newKey( 'rev_comment' )->insertWithTempTable( $dbw, $this->mComment );
-               $row += $commentFields;
-
-               if ( $wgContentHandlerUseDB ) {
-                       // NOTE: Store null for the default model and format, to save space.
-                       // XXX: Makes the DB sensitive to changed defaults.
-                       // Make this behavior optional? Only in miser mode?
-
-                       $model = $this->getContentModel();
-                       $format = $this->getContentFormat();
+               global $wgUser;
 
-                       $title = $this->getTitle();
+               // Note that $this->mRecord->getId() will typically return null here, but not always,
+               // e.g. not when restoring a revision.
 
-                       if ( $title === null ) {
-                               throw new MWException( "Insufficient information to determine the title of the "
-                                       . "revision's page!" );
+               if ( $this->mRecord->getUser( RevisionRecord::RAW ) === null ) {
+                       if ( $this->mRecord instanceof MutableRevisionRecord ) {
+                               $this->mRecord->setUser( $wgUser );
+                       } else {
+                               throw new MWException( 'Cannot insert revision with no associated user.' );
                        }
-
-                       $defaultModel = ContentHandler::getDefaultModelFor( $title );
-                       $defaultFormat = ContentHandler::getForModelID( $defaultModel )->getDefaultFormat();
-
-                       $row['rev_content_model'] = ( $model === $defaultModel ) ? null : $model;
-                       $row['rev_content_format'] = ( $format === $defaultFormat ) ? null : $format;
-               }
-
-               $dbw->insert( 'revision', $row, __METHOD__ );
-
-               if ( $this->mId === null ) {
-                       // Only if auto-increment was used
-                       $this->mId = $dbw->insertId();
                }
-               $commentCallback( $this->mId );
 
-               // Assertion to try to catch T92046
-               if ( (int)$this->mId === 0 ) {
-                       throw new UnexpectedValueException(
-                               'After insert, Revision mId is ' . var_export( $this->mId, 1 ) . ': ' .
-                                       var_export( $row, 1 )
-                       );
-               }
+               $rec = self::getRevisionStore()->insertRevisionOn( $this->mRecord, $dbw );
 
-               // Insert IP revision into ip_changes for use when querying for a range.
-               if ( $this->mUser === 0 && IP::isValid( $this->mUserText ) ) {
-                       $ipcRow = [
-                               'ipc_rev_id'        => $this->mId,
-                               'ipc_rev_timestamp' => $row['rev_timestamp'],
-                               'ipc_hex'           => IP::toHex( $row['rev_user_text'] ),
-                       ];
-                       $dbw->insert( 'ip_changes', $ipcRow, __METHOD__ );
-               }
+               $this->mRecord = $rec;
 
                // Avoid PHP 7.1 warning of passing $this by reference
                $revision = $this;
-               Hooks::run( 'RevisionInsertComplete', [ &$revision, $data, $flags ] );
+               // TODO: hard-deprecate in 1.32 (or even 1.31?)
+               Hooks::run( 'RevisionInsertComplete', [ &$revision, null, null ] );
 
-               return $this->mId;
-       }
-
-       protected function checkContentModel() {
-               global $wgContentHandlerUseDB;
-
-               // Note: may return null for revisions that have not yet been inserted
-               $title = $this->getTitle();
-
-               $model = $this->getContentModel();
-               $format = $this->getContentFormat();
-               $handler = $this->getContentHandler();
-
-               if ( !$handler->isSupportedFormat( $format ) ) {
-                       $t = $title->getPrefixedDBkey();
-
-                       throw new MWException( "Can't use format $format with content model $model on $t" );
-               }
-
-               if ( !$wgContentHandlerUseDB && $title ) {
-                       // if $wgContentHandlerUseDB is not set,
-                       // all revisions must use the default content model and format.
-
-                       $defaultModel = ContentHandler::getDefaultModelFor( $title );
-                       $defaultHandler = ContentHandler::getForModelID( $defaultModel );
-                       $defaultFormat = $defaultHandler->getDefaultFormat();
-
-                       if ( $this->getContentModel() != $defaultModel ) {
-                               $t = $title->getPrefixedDBkey();
-
-                               throw new MWException( "Can't save non-default content model with "
-                                       . "\$wgContentHandlerUseDB disabled: model is $model, "
-                                       . "default for $t is $defaultModel" );
-                       }
-
-                       if ( $this->getContentFormat() != $defaultFormat ) {
-                               $t = $title->getPrefixedDBkey();
-
-                               throw new MWException( "Can't use non-default content format with "
-                                       . "\$wgContentHandlerUseDB disabled: format is $format, "
-                                       . "default for $t is $defaultFormat" );
-                       }
-               }
-
-               $content = $this->getContent( self::RAW );
-               $prefixedDBkey = $title->getPrefixedDBkey();
-               $revId = $this->mId;
-
-               if ( !$content ) {
-                       throw new MWException(
-                               "Content of revision $revId ($prefixedDBkey) could not be loaded for validation!"
-                       );
-               }
-               if ( !$content->isValid() ) {
-                       throw new MWException(
-                               "Content of revision $revId ($prefixedDBkey) is not valid! Content model is $model"
-                       );
-               }
+               return $rec->getId();
        }
 
        /**
@@ -1748,103 +1031,7 @@ class Revision implements IDBAccessObject {
         * @return string
         */
        public static function base36Sha1( $text ) {
-               return Wikimedia\base_convert( sha1( $text ), 16, 36, 31 );
-       }
-
-       /**
-        * Get the text cache TTL
-        *
-        * @param WANObjectCache $cache
-        * @return int
-        */
-       private static function getCacheTTL( WANObjectCache $cache ) {
-               global $wgRevisionCacheExpiry;
-
-               if ( $cache->getQoS( $cache::ATTR_EMULATION ) <= $cache::QOS_EMULATION_SQL ) {
-                       // Do not cache RDBMs blobs in...the RDBMs store
-                       $ttl = $cache::TTL_UNCACHEABLE;
-               } else {
-                       $ttl = $wgRevisionCacheExpiry ?: $cache::TTL_UNCACHEABLE;
-               }
-
-               return $ttl;
-       }
-
-       /**
-        * Lazy-load the revision's text.
-        * Currently hardcoded to the 'text' table storage engine.
-        *
-        * @return string|bool The revision's text, or false on failure
-        */
-       private function loadText() {
-               $cache = ObjectCache::getMainWANInstance();
-
-               // No negative caching; negative hits on text rows may be due to corrupted replica DBs
-               return $cache->getWithSetCallback(
-                       $cache->makeKey( 'revisiontext', 'textid', $this->getTextId() ),
-                       self::getCacheTTL( $cache ),
-                       function () {
-                               return $this->fetchText();
-                       },
-                       [ 'pcGroup' => self::TEXT_CACHE_GROUP, 'pcTTL' => $cache::TTL_PROC_LONG ]
-               );
-       }
-
-       private function fetchText() {
-               $textId = $this->getTextId();
-
-               // If we kept data for lazy extraction, use it now...
-               if ( $this->mTextRow !== null ) {
-                       $row = $this->mTextRow;
-                       $this->mTextRow = null;
-               } else {
-                       $row = null;
-               }
-
-               // Callers doing updates will pass in READ_LATEST as usual. Since the text/blob tables
-               // do not normally get rows changed around, set READ_LATEST_IMMUTABLE in those cases.
-               $flags = $this->mQueryFlags;
-               $flags |= DBAccessObjectUtils::hasFlags( $flags, self::READ_LATEST )
-                       ? self::READ_LATEST_IMMUTABLE
-                       : 0;
-
-               list( $index, $options, $fallbackIndex, $fallbackOptions ) =
-                       DBAccessObjectUtils::getDBOptions( $flags );
-
-               if ( !$row ) {
-                       // Text data is immutable; check replica DBs first.
-                       $row = wfGetDB( $index )->selectRow(
-                               'text',
-                               [ 'old_text', 'old_flags' ],
-                               [ 'old_id' => $textId ],
-                               __METHOD__,
-                               $options
-                       );
-               }
-
-               // Fallback to DB_MASTER in some cases if the row was not found
-               if ( !$row && $fallbackIndex !== null ) {
-                       // Use FOR UPDATE if it was used to fetch this revision. This avoids missing the row
-                       // due to REPEATABLE-READ. Also fallback to the master if READ_LATEST is provided.
-                       $row = wfGetDB( $fallbackIndex )->selectRow(
-                               'text',
-                               [ 'old_text', 'old_flags' ],
-                               [ 'old_id' => $textId ],
-                               __METHOD__,
-                               $fallbackOptions
-                       );
-               }
-
-               if ( !$row ) {
-                       wfDebugLog( 'Revision', "No text row with ID '$textId' (revision {$this->getId()})." );
-               }
-
-               $text = self::getRevisionText( $row );
-               if ( $row && $text === false ) {
-                       wfDebugLog( 'Revision', "No blob for text row '$textId' (revision {$this->getId()})." );
-               }
-
-               return is_string( $text ) ? $text : false;
+               return SlotRecord::base36Sha1( $text );
        }
 
        /**
@@ -1863,58 +1050,17 @@ class Revision implements IDBAccessObject {
         * @return Revision|null Revision or null on error
         */
        public static function newNullRevision( $dbw, $pageId, $summary, $minor, $user = null ) {
-               global $wgContentHandlerUseDB;
-
-               $fields = [ 'page_latest', 'page_namespace', 'page_title',
-                                               'rev_text_id', 'rev_len', 'rev_sha1' ];
-
-               if ( $wgContentHandlerUseDB ) {
-                       $fields[] = 'rev_content_model';
-                       $fields[] = 'rev_content_format';
+               global $wgUser;
+               if ( !$user ) {
+                       $user = $wgUser;
                }
 
-               $current = $dbw->selectRow(
-                       [ 'page', 'revision' ],
-                       $fields,
-                       [
-                               'page_id' => $pageId,
-                               'page_latest=rev_id',
-                       ],
-                       __METHOD__,
-                       [ 'FOR UPDATE' ] // T51581
-               );
-
-               if ( $current ) {
-                       if ( !$user ) {
-                               global $wgUser;
-                               $user = $wgUser;
-                       }
-
-                       $row = [
-                               'page'       => $pageId,
-                               'user_text'  => $user->getName(),
-                               'user'       => $user->getId(),
-                               'comment'    => $summary,
-                               'minor_edit' => $minor,
-                               'text_id'    => $current->rev_text_id,
-                               'parent_id'  => $current->page_latest,
-                               'len'        => $current->rev_len,
-                               'sha1'       => $current->rev_sha1
-                       ];
-
-                       if ( $wgContentHandlerUseDB ) {
-                               $row['content_model'] = $current->rev_content_model;
-                               $row['content_format'] = $current->rev_content_format;
-                       }
-
-                       $row['title'] = Title::makeTitle( $current->page_namespace, $current->page_title );
+               $comment = CommentStoreComment::newUnsavedComment( $summary, null );
 
-                       $revision = new Revision( $row );
-               } else {
-                       $revision = null;
-               }
+               $title = Title::newFromID( $pageId );
+               $rec = self::getRevisionStore()->newNullRevision( $dbw, $title, $comment, $minor, $user );
 
-               return $revision;
+               return new Revision( $rec );
        }
 
        /**
@@ -1948,35 +1094,13 @@ class Revision implements IDBAccessObject {
        public static function userCanBitfield( $bitfield, $field, User $user = null,
                Title $title = null
        ) {
-               if ( $bitfield & $field ) { // aspect is deleted
-                       if ( $user === null ) {
-                               global $wgUser;
-                               $user = $wgUser;
-                       }
-                       if ( $bitfield & self::DELETED_RESTRICTED ) {
-                               $permissions = [ 'suppressrevision', 'viewsuppressed' ];
-                       } elseif ( $field & self::DELETED_TEXT ) {
-                               $permissions = [ 'deletedtext' ];
-                       } else {
-                               $permissions = [ 'deletedhistory' ];
-                       }
-                       $permissionlist = implode( ', ', $permissions );
-                       if ( $title === null ) {
-                               wfDebug( "Checking for $permissionlist due to $field match on $bitfield\n" );
-                               return call_user_func_array( [ $user, 'isAllowedAny' ], $permissions );
-                       } else {
-                               $text = $title->getPrefixedText();
-                               wfDebug( "Checking for $permissionlist on $text due to $field match on $bitfield\n" );
-                               foreach ( $permissions as $perm ) {
-                                       if ( $title->userCan( $perm, $user ) ) {
-                                               return true;
-                                       }
-                               }
-                               return false;
-                       }
-               } else {
-                       return true;
+               global $wgUser;
+
+               if ( !$user ) {
+                       $user = $wgUser;
                }
+
+               return RevisionRecord::userCanBitfield( $bitfield, $field, $user, $title );
        }
 
        /**
@@ -1988,18 +1112,7 @@ class Revision implements IDBAccessObject {
         * @return string|bool False if not found
         */
        static function getTimestampFromId( $title, $id, $flags = 0 ) {
-               $db = ( $flags & self::READ_LATEST )
-                       ? wfGetDB( DB_MASTER )
-                       : wfGetDB( DB_REPLICA );
-               // Casting fix for databases that can't take '' for rev_id
-               if ( $id == '' ) {
-                       $id = 0;
-               }
-               $conds = [ 'rev_id' => $id ];
-               $conds['rev_page'] = $title->getArticleID();
-               $timestamp = $db->selectField( 'revision', 'rev_timestamp', $conds, __METHOD__ );
-
-               return ( $timestamp !== false ) ? wfTimestamp( TS_MW, $timestamp ) : false;
+               return self::getRevisionStore()->getTimestampFromId( $title, $id, $flags );
        }
 
        /**
@@ -2010,12 +1123,7 @@ class Revision implements IDBAccessObject {
         * @return int
         */
        static function countByPageId( $db, $id ) {
-               $row = $db->selectRow( 'revision', [ 'revCount' => 'COUNT(*)' ],
-                       [ 'rev_page' => $id ], __METHOD__ );
-               if ( $row ) {
-                       return $row->revCount;
-               }
-               return 0;
+               return self::getRevisionStore()->countRevisionsByPageId( $db, $id );
        }
 
        /**
@@ -2026,11 +1134,7 @@ class Revision implements IDBAccessObject {
         * @return int
         */
        static function countByTitle( $db, $title ) {
-               $id = $title->getArticleID();
-               if ( $id ) {
-                       return self::countByPageId( $db, $id );
-               }
-               return 0;
+               return self::getRevisionStore()->countRevisionsByTitle( $db, $title );
        }
 
        /**
@@ -2050,28 +1154,11 @@ class Revision implements IDBAccessObject {
         * @return bool True if the given user was the only one to edit since the given timestamp
         */
        public static function userWasLastToEdit( $db, $pageId, $userId, $since ) {
-               if ( !$userId ) {
-                       return false;
-               }
-
                if ( is_int( $db ) ) {
                        $db = wfGetDB( $db );
                }
 
-               $res = $db->select( 'revision',
-                       'rev_user',
-                       [
-                               'rev_page' => $pageId,
-                               'rev_timestamp > ' . $db->addQuotes( $db->timestamp( $since ) )
-                       ],
-                       __METHOD__,
-                       [ 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 50 ] );
-               foreach ( $res as $row ) {
-                       if ( $row->rev_user != $userId ) {
-                               return false;
-                       }
-               }
-               return true;
+               return self::getRevisionStore()->userWasLastToEdit( $db, $pageId, $userId, $since );
        }
 
        /**
@@ -2079,54 +1166,24 @@ class Revision implements IDBAccessObject {
         *
         * This method allows for the use of caching, though accessing anything that normally
         * requires permission checks (aside from the text) will trigger a small DB lookup.
-        * The title will also be lazy loaded, though setTitle() can be used to preload it.
+        * The title will also be loaded if $pageIdOrTitle is an integer ID.
         *
-        * @param IDatabase $db
-        * @param int $pageId Page ID
-        * @param int $revId Known current revision of this page
+        * @param IDatabase $db ignored!
+        * @param int|Title $pageIdOrTitle Page ID or Title object
+        * @param int $revId Known current revision of this page. Determined automatically if not given.
         * @return Revision|bool Returns false if missing
         * @since 1.28
         */
-       public static function newKnownCurrent( IDatabase $db, $pageId, $revId ) {
-               $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
-               return $cache->getWithSetCallback(
-                       // Page/rev IDs passed in from DB to reflect history merges
-                       $cache->makeGlobalKey( 'revision', $db->getDomainID(), $pageId, $revId ),
-                       $cache::TTL_WEEK,
-                       function ( $curValue, &$ttl, array &$setOpts ) use ( $db, $pageId, $revId ) {
-                               $setOpts += Database::getCacheSetOptions( $db );
-
-                               $rev = Revision::loadFromPageId( $db, $pageId, $revId );
-                               // Reflect revision deletion and user renames
-                               if ( $rev ) {
-                                       $rev->mTitle = null; // mutable; lazy-load
-                                       $rev->mRefreshMutableFields = true;
-                               }
-
-                               return $rev ?: false; // don't cache negatives
-                       }
-               );
-       }
+       public static function newKnownCurrent( IDatabase $db, $pageIdOrTitle, $revId = 0 ) {
+               $title = $pageIdOrTitle instanceof Title
+                       ? $pageIdOrTitle
+                       : Title::newFromID( $pageIdOrTitle );
 
-       /**
-        * For cached revisions, make sure the user name and rev_deleted is up-to-date
-        */
-       private function loadMutableFields() {
-               if ( !$this->mRefreshMutableFields ) {
-                       return; // not needed
+               if ( !$title ) {
+                       return false;
                }
 
-               $this->mRefreshMutableFields = false;
-               $dbr = wfGetLB( $this->mWiki )->getConnectionRef( DB_REPLICA, [], $this->mWiki );
-               $row = $dbr->selectRow(
-                       [ 'revision', 'user' ],
-                       [ 'rev_deleted', 'user_name' ],
-                       [ 'rev_id' => $this->mId, 'user_id = rev_user' ],
-                       __METHOD__
-               );
-               if ( $row ) { // update values
-                       $this->mDeleted = (int)$row->rev_deleted;
-                       $this->mUserText = $row->user_name;
-               }
+               $record = self::getRevisionStore()->getKnownCurrentRevision( $title, $revId );
+               return $record ? new Revision( $record ) : false;
        }
 }
index d21bcef..0d266fb 100644 (file)
@@ -42,6 +42,7 @@ use MediaWiki\Linker\LinkRendererFactory;
 use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
 use MediaWiki\Shell\CommandFactory;
+use MediaWiki\Storage\BlobStoreFactory;
 use MediaWiki\Storage\RevisionStore;
 use MediaWiki\Storage\SqlBlobStore;
 
@@ -474,28 +475,22 @@ return [
                return $store;
        },
 
+       'BlobStoreFactory' => function ( MediaWikiServices $services ) {
+               global $wgContLang;
+               return new BlobStoreFactory(
+                       $services->getDBLoadBalancer(),
+                       $services->getMainWANObjectCache(),
+                       $services->getMainConfig(),
+                       $wgContLang
+               );
+       },
+
        'BlobStore' => function ( MediaWikiServices $services ) {
                return $services->getService( '_SqlBlobStore' );
        },
 
        '_SqlBlobStore' => function ( MediaWikiServices $services ) {
-               global $wgContLang; // TODO: manage $wgContLang as a service
-
-               $store = new SqlBlobStore(
-                       $services->getDBLoadBalancer(),
-                       $services->getMainWANObjectCache()
-               );
-
-               $config = $services->getMainConfig();
-               $store->setCompressBlobs( $config->get( 'CompressRevisions' ) );
-               $store->setCacheExpiry( $config->get( 'RevisionCacheExpiry' ) );
-               $store->setUseExternalStore( $config->get( 'DefaultExternalStore' ) !== false );
-
-               if ( $config->get( 'LegacyEncoding' ) ) {
-                       $store->setLegacyEncoding( $config->get( 'LegacyEncoding' ), $wgContLang );
-               }
-
-               return $store;
+               return $services->getBlobStoreFactory()->newSqlBlobStore();
        },
 
        ///////////////////////////////////////////////////////////////////////////
index d6f4b2f..4936b0b 100644 (file)
@@ -370,9 +370,8 @@ if ( $wgRCFilterByAge ) {
        // Note that we allow 1 link higher than the max for things like 56 days but a 60 day link.
        sort( $wgRCLinkDays );
 
-       // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+       // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
        for ( $i = 0; $i < count( $wgRCLinkDays ); $i++ ) {
-               // @codingStandardsIgnoreEnd
                if ( $wgRCLinkDays[$i] >= $rcMaxAgeDays ) {
                        $wgRCLinkDays = array_slice( $wgRCLinkDays, 0, $i + 1, false );
                        break;
diff --git a/includes/Storage/BlobStoreFactory.php b/includes/Storage/BlobStoreFactory.php
new file mode 100644 (file)
index 0000000..63ca74d
--- /dev/null
@@ -0,0 +1,105 @@
+<?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
+ */
+
+namespace MediaWiki\Storage;
+
+use Config;
+use Language;
+use WANObjectCache;
+use Wikimedia\Rdbms\LoadBalancer;
+
+/**
+ * Service for instantiating BlobStores
+ *
+ * This can be used to create BlobStore objects for other wikis.
+ *
+ * @since 1.31
+ */
+class BlobStoreFactory {
+
+       /**
+        * @var LoadBalancer
+        */
+       private $loadBalancer;
+
+       /**
+        * @var WANObjectCache
+        */
+       private $cache;
+
+       /**
+        * @var Config
+        */
+       private $config;
+
+       /**
+        * @var Language
+        */
+       private $contLang;
+
+       public function __construct(
+               LoadBalancer $loadBalancer,
+               WANObjectCache $cache,
+               Config $mainConfig,
+               Language $contLang
+       ) {
+               $this->loadBalancer = $loadBalancer;
+               $this->cache = $cache;
+               $this->config = $mainConfig;
+               $this->contLang = $contLang;
+       }
+
+       /**
+        * @since 1.31
+        *
+        * @param bool|string $wikiId The ID of the target wiki database. Use false for the local wiki.
+        *
+        * @return BlobStore
+        */
+       public function newBlobStore( $wikiId = false ) {
+               return $this->newSqlBlobStore( $wikiId );
+       }
+
+       /**
+        * @internal Please call newBlobStore and use the BlobStore interface.
+        *
+        * @param bool|string $wikiId The ID of the target wiki database. Use false for the local wiki.
+        *
+        * @return SqlBlobStore
+        */
+       public function newSqlBlobStore( $wikiId = false ) {
+               $store = new SqlBlobStore(
+                       $this->loadBalancer,
+                       $this->cache,
+                       $wikiId
+               );
+
+               $store->setCompressBlobs( $this->config->get( 'CompressRevisions' ) );
+               $store->setCacheExpiry( $this->config->get( 'RevisionCacheExpiry' ) );
+               $store->setUseExternalStore( $this->config->get( 'DefaultExternalStore' ) !== false );
+
+               if ( $this->config->get( 'LegacyEncoding' ) ) {
+                       $store->setLegacyEncoding( $this->config->get( 'LegacyEncoding' ), $this->contLang );
+               }
+
+               return $store;
+       }
+
+}
index 5cd157b..afe0f81 100644 (file)
@@ -22,7 +22,7 @@
 
 namespace MediaWiki\Storage;
 
-use \IDBAccessObject;
+use IDBAccessObject;
 use MediaWiki\Linker\LinkTarget;
 use Title;
 
index b8debb8..ce56efc 100644 (file)
@@ -32,7 +32,7 @@ use Content;
 use ContentHandler;
 use DBAccessObjectUtils;
 use Hooks;
-use \IDBAccessObject;
+use IDBAccessObject;
 use InvalidArgumentException;
 use IP;
 use LogicException;
@@ -1075,7 +1075,7 @@ class RevisionStore implements IDBAccessObject, RevisionFactory, RevisionLookup
                        $pageId = isset( $row->rev_page ) ? $row->rev_page : 0; // XXX: also check page_id?
                        $revId = isset( $row->rev_id ) ? $row->rev_id : 0;
 
-                       $title = $this->getTitle( $pageId, $revId );
+                       $title = $this->getTitle( $pageId, $revId, $queryFlags );
                }
 
                if ( !isset( $row->page_latest ) ) {
@@ -1143,7 +1143,7 @@ class RevisionStore implements IDBAccessObject, RevisionFactory, RevisionLookup
                        $pageId = isset( $fields['page'] ) ? $fields['page'] : 0;
                        $revId = isset( $fields['id'] ) ? $fields['id'] : 0;
 
-                       $title = $this->getTitle( $pageId, $revId );
+                       $title = $this->getTitle( $pageId, $revId, $queryFlags );
                }
 
                if ( !isset( $fields['page'] ) ) {
index 50ae8d5..341855d 100644 (file)
@@ -97,7 +97,8 @@ class RevisionStoreRecord extends RevisionRecord {
                        && $this->mPageId !== $this->mTitle->getArticleID()
                ) {
                        throw new InvalidArgumentException(
-                               'The given Title does not belong to page ID ' . $this->mPageId
+                               'The given Title does not belong to page ID ' . $this->mPageId .
+                               ' but actually belongs to ' . $this->mTitle->getArticleID()
                        );
                }
        }
index fcdc1b9..69e1539 100644 (file)
@@ -382,7 +382,7 @@ class SqlBlobStore implements IDBAccessObject, BlobStore {
                                return false;
                        }
 
-                       if ( $cacheKey ) {
+                       if ( $cacheKey && $this->wikiId === false ) {
                                // Make use of the wiki-local revision text cache.
                                // The cached value should be decompressed, so handle that and return here.
                                // NOTE: we rely on $this->cache being the right cache for $this->wikiId!
index b23bd5a..3de85e1 100644 (file)
@@ -4644,7 +4644,7 @@ class Title implements LinkTarget {
        /**
         * Get the last touched timestamp
         *
-        * @param IDatabase $db Optional db
+        * @param IDatabase|null $db
         * @return string|false Last-touched timestamp
         */
        public function getTouched( $db = null ) {
index 0e964bf..85e8db6 100644 (file)
@@ -335,8 +335,8 @@ class HistoryAction extends FormlessAction {
         * @return FeedItem
         */
        function feedItem( $row ) {
-               $rev = new Revision( $row );
-               $rev->setTitle( $this->getTitle() );
+               $rev = new Revision( $row, 0, $this->getTitle() );
+
                $text = FeedUtils::formatDiffRow(
                        $this->getTitle(),
                        $this->getTitle()->getPreviousRevisionID( $rev->getId() ),
@@ -639,12 +639,10 @@ class HistoryPager extends ReverseChronologicalPager {
         */
        function historyLine( $row, $next, $notificationtimestamp = false,
                $latest = false, $firstInList = false ) {
-               $rev = new Revision( $row );
-               $rev->setTitle( $this->getTitle() );
+               $rev = new Revision( $row, 0, $this->getTitle() );
 
                if ( is_object( $next ) ) {
-                       $prevRev = new Revision( $next );
-                       $prevRev->setTitle( $this->getTitle() );
+                       $prevRev = new Revision( $next, 0, $this->getTitle() );
                } else {
                        $prevRev = null;
                }
index e12a727..528e0e2 100644 (file)
@@ -80,8 +80,6 @@ class WatchAction extends FormAction {
                $this->getOutput()->addWikiMsg( $msgKey, $this->getTitle()->getPrefixedText() );
        }
 
-       /* Static utility methods */
-
        /**
         * Watch or unwatch a page
         * @since 1.22
index 4d37af3..df30a2d 100644 (file)
@@ -67,12 +67,12 @@ class ApiBlock extends ApiBase {
                                $params['user'] = $username;
                        }
                } else {
-                       $target = User::newFromName( $params['user'] );
+                       list( $target, $type ) = SpecialBlock::getTargetAndType( $params['user'] );
 
                        // T40633 - if the target is a user (not an IP address), but it
                        // doesn't exist or is unusable, error.
-                       if ( $target instanceof User &&
-                               ( $target->isAnon() /* doesn't exist */ || !User::isUsableName( $target->getName() ) )
+                       if ( $type === Block::TYPE_USER &&
+                               ( $target->isAnon() /* doesn't exist */ || !User::isUsableName( $params['user'] ) )
                        ) {
                                $this->dieWithError( [ 'nosuchusershort', $params['user'] ], 'nosuchuser' );
                        }
@@ -182,14 +182,14 @@ class ApiBlock extends ApiBase {
        }
 
        protected function getExamplesMessages() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        'action=block&user=192.0.2.5&expiry=3%20days&reason=First%20strike&token=123ABC'
                                => 'apihelp-block-example-ip-simple',
                        'action=block&user=Vandal&expiry=never&reason=Vandalism&nocreate=&autoblock=&noemail=&token=123ABC'
                                => 'apihelp-block-example-user-complex',
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        public function getHelpUrls() {
index edea266..84ea266 100644 (file)
@@ -71,7 +71,7 @@ class ApiEmailUser extends ApiBase {
                }
 
                $result = array_filter( [
-                       'result' => $retval->isGood() ? 'Success' : ( $retval->isOk() ? 'Warnings' : 'Failure' ),
+                       'result' => $retval->isGood() ? 'Success' : ( $retval->isOK() ? 'Warnings' : 'Failure' ),
                        'warnings' => $this->getErrorFormatter()->arrayFromStatus( $retval, 'warning' ),
                        'errors' => $this->getErrorFormatter()->arrayFromStatus( $retval, 'error' ),
                ] );
index 183f7e2..1749ce7 100644 (file)
@@ -361,9 +361,8 @@ class ApiErrorFormatter {
  * @deprecated Only for backwards compatibility, do not use
  * @ingroup API
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class ApiErrorFormatter_BackCompat extends ApiErrorFormatter {
-       // @codingStandardsIgnoreEnd
 
        /**
         * @param ApiResult $result Into which data will be added
index dc623ac..91c73a1 100644 (file)
@@ -25,7 +25,8 @@
  */
 
 /**
- * API Serialized PHP output formatter
+ * Formatter that outputs nothing, for when you don't care about the response
+ * at all
  * @ingroup API
  */
 class ApiFormatNone extends ApiFormatBase {
index 5a51b28..d7bc931 100644 (file)
@@ -116,11 +116,10 @@ class ApiRevisionDelete extends ApiBase {
                }
 
                $list->reloadFromMaster();
-               // @codingStandardsIgnoreStart Avoid function calls in a FOR loop test part
+               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $item = $list->reset(); $list->current(); $item = $list->next() ) {
                        $data['items'][$item->getId()] += $item->getApiData( $this->getResult() );
                }
-               // @codingStandardsIgnoreEnd
 
                $data['items'] = array_values( $data['items'] );
                ApiResult::setIndexedTagName( $data['items'], 'i' );
index 9304c2b..c9f6db3 100644 (file)
@@ -39,7 +39,7 @@ class ApiTag extends ApiBase {
                // Check if user can add tags
                if ( $params['tags'] ) {
                        $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $user );
-                       if ( !$ableToTag->isOk() ) {
+                       if ( !$ableToTag->isOK() ) {
                                $this->dieStatus( $ableToTag );
                        }
                }
index 6d7fea2..44be546 100644 (file)
@@ -9,7 +9,8 @@
                        "Maroen1990",
                        "محمد أحمد عبد الفتاح",
                        "ديفيد",
-                       "ASHmed"
+                       "ASHmed",
+                       "Yasser Yousssef"
                ]
        },
        "apihelp-main-param-action": "أي فعل للعمل.",
@@ -30,7 +31,9 @@
        "apihelp-block-param-noemail": "منع المستخدم من إرسال البريد الإلكتروني من خلال الويكي. (يتطلب صلاحية <code>blockemail</code>).",
        "apihelp-block-param-hidename": "إخفاء اسم المستخدم من سجل المنع. (يتطلب صلاحية <code>hideuser</code>).",
        "apihelp-block-param-allowusertalk": "تسمح للمستخدم بتحرير صفحة النقاش الخاصة (يعتمد على <var>[[mw:Special:MyLanguage/Manual:$wgBlockAllowsUTEdit|$wgBlockAllowsUTEdit]]</var>).",
+       "apihelp-block-param-reblock": "إذا كان المستخدم محظوراً بالفعل، يستبدل الحظر القائم.",
        "apihelp-block-param-watchuser": "مشاهدة صفحة المستخدم ونقاش IP.",
+       "apihelp-block-param-tags": "تغيير الوسوم للتطبيق على الإدخال في سجل الحظر.",
        "apihelp-block-example-ip-simple": "منع عنوان IP <kbd>192.0.2.5</kbd> لمدة ثلاثة أيام بسبب >المخالفة الأولى</kbd>.",
        "apihelp-block-example-user-complex": "منع المستخدم <kbd>المخرب</kbd> لأجل غير مسمى بسبب <kbd>التخريب</kbd>، ومنع إنشاء حساب جديد وإرسال بريد إلكتروني.",
        "apihelp-changeauthenticationdata-summary": "تغيير بيانات المصادقة للمستخدم الحالي.",
index fb36923..6b01875 100644 (file)
@@ -12,7 +12,8 @@
                        "Macofe",
                        "Hamilton Abreu",
                        "Umherirrender",
-                       "Fitoschido"
+                       "Fitoschido",
+                       "Athena in Wonderland"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Documentación]]\n* [[mw:Special:MyLanguage/API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Lista de discusión]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Anuncios da API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Erros e solicitudes]\n</div>\n<strong>Estado:</strong> Tódalas funcionalidades mostradas nesta páxina deberían estar funcionando, pero a API aínda está desenrolo, e pode ser modificada en calquera momento. Apúntese na [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ lista de discusión mediawiki-api-announce] para estar informado acerca das actualizacións.\n\n<strong>Solicitudes incorrectas:</strong> Cando se envían solicitudes incorrectas á API, envíase unha cabeceira HTTP coa chave \"MediaWiki-API-Error\" e, a seguir, tanto o valor da cabeceira como o código de erro retornado serán definidos co mesmo valor. Para máis información, consulte [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Erros e avisos]].\n\n<strong>Test:</strong> Para facilitar as probas das peticións da API, consulte [[Special:ApiSandbox]].",
        "api-help-param-upload": "Debe ser enviado como un ficheiro importado usando multipart/form-data.",
        "api-help-param-multi-separate": "Separe os valores con <kbd>|</kbd> ou [[Special:ApiHelp/main#main/datatypes|outros]].",
        "api-help-param-multi-max": "O número máximo de valores é {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} para os bots).",
-       "api-help-param-multi-max-simple": "O número máximo de valores é {{PLURAL:1$|1$}}.",
+       "api-help-param-multi-max-simple": "O número máximo de valores é {{PLURAL:$1|$1}}.",
        "api-help-param-multi-all": "Para especificar tódolos valores use <kbd>$1</kbd>.",
        "api-help-param-default": "Por defecto: $1",
        "api-help-param-default-empty": "Por defecto: <span class=\"apihelp-empty\">(baleiro)</span>",
index c54c622..fc2c789 100644 (file)
@@ -86,8 +86,8 @@
        "apihelp-query+alldeletedrevisions-paraminfo-useronly": "Kann nëmme mam <var>$3user</var> benotzt ginn.",
        "apihelp-query+alldeletedrevisions-param-user": "Nëmme Versioune vun dësem Benotzer opzielen.",
        "apihelp-query+alldeletedrevisions-param-excludeuser": "Versioune vun dësem Benotzer net opzielen.",
-       "apihelp-query+allfileusages-paramvalue-prop-title": "Setzt den Titel vum Fichier derbäi.",
-       "apihelp-query+alllinks-paramvalue-prop-title": "Setzt den Titel vum Link derbäi.",
+       "apihelp-query+allfileusages-paramvalue-prop-title": "Setzt den Titel vum Fichier dobäi.",
+       "apihelp-query+alllinks-paramvalue-prop-title": "Setzt den Titel vum Link dobäi.",
        "apihelp-query+allrevisions-summary": "Lëscht vun alle Versiounen.",
        "apihelp-query+allrevisions-param-user": "Nëmme Versioune vun dësem Benotzer opzielen.",
        "apihelp-query+allrevisions-param-excludeuser": "Versioune vun dësem Benotzer net opzielen.",
        "apihelp-query+allusers-param-activeusers": "Nëmme Benotzer opzielen déi an de leschten $1 {{PLURAL:$1|Dag|Deeg}} aktiv waren.",
        "apihelp-query+backlinks-example-simple": "Linken op d'<kbd>Main page</kbd> weisen.",
        "apihelp-query+blocks-summary": "Lëscht vun de gespaarte Benotzer an IP-Adressen.",
-       "apihelp-query+blocks-paramvalue-prop-range": "Setzt de Beräich vun den IP-Adressen derbäi déi vun der Spär betraff sinn.",
+       "apihelp-query+blocks-paramvalue-prop-range": "Setzt de Beräich vun den IP-Adressen dobäi déi vun der Spär betraff sinn.",
        "apihelp-query+blocks-example-simple": "Lëscht vun de Spären",
        "apihelp-query+categories-summary": "All Kategorien opzielen zu deenen dës Säit gehéiert.",
-       "apihelp-query+categories-paramvalue-prop-timestamp": "Setzt den Zäitstempel vun dem Ament derbäi wou d'Kategorie derbäigesat gouf.",
+       "apihelp-query+categories-paramvalue-prop-timestamp": "Setzt den Zäitstempel vun dem Ament dobäi wou d'Kategorie dobäigesat gouf.",
        "apihelp-query+categories-example-generator": "Informatioun iwwer all Kategorien, déi an der Säit <kbd>Albert Einstein</kbd> benotzt ginn, kréien.",
        "apihelp-query+categorymembers-summary": "All Säiten aus enger bestëmmter Kategorie opzielen.",
        "apihelp-query+categorymembers-example-simple": "Déi éischt 10 Säiten aus der <kbd>Category:Physics</kbd> kréien.",
        "apihelp-query+images-example-simple": "Eng Lëscht vun de Fichiere kréien déi op der [[Main Page|Haaptsäit]] benotzt ginn",
        "apihelp-query+imageusage-example-simple": "Säite weisen déi [[:File:Albert Einstein Head.jpg]] benotzen",
        "apihelp-query+info-paramvalue-prop-readable": "Ob de Benotzer dës Säit liese kann.",
-       "apihelp-query+iwlinks-paramvalue-prop-url": "Setzt déi komplett URL derbäi.",
+       "apihelp-query+iwlinks-paramvalue-prop-url": "Setzt déi komplett URL dobäi.",
        "apihelp-query+langlinks-param-lang": "Nëmme Sproochlinke mat dësem Sproochcode zréckginn.",
        "apihelp-query+links-param-namespace": "Nëmme Linken an dësen Nummräim weisen.",
        "apihelp-query+linkshere-summary": "All Säite fannen déi op déi Säit linken déi ugi gouf.",
        "apihelp-query+random-param-redirect": "Benotzt dofir <kbd>$1filterredir=Viruleedungen</kbd>.",
        "apihelp-query+recentchanges-summary": "Rezent Ännerungen opzielen.",
        "apihelp-query+recentchanges-param-user": "Nëmmen Ännerunge vun dësem Benotzer opzielen.",
-       "apihelp-query+recentchanges-paramvalue-prop-comment": "Setzt d'Bemierkung vun der Ännerung derbäi.",
+       "apihelp-query+recentchanges-paramvalue-prop-comment": "Setzt d'Bemierkung vun der Ännerung dobäi.",
        "apihelp-query+recentchanges-example-simple": "Rezent Ännerunge weisen",
        "apihelp-query+redirects-paramvalue-prop-title": "Titel vun all Viruleedung.",
        "apihelp-query+revisions-example-last5": "Déi lescht 5 Versioune vun der <kbd>Haaptsäit</kbd> kréien.",
        "apihelp-query+revisions+base-paramvalue-prop-comment": "Bemierkung vum Benotzer fir dës Versioun.",
        "apihelp-query+revisions+base-paramvalue-prop-content": "Text vun der Versioun.",
        "apihelp-query+search-param-namespace": "Nëmmen an dësen Nummräim sichen.",
-       "apihelp-query+search-paramvalue-prop-wordcount": "Setzt d'Zuel vun de Wierder vun der Säit derbäi.",
-       "apihelp-query+search-paramvalue-prop-timestamp": "Setzt den Zäitstempel vun der leschter Ännerung vun der Säit derbäi.",
+       "apihelp-query+search-paramvalue-prop-wordcount": "Setzt d'Zuel vun de Wierder vun der Säit dobäi.",
+       "apihelp-query+search-paramvalue-prop-timestamp": "Setzt den Zäitstempel vun der leschter Ännerung vun der Säit dobäi.",
        "apihelp-query+search-paramvalue-prop-score": "Ignoréiert.",
        "apihelp-query+search-paramvalue-prop-hasrelated": "Ignoréiert.",
        "apihelp-query+templates-param-namespace": "Schablounen nëmmen an dësen Nummräim weisen.",
        "apihelp-query+transcludedin-paramvalue-prop-title": "Titel vun all Säit.",
        "apihelp-query+usercontribs-summary": "All Ännerunge vun engem Benotzer kréien.",
-       "apihelp-query+usercontribs-paramvalue-prop-timestamp": "Setzt den Zäitstempel vun derÄnnerung derbäi.",
-       "apihelp-query+usercontribs-paramvalue-prop-comment": "Setzt d'Bemierkung vun der Ännerung derbäi.",
+       "apihelp-query+usercontribs-paramvalue-prop-timestamp": "Setzt den Zäitstempel vun der Ännerung dobäi.",
+       "apihelp-query+usercontribs-paramvalue-prop-comment": "Setzt d'Bemierkung vun der Ännerung dobäi.",
        "apihelp-query+userinfo-param-prop": "Informatioune fir dranzesetzen:",
        "apihelp-query+userinfo-paramvalue-prop-options": "Lëscht vun allen Astellungen déi den aktuelle Benotzer gemaach huet.",
-       "apihelp-query+userinfo-paramvalue-prop-editcount": "Setzt d'Gesamtzuel vun den Ännerunge vum aktuelle Benotzer derbäi.",
-       "apihelp-query+userinfo-paramvalue-prop-realname": "Setzt dem Benotzer säi richtegen Numm derbäi.",
-       "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Setzt de Registréierungsdatum vum Benotzer derbäi.",
+       "apihelp-query+userinfo-paramvalue-prop-editcount": "Setzt d'Gesamtzuel vun den Ännerunge vum aktuelle Benotzer dobäi.",
+       "apihelp-query+userinfo-paramvalue-prop-realname": "Setzt dem Benotzer säi richtegen Numm dobäi.",
+       "apihelp-query+userinfo-paramvalue-prop-registrationdate": "Setzt de Registréierungsdatum vum Benotzer dobäi.",
        "apihelp-query+users-paramvalue-prop-rights": "Weist all Rechter déi all Benotzer huet.",
        "apihelp-query+watchlist-param-user": "Nëmmen Ännerunge vun dësem Benotzer opzielen.",
        "apihelp-query+watchlist-param-excludeuser": "Ännerunge vun dësem Benotzer net opzielen.",
-       "apihelp-query+watchlist-paramvalue-prop-title": "Setzt den Titel vun der Säit derbäi.",
-       "apihelp-query+watchlist-paramvalue-prop-user": "Setzt de Benotzer derbäi deen d'Ännerung gemaach huet.",
-       "apihelp-query+watchlist-paramvalue-prop-comment": "Setzt d'Bemierkung vun der Ännerung derbäi.",
-       "apihelp-query+watchlist-paramvalue-prop-timestamp": "Setzt den Zäitstempel vun der Ännerung derbäi.",
+       "apihelp-query+watchlist-paramvalue-prop-title": "Setzt den Titel vun der Säit dobäi.",
+       "apihelp-query+watchlist-paramvalue-prop-user": "Setzt de Benotzer dobäi deen d'Ännerung gemaach huet.",
+       "apihelp-query+watchlist-paramvalue-prop-comment": "Setzt d'Bemierkung vun der Ännerung dobäi.",
+       "apihelp-query+watchlist-paramvalue-prop-timestamp": "Setzt den Zäitstempel vun der Ännerung dobäi.",
        "apihelp-query+watchlist-paramvalue-type-external": "Extern Ännerungen.",
        "apihelp-query+watchlist-paramvalue-type-new": "Ugeluecht Säiten.",
        "apihelp-query+watchlistraw-param-show": "Nëmmen Elementer opzielen déi dëse Critèren entspriechen.",
index 0089af4..dc9fb11 100644 (file)
        "apihelp-query+mystashedfiles-paramvalue-prop-type": "Hent filas MIME-type og medietype.",
        "apihelp-query+mystashedfiles-param-limit": "Hvor mange filer som skal hentes.",
        "apihelp-query+alltransclusions-param-prop": "Hvilken informasjon som skal inkluderes:",
+       "apihelp-query+alltransclusions-paramvalue-prop-title": "Legger til tittelen på transklusjonen.",
        "apihelp-query+allusers-param-prop": "Hvilken informasjon som skal inkluderes:",
+       "apihelp-query+allusers-paramvalue-prop-blockinfo": "Legger til informasjon om en gjeldende blokkering av brukeren.",
+       "apihelp-query+allusers-paramvalue-prop-groups": "Lister opp grupper brukeren er i. Dette bruker flere tjenerressurser og kan returnere færre resultater enn grensa.",
+       "apihelp-query+allusers-paramvalue-prop-implicitgroups": "Lister opp alle grupper brukeren automatisk er med i.",
+       "apihelp-query+allusers-paramvalue-prop-rights": "Lister opp rettigheter brukeren har.",
+       "apihelp-query+allusers-paramvalue-prop-editcount": "Legger til redigeringstelleren til brukeren.",
+       "apihelp-query+allusers-paramvalue-prop-registration": "Legger til tidsstempelet for når brukeren ble registrert, om tilgjengelig (kan være blank).",
+       "apihelp-query+allusers-paramvalue-prop-centralids": "Legger til sentrale ID-er og tilkoblingsstatus for brukeren.",
+       "apihelp-query+allusers-param-limit": "Hvor mange brukernavn som skal returneres.",
+       "apihelp-query+allusers-param-witheditsonly": "List bare opp brukere som har gjort redigeringer.",
+       "apihelp-query+allusers-param-activeusers": "List bare opp brukere som har vært aktiv {{PLURAL:$1|den siste dagene|de siste $1 dagene}}.",
+       "apihelp-query+allusers-param-attachedwiki": "Med <kbd>$1prop</kbd>, indiker også hvorvidt brukeren er tilkoblet med wikien som identifiseres av denne ID-en.",
+       "apihelp-query+allusers-example-Y": "List opp brukere fra og med <kbd>Y</kbd>.",
+       "apihelp-query+authmanagerinfo-summary": "Hent informasjon om den gjeldende autentiseringsstatusen.",
+       "apihelp-query+backlinks-summary": "Finn alle sider som lenker til den gitte siden.",
+       "apihelp-query+backlinks-param-title": "Tittel det skal søkes etter. Kan ikke brukes sammen med <var>$1pageid</var>.",
+       "apihelp-query+backlinks-param-pageid": "Side-ID det skal søkes etter. Kan ikke brukes sammen med <var>$1title</var>.",
+       "apihelp-query+backlinks-param-dir": "Retningen det skal listes opp i.",
        "apihelp-query+categorymembers-param-prop": "Hvilken informasjon som skal inkluderes:",
+       "apihelp-query+deletedrevs-paraminfo-modes": "{{PLURAL:$1|Modus|Moduser}}: $2",
        "apihelp-query+exturlusage-param-prop": "Hvilken informasjon som skal inkluderes:",
        "apihelp-query+iwbacklinks-param-limit": "Hvor mange sider som skal returneres totalt.",
        "apihelp-query+iwbacklinks-param-prop": "Hvilke egenskaper som skal hentes:",
        "apihelp-query+logevents-paramvalue-prop-comment": "Legger til kommentaren til loggoppføringen.",
        "apihelp-query+logevents-paramvalue-prop-parsedcomment": "Legger til den parsede kommentaren til loggoppføringen.",
        "apihelp-query+logevents-paramvalue-prop-details": "Lister opp ekstra detaljer om loggoppføringen.",
+       "apihelp-query+logevents-param-type": "Filtrer loggoppføringer til kun denne typen.",
+       "apihelp-query+logevents-param-action": "Filtrer logghandlinger til kun denne handlingen. Overstyrer <var>$1type</var>. I listen over mulige verdier kan verdier med jokertegnet stjerne, som <kbd>action/*</kbd> ha forskjellige strenger etter skråstreken.",
+       "apihelp-query+logevents-param-user": "Filtrer oppføringer til de som er gjort av den gitte brukeren.",
+       "apihelp-query+logevents-param-title": "Filtrer oppføringer til de som er relatert til ei side.",
+       "apihelp-query+logevents-param-namespace": "Filtrer oppføringer til de i det gitte navnerommet.",
+       "apihelp-query+logevents-param-prefix": "Filtrer oppføringer som starter med dette prefikset.",
+       "apihelp-query+logevents-param-tag": "List bare opp oppføringer som er tagget med denne taggen.",
+       "apihelp-query+logevents-param-limit": "Hvor mange oppføringer som skal returneres.",
+       "apihelp-query+logevents-example-simple": "List opp nylige loggoppføringer.",
+       "apihelp-query+pagepropnames-summary": "List opp alle sideegenskapsnavn i bruk på wikien.",
+       "apihelp-query+pagepropnames-param-limit": "Maksimalt antall navn som skal returneres.",
+       "apihelp-query+pagepropnames-example-simple": "Hent de 10 første egenskapsnavnene.",
+       "apihelp-query+pageprops-summary": "Hent diverse sideegenskaper definert i sideinnholdet.",
+       "apihelp-query+pageprops-param-prop": "List kun opp disse sideegenskapene (<kbd>[[Special:ApiHelp/query+pagepropnames|action=query&list=pagepropnames]]</kbd> returnerer sideegenskapsnavn i bruk). Nyttig for å sjekke om sider bruker en viss sideegenskap.",
+       "apihelp-query+pageprops-example-simple": "Hent egenskaper for sidene <kbd>Main Page</kbd> og <kbd>MediaWiki</kbd>.",
+       "apihelp-query+pageswithprop-summary": "Lister opp alle sider med en gitt sideegenskap.",
        "apihelp-query+pageswithprop-param-prop": "Hvilken informasjon som skal inkluderes:",
+       "apihelp-query+pageswithprop-paramvalue-prop-ids": "Legger til side-ID-en.",
+       "apihelp-query+pageswithprop-paramvalue-prop-title": "Legger til tittel- og navneroms-ID-en til sida.",
+       "apihelp-query+pageswithprop-paramvalue-prop-value": "Legger til verdien til sideegenskapen.",
+       "apihelp-query+pageswithprop-param-limit": "Maksimalt antall sider som skal returneres.",
+       "apihelp-query+pageswithprop-param-dir": "Hvilken retning det skal sorteres i.",
+       "apihelp-query+pageswithprop-example-simple": "List opp de første 10 sidene som bruker <code>&#123;&#123;DISPLAYTITLE:&#125;&#125;</code>.",
+       "apihelp-query+pageswithprop-example-generator": "Hent ekstra informasjon om de 10 første sidene som bruker <code>_&#95;NOTOC_&#95;</code>.",
+       "apihelp-query+prefixsearch-summary": "Utfør et prefikssøk for sidetitler.",
+       "apihelp-query+prefixsearch-param-search": "Søkestreng.",
+       "apihelp-query+prefixsearch-param-namespace": "Navnerom det skal søkes i.",
+       "apihelp-query+prefixsearch-param-limit": "Maksimalt antall resultater som skal returneres.",
+       "apihelp-query+prefixsearch-param-offset": "Antall resultater som skal hoppes over.",
+       "apihelp-query+prefixsearch-example-simple": "Søk etter sidetitler som begynner med <kbd>meaning</kbd>.",
+       "apihelp-query+prefixsearch-param-profile": "Søkeprofil som skal brukes.",
+       "apihelp-query+protectedtitles-summary": "List opp alle titler som er beskyttet fra opprettelse.",
+       "apihelp-query+protectedtitles-param-namespace": "List kun opp titler i disse navnerommene.",
+       "apihelp-query+protectedtitles-param-level": "List kun opp titler med disse beskyttelsesnivåene.",
+       "apihelp-query+protectedtitles-param-limit": "Hvor mange sider som skal returneres totalt.",
+       "apihelp-query+protectedtitles-param-prop": "Hvilke egenskaper som skal hentes:",
+       "apihelp-query+querypage-param-limit": "Antall resultater som skal returneres.",
+       "apihelp-query+querypage-example-ancientpages": "Returner resultater fra [[Special:Ancientpages]].",
+       "apihelp-query+random-summary": "Hent et sett av tilfeldige sider.",
        "apihelp-query+userinfo-param-prop": "Hvilken informasjon som skal inkluderes:",
        "apihelp-query+users-param-prop": "Hvilken informasjon som skal inkluderes:",
+       "apihelp-query+watchlist-param-type": "Hvilke typer endringer som skal vises:",
+       "apihelp-query+watchlist-paramvalue-type-edit": "Vanlige sideredigeringer.",
+       "apihelp-query+watchlist-paramvalue-type-external": "Eksterne endringer.",
+       "apihelp-query+watchlist-paramvalue-type-new": "Sideopprettelser",
+       "apihelp-query+watchlist-paramvalue-type-log": "Loggoppføringer.",
+       "apihelp-query+watchlist-paramvalue-type-categorize": "Endringer i kategorimedlemskap.",
+       "apihelp-query+watchlist-param-owner": "Brukes sammen med $1token for å få tilgang til en annen brukers overvåkningsliste.",
+       "apihelp-query+watchlist-param-token": "En sikkerhetsnøkkel (tilgjengelig i brukerens [[Special:Preferences#mw-prefsection-watchlist|innstillinger]]) for å tillate tilgang til en annen brukers overvåkningsliste.",
+       "apihelp-query+watchlistraw-param-namespace": "List kun opp sider i de gitte navnerommene.",
+       "apihelp-query+watchlistraw-param-limit": "Hvor mange resultater som skal returneres totalt per forespørsel.",
+       "apihelp-query+watchlistraw-param-prop": "Hvilke ekstra egenskaper som skal hentes:",
+       "apihelp-query+watchlistraw-paramvalue-prop-changed": "Legger til tidsstempel for når brukeren sist ble varslet om redigeringen.",
+       "apihelp-query+watchlistraw-param-show": "List kun opp elementer som tilfredsstiller disse kriteriene.",
+       "apihelp-query+watchlistraw-param-owner": "Brukes sammen med $1token for å få tilgang til en annen brukers overvåkningsliste.",
+       "apihelp-query+watchlistraw-param-token": "En sikkerhetsnøkkel (tilgjengelig i brukerens [[Special:Preferences#mw-prefsection-watchlist|innstillinger]]) for å tillate tilgang til en annen brukers overvåkningsliste.",
+       "apihelp-query+watchlistraw-param-dir": "Retningen det skal listes opp i.",
+       "apihelp-query+watchlistraw-example-simple": "List opp sider på den gjeldende brukerens overvåkningsliste.",
+       "apihelp-query+watchlistraw-example-generator": "Hent sideinfo for sider på den gjeldende brukerens overvåkningsliste.",
+       "apihelp-removeauthenticationdata-summary": "Fjern autentiseringsdata for den gjeldende brukeren.",
+       "apihelp-removeauthenticationdata-example-simple": "Forsøk å fjerne den gjeldende brukerens data for <kbd>FooAuthenticationRequest</kbd>.",
+       "apihelp-resetpassword-summary": "Send en epost for nullstilling av passord til en bruker.",
+       "apihelp-revisiondelete-summary": "Slett og gjenopprett revisjoner.",
+       "apihelp-revisiondelete-param-type": "Type revisjonssletting som utføres.",
+       "apihelp-revisiondelete-param-target": "Sidetittelen for revisjonssletting, om det kreves for typen.",
+       "apihelp-revisiondelete-param-ids": "Identifikatorer for revisjonene som skal slettes.",
+       "apihelp-revisiondelete-param-hide": "Hva som skal skjules for hver revisjon.",
+       "apihelp-revisiondelete-param-show": "Hva som skal vises for hver revisjon.",
+       "apihelp-revisiondelete-param-suppress": "Hvorvidt data skal skjules for administratorer i tillegg til andre.",
+       "apihelp-revisiondelete-param-reason": "Årsak for slettingen eller gjenopprettingen.",
+       "apihelp-revisiondelete-param-tags": "Tagger som skal brukes på oppføringen i sletteloggen.",
+       "apihelp-revisiondelete-example-revision": "Skjul innhold for revisjon <kbd>12345</kbd> på siden <kbd>Main Page</kbd>.",
+       "apihelp-revisiondelete-example-log": "Skjul alle data om loggoppføringen <kbd>67890</kbd> med årsak <kbd>BLP violation</kbd>.",
+       "apihelp-rollback-summary": "Omgjør den siste redigeringen på siden.",
+       "apihelp-rollback-extended-description": "Om den siste brukeren som redigerte siden gjorde flere redigeringer på rad, vil alle disse redigeringene fjernes.",
+       "apihelp-rollback-param-title": "Tittelen på siden som skal tilbakestilles. Kan ikke brukes sammen med <var>$1pageid</var>.",
+       "apihelp-rollback-param-pageid": "Side-ID for siden som skal tilbakestilles. Kan ikke brukes sammen med <var>$1title</var>.",
+       "apihelp-rollback-param-tags": "Tagger som skal påføres tilbakestillingen.",
+       "apihelp-rollback-param-user": "Navnet til brukeren hvis redigeringer skal tilbakestilles.",
+       "apihelp-rollback-param-summary": "Egendefinert redigeringssammendrag. Om denne er tom vil standardsammendraget brukes.",
+       "apihelp-rollback-param-markbot": "Merk de tilbakestilte redigeringene og tilbakestillingen som botredigeringer.",
+       "apihelp-rollback-example-simple": "Tilbakestill de siste redigeringene på siden <kbd>Main Page</kbd> av brukeren <kbd>Example</kbd>.",
+       "apihelp-rollback-example-summary": "Tilbakestill de siste redigeringene på siden <kbd>Main Page</kbd> av IP-adressen <kbd>192.0.2.5</kbd> med sammendraget <kbd>Reverting vandalism</kbd>, og merk disse redigeringene samt tilbakestillingen som botredigeringer.",
+       "apihelp-setnotificationtimestamp-summary": "Oppdater varselstidsstempelet for overvåkede sider.",
+       "apihelp-setpagelanguage-summary": "Endre språket til en side.",
+       "apihelp-setpagelanguage-extended-description-disabled": "Endring av språket til en side tillates ikke på denne wikien.\n\nSlå på <var>[[mw:Special:MyLanguage/Manual:$wgPageLanguageUseDB|$wgPageLanguageUseDB]]</var> for å bruke denne handlingen.",
+       "apihelp-setpagelanguage-param-title": "Tittelen på siden som skal endre språk. Kan ikke brukes sammen med <var>$1pageid</var>.",
+       "apihelp-setpagelanguage-param-pageid": "Side-ID til siden du ønsker å endre språk på. Kan ikke brukes sammen med <var>$1title</var>.",
+       "apihelp-setpagelanguage-param-lang": "Språkkoden for språket du ønsker å endre siden til. Bruk <kbd>default</kbd> for å tilbakestille siden til wikiens standardspråk.",
+       "apihelp-setpagelanguage-param-reason": "Årsak for endringen.",
+       "apihelp-setpagelanguage-param-tags": "Endringstagger som skal påføres loggoppføringen som oppstår på grunn av denne handlingen.",
+       "apihelp-setpagelanguage-example-language": "Endre språket til <kbd>Main Page</kbd> til baskisk.",
+       "apihelp-setpagelanguage-example-default": "Endre språket til siden med ID 123 til wikiens standardspråk.",
+       "apihelp-stashedit-param-title": "Tittelen på siden som redigeres.",
+       "apihelp-stashedit-param-section": "Seksjonsnummer. <kbd>0</kbd> for toppseksjonen, <kbd>new</kbd> for en ny seksjon.",
+       "apihelp-stashedit-param-sectiontitle": "Tittelen til en ny seksjon.",
+       "apihelp-stashedit-param-text": "Sideinnhold.",
+       "apihelp-stashedit-param-contentmodel": "Innholdsmodellen til det nye innholdet.",
+       "apihelp-stashedit-param-baserevid": "Revisjons-ID-en til grunnrevisjonen.",
+       "apihelp-stashedit-param-summary": "Endringssammendrag.",
+       "apihelp-tag-summary": "Legg til eller fjern endringstagger fra individuelle revisjoner eller loggoppføringer.",
+       "apihelp-tag-param-revid": "Én eller flere revisjons-ID-er taggen skal legges til på eller fjernes fra.",
+       "apihelp-tag-param-logid": "Én eller flere loggoppførings-ID-er taggen skal legges til på eller fjernes fra.",
+       "apihelp-tag-param-add": "Tagger som skal legges til. Kun manuelt definerte tagger kan legges til.",
+       "apihelp-tag-param-remove": "Tagger som skal fjernes. Kun tagger som er enten manuelt definert eller helt udefinerte kan fjernes.",
+       "apihelp-tag-param-reason": "Årsak for endringen.",
+       "apihelp-tag-param-tags": "Tagger som skal påføres loggoppføringen som vil oppstå på grunn av denne handlingen.",
+       "apihelp-tag-example-rev": "Legg til taggen <kbd>vandalism</kbd> til revisjons-ID-en 123 uten å oppgi årsak",
+       "apihelp-tag-example-log": "Fjern taggen <kbd>spam</kbd> fra loggoppførings-ID-en 123 med årsaken <kbd>Wrongly applied</kbd>",
+       "apihelp-tokens-extended-description": "Denne modulen er foreldet til fordel for [[Special:ApiHelp/query+tokens|action=query&meta=tokens]].",
+       "apihelp-tokens-example-edit": "Hent en redigeringsnøkkel (standard).",
+       "apihelp-tokens-example-emailmove": "Hent en epostnøkkel og en flyttingsnøkkel.",
+       "apihelp-unblock-summary": "Avblokker en bruker.",
+       "apihelp-userrights-param-user": "Brukernavn.",
+       "apihelp-userrights-param-userid": "Bruker-ID.",
+       "apihelp-userrights-param-remove": "Fjern brukeren fra disse gruppene.",
+       "apihelp-userrights-param-reason": "Årsak for endringen.",
+       "apihelp-userrights-param-tags": "Endringstagger som skal påføres oppføringen i brukerettighetsloggen.",
+       "apihelp-userrights-example-user": "Legg til brukeren <kbd>FooBot</kbd> i gruppa <kbd>bot</kbd>, og fjern den fra gruppene <kbd>sysop</kbd> og <kbd>bureaucrat</kbd>.",
+       "apihelp-userrights-example-userid": "Legg til brukeren med ID <kbd>123</kbd> til gruppa <kbd>bot</kbd>, og fjern den fra gruppene <kbd>sysop</kbd> og <kbd>bureaucrat</kbd>.",
+       "apihelp-userrights-example-expiry": "Legg til brukeren <kbd>SometimeSysop</kbd> til gruppa <kbd>sysop</kbd> midlertidig i én måned.",
+       "apihelp-validatepassword-summary": "Valider et passord mot wikiens passordkrav.",
+       "apihelp-validatepassword-param-password": "Passord som skal valideres.",
+       "apihelp-watch-example-watch": "Overvåk siden <kbd>Main Page</kbd>.",
+       "apihelp-watch-example-unwatch": "Avslutt overvåking av siden <kbd>Main Page</kbd>.",
+       "apihelp-format-example-generic": "Returner spørringsresultatet i formatet $1.",
        "apihelp-json-summary": "Resultatdata i JSON-format.",
        "apihelp-none-summary": "Ingen resultat.",
+       "api-help-main-header": "Hovedmodul",
+       "api-help-undocumented-module": "Ingen dokumentasjon for modulen $1.",
+       "api-help-flag-deprecated": "Modulen er foreldet.",
+       "api-help-flag-internal": "<strong>Denne modulen er intern eller ustabel.</strong> Hvordan den fungerer kan forandre seg uten forvarsel.",
        "api-help-flag-readrights": "Denne modulen krever lesetilgang.",
        "api-help-flag-writerights": "Denne modulen krever skrivetilgang.",
        "api-help-flag-mustbeposted": "Denne modulen aksepterer bare POST forespørsler.",
        "api-help-flag-generator": "Denne modulen kan brukes som en generator.",
+       "api-help-source": "Kilde: $1",
+       "api-help-source-unknown": "Kilde: <span class=\"apihelp-unknown\">ukjent</span>",
+       "api-help-license": "Lisens: [[$1|$2]]",
+       "api-help-license-noname": "Lisens: [[$1|Se lenke]]",
+       "api-help-license-unknown": "Lisens: <span class=\"apihelp-unknown\">ukjent</span>",
        "api-help-parameters": "{{PLURAL:$1|Parameter|Parametre}}:",
        "api-help-param-deprecated": "Utgått.",
        "api-help-param-required": "Denne parameteren er påkrevd.",
+       "api-help-datatypes-header": "Datatyper",
+       "api-help-param-type-limit": "Type: heltall eller <kbd>max</kbd>",
+       "api-help-param-type-integer": "Type: {{PLURAL:$1|1=heltall|2=liste over heltall}}",
+       "api-help-param-type-boolean": "Type: boolsk verdi ([[Special:ApiHelp/main#main/datatypes|detaljer]])",
+       "api-help-param-type-timestamp": "Type: {{PLURAL:$1|1=tidsstempel|2=liste over tidsstempler}} ([[Special:ApiHelp/main#main/datatypes|tillatte formater]])",
+       "api-help-param-type-user": "Type: {{PLURAL:$1|1=brukernavn|2=liste over brukernavn}}",
+       "api-help-param-list": "{{PLURAL:$1|1=Én av følgende verdier|2=Verdier (separer med <kbd>{{!}}</kbd> eller [[Special:ApiHelp/main#main/datatypes|alternativ]])}}: $2",
+       "api-help-param-list-can-be-empty": "{{PLURAL:$1|0=Må være tom|Kan være tom, eller $2}}",
+       "api-help-param-limit": "Ikke mer enn $1 er tillatt.",
+       "api-help-param-limit2": "Ikke mer enn $1 ($2 for botter) er tillatt.",
+       "api-help-param-integer-min": "{{PLURAL:$1|Verdien|Verdiene}} må ikke være mindre enn $2.",
+       "api-help-param-integer-max": "{{PLURAL:$1|Verdien|Verdiene}} må ikke være større enn $3.",
+       "api-help-param-integer-minmax": "{{PLURAL:$1|Verdien|Verdiene}} må være mellom $2 og $3.",
+       "api-help-param-multi-separate": "Separer verdier med <kbd>|</kbd> eller [[Special:ApiHelp/main#main/datatypes|alternativ]].",
+       "api-help-param-multi-max": "Maksimalt antall verdier er {{PLURAL:$1|$1}} ({{PLURAL:$2|$2}} for botter)",
+       "api-help-param-multi-max-simple": "Maksimalt antall verdier er {{PLURAL:$1|$1}}.",
+       "api-help-param-multi-all": "For å angi alle verdier, bruk <kbd>$1</kbd>.",
+       "api-help-param-default": "Standard: $1",
+       "api-help-param-default-empty": "Standard: <span class=\"apihelp-empty\">(tom)</span>",
+       "api-help-param-continue": "Når flere resultater er tilgjengelige, bruk denne for å fortsette.",
+       "api-help-param-no-description": "<span class=\"apihelp-empty\">(ingen beskrivelse)</span>",
+       "api-help-param-maxbytes": "Kan ikke være lengre enn $1 {{PLURAL:$1|byte}}.",
+       "api-help-param-maxchars": "Kan ikke være lengre enn $1 {{PLURAL:$1|tegn}}.",
+       "api-help-examples": "{{PLURAL:$1|Eksempel|Eksempler}}:",
+       "api-help-permissions": "{{PLURAL:$1|Tillatelse|Tillatelser}}:",
+       "api-help-permissions-granted-to": "{{PLURAL:$1|Gitt til}}: $2",
+       "api-help-open-in-apisandbox": "<small>[åpne i sandkasse]</small>",
+       "apierror-changeauth-norequest": "Kunne ikke opprette endringsforespørsel.",
+       "apierror-contentserializationexception": "Innholdsserialisering feliet: $1",
+       "apierror-contenttoobig": "Innholdet du oppga overskrider artikkelstørrelsesgrensen på $1 {{PLURAL:$1|kilobyte}}.",
+       "apierror-copyuploadbaddomain": "Opplasting via URL tillates ikke fra dette domenet.",
+       "apierror-copyuploadbadurl": "Opplasting tillates ikke fra denne URL-en.",
+       "apierror-create-titleexists": "Eksisterende titler kan ikke beskyttes med <kbd>create</kbd>.",
+       "apierror-csp-report": "Feil under prosessering av CSP-rapport: $1.",
+       "apierror-databaseerror": "[$1] Databasespørringsfeil.",
+       "apierror-deletedrevs-param-not-1-2": "Parameteren <var>$1</var> kan ikke brukes i modus 1 eller 2.",
+       "apierror-deletedrevs-param-not-3": "Parameteren <var>$1</var> kan ikke brukes i modus 3.",
+       "apierror-emptynewsection": "Oppretting av tomme nye seksjoner er ikke mulig.",
+       "apierror-emptypage": "Oppretting av nye, tomme sider tillates ikke.",
+       "apierror-exceptioncaught": "[$1] Unntak fanget: $2",
+       "apierror-filedoesnotexist": "Fila fins ikke.",
+       "apierror-fileexists-sharedrepo-perm": "Målfila fins på et delt fillager. Bruk parameteren <var>ignorewarnings</var> for å overstyre den.",
+       "apierror-filenopath": "Kan ikke hente lokal filsti.",
+       "apierror-filetypecannotberotated": "Filtypen kan ikke roteres.",
+       "apierror-formatphp": "Denne responsen kan ikke representeres med <kbd>format=php</kbd>. Se https://phabricator.wikimedia.org/T68776.",
+       "apierror-imageusage-badtitle": "Tittelen for <kbd>$1</kbd> må være ei fil.",
+       "apierror-import-unknownerror": "Ukjent feil under importering: $1.",
+       "apierror-integeroutofrange-abovebotmax": "<var>$1</var> kan ikke være over $2 (satt til $3) for botter eller administratorer.",
+       "apierror-integeroutofrange-abovemax": "<var>$1</var> kan ikke være over $2 (satt til $3) for brukere.",
+       "apierror-integeroutofrange-belowminimum": "<var>$1</var> kan ikke være mindre enn $2 (satt til $3).",
+       "apierror-invalidcategory": "Kategorinavnet du skrev inn er ikke gyldig.",
+       "apierror-invalidexpiry": "Ugyldig utløpstid «$1».",
+       "apierror-invalid-file-key": "Ikke en gyldig filnøkkel.",
+       "apierror-invalidlang": "Ugyldig språkkode for parameteren <var>$1</var>.",
+       "apierror-invalidoldimage": "Parameteren <var>oldimage</var> har et ugyldig format.",
+       "apierror-invalidparammix-cannotusewith": "Parameteren <kbd>$1</kbd> kan ikke brukes med <kbd>$2</kbd>.",
+       "apierror-invalidparammix-mustusewith": "Parameteren <kbd>$1</kbd> kan ikke brukes med <kbd>$2</kbd>.",
+       "apierror-invalidparammix-parse-new-section": "<kbd>section=new</kbd> kan ikke kombineres med parameterne <var>oldid</var>, <var>pageid</var> eller <var>page</var>. Bruk <var>title</var> og <var>text</var>.",
+       "apierror-invalidparammix": "{{PLURAL:$2|Parameterne}} $1 kan ikke brukes sammen.",
+       "apierror-invalidsection": "Parameteren <var>section</var> må være en gyldig seksjons-ID eller <kbd>new</kbd>.",
+       "apierror-invalidtitle": "Ugyldig tittel «$1».",
+       "apierror-invalidurlparam": "Ugyldig verdi for <var>$1urlparam</var> (<kbd>$2=$3</kbd>).",
+       "apierror-invaliduser": "Ugyldig brukernavn «$1».",
+       "apierror-invaliduserid": "Bruker-ID-en <var>$1</var> er ikke gyldig.",
+       "apierror-maxbytes": "Parameteren <var>$1</var> kan ikke være lengre enn $2 {{PLURAL:$2|byte}}",
+       "apierror-maxchars": "Parameteren <var>$1</var> kan ikke være lengre enn $2 {{PLURAL:$2|tegn}}",
+       "apierror-maxlag-generic": "Venter på en databasetjener: Henger etter med {{PLURAL:$1|ett sekund|$1 sekunder}}.",
+       "apierror-maxlag": "Venter på $2: Henger etter med {{PLURAL:$1|ett sekund|$1 sekunder}}.",
+       "apierror-mimesearchdisabled": "MIME-søk er slått av i Miser-modus.",
+       "apierror-missingcontent-pageid": "Manglende innhold for side-ID $1.",
+       "apierror-missingcontent-revid": "Manglende innhold for revisjons-ID $1.",
+       "apierror-missingparam-at-least-one-of": "{{PLURAL:$1|Parameteren|Minst én av parameterne}} $1 er påkrevd.",
+       "apierror-missingparam-one-of": "{{PLURAL:$2|Parameteren|Én av parameterne}} $1 er påkrevd.",
+       "apierror-missingparam": "Parameteren <var>$1</var> må være satt.",
+       "apierror-missingrev-pageid": "Ingen gjeldende revisjon av side-ID $1.",
+       "apierror-missingrev-title": "Ingen gjeldende revisjon av tittelen $1.",
+       "apierror-missingtitle-createonly": "Manglende titler kan bare beskyttes med <kbd>create</kbd>.",
+       "apierror-missingtitle": "Siden du oppga fins ikke.",
+       "apierror-missingtitle-byname": "Siden $1 fins ikke.",
+       "apierror-moduledisabled": "Modulen <kbd>$1</kbd> har blitt slått av.",
+       "apierror-multival-only-one-of": "{{PLURAL:$3|Kun|Kun én av} $2 tillates for parameteren <var>$3</var>.",
        "apierror-multival-only-one": "Bare én verdi er tillatt for parameteret <var>$1</var>.",
+       "apierror-multpages": "<var>$1</var> kan kun brukes med én enkel side.",
+       "apierror-mustbeloggedin-changeauth": "Du må være logget inn for å endre autentiseringsdata.",
+       "apierror-mustbeloggedin-generic": "Du må være logget inn.",
+       "apierror-mustbeloggedin-linkaccounts": "Du må være logget inn for å lenke kontoer.",
+       "apierror-mustbeloggedin-removeauth": "Du må være logget inn for å fjerne autentiseringsdata.",
        "apierror-mustbeloggedin": "Du må være logget inn for å $1.",
+       "apierror-mustbeposted": "Modulen <kbd>$1</kbd> krever en POST-forespørsel.",
+       "apierror-mustpostparams": "Følgende {{PLURAL:$2|parameter|parametre}} ble funnet i spørringsstrengen, men må være i POST-innholdet: $1.",
+       "apierror-noapiwrite": "Redigering av denne wikien via API er slått av. Sjekk at utsagnet <code>$wgEnableWriteAPI=true;</code> inkluderes i wikiens <code>LocalSettings.php</code>-fil.",
+       "apierror-nochanges": "Ingen endringer ble forespurt.",
+       "apierror-no-direct-editing": "Direkte redigering via API-et støttes ikke for innholdsmodellen $1 som brukes av $2.",
+       "apierror-noedit-anon": "Anonyme brukere kan ikke redigere sider.",
+       "apierror-noedit": "Du har ikke tillatelse til å redigere sider.",
+       "apierror-noimageredirect-anon": "Anonyme brukere kan ikke opprette bildeomdirigeringer.",
+       "apierror-noimageredirect": "Du har ikke tillatelse til å opprette bildeomdirigeringer.",
+       "apierror-nosuchlogid": "Det er ingen loggoppføring med ID $1.",
+       "apierror-nosuchpageid": "Det er ingen side med ID $1.",
+       "apierror-nosuchrcid": "Det er ingen nylig endring med ID $1.",
+       "apierror-nosuchrevid": "Det er ingen revisjon med ID $1.",
+       "apierror-nosuchsection": "Det er ingen seksjon $1.",
+       "apierror-nosuchsection-what": "Det er ingen seksjon $1 i $2.",
+       "apierror-nosuchuserid": "Det er ingen bruker med ID $1.",
+       "apierror-notarget": "Du har ikke angitt et gyldig mål for denne handlingen.",
+       "apierror-notpatrollable": "Revisjonen r$1 kan ikke patruljeres fordi den er for gammel.",
+       "apierror-nouploadmodule": "Ingen opplastingsmodul satt.",
        "apierror-offline": "Kunne ikke fortsette på grunn av tilkoblingsproblemer. Sjekk at internettforbindelsen din virker og prøv igjen.",
+       "apierror-opensearch-json-warnings": "Advarsel kan ikke representeres OpenSearch JSON-format.",
+       "apierror-pagecannotexist": "Navnerommet tillater ikke faktiske sider.",
+       "apierror-pagedeleted": "Siden har blitt slettet siden du hentet tidsstempelet dens.",
+       "apierror-pagelang-disabled": "Endring av sidespråk tillates ikke på denne wikien.",
+       "apierror-paramempty": "Parameteren <var>$1</var> kan ikke være tom.",
+       "apierror-parsetree-notwikitext": "<kbd>prop=parsetree</kbd> støttes kut for wikitekstinnhold.",
+       "apierror-parsetree-notwikitext-title": "<kbd>prop=parsetree</kbd> støttes  kun for wikitekstinnhold. $1 bruker innholdsmodellen $2.",
+       "apierror-pastexpiry": "Utløpstiden «$1» er i fortiden.",
+       "apierror-permissiondenied": "Du har ikke tillatelse til å $1.",
        "apierror-permissiondenied-generic": "Tilgang nektet.",
+       "apierror-permissiondenied-patrolflag": "Du trenger rettigheten <code>patrol</code> eller <code>patrolmarks</code> for å be om patruljert-flagget.",
+       "apierror-permissiondenied-unblock": "Du har ikke tillatelse til å avblokkere brukere.",
+       "apierror-prefixsearchdisabled": "Prefikssøk er slått av i Miser-modus.",
+       "apierror-protect-invalidaction": "Ugyldig beskyttelsestype «$1».",
+       "apierror-protect-invalidlevel": "Ugyldig beskyttelsesnivå «$1».",
+       "apierror-readapidenied": "Du må ha lesetilgang for å bruke denne modulen.",
+       "apierror-readonly": "Wikien er for tiden skrivebeskyttet.",
+       "apierror-revwrongpage": "r$1 er ikke en revisjon av $2.",
+       "apierror-searchdisabled": "<var>$1</var>-søk er slått av.",
+       "apierror-sectionreplacefailed": "Kunne ikke flette oppdatert seksjon.",
+       "apierror-sectionsnotsupported": "Seksjoner støttes ikke for innholdsmodellen $1.",
+       "apierror-sectionsnotsupported-what": "Seksjoner støttes ikke av $1.",
+       "apierror-siteinfo-includealldenied": "Kan ikke vise alle tjenernes info med mindre </var>$wgShowHostNames</var> er sann.",
+       "apierror-sizediffdisabled": "Størrelsesforskjell er slått av i Miser-modus.",
        "apierror-timeout": "Tjeneren svarte ikke innenfor forventet tid.",
        "apiwarn-validationfailed": "Bekreftelsesfeil <kbd>$1</kbd>: $2"
 }
index ac134f0..6c311d0 100644 (file)
        "apihelp-query+allusers-param-activeusers": "Wyświetl tylko użytkowników, aktywnych w ciągu {{PLURAL:$1|ostatniego dnia|ostatnich $1 dni}}.",
        "apihelp-query+allusers-example-Y": "Wyświetl użytkowników zaczynających się na <kbd>Y</kbd>.",
        "apihelp-query+backlinks-summary": "Znajdź wszystkie strony, które linkują do danej strony.",
+       "apihelp-query+backlinks-param-title": "Tytuł strony do wyszukania. Nie może być użyty równocześnie z <var>$1pageid</var>.",
        "apihelp-query+backlinks-param-namespace": "Przestrzeń nazw, z której wymieniać.",
        "apihelp-query+backlinks-example-simple": "Pokazuj linki do <kbd>Main page</kbd>.",
        "apihelp-query+blocks-summary": "Lista wszystkich zablokowanych użytkowników i adresów IP.",
        "apihelp-query+pageswithprop-paramvalue-prop-value": "Dodaje wartość właściwości strony.",
        "apihelp-query+pageswithprop-param-limit": "Maksymalna liczba zwracanych stron.",
        "apihelp-query+pageswithprop-param-dir": "W jakim kierunku sortować.",
+       "apihelp-query+pageswithprop-example-simple": "Lista pierwszych 10 stron za pomocą <code>&#123;&#123;DISPLAYTITLE:&#125;&#125;</code>.",
        "apihelp-query+pageswithprop-example-generator": "Pobierz dodatkowe informacje o pierwszych 10 stronach wykorzystując <code>_&#95;NOTOC_&#95;</code>.",
        "apihelp-query+prefixsearch-param-search": "Wyszukaj tekst.",
        "apihelp-query+prefixsearch-param-namespace": "Przestrzenie nazw do przeszukania.",
        "apihelp-query+revisions+base-paramvalue-prop-tags": "Znaczniki wersji.",
        "apihelp-query+revisions+base-param-limit": "Ograniczenie na liczbę wersji, które będą zwrócone.",
        "apihelp-query+search-summary": "Wykonaj wyszukiwanie pełnotekstowe.",
+       "apihelp-query+search-param-namespace": "Szukaj tylko w tych przestrzeniach nazw.",
        "apihelp-query+search-param-info": "Które metadane zwrócić.",
        "apihelp-query+search-paramvalue-prop-size": "Dodaje rozmiar strony w bajtach.",
        "apihelp-query+search-paramvalue-prop-wordcount": "Dodaje liczbę słów na stronie.",
        "apihelp-query+search-paramvalue-prop-redirecttitle": "Dodaje tytuł pasującego przekierowania.",
+       "apihelp-query+search-paramvalue-prop-sectiontitle": "Dodaje tytuł pasującej sekcji.",
+       "apihelp-query+search-paramvalue-prop-extensiondata": "Dodaje dodatkowe dane generowane przez rozszerzenia.",
        "apihelp-query+search-paramvalue-prop-hasrelated": "Zignorowano",
        "apihelp-query+search-param-limit": "Łączna liczba stron do zwrócenia.",
        "apihelp-query+search-param-interwiki": "Dołączaj wyniki wyszukiwań interwiki w wyszukiwarce, jeśli możliwe.",
        "apihelp-query+siteinfo-paramvalue-prop-general": "Ogólne informacje o systemie.",
        "apihelp-query+siteinfo-paramvalue-prop-namespaces": "Lista zarejestrowanych przestrzeni nazw i ich nazwy kanoniczne.",
        "apihelp-query+siteinfo-paramvalue-prop-namespacealiases": "Lista zarejestrowanych aliasów przestrzeni nazw.",
+       "apihelp-query+siteinfo-paramvalue-prop-specialpagealiases": "Lista aliasów stron specjalnych.",
        "apihelp-query+siteinfo-paramvalue-prop-magicwords": "Lista słów magicznych i ich aliasów.",
        "apihelp-query+siteinfo-param-numberingroup": "Wyświetla liczbę użytkowników w grupach użytkowników.",
        "apihelp-query+siteinfo-example-simple": "Pobierz informacje o stronie.",
        "apihelp-query+stashimageinfo-param-sessionkey": "Alias dla $1filekey, dla kompatybilności wstecznej.",
+       "apihelp-query+stashimageinfo-example-simple": "Zwraca informacje o ukrytym pliku.",
        "apihelp-query+tags-summary": "Lista znaczników zmian.",
        "apihelp-query+tags-param-limit": "Maksymalna liczba znaczników do wyświetlenia.",
        "apihelp-query+tags-paramvalue-prop-name": "Dodaje nazwę znacznika.",
        "apierror-integeroutofrange-abovemax": "Wartość <var>$1</var> dla użytkowników nie może przekraczać $2 (ustawiono $3).",
        "apierror-integeroutofrange-belowminimum": "Wartość <var>$1</var> nie może być mniejsza niż $2 (ustawiono $3).",
        "apierror-invalidcategory": "Wprowadzona nazwa kategorii jest nieprawidłowa.",
+       "apierror-invalidexpiry": "Nieprawidłowy czas wygaśnięcia „$1”.",
+       "apierror-invalid-file-key": "Nieprawidłowy klucz pliku.",
        "apierror-invalidlang": "Nieprawidłowy kod języka dla parametru <var>$1</var>.",
        "apierror-invalidoldimage": "Parametr <var>oldimage</var> ma nieprawidłowy format.",
        "apierror-invalidparammix": "{{PLURAL:$2|Parametry}} $1 nie mogą być używane razem.",
        "apierror-invaliduserid": "Identyfikator użytkownika <var>$1</var> jest nieprawidłowy.",
        "apierror-maxlag-generic": "Oczekiwania na serwer bazy danych: opóźnienie $1 {{PLURAL:$1|sekunda|sekundy|sekund}}.",
        "apierror-missingparam": "Parametr <var>$1</var> musi być podany.",
+       "apierror-missingrev-title": "Brak aktualnej wersji tytułu $1.",
        "apierror-missingtitle": "Wybrana przez ciebie strona nie istnieje.",
        "apierror-missingtitle-byname": "Strona $1 nie istnieje.",
        "apierror-moduledisabled": "Moduł <kbd>$1</kbd> został wyłączony.",
        "apierror-mustbeloggedin-generic": "Musisz być zalogowany.",
+       "apierror-mustbeloggedin-removeauth": "Aby usunąć dane uwierzytelniające, musisz się zalogować.",
        "apierror-mustbeloggedin": "Musisz się zalogować, aby mieć możliwość $1.",
+       "apierror-nochanges": "Nie zażądano żadnych zmian.",
        "apierror-nodeleteablefile": "Nie ma takiej starej wersji pliku.",
        "apierror-noedit-anon": "Niezarejestrowani użytkownicy nie mogą edytować stron.",
        "apierror-noedit": "Nie masz uprawnień do edytowania stron.",
        "apiwarn-invalidcategory": "„$1” nie jest kategorią.",
        "apiwarn-invalidtitle": "„$1” nie jest poprawnym tytułem.",
        "apiwarn-notfile": "„$1” nie jest plikiem.",
+       "apiwarn-tokennotallowed": "Działanie „$1” jest niedozwolone dla bieżącego użytkownika.",
        "apiwarn-toomanyvalues": "Podano zbyt wiele wartości dla parametru <var>$1</var>. Ograniczenie do $2.",
+       "apiwarn-validationfailed-keytoolong": "klucz zbyt długi (dozwolone nie więcej niż $1 bajtów).",
        "apiwarn-validationfailed": "Błąd walidacji dla <kbd>$1</kbd>: $2",
+       "apiwarn-wgDebugAPI": "<strong>Ostrzeżenie o zabezpieczeniach</strong>: włączone jest <var>$wgDebugAPI</var>.",
        "api-feed-error-title": "Błąd ($1)",
        "api-exception-trace": "$1 w $2($3)\n$4",
        "api-credits-header": "Twórcy",
index db03a3a..5c8a83c 100644 (file)
@@ -13,7 +13,8 @@
                        "Eduardo Addad de Oliveira",
                        "Warley Felipe C.",
                        "TheEduGobi",
-                       "Felipe L. Ewald"
+                       "Felipe L. Ewald",
+                       "Hamilton Abreu"
                ]
        },
        "apihelp-main-extended-description": "<div class=\"hlist plainlinks api-main-links\">\n* [[mw:Special:MyLanguage/API:Main_page|Documentação]]\n* [[mw:Special:MyLanguage/API:FAQ|FAQ]]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api Lista de discussão]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce Anúncios da API]\n* [https://phabricator.wikimedia.org/maniphest/query/GebfyV4uCaLd/#R Bugs & solicitações]\n</div>\n<strong>Status:</strong> Todos os recursos exibidos nesta página devem estar funcionando, mas a API ainda está em desenvolvimento ativo e pode mudar a qualquer momento. Inscrever-se na [https://lists.wikimedia.org/pipermail/mediawiki-api-announce/ lista de discussão mediawiki-api-announce] para aviso de atualizações.\n\n<strong>Requisições incorretas:</strong> Quando requisições erradas são enviadas para a API, um cabeçalho HTTP será enviado com a chave \"MediaWiki-API-Error\" e então o valor do cabeçalho e o código de erro enviados de volta serão definidos para o mesmo valor. Para mais informações, veja [[mw:Special:MyLanguage/API:Errors_and_warnings|API: Erros e avisos]].\n\n<strong>Testando:</strong> Para facilitar o teste das requisições da API, consulte [[Special:ApiSandbox]].",
index 60c9eae..47e5cd6 100644 (file)
@@ -14,8 +14,8 @@
        "apihelp-main-param-action": "A operação a ser realizada.",
        "apihelp-main-param-format": "O formato do resultado.",
        "apihelp-main-param-maxlag": "O atraso máximo pode ser usado quando o MediaWiki é instalado num ''cluster'' de bases de dados replicadas. Para impedir que as operações causem ainda mais atrasos de replicação do ''site'', este parâmetro pode fazer o cliente aguardar até que o atraso de replicação seja inferior ao valor especificado. Caso o atraso atual exceda esse valor, o código de erro <samp>maxlag</samp> é devolvido com uma mensagem como <samp>À espera do servidor $host: $lag segundos de atraso</samp>.<br />Consulte [[mw:Special:MyLanguage/Manual:Maxlag_parameter|Manual: Parâmetro maxlag]] para mais informações.",
-       "apihelp-main-param-smaxage": "Definir no cabeçalho HTTP <code>s-maxage</code> de controlo da ''cache'' este número de segundos. Os erros nunca são armazenados na ''cache''.",
-       "apihelp-main-param-maxage": "Definir no cabeçalho HTTP <code>max-age</code> de controlo da ''cache'' este número de segundos. Os erros nunca são armazenados na ''cache''.",
+       "apihelp-main-param-smaxage": "Definir no cabeçalho HTTP <code>s-maxage</code> de controlo da cache este número de segundos. Os erros nunca são armazenados na cache.",
+       "apihelp-main-param-maxage": "Definir no cabeçalho HTTP <code>max-age</code> de controlo da cache este número de segundos. Os erros nunca são armazenados na cache.",
        "apihelp-main-param-assert": "Se definido com o valor <kbd>user</kbd>, verificar que o utilizador está autenticado. Se definido com o valor <kbd>bot</kbd>, verificar que o utilizador tem o privilégio de conta robô.",
        "apihelp-main-param-assertuser": "Verificar que o utilizador atual é o utilizador nomeado.",
        "apihelp-main-param-requestid": "Qualquer valor fornecido aqui será incluído na resposta. Pode ser usado para distinguir pedidos.",
        "apihelp-expandtemplates-paramvalue-prop-categories": "Quaisquer categorias existentes na entrada que não estão representadas no texto em notação wiki de saída.",
        "apihelp-expandtemplates-paramvalue-prop-properties": "Propriedades da página, definidas por palavras mágicas expandidas, no texto em notação wiki.",
        "apihelp-expandtemplates-paramvalue-prop-volatile": "Indica se o resultado é volátil e não deve ser reutilizado noutra parte da página.",
-       "apihelp-expandtemplates-paramvalue-prop-ttl": "O período máximo a partir do qual os armazenamentos do resultado na ''cache'' devem ser invalidados.",
+       "apihelp-expandtemplates-paramvalue-prop-ttl": "O período máximo a partir do qual os armazenamentos do resultado na cache devem ser invalidados.",
        "apihelp-expandtemplates-paramvalue-prop-modules": "Quaisquer módulos ResourceLoader que as funções do analisador sintático solicitaram que fossem adicionados ao resultado de saída. Um dos valores <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> tem de ser solicitado em conjunto com o valor <kbd>modules</kbd>.",
        "apihelp-expandtemplates-paramvalue-prop-jsconfigvars": "Devolve as variáveis de configuração JavaScript específicas desta página.",
        "apihelp-expandtemplates-paramvalue-prop-encodedjsconfigvars": "Devolve as variáveis de configuração JavaScript específicas da página, no formato de uma ''string'' JSON.",
        "apihelp-feedrecentchanges-param-hidecategorization": "Ocultar mudanças de pertença a categorias.",
        "apihelp-feedrecentchanges-param-tagfilter": "Filtrar por etiqueta.",
        "apihelp-feedrecentchanges-param-target": "Mostrar apenas mudanças em páginas afluentes a esta.",
-       "apihelp-feedrecentchanges-param-showlinkedto": "Mostrar mudanças em páginas com ligações para a página selecionada.",
+       "apihelp-feedrecentchanges-param-showlinkedto": "Mostrar mudanças em páginas com hiperligações para a página selecionada.",
        "apihelp-feedrecentchanges-param-categories": "Mostrar apenas mudanças nas páginas que estão em todas estas categorias.",
        "apihelp-feedrecentchanges-param-categories_any": "Mostrar apenas mudanças nas páginas que estão em qualquer uma das categorias.",
        "apihelp-feedrecentchanges-example-simple": "Mostrar mudanças recentes.",
        "apihelp-parse-param-oldid": "Analisar o conteúdo desta revisão. Tem precedência sobre <var>$1page</var> e <var>$1pageid</var>.",
        "apihelp-parse-param-prop": "As informações que devem ser obtidas:",
        "apihelp-parse-paramvalue-prop-text": "Fornece o texto analisado, de um texto com notação wiki.",
-       "apihelp-parse-paramvalue-prop-langlinks": "Fornece os links interlínguas do texto analisado.",
-       "apihelp-parse-paramvalue-prop-categories": "Fornece as categorias do texto analisado.",
+       "apihelp-parse-paramvalue-prop-langlinks": "Fornece as hiperligações interlínguas do texto wiki analisado.",
+       "apihelp-parse-paramvalue-prop-categories": "Fornece as categorias do texto wiki analisado.",
        "apihelp-parse-paramvalue-prop-categorieshtml": "Fornece a versão HTML das categorias.",
-       "apihelp-parse-paramvalue-prop-links": "Fornece os links internos do texto analisado.",
-       "apihelp-parse-paramvalue-prop-templates": "Fornece as predefinições do texto analisado.",
-       "apihelp-parse-paramvalue-prop-images": "Fornece as imagens do texto analisado.",
-       "apihelp-parse-paramvalue-prop-externallinks": "Fornece os links externos do texto analisado.",
-       "apihelp-parse-paramvalue-prop-sections": "Fornece as secções do texto analisado.",
+       "apihelp-parse-paramvalue-prop-links": "Fornece as hiperligações internas do texto wiki analisado.",
+       "apihelp-parse-paramvalue-prop-templates": "Fornece as predefinições do texto wiki analisado.",
+       "apihelp-parse-paramvalue-prop-images": "Fornece as imagens do texto wiki analisado.",
+       "apihelp-parse-paramvalue-prop-externallinks": "Fornece as hiperligações externas do texto wiki analisado.",
+       "apihelp-parse-paramvalue-prop-sections": "Fornece as secções do texto wiki analisado.",
        "apihelp-parse-paramvalue-prop-revid": "Adiciona o identificador de revisão da página analisada.",
-       "apihelp-parse-paramvalue-prop-displaytitle": "Adiciona o título do texto analisado.",
+       "apihelp-parse-paramvalue-prop-displaytitle": "Adiciona o título do texto wiki analisado.",
        "apihelp-parse-paramvalue-prop-headitems": "Fornece os elementos a colocar no <code>&lt;head&gt;</code> da página.",
        "apihelp-parse-paramvalue-prop-headhtml": "Fornece o <code>&lt;head&gt;</code> analisado da página.",
        "apihelp-parse-paramvalue-prop-modules": "Fornece os módulos ResourceLoader usados na página. Para carregá-los, usar <code>mw.loader.using()</code>. Uma das variáveis <kbd>jsconfigvars</kbd> ou <kbd>encodedjsconfigvars</kbd> tem de ser pedida em conjunto com <kbd>modules</kbd>.",
        "apihelp-parse-paramvalue-prop-jsconfigvars": "Fornece as variáveis de configuração JavaScript específicas da página. Para aplicá-las, usar <code>mw.config.set()</code>.",
        "apihelp-parse-paramvalue-prop-encodedjsconfigvars": "Fornece as variáveis de configuração JavaScript específicas da página, no formato de uma ''string'' JSON.",
        "apihelp-parse-paramvalue-prop-indicators": "Fornece o HTML dos indicadores de estado de página que são usados na página.",
-       "apihelp-parse-paramvalue-prop-iwlinks": "Fornece os links interwikis do texto analisado.",
+       "apihelp-parse-paramvalue-prop-iwlinks": "Fornece as hiperligações interwikis do texto wiki analisado.",
        "apihelp-parse-paramvalue-prop-wikitext": "Fornece o texto original com notação wiki que foi analisado.",
        "apihelp-parse-paramvalue-prop-properties": "Fornece várias propriedades definidas no texto analisado.",
        "apihelp-parse-paramvalue-prop-limitreportdata": "Fornece o relatório de limites de forma estruturada. Não fornece dados quando <var>$1disablelimitreport</var> está definido.",
        "apihelp-parse-param-wrapoutputclass": "A classe CSS a utilizar para envolver o resultado do analisador sintático.",
        "apihelp-parse-param-pst": "Fazer uma transformação anterior à gravação do texto de entrada, antes de analisá-lo. Só é válido quando usado com texto.",
        "apihelp-parse-param-onlypst": "Fazer uma transformação anterior à gravação (PST, ''pre-save transform'') do texto de entrada, mas não o analisar. Devolve o mesmo texto após aplicação da PST. Só é válido quando usado com <var>$1text</var>.",
-       "apihelp-parse-param-effectivelanglinks": "Inclui links interlínguas fornecidos por extensões (para ser usado com <kbd>$1prop=langlinks</kbd>).",
+       "apihelp-parse-param-effectivelanglinks": "Inclui hiperligações interlínguas fornecidas por extensões (para ser usado com <kbd>$1prop=langlinks</kbd>).",
        "apihelp-parse-param-section": "Analisar apenas o conteúdo desta secção.\n\nQuando tiver o valor <kbd>new</kbd>, analisar <var>$1text</var> e <var>$1sectiontitle</var> como se fosse adicionar uma nova secção à página.\n\n<kbd>new</kbd> só é permitido quando se especifica <var>text</var>.",
        "apihelp-parse-param-sectiontitle": "O novo título da secção quando <var>section</var> tem o valor <kbd>new</kbd>.\n\nAo contrário da edição de páginas, este não toma o valor de <var>summary</var> se for omitido ou estiver vazio.",
        "apihelp-parse-param-disablelimitreport": "Omitir o relatório de limites (\"NewPP limit report\") do resultado de saída do analisador sintático.",
        "apihelp-parse-param-disablepp": "Em vez deste, usar <var>$1disablelimitreport</var>.",
-       "apihelp-parse-param-disableeditsection": "Omitir links para edição da secção no resultado da análise sintática.",
+       "apihelp-parse-param-disableeditsection": "Omitir as hiperligações para edição da secção no resultado da análise sintática.",
        "apihelp-parse-param-disabletidy": "Não fazer a limpeza do HTML (isto é, o ''tidy'') no resultado da análise sintática.",
        "apihelp-parse-param-generatexml": "Gerar a árvore de análise XML (requer o modelo de conteúdo <code>$1</code>; substituído por <kbd>$2prop=parsetree</kbd>).",
        "apihelp-parse-param-preview": "Executar a análise em modo de antevisão.",
        "apihelp-protect-example-protect": "Proteger uma página.",
        "apihelp-protect-example-unprotect": "Desproteger uma página definindo a restrição <kbd>all</kbd> (isto é, todos podem executar a operação).",
        "apihelp-protect-example-unprotect2": "Desproteger uma página definindo que não há restrições.",
-       "apihelp-purge-summary": "Limpar a ''cache'' para os títulos especificados.",
-       "apihelp-purge-param-forcelinkupdate": "Atualizar as tabelas de ligações.",
-       "apihelp-purge-param-forcerecursivelinkupdate": "Atualizar a tabela de ligações, e atualizar as tabelas de ligações de qualquer página que usa esta página como modelo.",
+       "apihelp-purge-summary": "Limpar a cache para os títulos especificados.",
+       "apihelp-purge-param-forcelinkupdate": "Atualizar as tabelas de hiperligações.",
+       "apihelp-purge-param-forcerecursivelinkupdate": "Atualizar a tabela de hiperligações, e atualizar as tabelas de hiperligações de qualquer página que usa esta página como modelo.",
        "apihelp-purge-example-simple": "Purgar as páginas <kbd>Main Page</kbd> e <kbd>API</kbd>.",
        "apihelp-purge-example-generator": "Purgar as primeiras 10 páginas no espaço nominal principal.",
        "apihelp-query-summary": "Obter dados de, e sobre, o MediaWiki.",
        "apihelp-query+allimages-example-recent": "Mostrar uma lista dos ficheiros carregados recentemente, semelhante a [[Special:NewFiles]].",
        "apihelp-query+allimages-example-mimetypes": "Mostrar uma lista dos ficheiros com os tipos MIME <kbd>image/png</kbd> ou <kbd>image/gif</kbd>.",
        "apihelp-query+allimages-example-generator": "Mostrar informação sobre 4 ficheiros, começando pela letra <kbd>T</kbd>.",
-       "apihelp-query+alllinks-summary": "Enumerar todos os ''links'' que apontam para um determinado espaço nominal.",
+       "apihelp-query+alllinks-summary": "Enumerar todas as hiperligações que apontam para um determinado espaço nominal.",
        "apihelp-query+alllinks-param-from": "O título da hiperligação a partir da qual será começada a enumeração.",
-       "apihelp-query+alllinks-param-to": "O título do ''link'' no qual será terminada a enumeração.",
+       "apihelp-query+alllinks-param-to": "O título da hiperligação na qual será terminada a enumeração.",
        "apihelp-query+alllinks-param-prefix": "Procurar todos os títulos ligados que começam por este valor.",
        "apihelp-query+alllinks-param-unique": "Mostrar só títulos ligados únicos. Não pode ser usado com <kbd>$1prop=ids</kbd>.\nAo ser usado como gerador, produz páginas de destino em vez de páginas de origem.",
        "apihelp-query+alllinks-param-prop": "As informações que devem ser incluídas:",
-       "apihelp-query+alllinks-paramvalue-prop-ids": "Adiciona o identificador da página que contém a ligação (não pode ser usado com <var>$1unique</var>).",
+       "apihelp-query+alllinks-paramvalue-prop-ids": "Adiciona o identificador da página que contém a hiperligação (não pode ser usado com <var>$1unique</var>).",
        "apihelp-query+alllinks-paramvalue-prop-title": "Adiciona o título da hiperligação.",
        "apihelp-query+alllinks-param-namespace": "O espaço nominal a ser enumerado.",
        "apihelp-query+alllinks-param-limit": "O número total de entradas a serem devolvidas.",
        "apihelp-query+alllinks-param-dir": "A direção de listagem.",
        "apihelp-query+alllinks-example-B": "Listar os títulos para os quais existem ligações, incluindo títulos em falta, com os identificadores das páginas que contêm as respetivas ligações, começando pela letra <kbd>B</kbd>.",
-       "apihelp-query+alllinks-example-unique": "Listar os títulos únicos para os quais existem ligações.",
-       "apihelp-query+alllinks-example-unique-generator": "Obtém todos os títulos para os quais existem ligações, marcando aqueles em falta.",
+       "apihelp-query+alllinks-example-unique": "Listar os títulos únicos para os quais existem hiperligações.",
+       "apihelp-query+alllinks-example-unique-generator": "Obtém todos os títulos para os quais existem hiperligações, marcando aqueles em falta.",
        "apihelp-query+alllinks-example-generator": "Obtém as páginas que contêm as ligações.",
        "apihelp-query+allmessages-summary": "Devolver as mensagens deste ''site''.",
        "apihelp-query+allmessages-param-messages": "Mensagens a serem produzidas no resultado. <kbd>*</kbd> (o valor por omissão) significa todas as mensagens.",
        "apihelp-query+allpages-param-prfiltercascade": "Filtrar as proteções com base na proteção em cascata (ignorado se $1prtype não estiver presente).",
        "apihelp-query+allpages-param-limit": "O número total de páginas a serem devolvidas.",
        "apihelp-query+allpages-param-dir": "A direção de listagem.",
-       "apihelp-query+allpages-param-filterlanglinks": "Filtrar dependo de uma página ter ''links'' interlínguas. Note que isto pode não tomar em consideração ''links'' interlínguas adicionados por extensões.",
+       "apihelp-query+allpages-param-filterlanglinks": "Filtrar dependo de uma página conter hiperligações interlínguas. Note que isto pode não ter em consideração hiperligações interlínguas adicionadas por extensões.",
        "apihelp-query+allpages-param-prexpiry": "O tipo de expiração pelo qual as páginas serão filtradas:\n;indefinite:Obter só páginas com um período de expiração indefinido.\n;definite:Obter só páginas com um período de expiração definido (específico).\n;all:Obter páginas com qualquer período de expiração.",
        "apihelp-query+allpages-example-B": "Mostrar uma lista de páginas, começando na letra <kbd>B</kbd>.",
        "apihelp-query+allpages-example-generator": "Mostrar informação sobre 4 páginas, começando na letra <kbd>T</kbd>.",
        "apihelp-query+authmanagerinfo-example-login": "Obter os pedidos que podem ser usados ao iniciar uma sessão.",
        "apihelp-query+authmanagerinfo-example-login-merged": "Obter os pedidos que podem ser usados ao iniciar uma sessão, com os campos combinados.",
        "apihelp-query+authmanagerinfo-example-securitysensitiveoperation": "Testar se a autenticação é suficiente para a operação <kbd>foo</kbd>.",
-       "apihelp-query+backlinks-summary": "Encontrar todas as páginas que contêm ligações para a página indicada.",
+       "apihelp-query+backlinks-summary": "Encontrar todas as páginas que contêm hiperligações para a página indicada.",
        "apihelp-query+backlinks-param-title": "O título a ser procurado. Não pode ser usado em conjunto com <var>$1pageid</var>.",
        "apihelp-query+backlinks-param-pageid": "O identificador do título a ser procurado. Não pode ser usado em conjunto com <var>$1title</var>.",
        "apihelp-query+backlinks-param-namespace": "O espaço nominal a ser enumerado.",
        "apihelp-query+backlinks-param-dir": "A direção de listagem.",
        "apihelp-query+backlinks-param-filterredir": "Como filtrar os redirecionamentos. Se definido como <kbd>nonredirects</kbd> quando <var>$1redirect</var> está ativado, isto só é aplicado ao segundo nível.",
        "apihelp-query+backlinks-param-limit": "O número total de páginas a serem devolvidas. Se <var>$1redirect</var> estiver ativado, o limite aplica-se a cada nível em separado (o que significa que até 2 * <var>$1limit</var> resultados podem ser devolvidos).",
-       "apihelp-query+backlinks-param-redirect": "Se a página que contém a ligação é um redirecionamento, procurar também todas as páginas que contêm ligações para esse redirecionamento. O limite máximo é reduzido para metade.",
-       "apihelp-query+backlinks-example-simple": "Mostrar as ligações para <kbd>Main page</kbd>.",
-       "apihelp-query+backlinks-example-generator": "Obter informações sobre as páginas com ligações para <kbd>Main page</kbd>.",
+       "apihelp-query+backlinks-param-redirect": "Se a página que contém a hiperligação é um redirecionamento, procurar também todas as páginas que contêm hiperligações para esse redirecionamento. O limite máximo é reduzido para metade.",
+       "apihelp-query+backlinks-example-simple": "Mostrar as hiperligações para <kbd>Main page</kbd>.",
+       "apihelp-query+backlinks-example-generator": "Obter informações sobre as páginas com hiperligações para <kbd>Main page</kbd>.",
        "apihelp-query+blocks-summary": "Listar todos os utilizadores e endereços IP bloqueados.",
        "apihelp-query+blocks-param-start": "A data e hora a partir da qual será começada a enumeração.",
        "apihelp-query+blocks-param-end": "A data e hora na qual será terminada a enumeração.",
        "apihelp-query+embeddedin-example-generator": "Obter informação sobre as páginas que transcluem <kbd>Template:Stub</kbd>.",
        "apihelp-query+extlinks-summary": "Devolve todos os URL externos (que não sejam interwikis) das páginas especificadas.",
        "apihelp-query+extlinks-param-limit": "O número de ''links'' a serem devolvidos.",
-       "apihelp-query+extlinks-param-protocol": "Protocolo do URL. Se vazio e <var>$1query</var> está definido, o protocolo é <kbd>http</kbd>. Deixe isto e  <var>$1query</var> vazios para listar todos os ''links'' externos.",
+       "apihelp-query+extlinks-param-protocol": "Protocolo do URL. Se vazio e <var>$1query</var> está definido, o protocolo é <kbd>http</kbd>. Deixe este parâmetro e <var>$1query</var> vazios para listar todas as hiperligações externas.",
        "apihelp-query+extlinks-param-query": "Texto de pesquisa sem protocolo. Útil para verificar se uma determinada página contém um determinado URL externo.",
        "apihelp-query+extlinks-param-expandurl": "Expandir os URL relativos a protocolo com o protocolo canónico.",
-       "apihelp-query+extlinks-example-simple": "Obter uma lista das ligações externas na <kbd>Main Page</kbd>.",
+       "apihelp-query+extlinks-example-simple": "Obter uma lista das hiperligações externas da <kbd>Main Page</kbd>.",
        "apihelp-query+exturlusage-summary": "Enumerar as páginas que contêm um determinado URL.",
        "apihelp-query+exturlusage-param-prop": "As informações que devem ser incluídas:",
        "apihelp-query+exturlusage-paramvalue-prop-ids": "Adiciona o identificador da página.",
        "apihelp-query+exturlusage-paramvalue-prop-title": "Adiciona o título e o identificador do espaço nominal da página.",
        "apihelp-query+exturlusage-paramvalue-prop-url": "Adiciona o URL usado na página.",
-       "apihelp-query+exturlusage-param-protocol": "Protocolo do URL. Se vazio e <var>$1query</var> está definido, o protocolo é <kbd>http</kbd>. Deixe isto e  <var>$1query</var> vazios para listar todos os ''links'' externos.",
-       "apihelp-query+exturlusage-param-query": "Texto da pesquisa sem um protocolo. Ver [[Special:LinkSearch]]. Deixar vazio para listar todos os ''links'' externos.",
+       "apihelp-query+exturlusage-param-protocol": "Protocolo do URL. Se vazio e <var>$1query</var> está definido, o protocolo é <kbd>http</kbd>. Deixe este parâmetro e <var>$1query</var> vazios para listar todas as hiperligações externas.",
+       "apihelp-query+exturlusage-param-query": "Texto da pesquisa sem um protocolo. Ver [[Special:LinkSearch]]. Deixar vazio para listar todas as hiperligações externas.",
        "apihelp-query+exturlusage-param-namespace": "Os espaços nominais a serem enumerados.",
        "apihelp-query+exturlusage-param-limit": "O número de páginas a serem devolvidas.",
        "apihelp-query+exturlusage-param-expandurl": "Expandir os URL relativos a protocolo com o protocolo canónico.",
-       "apihelp-query+exturlusage-example-simple": "Mostrar as páginas com ligações para <kbd>http://www.mediawiki.org</kbd>.",
+       "apihelp-query+exturlusage-example-simple": "Mostrar as páginas com hiperligações para <kbd>http://www.mediawiki.org</kbd>.",
        "apihelp-query+filearchive-summary": "Enumerar todos os ficheiros eliminados sequencialmente.",
        "apihelp-query+filearchive-param-from": "O título da imagem a partir do qual será começada a enumeração.",
        "apihelp-query+filearchive-param-to": "O título da imagem no qual será terminada a enumeração.",
        "apihelp-query+info-example-simple": "Obter informações sobre a página <kbd>Main Page</kbd>.",
        "apihelp-query+info-example-protection": "Obter informação geral e de proteção sobre a página <kbd>Main Page</kbd>.",
        "apihelp-query+iwbacklinks-summary": "Encontrar todas as páginas que contêm ''links'' para as páginas indicadas.",
-       "apihelp-query+iwbacklinks-extended-description": "Pode ser usado para encontrar todos os ''links'' com um prefixo, ou todos os ''links'' para um título (com um prefixo especificado). Se nenhum parâmetro for usado, isso efetivamente significa \"todos os ''links'' interwikis\".",
+       "apihelp-query+iwbacklinks-extended-description": "Pode ser usado para encontrar todas as hiperligações com um prefixo, ou todas as hiperligações para um título (com um prefixo especificado). Se nenhum dos parâmetros for usado, isso efetivamente significa \"todas as hiperligações interwikis\".",
        "apihelp-query+iwbacklinks-param-prefix": "O prefixo interwikis.",
        "apihelp-query+iwbacklinks-param-title": "A hiperligação interwikis a ser procurada. Tem de ser usado em conjunto com <var>$1blprefix</var>.",
        "apihelp-query+iwbacklinks-param-limit": "O número total de páginas a serem devolvidas.",
        "apihelp-query+iwbacklinks-param-prop": "As propriedades a serem obtidas:",
-       "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "Adiciona o prefixo do ''link'' interwikis.",
-       "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Adiciona o título do ''link'' interwikis.",
+       "apihelp-query+iwbacklinks-paramvalue-prop-iwprefix": "Adiciona o prefixo da hiperligação interwikis.",
+       "apihelp-query+iwbacklinks-paramvalue-prop-iwtitle": "Adiciona o título da hiperligação interwikis.",
        "apihelp-query+iwbacklinks-param-dir": "A direção de listagem.",
-       "apihelp-query+iwbacklinks-example-simple": "Obter as páginas que contêm ligações para [[wikibooks:Test]].",
-       "apihelp-query+iwbacklinks-example-generator": "Obter informação sobre as páginas que contêm ligações para [[wikibooks:Test]].",
-       "apihelp-query+iwlinks-summary": "Devolve todos os ''links'' interwikis das páginas indicadas.",
+       "apihelp-query+iwbacklinks-example-simple": "Obter as páginas que contêm hiperligações para [[wikibooks:Test]].",
+       "apihelp-query+iwbacklinks-example-generator": "Obter informação sobre as páginas que contêm hiperligações para [[wikibooks:Test]].",
+       "apihelp-query+iwlinks-summary": "Devolve todas as hiperligações interwikis das páginas indicadas.",
        "apihelp-query+iwlinks-param-url": "Indica se deve ser obtido o URL completo (não pode ser usado com $1prop).",
        "apihelp-query+iwlinks-param-prop": "As propriedades adicionais que devem ser obtidas para cada hiperligação interlínguas:",
        "apihelp-query+iwlinks-paramvalue-prop-url": "Adiciona o URL completo.",
-       "apihelp-query+iwlinks-param-limit": "O número de ''links'' interwikis a serem devolvidos.",
-       "apihelp-query+iwlinks-param-prefix": "Devolver só os ''links'' interwikis com este prefixo.",
+       "apihelp-query+iwlinks-param-limit": "O número de hiperligações interwikis a serem devolvidas.",
+       "apihelp-query+iwlinks-param-prefix": "Devolver só as hiperligações interwikis com este prefixo.",
        "apihelp-query+iwlinks-param-title": "Hiperligação interwikis a ser procurada. Tem de ser usado em conjunto com <var>$1prefix</var>.",
        "apihelp-query+iwlinks-param-dir": "A direção de listagem.",
-       "apihelp-query+iwlinks-example-simple": "Obter os ''links'' interwikis da página <kbd>Main Page</kbd>.",
-       "apihelp-query+langbacklinks-summary": "Encontrar todas as páginas que contêm ''links'' para o ''link'' interlínguas indicado.",
-       "apihelp-query+langbacklinks-extended-description": "Pode ser usado para encontrar todos os ''links'' para um determinado código de língua, ou todos os ''links'' para um determinado título (de uma língua). Se nenhum for usado, isso efetivamente significa \"todos os ''links'' interlínguas\".\n\nNote que os ''links'' interlínguas adicionados por extensões podem não ser considerados.",
+       "apihelp-query+iwlinks-example-simple": "Obter as hiperligações interwikis da página <kbd>Main Page</kbd>.",
+       "apihelp-query+langbacklinks-summary": "Encontrar todas as páginas que contêm hiperligações para a hiperligação interlínguas indicada.",
+       "apihelp-query+langbacklinks-extended-description": "Pode ser usado para encontrar todas as hiperligações para um determinado código de língua, ou todas as hiperligações para um determinado título (de uma língua). Se nenhum dos parâmetros for usado, isso efetivamente significa \"todas as hiperligações interlínguas\".\n\nNote que as hiperligações interlínguas adicionadas por extensões podem não ser consideradas.",
        "apihelp-query+langbacklinks-param-lang": "A língua da hiperligação da língua.",
        "apihelp-query+langbacklinks-param-title": "Hiperligação interlínguas a ser procurada. Tem de ser usado com $1lang.",
        "apihelp-query+langbacklinks-param-limit": "O número total de páginas a serem devolvidas.",
        "apihelp-query+langbacklinks-param-prop": "As propriedades a serem obtidas:",
-       "apihelp-query+langbacklinks-paramvalue-prop-lllang": "Adiciona o código de língua da ligação interlínguas.",
-       "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "Adiciona o título do ''link'' interlínguas.",
+       "apihelp-query+langbacklinks-paramvalue-prop-lllang": "Adiciona o código de língua da hiperligação interlínguas.",
+       "apihelp-query+langbacklinks-paramvalue-prop-lltitle": "Adiciona o título da hiperligação interlínguas.",
        "apihelp-query+langbacklinks-param-dir": "A direção de listagem.",
-       "apihelp-query+langbacklinks-example-simple": "Obter as páginas que contêm ligações para [[:fr:Test]].",
-       "apihelp-query+langbacklinks-example-generator": "Obter informações sobre as páginas que contêm ligações para [[:fr:Test]].",
-       "apihelp-query+langlinks-summary": "Devolve todos os ''links'' interlínguas das páginas indicadas.",
-       "apihelp-query+langlinks-param-limit": "O número de ''links'' interlínguas a serem devolvidos.",
+       "apihelp-query+langbacklinks-example-simple": "Obter as páginas que contêm hiperligações para [[:fr:Test]].",
+       "apihelp-query+langbacklinks-example-generator": "Obter informações sobre as páginas que contêm hiperligações para [[:fr:Test]].",
+       "apihelp-query+langlinks-summary": "Devolve todas as hiperligações interlínguas das páginas indicadas.",
+       "apihelp-query+langlinks-param-limit": "O número de hiperligações interlínguas a serem devolvidas.",
        "apihelp-query+langlinks-param-url": "Indica se deve ser obtido o URL completo (não pode ser usado com $1prop).",
        "apihelp-query+langlinks-param-prop": "As propriedades adicionais que devem ser obtidas para cada hiperligação interlínguas:",
        "apihelp-query+langlinks-paramvalue-prop-url": "Adiciona o URL completo.",
        "apihelp-query+langlinks-paramvalue-prop-langname": "Adiciona o nome da língua localizado (melhor esforço). Usar <var>$1inlanguagecode</var> para controlar a língua.",
        "apihelp-query+langlinks-paramvalue-prop-autonym": "Adiciona o nome nativo da língua.",
-       "apihelp-query+langlinks-param-lang": "Devolver só os ''links'' interlínguas com este código de língua.",
+       "apihelp-query+langlinks-param-lang": "Devolver só as hiperligações interlínguas com este código de língua.",
        "apihelp-query+langlinks-param-title": "A hiperligação a ser procurada. Tem de ser usado com <var>$1lang</var>.",
        "apihelp-query+langlinks-param-dir": "A direção de listagem.",
        "apihelp-query+langlinks-param-inlanguagecode": "O código de língua para os nomes de língua localizados.",
-       "apihelp-query+langlinks-example-simple": "Obter os ''links'' interlínguas da página <kbd>Main Page</kbd>.",
-       "apihelp-query+links-summary": "Devolve todos os ''links'' das páginas indicadas.",
-       "apihelp-query+links-param-namespace": "Mostrar apenas os ''links'' destes espaços nominais.",
+       "apihelp-query+langlinks-example-simple": "Obter as hiperligações interlínguas da página <kbd>Main Page</kbd>.",
+       "apihelp-query+links-summary": "Devolve todas as hiperligações das páginas indicadas.",
+       "apihelp-query+links-param-namespace": "Mostrar apenas as hiperligações destes espaços nominais.",
        "apihelp-query+links-param-limit": "O número de ''links'' a serem devolvidos.",
-       "apihelp-query+links-param-titles": "Listar só as ligações para estes títulos. Útil para verificar se uma determinada página contém ligações para um determinado título.",
+       "apihelp-query+links-param-titles": "Listar só as hiperligações para estes títulos. Útil para verificar se uma determinada página contém hiperligações para um determinado título.",
        "apihelp-query+links-param-dir": "A direção de listagem.",
        "apihelp-query+links-example-simple": "Obter os ''links'' da página <kbd>Main Page</kbd>.",
        "apihelp-query+links-example-generator": "Obter informação sobre as páginas ligadas na página <kbd>Main Page</kbd>.",
-       "apihelp-query+links-example-namespaces": "Obter os ''links'' da página <kbd>Main Page</kbd> nos espaços nominais {{ns:user}} e {{ns:template}}.",
-       "apihelp-query+linkshere-summary": "Encontrar todas as páginas que contêm ''links'' para as páginas indicadas.",
+       "apihelp-query+links-example-namespaces": "Obter as hiperligações da página <kbd>Main Page</kbd> nos espaços nominais {{ns:user}} e {{ns:template}}.",
+       "apihelp-query+linkshere-summary": "Encontrar todas as páginas que contêm hiperligações para as páginas indicadas.",
        "apihelp-query+linkshere-param-prop": "As propriedades a serem obtidas:",
        "apihelp-query+linkshere-paramvalue-prop-pageid": "O identificador de cada página.",
        "apihelp-query+linkshere-paramvalue-prop-title": "O título de cada página.",
        "apihelp-query+linkshere-param-namespace": "Incluir só as páginas nestes espaços nominais.",
        "apihelp-query+linkshere-param-limit": "O número de páginas a serem devolvidas.",
        "apihelp-query+linkshere-param-show": "Mostrar só as páginas que correspondem a estes critérios:\n;redirect:Mostrar só os redirecionamentos.\n;!redirect:Mostrar só os não redirecionamentos.",
-       "apihelp-query+linkshere-example-simple": "Obter uma lista das páginas com ligações para a página [[Main Page]].",
-       "apihelp-query+linkshere-example-generator": "Obter informação sobre as páginas com ligações para a página [[Main Page]].",
+       "apihelp-query+linkshere-example-simple": "Obter uma lista das páginas com hiperligações para a página [[Main Page]].",
+       "apihelp-query+linkshere-example-generator": "Obter informação sobre as páginas com hiperligações para a página [[Main Page]].",
        "apihelp-query+logevents-summary": "Obter eventos dos registos.",
        "apihelp-query+logevents-param-prop": "As propriedades a serem obtidas:",
        "apihelp-query+logevents-paramvalue-prop-ids": "Adiciona o identificador do evento do registo.",
        "apihelp-query+protectedtitles-paramvalue-prop-expiry": "Adiciona a data e hora a que a proteção será removida.",
        "apihelp-query+protectedtitles-paramvalue-prop-level": "Adiciona o nível de proteção.",
        "apihelp-query+protectedtitles-example-simple": "Lista os títulos protegidos.",
-       "apihelp-query+protectedtitles-example-generator": "Encontrar as ligações para os títulos protegidos que pertencem ao espaço nominal principal.",
+       "apihelp-query+protectedtitles-example-generator": "Encontrar as hiperligações para os títulos protegidos que pertencem ao espaço nominal principal.",
        "apihelp-query+querypage-summary": "Obter uma lista fornecida por uma página especial baseada em consultas (''QueryPage'').",
        "apihelp-query+querypage-param-page": "O nome da página especial. Note que este é sensível a maiúsculas e minúsculas.",
        "apihelp-query+querypage-param-limit": "O número de resultados a serem devolvidos.",
        "api-help-source": "Fonte: $1",
        "api-help-source-unknown": "Fonte: <span class=\"apihelp-unknown\">desconhecida</span>",
        "api-help-license": "Licença: [[$1|$2]]",
-       "api-help-license-noname": "Licença: [[$1|Ver ligação]]",
+       "api-help-license-noname": "Licença: [[$1|Ver hiperligação]]",
        "api-help-license-unknown": "Licença: <span class=\"apihelp-unknown\">desconhecida</span>",
        "api-help-parameters": "{{PLURAL:$1|Parâmetro|Parâmetros}}:",
        "api-help-param-deprecated": "Obsoleto.",
index e60ce87..e825170 100644 (file)
        "apihelp-imagerotate-param-tags": "Изменить метки записи в журнале загрузок.",
        "apihelp-imagerotate-example-simple": "Повернуть <kbd>File:Example.png</kbd> на <kbd>90</kbd> градусов.",
        "apihelp-imagerotate-example-generator": "Повернуть все изображения в <kbd>Category:Flip</kbd> на <kbd>180</kbd> градусов.",
-       "apihelp-import-summary": "Импорт страницы из другой вики, или из XML-файла.",
+       "apihelp-import-summary": "Импорт страницы из другой вики или XML-файла.",
        "apihelp-import-extended-description": "Обратите внимание, что HTTP POST-запрос должен быть осуществлён как загрузка файла (то есть, с использованием многотомных данных) при отправки файла через параметр <var>xml</var>.",
        "apihelp-import-param-summary": "Описание записи журнала импорта.",
        "apihelp-import-param-xml": "Загруженный XML-файл.",
+       "apihelp-import-param-interwikiprefix": "Для загруженных импортов: префикс интервики для неизвестных имён участников (а также известных, если задан <var>$1assignknownusers</var>).",
+       "apihelp-import-param-assignknownusers": "Связать правки с локальными участниками, когда участники с такими именами существуют.",
        "apihelp-import-param-interwikisource": "Для импорта из других вики: импортируемая вики.",
        "apihelp-import-param-interwikipage": "Для импорта из других вики: импортируемая страница.",
        "apihelp-import-param-fullhistory": "Для импорта из других вики: импортировать полную историю, а не только текущую страницу.",
        "apihelp-linkaccount-summary": "Связать аккаунт третьей стороны с текущим участником.",
        "apihelp-linkaccount-example-link": "Начать связывание аккаунта с <kbd>Example</kdb>.",
        "apihelp-login-summary": "Вход и получение аутентификационных cookie.",
-       "apihelp-login-extended-description": "Это действие должно быть использовано только в комбинации со [[Special:BotPasswords]]; использование этого модуля для входа в основной аккаунт не поддерживается и может сбиться без предупреждения. Для безопасного входа в основной аккаунт, используйте <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
+       "apihelp-login-extended-description": "Это действие должно быть использовано только в комбинации со [[Special:BotPasswords]]; использование этого модуля для входа в основной аккаунт устарело и может сбиться без предупреждения. Для безопасного входа в основной аккаунт, используйте <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
        "apihelp-login-extended-description-nobotpasswords": "Это действие не поддерживается и может сбиться без предупреждения. Для безопасного входа, используйте <kbd>[[Special:ApiHelp/clientlogin|action=clientlogin]]</kbd>.",
        "apihelp-login-param-name": "Имя участника.",
        "apihelp-login-param-password": "Пароль.",
        "apihelp-query+allrevisions-param-generatetitles": "При использовании в качестве генератора, генерирует названия страниц вместо идентификаторов версий.",
        "apihelp-query+allrevisions-example-user": "Перечислить последние 50 правок участника <kbd>Example</kbd>.",
        "apihelp-query+allrevisions-example-ns-main": "Перечислить первые 50 правок в основном пространстве.",
-       "apihelp-query+mystashedfiles-summary": "Получить список файлов в тайнике (upload stash) текущего участника.",
+       "apihelp-query+mystashedfiles-summary": "Получить список файлов во временном хранилище текущего участника.",
        "apihelp-query+mystashedfiles-param-prop": "Какие свойства файлов запрашивать.",
        "apihelp-query+mystashedfiles-paramvalue-prop-size": "Запросить размер и разрешение изображения.",
        "apihelp-query+mystashedfiles-paramvalue-prop-type": "Запросить MIME- и медиа-тип файла.",
        "apihelp-query+mystashedfiles-param-limit": "Сколько файлов получить.",
-       "apihelp-query+mystashedfiles-example-simple": "Получить ключ, размер и разрешение файлов в тайнике текущего участника.",
+       "apihelp-query+mystashedfiles-example-simple": "Получить ключ, размер и разрешение файлов во временном хранилище текущего участника.",
        "apihelp-query+alltransclusions-summary": "Перечисление всех включений (страниц, вставленных с помощью &#123;&#123;x&#125;&#125;), включая несуществующие.",
        "apihelp-query+alltransclusions-param-from": "Название включения, с которого начать перечисление.",
        "apihelp-query+alltransclusions-param-to": "Название включения, на котором закончить перечисление.",
        "apihelp-query+deletedrevs-param-excludeuser": "Не перечислять правки данного участника.",
        "apihelp-query+deletedrevs-param-namespace": "Перечислять только страницы этого пространства имён.",
        "apihelp-query+deletedrevs-param-limit": "Максимальное количество правок в списке.",
-       "apihelp-query+deletedrevs-param-prop": "Ð\9aакие Ñ\81войÑ\81Ñ\82ва Ð²Ð¾Ð·Ð²Ñ\80аÑ\89аÑ\82Ñ\8c:\n;revid: Ð\94обавлÑ\8fеÑ\82 Ð¸Ð´ÐµÐ½Ñ\82иÑ\84икаÑ\82оÑ\80 Ñ\83далÑ\91нной Ð¿Ñ\80авки.\n;parentid: Ð\94обавлÑ\8fеÑ\82 Ð¸Ð´ÐµÐ½Ñ\82иÑ\84икаÑ\82оÑ\80 Ð¿Ñ\80едÑ\8bдÑ\83Ñ\89ей Ð²ÐµÑ\80Ñ\81ии Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\8b.\n;user: Ð\94обавлÑ\8fеÑ\82 Ð½Ð¸Ðº Ñ\83Ñ\87аÑ\81Ñ\82ника, Ñ\81делавÑ\88его Ð¿Ñ\80авкÑ\83.\n;userid: Ð\94обавлÑ\8fеÑ\82 Ð¸Ð´ÐµÐ½Ñ\82иÑ\84икаÑ\82оÑ\80 Ñ\83Ñ\87аÑ\81Ñ\82ника, Ñ\81делавÑ\88его Ð¿Ñ\80авкÑ\83.\n;comment: Ð\94обавлÑ\8fеÑ\82 Ð¾Ð¿Ð¸Ñ\81ание Ð¿Ñ\80авки.\n;parsedcomment: Ð\94обавлÑ\8fеÑ\82 Ñ\80аÑ\81паÑ\80Ñ\81енное Ð¾Ð¿Ð¸Ñ\81ание Ð¿Ñ\80авки.\n;minor: Ð\9eÑ\82меÑ\87аеÑ\82, Ð±Ñ\8bла Ð»Ð¸ Ð¿Ñ\80авка Ð¼Ð°Ð»Ñ\8bм.\n;len: Ð\94обавлÑ\8fеÑ\82 Ð´Ð»Ð¸Ð½Ñ\83 (в Ð±Ð°Ð¹Ñ\82аÑ\85) Ð¿Ñ\80авки.\n;sha1: Ð\94обавлÑ\8fеÑ\82 Ñ\85Ñ\8dÑ\88 SHA-1 (base 16) Ð¿Ñ\80авки.\n;content: Ð\94обавлÑ\8fеÑ\82 Ñ\81одеÑ\80жимое Ð¿Ñ\80авки.\n;token: <span class=\"apihelp-deprecated\">Ð\9dе Ð¿Ð¾Ð´Ð´ÐµÑ\80живаеÑ\82Ñ\81Ñ\8f.</span> Возвращает токен редактирования.\n;tags: Теги правки.",
+       "apihelp-query+deletedrevs-param-prop": "Ð\9aакие Ñ\81войÑ\81Ñ\82ва Ð²Ð¾Ð·Ð²Ñ\80аÑ\89аÑ\82Ñ\8c:\n;revid: Ð\94обавлÑ\8fеÑ\82 Ð¸Ð´ÐµÐ½Ñ\82иÑ\84икаÑ\82оÑ\80 Ñ\83далÑ\91нной Ð¿Ñ\80авки.\n;parentid: Ð\94обавлÑ\8fеÑ\82 Ð¸Ð´ÐµÐ½Ñ\82иÑ\84икаÑ\82оÑ\80 Ð¿Ñ\80едÑ\8bдÑ\83Ñ\89ей Ð²ÐµÑ\80Ñ\81ии Ñ\81Ñ\82Ñ\80аниÑ\86Ñ\8b.\n;user: Ð\94обавлÑ\8fеÑ\82 Ð½Ð¸Ðº Ñ\83Ñ\87аÑ\81Ñ\82ника, Ñ\81делавÑ\88его Ð¿Ñ\80авкÑ\83.\n;userid: Ð\94обавлÑ\8fеÑ\82 Ð¸Ð´ÐµÐ½Ñ\82иÑ\84икаÑ\82оÑ\80 Ñ\83Ñ\87аÑ\81Ñ\82ника, Ñ\81делавÑ\88его Ð¿Ñ\80авкÑ\83.\n;comment: Ð\94обавлÑ\8fеÑ\82 Ð¾Ð¿Ð¸Ñ\81ание Ð¿Ñ\80авки.\n;parsedcomment: Ð\94обавлÑ\8fеÑ\82 Ñ\80аÑ\81паÑ\80Ñ\81енное Ð¾Ð¿Ð¸Ñ\81ание Ð¿Ñ\80авки.\n;minor: Ð\9eÑ\82меÑ\87аеÑ\82, Ð±Ñ\8bла Ð»Ð¸ Ð¿Ñ\80авка Ð¼Ð°Ð»Ñ\8bм.\n;len: Ð\94обавлÑ\8fеÑ\82 Ð´Ð»Ð¸Ð½Ñ\83 (в Ð±Ð°Ð¹Ñ\82аÑ\85) Ð¿Ñ\80авки.\n;sha1: Ð\94обавлÑ\8fеÑ\82 Ñ\85Ñ\8dÑ\88 SHA-1 (base 16) Ð¿Ñ\80авки.\n;content: Ð\94обавлÑ\8fеÑ\82 Ñ\81одеÑ\80жимое Ð¿Ñ\80авки.\n;token: <span class=\"apihelp-deprecated\">УÑ\81Ñ\82аÑ\80ело.</span> Возвращает токен редактирования.\n;tags: Теги правки.",
        "apihelp-query+deletedrevs-example-mode1": "Список последних удалённых правок страниц <kbd>Main Page</kbd> и <kbd>Talk:Main Page</kbd> с содержимым (режим 1).",
        "apihelp-query+deletedrevs-example-mode2": "Список последних 50 удалённых правок участника <kbd>Bob</kbd> (режим 2).",
        "apihelp-query+deletedrevs-example-mode3-main": "Список последних 50 удалённых правок в основном пространстве имён (режим 3)",
        "apihelp-query+revisions+base-paramvalue-prop-parsedcomment": "Распарсенное описание правки.",
        "apihelp-query+revisions+base-paramvalue-prop-content": "Текст версии.",
        "apihelp-query+revisions+base-paramvalue-prop-tags": "Метки версии.",
-       "apihelp-query+revisions+base-paramvalue-prop-parsetree": "<span class=\"apihelp-deprecated\">Ð\9dе Ð¿Ð¾Ð´Ð´ÐµÑ\80живаеÑ\82Ñ\81Ñ\8f.</span> Вместо этого используйте <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd> или <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>. Дерево парсинга XML содержимого версии (требуется модель содержимого <code>$1</code>).",
+       "apihelp-query+revisions+base-paramvalue-prop-parsetree": "<span class=\"apihelp-deprecated\">УÑ\81Ñ\82аÑ\80ело.</span> Вместо этого используйте <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd> или <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>. Дерево парсинга XML содержимого версии (требуется модель содержимого <code>$1</code>).",
        "apihelp-query+revisions+base-param-limit": "Сколько версий вернуть.",
        "apihelp-query+revisions+base-param-expandtemplates": "Вместо этого используйте <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd>. Раскрыть шаблоны в содержимом версии (требуется $1prop=content).",
        "apihelp-query+revisions+base-param-generatexml": "Вместо этого используйте <kbd>[[Special:ApiHelp/expandtemplates|action=expandtemplates]]</kbd> или <kbd>[[Special:ApiHelp/parse|action=parse]]</kbd>. Сгенерировать дерево парсинга XML содержимого версии (требуется $1prop=content).",
        "apihelp-query+search-paramvalue-prop-sectiontitle": "Добавляет заголовок найденного раздела.",
        "apihelp-query+search-paramvalue-prop-categorysnippet": "Добавляет распарсенный фрагмент найденной категории.",
        "apihelp-query+search-paramvalue-prop-isfilematch": "Добавляет логическое значение, обозначающее, удовлетворяет ли поисковому запросу содержимое файла.",
+       "apihelp-query+search-paramvalue-prop-extensiondata": "Добавляет дополнительные данные, сгенерированные расширениями.",
        "apihelp-query+search-paramvalue-prop-score": "Игнорируется.",
        "apihelp-query+search-paramvalue-prop-hasrelated": "Игнорируется.",
        "apihelp-query+search-param-limit": "Сколько страниц вернуть.",
        "apihelp-query+siteinfo-example-simple": "Запросить информацию о сайте.",
        "apihelp-query+siteinfo-example-interwiki": "Запросить список локальных префиксов интервик.",
        "apihelp-query+siteinfo-example-replag": "Проверить текущее отставание репликации.",
-       "apihelp-query+stashimageinfo-summary": "Возвращает информацию о файлах в тайнике (upload stash).",
+       "apihelp-query+stashimageinfo-summary": "Возвращает информацию о файлах во временном хранилище.",
        "apihelp-query+stashimageinfo-param-filekey": "Ключ, идентифицирующий предыдущую временную загрузку.",
        "apihelp-query+stashimageinfo-param-sessionkey": "Синоним $1filekey для обратной совместимости.",
-       "apihelp-query+stashimageinfo-example-simple": "Вернуть информацию о файле в тайнике.",
+       "apihelp-query+stashimageinfo-example-simple": "Вернуть информацию о файле во временном хранилище.",
        "apihelp-query+stashimageinfo-example-params": "Вернуть эскизы двух файлов в тайнике.",
        "apihelp-query+tags-summary": "Список меток правок.",
        "apihelp-query+tags-param-limit": "Максимальное количество меток в списке.",
        "apihelp-tag-example-rev": "Добавить метку <kbd>vandalism</kbd> к версии с идентификатором 123 без указания причины.",
        "apihelp-tag-example-log": "Удаление метки <kbd>spam</kbd> из записи журнала с идентификатором 123 с причиной <kbd>Wrongly applied</kbd>.",
        "apihelp-tokens-summary": "Получение токенов для действий, связанных с редактированием данных.",
-       "apihelp-tokens-extended-description": "Этот модуль не поддерживается в пользу [[Special:ApiHelp/query+tokens|action=query&meta=tokens]].",
+       "apihelp-tokens-extended-description": "Этот модуль устарел в пользу [[Special:ApiHelp/query+tokens|action=query&meta=tokens]].",
        "apihelp-tokens-param-type": "Типы запрашиваемых токенов.",
        "apihelp-tokens-example-edit": "Получить токен редактирования (по умолчанию).",
        "apihelp-tokens-example-emailmove": "Получить токен электронной почты и переименования.",
        "apihelp-upload-param-url": "Ссылка на запрашиваемый файл.",
        "apihelp-upload-param-filekey": "Ключ, идентифицирующий предыдущую временную загрузку.",
        "apihelp-upload-param-sessionkey": "Синоним $1filekey, обслуживаемый для обратной совместимости.",
-       "apihelp-upload-param-stash": "Ð\95Ñ\81ли Ð·Ð°Ð´Ð°Ð½Ð¾, Ñ\81еÑ\80веÑ\80 Ð²Ñ\80еменно Ð¿Ð¾Ð¼ÐµÑ\81Ñ\82иÑ\82 Ñ\84айл Ð² Ñ\82айник Ð²Ð¼ÐµÑ\81Ñ\82о Ð·Ð°Ð³Ñ\80Ñ\83зки ÐµÐ³Ð¾ Ð² Ñ\85Ñ\80анилиÑ\89е.",
+       "apihelp-upload-param-stash": "Ð\95Ñ\81ли Ð·Ð°Ð´Ð°Ð½Ð¾, Ñ\81еÑ\80веÑ\80 Ð¿Ð¾Ð¼ÐµÑ\81Ñ\82иÑ\82 Ñ\84айл Ð²Ð¾ Ð²Ñ\80еменное Ñ\85Ñ\80анилиÑ\89е, Ð½Ðµ Ð´Ð¾Ð±Ð°Ð²Ð¸Ð² Ð² Ð¿Ð¾Ñ\81Ñ\82оÑ\8fнное.",
        "apihelp-upload-param-filesize": "Полны размер файла.",
        "apihelp-upload-param-offset": "Смещение блока в байтах.",
        "apihelp-upload-param-chunk": "Содержимое кусочка.",
        "api-help-lead": "Это автоматически сгенерированная страница документации MediaWiki API.\n\nДокументация и примеры: https://www.mediawiki.org/wiki/API",
        "api-help-main-header": "Главный модуль",
        "api-help-undocumented-module": "Нет документации для модуля $1.",
-       "api-help-flag-deprecated": "Этот модуль не поддерживается.",
+       "api-help-flag-deprecated": "Этот модуль устарел.",
        "api-help-flag-internal": "<strong>Этот модуль внутренний или нестабильный.</strong> Его операции могут измениться без предупреждения.",
        "api-help-flag-readrights": "Этот модуль требует прав на чтение.",
        "api-help-flag-writerights": "Этот модуль требует прав на запись.",
        "api-help-license-noname": "Лицензия: [[$1|см. ссылку]]",
        "api-help-license-unknown": "Лицензия: <span class=\"apihelp-unknown\">unknown</span>",
        "api-help-parameters": "Параметр{{PLURAL:$1||ы}}:",
-       "api-help-param-deprecated": "Ð\9dе Ð¿Ð¾Ð´Ð´ÐµÑ\80живаеÑ\82Ñ\81Ñ\8f.",
+       "api-help-param-deprecated": "УÑ\81Ñ\82аÑ\80ело.",
        "api-help-param-required": "Это обязательный параметр.",
        "api-help-datatypes-header": "Типы данных",
        "api-help-datatypes": "Ввод в MediaWiki должен быть NFC-нормализованным UTF-8. MediaWiki может попытаться преобразовать другой ввод, но это приведёт к провалу некоторых операций (таких, как [[Special:ApiHelp/edit|редактирование]] со сверкой MD5).\n\nНекоторые типы параметров в запросах API требуют дополнительных пояснений:\n;логический\n:Логические параметры работают как флажки (checkboxes) в HTML: если параметр задан, независимо от его значения, он воспринимается за истину. Для передачи ложного значения просто опустите параметр.\n;временные метки\n:Временные метки могут быть заданы в нескольких форматах. Рекомендуемым является дата и время ISO 8601. Всё время считается в UTC, любые включённые часовые пояса игнорируются.\n:* Дата и время ISO 8601: <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>Z</kbd> (знаки препинания и <kbd>Z</kbd> необязательны)\n:* Дата и время ISO 8601 с (игнорируемой) дробной частью секунд: <kbd><var>2001</var>-<var>01</var>-<var>15</var>T<var>14</var>:<var>56</var>:<var>00</var>.<var>00001</var>Z</kbd> (дефисы, двоеточия и <kbd>Z</kbd> необязательны)\n:* Формат MediaWiki: <kbd><var>2001</var><var>01</var><var>15</var><var>14</var><var>56</var><var>00</var></kbd>\n:* Общий числовой формат: <kbd><var>2001</var>-<var>01</var>-<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd> (необязательный часовой пояс <kbd>GMT</kbd>, <kbd>+<var>##</var></kbd> или <kbd>-<var>##</var></kbd> игнорируется)\n:* Формат EXIF: <kbd><var>2001</var>:<var>01</var>:<var>15</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Формат RFC 2822 (часовой пояс может быть опущен): <kbd><var>Mon</var>, <var>15</var> <var>Jan</var> <var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Формат RFC 850 (часовой пояс может быть опущен): <kbd><var>Monday</var>, <var>15</var>-<var>Jan</var>-<var>2001</var> <var>14</var>:<var>56</var>:<var>00</var></kbd>\n:* Формат ctime языка программирования C: <kbd><var>Mon</var> <var>Jan</var> <var>15</var> <var>14</var>:<var>56</var>:<var>00</var> <var>2001</var></kbd>\n:* Количество секунд, прошедших с 1970-01-01T00:00:00Z, в виде челого числа с от 1 до 13 знаками (исключая <kbd>0</kbd>)\n:* Строка <kbd>now</kbd>\n;альтернативный разделитель значений\n:Параметры, принимающие несколько значений, обычно отправляются со значениями, разделёнными с помощью символа пайпа, например, <kbd>param=value1|value2</kbd> или <kbd>param=value1%7Cvalue2</kbd>. Если значение должно содержать символ пайпа, используйте U+001F (Unit Separator) в качестве разделителя ''и'' добавьте в начало значения U+001F, например, <kbd>param=%1Fvalue1%1Fvalue2</kbd>.",
        "api-help-param-direction": "В каком порядке перечислять:\n;newer: Начать с самых старых. Обратите внимание: $1start должно быть раньше $1end.\n;older: Начать с самых новых (по умолчанию). Обратите внимание: $1start должно быть позже $1end.",
        "api-help-param-continue": "Когда доступно больше результатов, используйте это для продолжения.",
        "api-help-param-no-description": "<span class=\"apihelp-empty\">(описание отсутствует)</span>",
+       "api-help-param-maxbytes": "Не может быть длиннее $1 {{PLURAL:$1|байта|байтов}}.",
+       "api-help-param-maxchars": "Не может быть длиннее $1 {{PLURAL:$1|символа|символов}}.",
        "api-help-examples": "Пример{{PLURAL:$1||ы}}:",
        "api-help-permissions": "{{PLURAL:$1|Разрешение|Разрешения}}:",
        "api-help-permissions-granted-to": "{{PLURAL:$1|Гарантируется}}: $2",
        "apierror-blockedfrommail": "Отправка электронной почты была для вас заблокирована.",
        "apierror-blocked": "Редактирование было для вас заблокировано.",
        "apierror-botsnotsupported": "Этот интерфейс не поддерживается для ботов.",
-       "apierror-cannot-async-upload-file": "Параметры <var>async</var> и <var>file</var> не могут применяться вместе. Если вы хотите ассинхронно обработать загруженный файл, сначала загрузите его в тайник (используя параметр <var>stash</var>), а затем опубликуйте этот файл ассинхронно (используя параметры <var>filekey</var> и <var>async</var>).",
+       "apierror-cannot-async-upload-file": "Параметры <var>async</var> и <var>file</var> не могут применяться вместе. Если вы хотите ассинхронно обработать загруженный файл, сначала загрузите его во временное хранилище (используя параметр <var>stash</var>), а затем опубликуйте этот файл ассинхронно (используя параметры <var>filekey</var> и <var>async</var>).",
        "apierror-cannotreauthenticate": "Это действие недоступно, так как ваша личность не может быть подтверждена.",
        "apierror-cannotviewtitle": "У вас нет прав на просмотр $1.",
        "apierror-cantblock-email": "У вас нет прав блокировать участникам отправку электронной почты через интерфейс вики.",
        "apierror-invalidurlparam": "Некорректное значение <var>$1urlparam</var> (<kbd>$2=$3</kbd>).",
        "apierror-invaliduser": "Некорректное имя участника «$1».",
        "apierror-invaliduserid": "Некорректный идентификатор участника <var>$1</var>.",
+       "apierror-maxbytes": "Параметр <var>$1</var> не может быть длиннее $2 {{PLURAL:$2|байта|байтов}}",
+       "apierror-maxchars": "Параметр <var>$1</var> не может быть длиннее $2 {{PLURAL:$2|символа|символов}}",
        "apierror-maxlag-generic": "Ожидание сервера базы данных: $1 {{PLURAL:$1|секунда|секунды|секунд}} задержки.",
        "apierror-maxlag": "Ожидание $2: $1 {{PLURAL:$1|секунда|секунды|секунд}} задержки.",
        "apierror-mimesearchdisabled": "Поиск по MIME отключен в жадном режиме.",
        "apierror-mustbeloggedin-generic": "Вы должны быть авторизованы.",
        "apierror-mustbeloggedin-linkaccounts": "Вы должны быть авторизованы для привязывания аккаунтов.",
        "apierror-mustbeloggedin-removeauth": "Вы должны быть авторизованы для удаления аутентификационных данных.",
-       "apierror-mustbeloggedin-uploadstash": "Тайник Ð·Ð°Ð³Ñ\80Ñ\83зки (upload stash) Ð´Ð¾Ñ\81Ñ\82Ñ\83пен только для авторизованных участников.",
+       "apierror-mustbeloggedin-uploadstash": "Ð\92Ñ\80еменное Ñ\85Ñ\80анилиÑ\89е Ð´Ð¾Ñ\81Ñ\82Ñ\83пно только для авторизованных участников.",
        "apierror-mustbeloggedin": "Вы должны быть авторизованы в $1.",
        "apierror-mustbeposted": "Модуль <kbd>$1</kbd> требует запроса POST.",
        "apierror-mustpostparams": "{{PLURAL:$2|Следующий параметр был найден|Следующие параметры были найдены}} в строке запроса, но {{PLURAL:$2|должен|должны}} находиться в теле POST: $1.",
        "apierror-sizediffdisabled": "Подсчёт разницы размеров отключён в жадном режиме.",
        "apierror-spamdetected": "Ваша правка была отклонена, так как содержит спам: <code>$1</code>.",
        "apierror-specialpage-cantexecute": "У вас нет прав, чтобы просматривать результаты этой служебной страницы.",
-       "apierror-stashedfilenotfound": "Невозможно найти файл в тайнике: $1.",
+       "apierror-stashedfilenotfound": "Невозможно найти файл во временном хранилище: $1.",
        "apierror-stashedit-missingtext": "Не найдено содержимого тайника для данного хэша.",
        "apierror-stashfailed-complete": "Загрузка по кусочкам уже завершена, проверьте статус для получения подробной информации.",
        "apierror-stashfailed-nosession": "Не найдено сессии загрузки по кусочкам с заданным ключом.",
-       "apierror-stashfilestorage": "Невозможно сохранить загрузку в тайник: $1",
+       "apierror-stashfilestorage": "Невозможно сохранить файл во временном хранилище: $1",
        "apierror-stashinvalidfile": "Некорректный файл в тайнике.",
        "apierror-stashnosuchfilekey": "Нет такого ключа файла: $1.",
        "apierror-stashpathinvalid": "Ключ файла относится к некорректному формату или сам некорректен: $1.",
        "apierror-stashwrongowner": "Некорректный владелец: $1",
-       "apierror-stashzerolength": "Файл имеет нулевую длину и не может быть сохранён в тайник: $1",
+       "apierror-stashzerolength": "Файл имеет нулевую длину и не может быть сохранён во временное хранилище: $1",
        "apierror-systemblocked": "Вы были заблокированы автоматически MediaWiki.",
        "apierror-templateexpansion-notwikitext": "Раскрытие шаблонов разрешено только для вики-текстового содержимого. $1 использует модель содержимого $2.",
        "apierror-timeout": "Сервер не ответил за ожидаемое время.",
        "apierror-unsupportedrepo": "Локальное хранилище файлов не поддерживает запрос всех изображений.",
        "apierror-upload-filekeyneeded": "Необходимо задать <var>filekey</var>, если <var>offset</var> не ноль.",
        "apierror-upload-filekeynotallowed": "Невозможно обработать <var>filekey</var>, если <var>offset</var> равен 0.",
-       "apierror-upload-inprogress": "Процесс загрузки из тайника уже запущен.",
+       "apierror-upload-inprogress": "Процесс загрузки из временного хранилища уже запущен.",
        "apierror-upload-missingresult": "Нет результатов данных статуса.",
        "apierror-urlparamnormal": "Невозможно нормализовать параметры изображения для $1.",
        "apierror-writeapidenied": "У вас нет прав на редактирование этой вики через API.",
        "apiwarn-badutf8": "Значение, переданное <var>$1</var>, содержит некорректные или ненормализованные данные. Текстовые данные должны быть корректным NFC-нормализованным Юникодом без символов управления C0, кроме HT (\\t), LF (\\n) и CR (\\r).",
        "apiwarn-checktoken-percentencoding": "Проверьте, что символы вроде «+» в токене корректно закодированы %-последовательностями в ссылке.",
        "apiwarn-compare-nocontentmodel": "Модель содержимого не может быть определена, предполагается $1.",
-       "apiwarn-deprecation-deletedrevs": "<kbd>list=deletedrevs</kbd> не поддерживается. Пожалуйста, вместо него используйте <kbd>prop=deletedrevisions</kbd> или <kbd>list=alldeletedrevisions</kbd>.",
+       "apiwarn-deprecation-deletedrevs": "<kbd>list=deletedrevs</kbd> устарел. Пожалуйста, вместо него используйте <kbd>prop=deletedrevisions</kbd> или <kbd>list=alldeletedrevisions</kbd>.",
        "apiwarn-deprecation-expandtemplates-prop": "Поскольку никакие значения не были указаны в параметре <var>prop</var>, был использован наследованный формат. Этот формат является устаревшим, и в будущем параметру <var>prop</var> будет присвоено значение по умолчанию, что приведёт к повсеместному использованию нового формата.",
        "apiwarn-deprecation-httpsexpected": "Использован HTTP, где ожидался HTTPS.",
-       "apiwarn-deprecation-login-botpw": "Вход в основной аккаунт через <kbd>action=login</kbd> не поддерживается и может быть отключен без предупреждения. Для продолжения авторизации с <kbd>action=login</kbd>, см.\n[[Special:BotPasswords]]. Для безопасного продолжения использования входа в основной аккаунт, см. <kbd>action=clientlogin</kbd>.",
+       "apiwarn-deprecation-login-botpw": "Вход в основной аккаунт через <kbd>action=login</kbd> устарел и может быть отключен без предупреждения. Для продолжения авторизации с <kbd>action=login</kbd>, см.\n[[Special:BotPasswords]]. Для безопасного продолжения использования входа в основной аккаунт, см. <kbd>action=clientlogin</kbd>.",
        "apiwarn-deprecation-login-nobotpw": "Вход в основной аккаунт через <kbd>action=login</kbd> не поддерживается и может быть отключен без предупреждения. Для безопасной авторизации, см. <kbd>action=clientlogin</kbd>.",
-       "apiwarn-deprecation-login-token": "Запрос токена через <kbd>action=login</kbd> не поддерживается. Вместо этого, см. <kbd>action=query&meta=tokens&type=login</kbd>.",
+       "apiwarn-deprecation-login-token": "Запрос токена через <kbd>action=login</kbd> устарел. Используйте <kbd>action=query&meta=tokens&type=login</kbd>.",
        "apiwarn-deprecation-parameter": "Параметр <var>$1</var> не поддерживается.",
-       "apiwarn-deprecation-parse-headitems": "<kbd>prop=headitems</kbd> не поддерживается с MediaWiki 1.28. Используйте <kbd>prop=headhtml</kbd> при создании новых HTML документов, или <kbd>prop=modules|jsconfigvars</kbd> при обновлении документов на стороне клиента.",
-       "apiwarn-deprecation-purge-get": "Использование <kbd>action=purge</kbd> посредством GET не поддерживается. Используйте POST.",
+       "apiwarn-deprecation-parse-headitems": "<kbd>prop=headitems</kbd> устарело с MediaWiki 1.28. Используйте <kbd>prop=headhtml</kbd> при создании новых HTML документов или <kbd>prop=modules|jsconfigvars</kbd> при обновлении документов на стороне клиента.",
+       "apiwarn-deprecation-purge-get": "Использование <kbd>action=purge</kbd> посредством GET устарело. Используйте POST.",
        "apiwarn-deprecation-withreplacement": "<kbd>$1</kbd> не поддерживается. Пожалуйста, используйте <kbd>$2</kbd>.",
        "apiwarn-difftohidden": "Невозможно сравнить с r$1: содержимое скрыто.",
        "apiwarn-errorprinterfailed": "Сборщик ошибок упал. Будет совершена повторная попытка без параметров.",
        "apiwarn-tokens-origin": "Токены не могут быть получены, пока не применено правило ограничения домена.",
        "apiwarn-toomanyvalues": "Слишком много значений передано параметру <var>$1</var>. Максимальное число — $2.",
        "apiwarn-truncatedresult": "Результат был усечён, поскольку в противном случае он был бы больше лимита в $1 {{PLURAL:$1|байт|байта|байт}}.",
-       "apiwarn-unclearnowtimestamp": "Передача «$2» в качестве параметра временной метки <var>$1</var> не поддерживается. Если по какой-то причине вы хотите прямо указать текущее время без вычисления его на стороне клиента, используйте <kbd>now</kbd>.",
+       "apiwarn-unclearnowtimestamp": "Передача «$2» в качестве параметра временной метки <var>$1</var> устарело. Если по какой-то причине вы хотите прямо указать текущее время без вычисления его на стороне клиента, используйте <kbd>now</kbd>.",
        "apiwarn-unrecognizedvalues": "{{PLURAL:$3|Нераспознанное значение|Нераспознанные значения}} параметра <var>$1</var>: $2.",
        "apiwarn-unsupportedarray": "Параметр <var>$1</var> использует неподдерживаемый синтаксис массивов PHP.",
        "apiwarn-urlparamwidth": "Значение ширины ($2), переданное в <var>$1urlparam</var>, было проигнорировано в пользу значения ($3), полученного из параметров <var>$1urlwidth</var>/<var>$1urlheight</var>.",
index a59ba97..dd4c49e 100644 (file)
@@ -34,7 +34,6 @@ class DependencyWrapper {
        private $deps;
 
        /**
-        * Create an instance.
         * @param mixed $value The user-supplied value
         * @param CacheDependency|CacheDependency[] $deps A dependency or dependency
         *   array. All dependencies must be objects implementing CacheDependency.
index 8c70be2..e77e251 100644 (file)
@@ -273,7 +273,7 @@ class CacheHelper implements ICacheHelper {
                                $itemKey = array_keys( array_slice( $this->cachedChunks, 0, 1 ) );
                                $itemKey = array_shift( $itemKey );
 
-                               if ( !is_integer( $itemKey ) ) {
+                               if ( !is_int( $itemKey ) ) {
                                        wfWarn( "Attempted to get item with non-numeric key while " .
                                                "the next item in the queue has a key ($itemKey) in " . __METHOD__ );
                                } elseif ( is_null( $itemKey ) ) {
index 768f980..d6e9b74 100644 (file)
@@ -1048,8 +1048,7 @@ class MessageCache {
                if ( $titleObj->getLatestRevID() ) {
                        $revision = Revision::newKnownCurrent(
                                $dbr,
-                               $titleObj->getArticleID(),
-                               $titleObj->getLatestRevID()
+                               $titleObj
                        );
                } else {
                        $revision = false;
index a0ce95e..5e0a688 100644 (file)
@@ -109,7 +109,8 @@ class LocalisationCache {
        static public $allKeys = [
                'fallback', 'namespaceNames', 'bookstoreList',
                'magicWords', 'messages', 'rtl', 'capitalizeAllNouns', 'digitTransformTable',
-               'separatorTransformTable', 'fallback8bitEncoding', 'linkPrefixExtension',
+               'separatorTransformTable', 'minimumGroupingDigits',
+               'fallback8bitEncoding', 'linkPrefixExtension',
                'linkTrail', 'linkPrefixCharset', 'namespaceAliases',
                'dateFormats', 'datePreferences', 'datePreferenceMigrationMap',
                'defaultDateFormat', 'extraUserToggles', 'specialPageAliases',
index e6d918a..6977172 100644 (file)
@@ -72,9 +72,8 @@ class ChangeTagsLogList extends ChangeTagsList {
         * @return Status
         */
        public function updateChangeTagsOnAll( $tagsToAdd, $tagsToRemove, $params, $reason, $user ) {
-               // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $this->reset(); $this->current(); $this->next() ) {
-                       // @codingStandardsIgnoreEnd
                        $item = $this->current();
                        $status = ChangeTags::updateTagsWithChecks( $tagsToAdd, $tagsToRemove,
                                null, null, $item->getId(), $params, $reason, $user );
index 61259b4..19b7e20 100644 (file)
@@ -80,9 +80,8 @@ class ChangeTagsRevisionList extends ChangeTagsList {
         * @return Status
         */
        public function updateChangeTagsOnAll( $tagsToAdd, $tagsToRemove, $params, $reason, $user ) {
-               // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $this->reset(); $this->current(); $this->next() ) {
-                       // @codingStandardsIgnoreEnd
                        $item = $this->current();
                        $status = ChangeTags::updateTagsWithChecks( $tagsToAdd, $tagsToRemove,
                                null, $item->getId(), null, $params, $reason, $user );
index cd25352..e175765 100644 (file)
@@ -99,7 +99,7 @@ class ConfigFactory implements SalvageableService {
         * Will override if it's already registered.
         * Use "*" for $name to provide a fallback config for all unknown names.
         * @param string $name
-        * @param callable|Config $callback A factory callabck that takes this ConfigFactory
+        * @param callable|Config $callback A factory callback that takes this ConfigFactory
         *        as an argument and returns a Config instance, or an existing Config instance.
         * @throws InvalidArgumentException If an invalid callback is provided
         */
index 6a0a63b..3e58782 100644 (file)
@@ -483,11 +483,11 @@ interface Content {
         * @since 1.21
         *
         * @param WikiPage $page The deleted page
-        * @param ParserOutput $parserOutput Optional parser output object
+        * @param ParserOutput|null $parserOutput Optional parser output object
         *    for efficient access to meta-information about the content object.
         *    Provide if you have one handy.
         *
-        * @return DataUpdate[] A list of DataUpdate instances that will clean up the
+        * @return DeferrableUpdate[] A list of DeferrableUpdate instances that will clean up the
         *    database after deletion.
         */
        public function getDeletionUpdates( WikiPage $page,
index ced2a66..4a7944c 100644 (file)
  */
 class TextContentHandler extends ContentHandler {
 
-       // @codingStandardsIgnoreStart T59585
        public function __construct( $modelId = CONTENT_MODEL_TEXT, $formats = [ CONTENT_FORMAT_TEXT ] ) {
                parent::__construct( $modelId, $formats );
        }
-       // @codingStandardsIgnoreEnd
 
        /**
         * Returns the content's text as-is.
index 6358f11..189b346 100644 (file)
@@ -26,9 +26,9 @@ interface MutableContext {
        /**
         * Set the Config object
         *
-        * @param Config $c
+        * @param Config $config
         */
-       public function setConfig( Config $c );
+       public function setConfig( Config $config );
 
        /**
         * Set the WebRequest object
index c2d0de1..47d1684 100644 (file)
@@ -81,17 +81,13 @@ class RequestContext implements IContextSource, MutableContext {
        private static $instance = null;
 
        /**
-        * Set the Config object
-        *
-        * @param Config $c
+        * @param Config $config
         */
-       public function setConfig( Config $c ) {
-               $this->config = $c;
+       public function setConfig( Config $config ) {
+               $this->config = $config;
        }
 
        /**
-        * Get the Config object
-        *
         * @return Config
         */
        public function getConfig() {
@@ -441,8 +437,6 @@ class RequestContext implements IContextSource, MutableContext {
                return $this->skin;
        }
 
-       /** Helpful methods **/
-
        /**
         * Get a Message object with context set
         * Parameters are the same as wfMessage()
@@ -458,8 +452,6 @@ class RequestContext implements IContextSource, MutableContext {
                return call_user_func_array( 'wfMessage', $args )->setContext( $this );
        }
 
-       /** Static methods **/
-
        /**
         * Get the RequestContext object associated with the main request
         *
index 9b59191..f3d61f0 100644 (file)
@@ -279,7 +279,7 @@ class MWExceptionHandler {
                // HHVM: Class undefined: foo
                // PHP5: Class 'foo' not found
                if ( preg_match( "/Class (undefined: \w+|'\w+' not found)/", $msg ) ) {
-                       // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
+                       // phpcs:disable Generic.Files.LineLength
                        $msg = <<<TXT
 {$msg}
 
@@ -287,7 +287,7 @@ MediaWiki or an installed extension requires this class but it is not embedded d
 
 Please see <a href="https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries">mediawiki.org</a> for help on installing the required components.
 TXT;
-                       // @codingStandardsIgnoreEnd
+                       // phpcs:enable
                }
 
                // We can't just create an exception and log it as it is likely that
index 0b61979..8182d62 100644 (file)
@@ -20,7 +20,8 @@
  * @file
  * @ingroup FileBackend
  */
-use \MediaWiki\Logger\LoggerFactory;
+
+use MediaWiki\Logger\LoggerFactory;
 use MediaWiki\MediaWikiServices;
 
 /**
index d959dd2..296c4b3 100644 (file)
@@ -213,11 +213,11 @@ class HTMLForm extends ContextSource {
        protected $mAction = false;
 
        /**
-        * Form attribute autocomplete. false does not set the attribute
+        * Form attribute autocomplete. A typical value is "off". null does not set the attribute
         * @since 1.27
-        * @var bool|string
+        * @var string|null
         */
-       protected $mAutocomplete = false;
+       protected $mAutocomplete = null;
 
        protected $mUseMultipart = false;
        protected $mHiddenFields = [];
@@ -1062,7 +1062,7 @@ class HTMLForm extends ContextSource {
                if ( $this->mId ) {
                        $attribs['id'] = $this->mId;
                }
-               if ( $this->mAutocomplete ) {
+               if ( is_string( $this->mAutocomplete ) ) {
                        $attribs['autocomplete'] = $this->mAutocomplete;
                }
                if ( $this->mName ) {
@@ -1868,12 +1868,12 @@ class HTMLForm extends ContextSource {
        }
 
        /**
-        * Set the value for the autocomplete attribute of the form.
-        * When set to false (which is the default state), the attribute get not set.
+        * Set the value for the autocomplete attribute of the form. A typical value is "off".
+        * When set to null (which is the default state), the attribute get not set.
         *
         * @since 1.27
         *
-        * @param string|bool $autocomplete
+        * @param string|null $autocomplete
         *
         * @return HTMLForm $this for chaining calls
         */
index 10db90c..66d6143 100644 (file)
@@ -38,8 +38,8 @@ class HTMLFormFieldLayout extends OOUI\FieldLayout {
        use HTMLFormElement;
 
        public function __construct( $fieldWidget, array $config = [] ) {
-               // Parent constructor
                parent::__construct( $fieldWidget, $config );
+
                // Traits
                $this->initializeHTMLFormElement( $config );
        }
@@ -53,8 +53,8 @@ class HTMLFormActionFieldLayout extends OOUI\ActionFieldLayout {
        use HTMLFormElement;
 
        public function __construct( $fieldWidget, $buttonWidget = false, array $config = [] ) {
-               // Parent constructor
                parent::__construct( $fieldWidget, $buttonWidget, $config );
+
                // Traits
                $this->initializeHTMLFormElement( $config );
        }
index 1b5d1fb..4019f81 100644 (file)
@@ -8,8 +8,7 @@ class HTMLEditTools extends HTMLFormField {
        public function getTableRow( $value ) {
                $msg = $this->formatMsg();
 
-               return
-                       '<tr><td></td><td class="mw-input">' .
+               return '<tr><td></td><td class="mw-input">' .
                        '<div class="mw-editTools">' .
                        $msg->parseAsBlock() .
                        "</div></td></tr>\n";
index 28f3f82..ed5ec1a 100644 (file)
@@ -125,7 +125,9 @@ class WikiImporter {
                if ( is_callable( $this->mNoticeCallback ) ) {
                        call_user_func( $this->mNoticeCallback, $msg, $params );
                } else { # No ImportReporter -> CLI
-                       echo wfMessage( $msg, $params )->text() . "\n";
+                       // T177997: the command line importers should call setNoticeCallback()
+                       // for their own custom callback to echo the notice
+                       wfDebug( wfMessage( $msg, $params )->text() . "\n" );
                }
        }
 
index 54ff712..242f148 100644 (file)
@@ -179,12 +179,12 @@ abstract class DatabaseUpdater {
        /**
         * @param Database $db
         * @param bool $shared
-        * @param Maintenance $maintenance
+        * @param Maintenance|null $maintenance
         *
         * @throws MWException
         * @return DatabaseUpdater
         */
-       public static function newForDB( Database $db, $shared = false, $maintenance = null ) {
+       public static function newForDB( Database $db, $shared = false, Maintenance $maintenance = null ) {
                $type = $db->getType();
                if ( in_array( $type, Installer::getDBTypes() ) ) {
                        $class = ucfirst( $type ) . 'Updater';
@@ -616,7 +616,7 @@ abstract class DatabaseUpdater {
         * 1.13...) with the values being arrays of updates, identical to how
         * updaters.inc did it (for now)
         *
-        * @return array
+        * @return array[]
         */
        abstract protected function getCoreUpdateList();
 
index 2bb15b8..5ea9bfe 100644 (file)
@@ -595,11 +595,10 @@ abstract class Installer {
                global $wgAutoloadClasses;
                $wgAutoloadClasses = [];
 
-               // @codingStandardsIgnoreStart
                // LocalSettings.php should not call functions, except wfLoadSkin/wfLoadExtensions
                // Define the required globals here, to ensure, the functions can do it work correctly.
+               // phpcs:ignore MediaWiki.VariableAnalysis.UnusedGlobalVariables
                global $wgExtensionDirectory, $wgStyleDirectory;
-               // @codingStandardsIgnoreEnd
 
                MediaWiki\suppressWarnings();
                $_lsExists = file_exists( "$IP/LocalSettings.php" );
index 05f078f..e5418e4 100644 (file)
@@ -335,11 +335,11 @@ class OracleInstaller extends DatabaseInstaller {
         * @return bool Whether the connection string is valid.
         */
        public static function checkConnectStringFormat( $connect_string ) {
-               // @@codingStandardsIgnoreStart Long lines with regular expressions.
+               // phpcs:disable Generic.Files.LineLength
                // @todo Very long regular expression. Make more readable?
                $isValid = preg_match( '/^[[:alpha:]][\w\-]*(?:\.[[:alpha:]][\w\-]*){0,2}$/', $connect_string ); // TNS name
                $isValid |= preg_match( '/^(?:\/\/)?[\w\-\.]+(?::[\d]+)?(?:\/(?:[\w\-\.]+(?::(pooled|dedicated|shared))?)?(?:\/[\w\-\.]+)?)?$/', $connect_string ); // EZConnect
-               // @@codingStandardsIgnoreEnd
+               // phpcs:enable
                return (bool)$isValid;
        }
 }
index c86b824..54a7de8 100644 (file)
        "config-help-tooltip": "feu clic per ampliar",
        "config-nofile": "No s'ha pogut trobar el fitxer «$1». S'ha suprimit?",
        "config-extension-link": "Sabíeu que el vostre wiki permet l'ús d'[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions extensions]?\n\nPodeu navegar les [https://www.mediawiki.org/wiki/Special:MyLanguage/Category:Extensions_by_category extensions per categoria] o la [https://www.mediawiki.org/wiki/Extension_Matrix matriu d'extensions] per a veure'n una llista sencera.",
+       "config-skins-screenshots": "$1 (captures de pantalla: $2)",
+       "config-screenshot": "captura de pantalla",
        "mainpagetext": "<strong>MediaWiki s'ha instal·lat.</strong>",
        "mainpagedocfooter": "Consulteu la [https://meta.wikimedia.org/wiki/Help:Contents Guia d'Usuari] per a més informació sobre com utilitzar aquest programari wiki.\n\n== Primers passos ==\n\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Llista de paràmetres configurables]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ PMF del MediaWiki]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Llista de correu per a anuncis del MediaWiki]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Traducció de MediaWiki en la vostra llengua]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Aprengueu com combatre la brossa que pot atacar el vostre wiki]"
 }
index 6185ef4..66c86b8 100644 (file)
        "config-install-mainpage-failed": "Het was niet mogelijk de hoofdpagina in te voegen: $1",
        "config-install-done": "<strong>Gefeliciteerd!</strong>\nU hebt MediaWiki geïnstalleerd.\n\nHet installatieprogramma heeft het bestand <code>LocalSettings.php</code> aangemaakt.\nDit bevat al uw instellingen.\n\nU moet het bestand downloaden en in de hoofdmap van uw wiki-installatie plaatsen, in dezelfde map als index.php.\nDe download zou automatisch moeten zijn gestart.\n\nAls de download niet is gestart of als u de download hebt geannuleerd, dan kunt u de download opnieuw starten door op de onderstaande koppeling te klikken:\n\n$3\n\n<strong>Let op:</strong> als u dit niet nu doet, dan is het bestand als u later de installatieprocedure afsluit zonder het bestand te downloaden niet meer beschikbaar.\n\nNa het plaatsen van het bestand met instellingen kunt u <strong>[$2 uw wiki gebruiken]</strong>.",
        "config-install-done-path": "<strong>Gefeliciteerd!</strong>\nU hebt MediaWiki geïnstalleerd.\n\nHet installatieprogramma heeft het bestand <code>LocalSettings.php</code> aangemaakt.\nDit bevat al uw instellingen.\n\nU moet het bestand downloaden en in <code>$4</code> plaatsen. De download zou automatisch moeten zijn gestart.\n\nAls de download niet is gestart of als u de download hebt geannuleerd, dan kunt u de download opnieuw starten door op de onderstaande koppeling te klikken:\n\n$3\n\n<strong>Let op:</strong> Als u dit niet nu doet, dan is het bestand als u later de installatieprocedure afsluit zonder het bestand te downloaden niet meer beschikbaar.\n\nNa het plaatsen van het bestand met instellingen kunt u <strong>[$2 uw wiki gebruiken]</strong>.",
+       "config-install-success": "MediaWiki is geïnstalleerd. U kunt nu\n<$1$2> bezoeken om uw wiki te bekijken.\nAls u vragen heeft, bezoek dan onze lijst met veelgestelde vragen:\n<https://www.mediawiki.org/wiki/Manual:FAQ>, of gebruik een van de hulpforums vermeldt op die pagina.",
        "config-download-localsettings": "<code>LocalSettings.php</code> downloaden",
        "config-help": "hulp",
        "config-help-tooltip": "klik om uit te vouwen",
index a19dbc3..7d2ab8f 100644 (file)
        "config-install-mainpage-failed": "Nie udało się wstawić strony głównej: $1",
        "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-install-done-path": "<strong>Gratulacje!</strong>\nZainstalowałeś właśnie MediaWiki.\n\nInstalator wygenerował plik <code>LocalSettings.php</code>.\nZawiera całą Twoją konfigurację.\n\nMusisz go pobrać i umieścić w <code>$4</code>. Pobieranie powinno rozpocząć się automatycznie.\n\nJeżeli nie pojawiła się informacja o pobieraniu lub jeżeli ja anulowałeś, kliknij poniższy link:\n\n$3\n\n<strong>Uwaga:</strong> Jeżeli nie zrobisz tego teraz, wygenerowany plik konfiguracyjny nie będzie potem dostępny, jeżeli wyjdziesz z instalacji bez jego pobrania.\n\nGdy to będzie zrobione, możesz <strong>[$2 wejść na swoją wiki]</strong>.",
+       "config-install-success": "MediaWiki została pomyślnie zainstalowana. Możesz teraz\nodwiedzić <$1$2>, aby zobaczyć swoją wiki.\nJeśli masz pytania, sprawdź naszą listę najczęściej zadawanych pytań:\n<https://www.mediawiki.org/wiki/Manual:FAQ> lub użyj jednej z\nform wsparcia odsyłanej z tej strony.",
        "config-download-localsettings": "Pobierz <code>LocalSettings.php</code>",
        "config-help": "pomoc",
        "config-help-tooltip": "kliknij, aby rozwinąć",
        "config-nofile": "Nie udało się odnaleźć pliku \"$1\". Czy nie został usunięty?",
        "config-extension-link": "Czy wiesz, że twoja wiki obsługuje [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Extensions rozszerzenia]?\n\nMożesz przejrzeć [https://www.mediawiki.org/wiki/Category:Extensions_by_category rozszerzenia według kategorii] lub [https://www.mediawiki.org/wiki/Extension_Matrix Extension Matrix], aby zobaczyć pełną listę rozszerzeń.",
+       "config-skins-screenshots": "$1 (zrzut ekranu: $2)",
        "config-screenshot": "zrzut ekranu",
        "mainpagetext": "<strong>Instalacja MediaWiki powiodła się.</strong>",
        "mainpagedocfooter": "Zapoznaj się z [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Contents Podręcznikiem użytkownika] zawierającym informacje o tym jak korzystać z oprogramowania wiki.\n\n== Na początek ==\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Configuration_settings Lista ustawień konfiguracyjnych]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:FAQ MediaWiki FAQ]\n* [https://lists.wikimedia.org/mailman/listinfo/mediawiki-announce Komunikaty o nowych wersjach MediaWiki (lista dyskusyjna)]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Localisation#Translation_resources Przetłumacz MediaWiki na swój język]\n* [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Combating_spam Dowiedz się, jak walczyć ze spamem na swojej wiki]"
index ea365a5..d455fe1 100644 (file)
@@ -72,7 +72,7 @@
        "config-no-db": "Não foi possível encontrar um controlador apropriado da base de dados! Precisa de instalar um controlador da base de dados para o PHP. {{PLURAL:$2|É aceite o seguinte tipo|São aceites os seguintes tipos}} de base de dados: $1.\n\nSe fez a compilação do PHP, reconfigure-o com um cliente de base 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 precisa de instalar também, por exemplo, o pacote <code>php5-mysql</code>.",
        "config-outdated-sqlite": "<strong>Aviso:</strong> Tem a versão $1 do SQLite, que é anterior à versão mínima necessária, a $2. O SQLite não estará disponível.",
        "config-no-fts3": "<strong>Aviso:</strong> O SQLite foi compilado sem o módulo [//sqlite.org/fts3.html FTS3]; as funcionalidades de pesquisa não estarão disponíveis nesta instalação.",
-       "config-pcre-old": "<strong>Erro fatal:</strong> É necessário o PCRE $1 ou versão posterior.\nO <i>link</i> do seu binário PHP foi feito com o PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Mais informações].",
+       "config-pcre-old": "<strong>Erro fatal:</strong> É necessário o PCRE $1 ou versão posterior.\nO seu binário PHP foi linkado com o PCRE $2.\n[https://www.mediawiki.org/wiki/Manual:Errors_and_symptoms/PCRE Mais informações].",
        "config-pcre-no-utf8": "'''Erro fatal''': O módulo PCRE do PHP parece ter sido compilado sem suporte PCRE_UTF8.\nO MediaWiki necessita do suporte UTF-8 para funcionar corretamente.",
        "config-memory-raised": "A configuração <code>memory_limit</code> do PHP era $1; foi aumentada para $2.",
        "config-memory-bad": "<strong>Aviso:</strong> A configuração <code>memory_limit</code> do PHP é $1.\nIsto é provavelmente demasiado baixo.\nA instalação poderá falhar!",
        "config-type-sqlite": "SQLite",
        "config-type-oracle": "Oracle",
        "config-type-mssql": "Microsoft SQL Server",
-       "config-support-info": "O MediaWiki suporta as seguintes plataformas de base de dados:\n\n$1\n\nSe a plataforma que pretende usar não está listada abaixo, siga as instruções nos links acima para ativar o suporte.",
+       "config-support-info": "O MediaWiki suporta as seguintes plataformas de base de dados:\n\n$1\n\nSe a plataforma que pretende usar não está listada abaixo, siga as instruções nas hiperligações acima para ativar o suporte.",
        "config-dbsupport-mysql": "* [{{int:version-db-mysql-url}} MySQL] é a plataforma primária do MediaWiki e é a melhor suportada. O MediaWiki também trabalha com [{{int:version-db-mariadb-url}} MariaDB] e [{{int:version-db-percona-url}} Percona Server], que são compatíveis com MySQL. ([http://www.php.net/manual/en/mysql.installation.php Como compilar PHP com suporte a MySQL])",
        "config-dbsupport-postgres": "* O [{{int:version-db-postgres-url}} PostgreSQL] é uma plataforma popular de base de dados de código aberto, alternativa ao MySQL. ([http://www.php.net/manual/en/pgsql.installation.php Como compilar o PHP com suporte PostgreSQL])",
        "config-dbsupport-sqlite": "* O [{{int:version-db-sqlite-url}} SQLite] é uma plataforma de base de dados ligeira muito bem suportada. ([http://www.php.net/manual/en/pdo.installation.php Como compilar o PHP com suporte SQLite], usa PDO)",
        "config-email-watchlist": "Ativar notificação de alterações às páginas vigiadas",
        "config-email-watchlist-help": "Permitir que os utilizadores recebam notificações de alterações às suas páginas vigiadas, se tiverem ativado esta funcionalidade nas suas preferências.",
        "config-email-auth": "Ativar autenticação do correio eletrónico",
-       "config-email-auth-help": "Se esta opção for ativada, os utilizadores têm de confirmar o seu endereço de correio eletrónico usando um link que lhes é enviado sempre que o definirem ou alterarem.\nSó os endereços de correio eletrónico autenticados podem receber mensagens eletrónicas dos outros utilizadores ou alterar as mensagens de notificação.\nÉ '''recomendado''' que esta opção seja ativada nas wikis de acesso público para impedir o uso abusivo das funcionalidades de correio eletrónico.",
+       "config-email-auth-help": "Se esta opção for ativada, os utilizadores têm de confirmar o seu endereço de correio eletrónico usando uma hiperligação que lhes é enviada sempre que o definirem ou alterarem.\nSó os endereços de correio eletrónico autenticados podem receber mensagens eletrónicas dos outros utilizadores ou alterar as mensagens de notificação.\nÉ '''recomendado''' que esta opção seja ativada nas wikis de acesso público para impedir o uso abusivo das funcionalidades de correio eletrónico.",
        "config-email-sender": "Endereço de correio eletrónico de retorno:",
        "config-email-sender-help": "Introduza o endereço de correio eletrónico que será usado como endereço de retorno nas mensagens eletrónicas de saída.\nÉ para este endereço que serão enviadas as mensagens que não podem ser entregues.\nMuitos servidores de correio eletrónico exigem que pelo menos a parte do nome do domínio seja válida. \\",
        "config-upload-settings": "Carregamento de imagens e ficheiros",
        "config-install-tables": "A criar as tabelas",
        "config-install-tables-exist": "<strong>Aviso:</strong> As tabelas do MediaWiki parecem já existir.\nA criação das tabelas será saltada.",
        "config-install-tables-failed": "<strong>Erro:</strong> A criação das tabelas falhou com o seguinte erro: $1",
-       "config-install-interwiki": "A preencher a tabela padrão de links interwikis",
+       "config-install-interwiki": "A preencher a tabela padrão de hiperligações interwikis",
        "config-install-interwiki-list": "Não foi possível ler o ficheiro <code>interwiki.list</code>.",
        "config-install-interwiki-exists": "<strong>Aviso:</strong> A tabela de interwikis parece já conter entradas.\nO preenchimento padrão desta tabela será saltado.",
        "config-install-stats": "A inicializar as estatísticas",
        "config-install-mainpage-exists": "A página principal já existe; a saltar este passo",
        "config-install-extension-tables": "A criar as tabelas das extensões ativadas",
        "config-install-mainpage-failed": "Não foi possível inserir a página principal: $1",
-       "config-install-done": "<strong>Parabéns!</strong>\nTerminou a instalação do MediaWiki.\n\nO instalador gerou um ficheiro <code>LocalSettings.php</code>.\nEste ficheiro contém todas as configurações.\n\nPrecisa de descarregar o ficheiro e colocá-lo no diretório de raiz da sua instalação (o mesmo diretório onde está o ficheiro index.php). Este descarregamento deverá ter sido iniciado automaticamente.\n\nSe o descarregamento não foi iniciado, ou se o cancelou, pode recomeçá-lo clicando na ligação abaixo:\n\n$3\n\n<strong>Nota</strong>: Se não o descarregar agora, o ficheiro que foi gerado deixará de estar disponível quando sair do processo de instalação.\n\nDepois de terminar o passo anterior, pode <strong>[$2 entrar na wiki]</strong>.",
+       "config-install-done": "<strong>Parabéns!</strong>\nTerminou a instalação do MediaWiki.\n\nO instalador gerou um ficheiro <code>LocalSettings.php</code>.\nEste ficheiro contém todas as configurações.\n\nPrecisa de descarregar o ficheiro e colocá-lo no diretório de raiz da sua instalação (o mesmo diretório onde está o ficheiro index.php). Este descarregamento deverá ter sido iniciado automaticamente.\n\nSe o descarregamento não foi iniciado, ou se o cancelou, pode recomeçá-lo clicando na hiperligação abaixo:\n\n$3\n\n<strong>Nota</strong>: Se não o descarregar agora, o ficheiro que foi gerado deixará de estar disponível quando sair do processo de instalação.\n\nDepois de terminar o passo anterior, pode <strong>[$2 entrar na wiki]</strong>.",
        "config-install-done-path": "<strong>Parabéns!</strong>\nTerminou a instalação do MediaWiki.\n\nO instalador gerou um ficheiro <code>LocalSettings.php</code>.\nEste ficheiro contém todas as configurações.\n\nPrecisa de descarregar o ficheiro e colocá-lo no diretório <code>$4</code>. Este descarregamento deverá ter sido iniciado automaticamente.\n\nSe o descarregamento não foi iniciado, ou se o cancelou, pode recomeçá-lo clicando na ligação abaixo:\n\n$3\n\n<strong>Nota</strong>: Se não fizer o descarregamento agora, o ficheiro que foi gerado deixará de estar disponível quando sair do processo de instalação.\n\nDepois de terminar o passo anterior, pode <strong>[$2 entrar na wiki]</strong>.",
        "config-install-success": "O MediaWiki foi instalado com sucesso. Já pode consultar <$1$2> para visualizar a sua wiki.\nSe tiver dúvidas, veja a nossa lista de perguntas frequentes:\n<https://www.mediawiki.org/wiki/Manual:FAQ/pt> ou utilize um dos fóruns de suporte vinculados nessa página.",
        "config-download-localsettings": "Descarregar <code>LocalSettings.php</code>",
index d9c0424..d5103da 100644 (file)
@@ -1,6 +1,4 @@
 <?php
-namespace MediaWiki\Interwiki;
-
 /**
  * InterwikiLookup implementing the "classic" interwiki storage (hardcoded up to MW 1.26).
  *
@@ -21,14 +19,17 @@ namespace MediaWiki\Interwiki;
  *
  * @file
  */
-use \Cdb\Exception as CdbException;
-use \Cdb\Reader as CdbReader;
-use Wikimedia\Rdbms\Database;
+
+namespace MediaWiki\Interwiki;
+
+use Cdb\Exception as CdbException;
+use Cdb\Reader as CdbReader;
 use Hooks;
 use Interwiki;
 use Language;
 use MapCacheLRU;
 use WANObjectCache;
+use Wikimedia\Rdbms\Database;
 
 /**
  * InterwikiLookup implementing the "classic" interwiki storage (hardcoded up to MW 1.26).
index e743311..118b0f9 100644 (file)
@@ -184,9 +184,8 @@ class JobQueueFederated extends JobQueue {
                // Try to insert the jobs and update $partitionsTry on any failures.
                // Retry to insert any remaning jobs again, ignoring the bad partitions.
                $jobsLeft = $jobs;
-               // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $i = $this->maxPartitionsTry; $i > 0 && count( $jobsLeft ); --$i ) {
-                       // @codingStandardsIgnoreEnd
                        try {
                                $partitionRing->getLiveRing();
                        } catch ( UnexpectedValueException $e ) {
index 5c0f89f..d0969e4 100644 (file)
@@ -20,7 +20,8 @@
  * @file
  * @ingroup JobQueue
  */
-use \MediaWiki\MediaWikiServices;
+
+use MediaWiki\MediaWikiServices;
 
 /**
  * Job to prune link tables for pages that were deleted
index ee88d0d..a9cbba2 100644 (file)
@@ -29,8 +29,6 @@
  */
 class CSSMin {
 
-       /* Constants */
-
        /** @var string Strip marker for comments. **/
        const PLACEHOLDER = "\x7fPLACEHOLDER\x7f";
 
@@ -42,8 +40,6 @@ class CSSMin {
        const EMBED_REGEX = '\/\*\s*\@embed\s*\*\/';
        const COMMENT_REGEX = '\/\*.*?\*\/';
 
-       /* Protected Static Members */
-
        /** @var array List of common image files extensions and MIME-types */
        protected static $mimeTypes = [
                'gif' => 'image/gif',
@@ -57,8 +53,6 @@ class CSSMin {
                'svg' => 'image/svg+xml',
        ];
 
-       /* Static Methods */
-
        /**
         * Get a list of local files referenced in a stylesheet (includes non-existent files).
         *
index 141a515..e0bbb59 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-// @codingStandardsIgnoreFile File external to MediaWiki. Ignore coding conventions checks.
+// phpcs:ignoreFile -- File external to MediaWiki. Ignore coding conventions checks.
 /**
  * JavaScript Minifier
  *
@@ -18,7 +18,6 @@
  */
 class JavaScriptMinifier {
 
-       /* Class constants */
        /* Parsing states.
         * The state machine is only necessary to decide whether to parse a slash as division
         * operator or as regexp literal.
@@ -64,8 +63,6 @@ class JavaScriptMinifier {
        // Sanity limit to avoid excessive memory usage
        const STACK_LIMIT = 1000;
 
-       /* Static functions */
-
        /**
         * Returns minified JavaScript code.
         *
@@ -74,11 +71,10 @@ class JavaScriptMinifier {
         *       or when required to guard against semicolon insertion.
         *
         * @param string $s JavaScript code to minify
-        * @param bool $statementsOnOwnLine Whether to put each statement on its own line
         * @param int $maxLineLength Maximum length of a single line, or -1 for no maximum.
         * @return String Minified code
         */
-       public static function minify( $s, $statementsOnOwnLine = false, $maxLineLength = 1000 ) {
+       public static function minify( $s, $maxLineLength = 1000 ) {
                // First we declare a few tables that contain our parsing rules
 
                // $opChars : characters, which can be combined without whitespace in between them
@@ -387,23 +383,6 @@ class JavaScriptMinifier {
                        )
                );
 
-               // Rules for when newlines should be inserted if
-               // $statementsOnOwnLine is enabled.
-               // $newlineBefore is checked before switching state,
-               // $newlineAfter is checked after
-               $newlineBefore = array(
-                       self::STATEMENT => array(
-                               self::TYPE_BRACE_CLOSE => true,
-                       ),
-               );
-               $newlineAfter = array(
-                       self::STATEMENT => array(
-                               self::TYPE_BRACE_OPEN => true,
-                               self::TYPE_PAREN_CLOSE => true,
-                               self::TYPE_SEMICOLON => true,
-                       ),
-               );
-
                // $divStates : Contains all states that can be followed by a division operator
                $divStates = array(
                        self::EXPRESSION_OP          => true,
@@ -467,18 +446,24 @@ class JavaScriptMinifier {
                        // We have to distinguish between regexp literals and division operators
                        // A division operator is only possible in certain states
                        } elseif( $ch === '/' && !isset( $divStates[$state] ) ) {
-                               // Regexp literal, search to the end, skipping over backslash escapes and
-                               // character classes
+                               // Regexp literal
                                for( ; ; ) {
                                        do{
+                                               // Skip until we find "/" (end of regexp), "\" (backslash escapes),
+                                               // or "[" (start of character classes).
                                                $end += strcspn( $s, '/[\\', $end ) + 2;
+                                               // If backslash escape, keep searching...
                                        } while( $end - 2 < $length && $s[$end - 2] === '\\' );
                                        $end--;
+                                       // If the end, stop here.
                                        if( $end - 1 >= $length || $s[$end - 1] === '/' ) {
                                                break;
                                        }
+                                       // (Implicit else), we must've found the start of a char class,
+                                       // skip until we find "]" (end of char class), or "\" (backslash escape)
                                        do{
                                                $end += strcspn( $s, ']\\', $end ) + 2;
+                                               // If backslash escape, keep searching...
                                        } while( $end - 2 < $length && $s[$end - 2] === '\\' );
                                        $end--;
                                };
@@ -580,15 +565,6 @@ class JavaScriptMinifier {
                        $pos = $end;
                        $newlineFound = false;
 
-                       // Output a newline after the token if required
-                       // This is checked before AND after switching state
-                       $newlineAdded = false;
-                       if ( $statementsOnOwnLine && !$newlineAdded && isset( $newlineBefore[$state][$type] ) ) {
-                               $out .= "\n";
-                               $lineLength = 0;
-                               $newlineAdded = true;
-                       }
-
                        // Now that we have output our token, transition into the new state.
                        if( isset( $push[$state][$type] ) && count( $stack ) < self::STACK_LIMIT ) {
                                $stack[] = $push[$state][$type];
@@ -598,12 +574,6 @@ class JavaScriptMinifier {
                        } elseif( isset( $goto[$state][$type] ) ) {
                                $state = $goto[$state][$type];
                        }
-
-                       // Check for newline insertion again
-                       if ( $statementsOnOwnLine && !$newlineAdded && isset( $newlineAfter[$state][$type] ) ) {
-                               $out .= "\n";
-                               $lineLength = 0;
-                       }
                }
                return $out;
        }
index 7feac7d..e3c2d75 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-// @codingStandardsIgnoreFile File external to MediaWiki. Ignore coding conventions checks.
+// phpcs:ignoreFile -- File external to MediaWiki. Ignore coding conventions checks.
 /**
  * JSMinPlus version 1.4
  *
index 2ad8ac8..6261335 100644 (file)
@@ -70,7 +70,7 @@ class ScopedLock {
        public static function factory(
                LockManager $manager, array $paths, $type, StatusValue $status, $timeout = 0
        ) {
-               $pathsByType = is_integer( $type ) ? [ $type => $paths ] : $paths;
+               $pathsByType = is_int( $type ) ? [ $type => $paths ] : $paths;
                $lockStatus = $manager->lockByType( $pathsByType, $timeout );
                $status->merge( $lockStatus );
                if ( $lockStatus->isOK() ) {
index 5cb49a9..20e30c5 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-// @codingStandardsIgnoreFile It's an external lib and it isn't. Let's not bother.
+// phpcs:ignoreFile -- It's an external lib and it isn't. Let's not bother.
 /**
  * Memcached client for PHP.
  *
index 36b45a1..562819e 100644 (file)
@@ -1374,8 +1374,8 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         * This works the same as getWithSetCallback() except:
         *   - a) The $keys argument expects the result of WANObjectCache::makeMultiKeys()
         *   - b) The $callback argument expects a callback returning a map of (ID => new value)
-        *        for all entity IDs in $regenById and it takes the following arguments:
-        *          - $ids: a list of entity IDs to regenerate
+        *        for all entity IDs in $ids and it takes the following arguments:
+        *          - $ids: a list of entity IDs that require cache regeneration
         *          - &$ttls: a reference to the (entity ID => new TTL) map
         *          - &$setOpts: a reference to options for set() which can be altered
         *   - c) The return value is a map of (cache key => value) in the order of $keyedIds
index a9eaa99..591e287 100644 (file)
@@ -939,7 +939,7 @@ class LoadBalancer implements ILoadBalancer {
         * @return bool
         */
        private function isOpen( $index ) {
-               if ( !is_integer( $index ) ) {
+               if ( !is_int( $index ) ) {
                        return false;
                }
 
index d75d9c0..06915b2 100644 (file)
@@ -99,27 +99,22 @@ class BufferingStatsdDataFactory extends StatsdDataFactory implements IBuffering
                return $this->buffer;
        }
 
-       /**
-        * Check whether this data factory has any data.
-        * @return bool
-        */
        public function hasData() {
                return !empty( $this->buffer );
        }
 
-       /**
-        * Return data from the factory.
-        * @return StatsdData[]
-        */
        public function getData() {
                return $this->buffer;
        }
 
-       /**
-        * Set collection enable status.
-        * @param bool $enabled Will collection be enabled?
-        * @return void
-        */
+       public function clearData() {
+               $this->buffer = [];
+       }
+
+       public function getDataCount() {
+               return count( $this->buffer );
+       }
+
        public function setEnabled( $enabled ) {
                $this->enabled = $enabled;
        }
index f77b26c..77b4c35 100644 (file)
@@ -9,22 +9,34 @@ use Liuggio\StatsdClient\Factory\StatsdDataFactoryInterface;
  */
 interface IBufferingStatsdDataFactory extends StatsdDataFactoryInterface {
        /**
-        * Check whether this data factory has any data.
+        * Check whether this data factory has any buffered data.
         * @return bool
         */
        public function hasData();
 
        /**
-        * Return data from the factory.
+        * Return the buffered data from the factory.
         * @return StatsdData[]
         */
        public function getData();
 
+       /**
+        * Clear all buffered data from the factory
+        * @since 1.31
+        */
+       public function clearData();
+
+       /**
+        * Return the number of buffered statsd data entries
+        * @return int
+        * @since 1.31
+        */
+       public function getDataCount();
+
        /**
         * Set collection enable status.
         * @param bool $enabled Will collection be enabled?
         * @return void
         */
        public function setEnabled( $enabled );
-
 }
index ed16311..63de8f2 100644 (file)
@@ -105,27 +105,22 @@ class NullStatsdDataFactory implements IBufferingStatsdDataFactory {
                return $data;
        }
 
-       /**
-        * Check whether this data factory has any data.
-        * @return bool
-        */
        public function hasData() {
                return false;
        }
 
-       /**
-        * Return data from the factory.
-        * @return StatsdData[]
-        */
        public function getData() {
                return [];
        }
 
-       /**
-        * Set collection enable status.
-        * @param bool $enabled Will collection be enabled?
-        * @return void
-        */
+       public function clearData() {
+               // Nothing to do, always empty
+       }
+
+       public function getDataCount() {
+               return 0;
+       }
+
        public function setEnabled( $enabled ) {
                // Nothing to do, null factory is always disabled.
        }
index 931c085..88e816a 100644 (file)
@@ -1318,7 +1318,7 @@ class XMPReader implements LoggerAwareInterface {
                }
        }
 
-       // @codingStandardsIgnoreStart Generic.Files.LineLength
+       // phpcs:disable Generic.Files.LineLength
        /**
         * Process attributes.
         * Simple values can be stored as either a tag or attribute
@@ -1334,7 +1334,7 @@ class XMPReader implements LoggerAwareInterface {
         * @param array $attribs Array attribute=>value
         * @throws RuntimeException
         */
-       // @codingStandardsIgnoreEnd
+       // phpcs:enable
        private function doAttribs( $attribs ) {
                // first check for rdf:parseType attribute, as that can change
                // how the attributes are interperted.
index 76ae279..7aec28e 100644 (file)
@@ -262,14 +262,12 @@ class XMPValidate implements LoggerAwareInterface {
                        return;
                }
                $res = [];
-               // @codingStandardsIgnoreStart Long line that cannot be broken
                if ( !preg_match(
                        /* ahh! scary regex... */
+                       // phpcs:ignore Generic.Files.LineLength
                        '/^([0-3]\d{3})(?:-([01]\d)(?:-([0-3]\d)(?:T([0-2]\d):([0-6]\d)(?::([0-6]\d)(?:\.\d+)?)?([-+]\d{2}:\d{2}|Z)?)?)?)?$/D',
                        $val, $res )
                ) {
-                       // @codingStandardsIgnoreEnd
-
                        $this->logger->info( __METHOD__ . " Expected date but got $val" );
                        $val = null;
                } else {
index 3ec8772..fa5b0a6 100644 (file)
@@ -29,9 +29,8 @@
  *
  * @ingroup Media
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class BitmapHandler_ClientOnly extends BitmapHandler {
-       // @codingStandardsIgnoreEnd
 
        /**
         * @param File $image
index 2cfd2a1..c286055 100644 (file)
  * @ingroup Cache
  */
 
+use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\DBError;
 use Wikimedia\Rdbms\DBQueryError;
 use Wikimedia\Rdbms\DBConnectionError;
-use \MediaWiki\MediaWikiServices;
-use \Wikimedia\WaitConditionLoop;
-use \Wikimedia\Rdbms\TransactionProfiler;
 use Wikimedia\Rdbms\LoadBalancer;
+use Wikimedia\Rdbms\TransactionProfiler;
+use Wikimedia\WaitConditionLoop;
 
 /**
  * Class to store objects in the database
index 1dcdc65..b5ff805 100644 (file)
@@ -539,13 +539,13 @@ class ImagePage extends Article {
                                // The dirmark, however, must not be immediately adjacent
                                // to the filename, because it can get copied with it.
                                // See T27277.
-                               // @codingStandardsIgnoreStart Ignore long line
+                               // phpcs:disable Generic.Files.LineLength
                                $out->addWikiText( <<<EOT
 <div class="fullMedia"><span class="dangerousLink">{$medialink}</span> $dirmark<span class="fileInfo">$longDesc</span></div>
 <div class="mediaWarning">$warning</div>
 EOT
                                );
-                               // @codingStandardsIgnoreEnd
+                               // phpcs:enable
                        } else {
                                $out->addWikiText( <<<EOT
 <div class="fullMedia">{$medialink} {$dirmark}<span class="fileInfo">$longDesc</span>
@@ -632,7 +632,7 @@ EOT
         * @param string $sizeLinkBigImagePreview HTML for the current size
         * @return string HTML output
         */
-       private function getThumbPrevText( $params, $sizeLinkBigImagePreview ) {
+       protected function getThumbPrevText( $params, $sizeLinkBigImagePreview ) {
                if ( $sizeLinkBigImagePreview ) {
                        // Show a different message of preview is different format from original.
                        $previewTypeDiffers = false;
@@ -670,7 +670,7 @@ EOT
         * @param int $height
         * @return string
         */
-       private function makeSizeLink( $params, $width, $height ) {
+       protected function makeSizeLink( $params, $width, $height ) {
                $params['width'] = $width;
                $params['height'] = $height;
                $thumbnail = $this->displayImg->transform( $params );
index c03d6b2..05247ca 100644 (file)
@@ -176,44 +176,32 @@ class PageArchive {
         * @return ResultWrapper
         */
        public function listRevisions() {
-               $dbr = wfGetDB( DB_REPLICA );
-               $commentQuery = CommentStore::newKey( 'ar_comment' )->getJoin();
-
-               $tables = [ 'archive' ] + $commentQuery['tables'];
-
-               $fields = [
-                       'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text',
-                       'ar_len', 'ar_deleted', 'ar_rev_id', 'ar_sha1',
-                       'ar_page_id'
-               ] + $commentQuery['fields'];
-
-               if ( $this->config->get( 'ContentHandlerUseDB' ) ) {
-                       $fields[] = 'ar_content_format';
-                       $fields[] = 'ar_content_model';
-               }
-
-               $conds = [ 'ar_namespace' => $this->title->getNamespace(),
-                       'ar_title' => $this->title->getDBkey() ];
+               $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
+               $queryInfo = $revisionStore->getArchiveQueryInfo();
 
+               $conds = [
+                       'ar_namespace' => $this->title->getNamespace(),
+                       'ar_title' => $this->title->getDBkey(),
+               ];
                $options = [ 'ORDER BY' => 'ar_timestamp DESC' ];
 
-               $join_conds = [] + $commentQuery['joins'];
-
                ChangeTags::modifyDisplayQuery(
-                       $tables,
-                       $fields,
+                       $queryInfo['tables'],
+                       $queryInfo['fields'],
                        $conds,
-                       $join_conds,
+                       $queryInfo['joins'],
                        $options,
                        ''
                );
 
-               return $dbr->select( $tables,
-                       $fields,
+               $dbr = wfGetDB( DB_REPLICA );
+               return $dbr->select(
+                       $queryInfo['tables'],
+                       $queryInfo['fields'],
                        $conds,
                        __METHOD__,
                        $options,
-                       $join_conds
+                       $queryInfo['joins']
                );
        }
 
@@ -542,47 +530,23 @@ class PageArchive {
                        $oldWhere['ar_timestamp'] = array_map( [ &$dbw, 'timestamp' ], $timestamps );
                }
 
-               $commentQuery = CommentStore::newKey( 'ar_comment' )->getJoin();
-
-               $tables = [ 'archive', 'revision' ] + $commentQuery['tables'];
-
-               $fields = [
-                       'ar_id',
-                       'ar_rev_id',
-                       'rev_id',
-                       'ar_text',
-                       'ar_user',
-                       'ar_user_text',
-                       'ar_timestamp',
-                       'ar_minor_edit',
-                       'ar_flags',
-                       'ar_text_id',
-                       'ar_deleted',
-                       'ar_page_id',
-                       'ar_len',
-                       'ar_sha1'
-               ] + $commentQuery['fields'];
-
-               if ( $this->config->get( 'ContentHandlerUseDB' ) ) {
-                       $fields[] = 'ar_content_format';
-                       $fields[] = 'ar_content_model';
-               }
-
-               $join_conds = [
-                       'revision' => [ 'LEFT JOIN', 'ar_rev_id=rev_id' ],
-               ] + $commentQuery['joins'];
+               $revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
+               $queryInfo = $revisionStore->getArchiveQueryInfo();
+               $queryInfo['tables'][] = 'revision';
+               $queryInfo['fields'][] = 'rev_id';
+               $queryInfo['joins']['revision'] = [ 'LEFT JOIN', 'ar_rev_id=rev_id' ];
 
                /**
                 * Select each archived revision...
                 */
                $result = $dbw->select(
-                       $tables,
-                       $fields,
+                       $queryInfo['tables'],
+                       $queryInfo['fields'],
                        $oldWhere,
                        __METHOD__,
                        /* options */
                        [ 'ORDER BY' => 'ar_timestamp' ],
-                       $join_conds
+                       $queryInfo['joins']
                );
 
                $rev_count = $result->numRows();
index b411855..5029d1d 100644 (file)
@@ -21,8 +21,9 @@
  */
 
 use MediaWiki\Edit\PreparedEdit;
-use \MediaWiki\Logger\LoggerFactory;
-use \MediaWiki\MediaWikiServices;
+use MediaWiki\Logger\LoggerFactory;
+use MediaWiki\MediaWikiServices;
+use Wikimedia\Assert\Assert;
 use Wikimedia\Rdbms\FakeResultWrapper;
 use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\DBError;
@@ -671,7 +672,7 @@ class WikiPage implements Page, IDBAccessObject {
                        $revision = Revision::newFromPageId( $this->getId(), $latest, $flags );
                } else {
                        $dbr = wfGetDB( DB_REPLICA );
-                       $revision = Revision::newKnownCurrent( $dbr, $this->getId(), $latest );
+                       $revision = Revision::newKnownCurrent( $dbr, $this->getTitle(), $latest );
                }
 
                if ( $revision ) { // sanity
@@ -1264,8 +1265,11 @@ class WikiPage implements Page, IDBAccessObject {
                        $conditions['page_latest'] = $lastRevision;
                }
 
+               $revId = $revision->getId();
+               Assert::parameter( $revId > 0, '$revision->getId()', 'must be > 0' );
+
                $row = [ /* SET */
-                       'page_latest'      => $revision->getId(),
+                       'page_latest'      => $revId,
                        'page_touched'     => $dbw->timestamp( $revision->getTimestamp() ),
                        'page_is_new'      => ( $lastRevision === 0 ) ? 1 : 0,
                        'page_is_redirect' => $rt !== null ? 1 : 0,
index 13d8a3a..b871735 100644 (file)
@@ -96,10 +96,9 @@ class Parser {
        # at least one character of a host name (embeds EXT_LINK_URL_CLASS)
        const EXT_LINK_ADDR = '(?:[0-9.]+|\\[(?i:[0-9a-f:.]+)\\]|[^][<>"\\x00-\\x20\\x7F\p{Zs}\x{FFFD}])';
        # RegExp to make image URLs (embeds IPv6 part of EXT_LINK_ADDR)
-       // @codingStandardsIgnoreStart Generic.Files.LineLength
+       // phpcs:ignore Generic.Files.LineLength
        const EXT_IMAGE_REGEX = '/^(http:\/\/|https:\/\/)((?:\\[(?i:[0-9a-f:.]+)\\])?[^][<>"\\x00-\\x20\\x7F\p{Zs}\x{FFFD}]+)
                \\/([A-Za-z0-9_.,~%\\-+&;#*?!=()@\\x80-\\xFF]+)\\.((?i)gif|png|jpg|jpeg)$/Sxu';
-       // @codingStandardsIgnoreEnd
 
        # Regular expression for a non-newline space
        const SPACE_NOT_NL = '(?:\t|&nbsp;|&\#0*160;|&\#[Xx]0*[Aa]0;|\p{Zs})';
@@ -2139,11 +2138,8 @@ class Parser {
 
                $useSubpages = $this->areSubpagesAllowed();
 
-               // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
                # Loop for each link
                for ( ; $line !== false && $line !== null; $a->next(), $line = $a->current() ) {
-                       // @codingStandardsIgnoreEnd
-
                        # Check for excessive memory usage
                        if ( $holders->isBig() ) {
                                # Too big
@@ -3114,10 +3110,32 @@ class Parser {
                                        throw $ex;
                                }
 
-                               # The interface for parser functions allows for extracting
-                               # flags into the local scope. Extract any forwarded flags
-                               # here.
-                               extract( $result );
+                               // Extract any forwarded flags
+                               if ( isset( $result['title'] ) ) {
+                                       $title = $result['title'];
+                               }
+                               if ( isset( $result['found'] ) ) {
+                                       $found = $result['found'];
+                               }
+                               if ( array_key_exists( 'text', $result ) ) {
+                                       // a string or null
+                                       $text = $result['text'];
+                               }
+                               if ( isset( $result['nowiki'] ) ) {
+                                       $nowiki = $result['nowiki'];
+                               }
+                               if ( isset( $result['isHTML'] ) ) {
+                                       $isHTML = $result['isHTML'];
+                               }
+                               if ( isset( $result['forceRawInterwiki'] ) ) {
+                                       $forceRawInterwiki = $result['forceRawInterwiki'];
+                               }
+                               if ( isset( $result['isChildObj'] ) ) {
+                                       $isChildObj = $result['isChildObj'];
+                               }
+                               if ( isset( $result['isLocalObj'] ) ) {
+                                       $isLocalObj = $result['isLocalObj'];
+                               }
                        }
                }
 
@@ -3498,13 +3516,7 @@ class Parser {
         * @return Revision|bool False if missing
         */
        public static function statelessFetchRevision( Title $title, $parser = false ) {
-               $pageId = $title->getArticleID();
-               $revId = $title->getLatestRevID();
-
-               $rev = Revision::newKnownCurrent( wfGetDB( DB_REPLICA ), $pageId, $revId );
-               if ( $rev ) {
-                       $rev->setTitle( $title );
-               }
+               $rev = Revision::newKnownCurrent( wfGetDB( DB_REPLICA ), $title );
 
                return $rev;
        }
@@ -3561,9 +3573,8 @@ class Parser {
                $deps = [];
 
                # Loop to fetch the article, with up to 1 redirect
-               // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $i = 0; $i < 2 && is_object( $title ); $i++ ) {
-                       // @codingStandardsIgnoreEnd
                        # Give extensions a chance to select the revision instead
                        $id = false; # Assume current
                        Hooks::run( 'BeforeParserFetchTemplateAndtitle',
@@ -3868,11 +3879,12 @@ class Parser {
                        }
 
                        if ( is_array( $output ) ) {
-                               # Extract flags to local scope (to override $markerType)
+                               // Extract flags
                                $flags = $output;
                                $output = $flags[0];
-                               unset( $flags[0] );
-                               extract( $flags );
+                               if ( isset( $flags['markerType'] ) ) {
+                                       $markerType = $flags['markerType'];
+                               }
                        }
                } else {
                        if ( is_null( $attrText ) ) {
@@ -4236,9 +4248,8 @@ class Parser {
                        $anchor = $safeHeadline;
                        $fallbackAnchor = $fallbackHeadline;
                        if ( isset( $refers[$arrayKey] ) ) {
-                               // @codingStandardsIgnoreStart
+                               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall,Generic.Formatting.DisallowMultipleStatements
                                for ( $i = 2; isset( $refers["${arrayKey}_$i"] ); ++$i );
-                               // @codingStandardsIgnoreEnd
                                $anchor .= "_$i";
                                $linkAnchor .= "_$i";
                                $refers["${arrayKey}_$i"] = true;
@@ -4246,9 +4257,8 @@ class Parser {
                                $refers[$arrayKey] = true;
                        }
                        if ( $fallbackHeadline !== false && isset( $refers[$fallbackArrayKey] ) ) {
-                               // @codingStandardsIgnoreStart
+                               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall,Generic.Formatting.DisallowMultipleStatements
                                for ( $i = 2; isset( $refers["${fallbackArrayKey}_$i"] ); ++$i );
-                               // @codingStandardsIgnoreEnd
                                $fallbackAnchor .= "_$i";
                                $refers["${fallbackArrayKey}_$i"] = true;
                        } else {
index 2588962..79021dd 100644 (file)
@@ -24,9 +24,8 @@
 /**
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class Preprocessor_DOM extends Preprocessor {
-       // @codingStandardsIgnoreEnd
 
        /**
         * @var Parser
@@ -559,8 +558,16 @@ class Preprocessor_DOM extends Preprocessor {
                                                'count' => $count ];
                                        $stack->push( $piece );
                                        $accum =& $stack->getAccum();
-                                       $flags = $stack->getFlags();
-                                       extract( $flags );
+                                       $stackFlags = $stack->getFlags();
+                                       if ( isset( $stackFlags['findEquals'] ) ) {
+                                               $findEquals = $stackFlags['findEquals'];
+                                       }
+                                       if ( isset( $stackFlags['findPipe'] ) ) {
+                                               $findPipe = $stackFlags['findPipe'];
+                                       }
+                                       if ( isset( $stackFlags['inHeading'] ) ) {
+                                               $inHeading = $stackFlags['inHeading'];
+                                       }
                                        $i += $count;
                                }
                        } elseif ( $found == 'line-end' ) {
@@ -610,8 +617,16 @@ class Preprocessor_DOM extends Preprocessor {
                                // Unwind the stack
                                $stack->pop();
                                $accum =& $stack->getAccum();
-                               $flags = $stack->getFlags();
-                               extract( $flags );
+                               $stackFlags = $stack->getFlags();
+                               if ( isset( $stackFlags['findEquals'] ) ) {
+                                       $findEquals = $stackFlags['findEquals'];
+                               }
+                               if ( isset( $stackFlags['findPipe'] ) ) {
+                                       $findPipe = $stackFlags['findPipe'];
+                               }
+                               if ( isset( $stackFlags['inHeading'] ) ) {
+                                       $inHeading = $stackFlags['inHeading'];
+                               }
 
                                // Append the result to the enclosing accumulator
                                $accum .= $element;
@@ -640,8 +655,16 @@ class Preprocessor_DOM extends Preprocessor {
 
                                        $stack->push( $piece );
                                        $accum =& $stack->getAccum();
-                                       $flags = $stack->getFlags();
-                                       extract( $flags );
+                                       $stackFlags = $stack->getFlags();
+                                       if ( isset( $stackFlags['findEquals'] ) ) {
+                                               $findEquals = $stackFlags['findEquals'];
+                                       }
+                                       if ( isset( $stackFlags['findPipe'] ) ) {
+                                               $findPipe = $stackFlags['findPipe'];
+                                       }
+                                       if ( isset( $stackFlags['inHeading'] ) ) {
+                                               $inHeading = $stackFlags['inHeading'];
+                                       }
                                } else {
                                        # Add literal brace(s)
                                        $accum .= htmlspecialchars( str_repeat( $curChar, $count ) );
@@ -748,8 +771,16 @@ class Preprocessor_DOM extends Preprocessor {
                                                $accum .= $s;
                                        }
                                }
-                               $flags = $stack->getFlags();
-                               extract( $flags );
+                               $stackFlags = $stack->getFlags();
+                               if ( isset( $stackFlags['findEquals'] ) ) {
+                                       $findEquals = $stackFlags['findEquals'];
+                               }
+                               if ( isset( $stackFlags['findPipe'] ) ) {
+                                       $findPipe = $stackFlags['findPipe'];
+                               }
+                               if ( isset( $stackFlags['inHeading'] ) ) {
+                                       $inHeading = $stackFlags['inHeading'];
+                               }
 
                                # Add XML element to the enclosing accumulator
                                $accum .= $element;
@@ -992,9 +1023,8 @@ class PPDPart {
  * An expansion frame, used as a context to expand the result of preprocessToObj()
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPFrame_DOM implements PPFrame {
-       // @codingStandardsIgnoreEnd
 
        /**
         * @var Preprocessor
@@ -1610,9 +1640,8 @@ class PPFrame_DOM implements PPFrame {
  * Expansion frame with template arguments
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPTemplateFrame_DOM extends PPFrame_DOM {
-       // @codingStandardsIgnoreEnd
 
        public $numberedArgs, $namedArgs;
 
@@ -1789,9 +1818,8 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
  * Expansion frame with custom arguments
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPCustomFrame_DOM extends PPFrame_DOM {
-       // @codingStandardsIgnoreEnd
 
        public $args;
 
@@ -1842,9 +1870,8 @@ class PPCustomFrame_DOM extends PPFrame_DOM {
 /**
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPNode_DOM implements PPNode {
-       // @codingStandardsIgnoreEnd
 
        /**
         * @var DOMElement
index 735c33a..468b009 100644 (file)
@@ -39,9 +39,8 @@
  *
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class Preprocessor_Hash extends Preprocessor {
-       // @codingStandardsIgnoreEnd
 
        /**
         * @var Parser
@@ -497,7 +496,16 @@ class Preprocessor_Hash extends Preprocessor {
                                                'count' => $count ];
                                        $stack->push( $piece );
                                        $accum =& $stack->getAccum();
-                                       extract( $stack->getFlags() );
+                                       $stackFlags = $stack->getFlags();
+                                       if ( isset( $stackFlags['findEquals'] ) ) {
+                                               $findEquals = $stackFlags['findEquals'];
+                                       }
+                                       if ( isset( $stackFlags['findPipe'] ) ) {
+                                               $findPipe = $stackFlags['findPipe'];
+                                       }
+                                       if ( isset( $stackFlags['inHeading'] ) ) {
+                                               $inHeading = $stackFlags['inHeading'];
+                                       }
                                        $i += $count;
                                }
                        } elseif ( $found == 'line-end' ) {
@@ -554,7 +562,16 @@ class Preprocessor_Hash extends Preprocessor {
                                // Unwind the stack
                                $stack->pop();
                                $accum =& $stack->getAccum();
-                               extract( $stack->getFlags() );
+                               $stackFlags = $stack->getFlags();
+                               if ( isset( $stackFlags['findEquals'] ) ) {
+                                       $findEquals = $stackFlags['findEquals'];
+                               }
+                               if ( isset( $stackFlags['findPipe'] ) ) {
+                                       $findPipe = $stackFlags['findPipe'];
+                               }
+                               if ( isset( $stackFlags['inHeading'] ) ) {
+                                       $inHeading = $stackFlags['inHeading'];
+                               }
 
                                // Append the result to the enclosing accumulator
                                array_splice( $accum, count( $accum ), 0, $element );
@@ -584,7 +601,16 @@ class Preprocessor_Hash extends Preprocessor {
 
                                        $stack->push( $piece );
                                        $accum =& $stack->getAccum();
-                                       extract( $stack->getFlags() );
+                                       $stackFlags = $stack->getFlags();
+                                       if ( isset( $stackFlags['findEquals'] ) ) {
+                                               $findEquals = $stackFlags['findEquals'];
+                                       }
+                                       if ( isset( $stackFlags['findPipe'] ) ) {
+                                               $findPipe = $stackFlags['findPipe'];
+                                       }
+                                       if ( isset( $stackFlags['inHeading'] ) ) {
+                                               $inHeading = $stackFlags['inHeading'];
+                                       }
                                } else {
                                        # Add literal brace(s)
                                        self::addLiteral( $accum, str_repeat( $curChar, $count ) );
@@ -695,7 +721,16 @@ class Preprocessor_Hash extends Preprocessor {
                                        }
                                }
 
-                               extract( $stack->getFlags() );
+                               $stackFlags = $stack->getFlags();
+                               if ( isset( $stackFlags['findEquals'] ) ) {
+                                       $findEquals = $stackFlags['findEquals'];
+                               }
+                               if ( isset( $stackFlags['findPipe'] ) ) {
+                                       $findPipe = $stackFlags['findPipe'];
+                               }
+                               if ( isset( $stackFlags['inHeading'] ) ) {
+                                       $inHeading = $stackFlags['inHeading'];
+                               }
 
                                # Add XML element to the enclosing accumulator
                                array_splice( $accum, count( $accum ), 0, $element );
@@ -753,9 +788,8 @@ class Preprocessor_Hash extends Preprocessor {
  * Stack class to help Preprocessor::preprocessToObj()
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPDStack_Hash extends PPDStack {
-       // @codingStandardsIgnoreEnd
 
        public function __construct() {
                $this->elementClass = 'PPDStackElement_Hash';
@@ -767,9 +801,8 @@ class PPDStack_Hash extends PPDStack {
 /**
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPDStackElement_Hash extends PPDStackElement {
-       // @codingStandardsIgnoreEnd
 
        public function __construct( $data = [] ) {
                $this->partClass = 'PPDPart_Hash';
@@ -821,9 +854,8 @@ class PPDStackElement_Hash extends PPDStackElement {
 /**
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPDPart_Hash extends PPDPart {
-       // @codingStandardsIgnoreEnd
 
        public function __construct( $out = '' ) {
                if ( $out !== '' ) {
@@ -839,9 +871,8 @@ class PPDPart_Hash extends PPDPart {
  * An expansion frame, used as a context to expand the result of preprocessToObj()
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPFrame_Hash implements PPFrame {
-       // @codingStandardsIgnoreEnd
 
        /**
         * @var Parser
@@ -1439,9 +1470,8 @@ class PPFrame_Hash implements PPFrame {
  * Expansion frame with template arguments
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPTemplateFrame_Hash extends PPFrame_Hash {
-       // @codingStandardsIgnoreEnd
 
        public $numberedArgs, $namedArgs, $parent;
        public $numberedExpansionCache, $namedExpansionCache;
@@ -1622,9 +1652,8 @@ class PPTemplateFrame_Hash extends PPFrame_Hash {
  * Expansion frame with custom arguments
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPCustomFrame_Hash extends PPFrame_Hash {
-       // @codingStandardsIgnoreEnd
 
        public $args;
 
@@ -1675,9 +1704,8 @@ class PPCustomFrame_Hash extends PPFrame_Hash {
 /**
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPNode_Hash_Tree implements PPNode {
-       // @codingStandardsIgnoreEnd
 
        public $name;
 
@@ -2023,9 +2051,8 @@ class PPNode_Hash_Tree implements PPNode {
 /**
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPNode_Hash_Text implements PPNode {
-       // @codingStandardsIgnoreEnd
 
        public $value;
        private $store, $index;
@@ -2094,9 +2121,8 @@ class PPNode_Hash_Text implements PPNode {
 /**
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPNode_Hash_Array implements PPNode {
-       // @codingStandardsIgnoreEnd
 
        public $value;
 
@@ -2152,9 +2178,8 @@ class PPNode_Hash_Array implements PPNode {
 /**
  * @ingroup Parser
  */
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PPNode_Hash_Attr implements PPNode {
-       // @codingStandardsIgnoreEnd
 
        public $name, $value;
        private $store, $index;
index 20fee2d..b570a43 100644 (file)
@@ -477,7 +477,16 @@ class Sanitizer {
        public static function removeHTMLtags( $text, $processCallback = null,
                $args = [], $extratags = [], $removetags = [], $warnCallback = null
        ) {
-               extract( self::getRecognizedTagData( $extratags, $removetags ) );
+               $tagData = self::getRecognizedTagData( $extratags, $removetags );
+               $htmlpairs = $tagData['htmlpairs'];
+               $htmlsingle = $tagData['htmlsingle'];
+               $htmlsingleonly = $tagData['htmlsingleonly'];
+               $htmlnest = $tagData['htmlnest'];
+               $tabletags = $tagData['tabletags'];
+               $htmllist = $tagData['htmllist'];
+               $listtags = $tagData['listtags'];
+               $htmlsingleallowed = $tagData['htmlsingleallowed'];
+               $htmlelements = $tagData['htmlelements'];
 
                # Remove HTML comments
                $text = self::removeHTMLcomments( $text );
index b3776bd..502f1e0 100644 (file)
@@ -20,7 +20,7 @@
  * @file
  */
 
-use \Cdb\Reader as CdbReader;
+use Cdb\Reader as CdbReader;
 
 /**
  * Functions to check passwords against a policy requirement
index bd7072a..ba0b4cb 100644 (file)
@@ -209,9 +209,8 @@ abstract class PoolCounter {
        }
 }
 
-// @codingStandardsIgnoreStart Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class PoolCounter_Stub extends PoolCounter {
-       // @codingStandardsIgnoreEnd
 
        public function __construct() {
                /* No parameters needed */
index 65ea833..9515f25 100644 (file)
@@ -152,7 +152,7 @@ class PoolCounterRedis extends PoolCounter {
                }
                $conn = $status->value;
 
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                static $script =
                /** @lang Lua */
 <<<LUA
@@ -191,7 +191,7 @@ class PoolCounterRedis extends PoolCounter {
                end
                return 1
 LUA;
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
 
                try {
                        $conn->luaEval( $script,
index b2e1c49..63a495a 100644 (file)
@@ -236,8 +236,6 @@ class ResourceLoader implements LoggerAwareInterface {
                return $data;
        }
 
-       /* Methods */
-
        /**
         * Register core modules and runs registration hooks.
         * @param Config $config [optional]
@@ -1210,8 +1208,6 @@ MESSAGE;
                return $moduleNames;
        }
 
-       /* Static Methods */
-
        /**
         * Return JS code that calls mw.loader.implement with given module properties.
         *
index 4675191..f2f3383 100644 (file)
@@ -26,7 +26,6 @@
  * ResourceLoader module based on local JavaScript/CSS files.
  */
 class ResourceLoaderFileModule extends ResourceLoaderModule {
-       /* Protected Members */
 
        /** @var string Local base path, see __construct() */
        protected $localBasePath = '';
@@ -149,8 +148,6 @@ class ResourceLoaderFileModule extends ResourceLoaderModule {
         */
        protected $missingLocalFileRefs = [];
 
-       /* Methods */
-
        /**
         * Constructs a new module from an options array.
         *
index dd239d0..3cf09d8 100644 (file)
@@ -26,7 +26,6 @@
  * and local base path, for use with ResourceLoaderFileModule.
  */
 class ResourceLoaderFilePath {
-       /* Protected Members */
 
        /** @var string Local base path */
        protected $localBasePath;
@@ -38,8 +37,6 @@ class ResourceLoaderFilePath {
         * @var string Path to the file */
        protected $path;
 
-       /* Methods */
-
        /**
         * @param string $path Path to the file.
         * @param string $localBasePath Base path to prepend when generating a local path.
index b3c1cd1..0104ec3 100644 (file)
@@ -65,8 +65,6 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
        # pages like Special:UserLogin and Special:Preferences
        protected $origin = self::ORIGIN_CORE_SITEWIDE;
 
-       /* Protected Members */
-
        protected $name = null;
        protected $targets = [ 'desktop' ];
 
@@ -94,8 +92,6 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
         */
        protected $logger;
 
-       /* Methods */
-
        /**
         * Get this module's name. This is set when the module is registered
         * with ResourceLoader::register()
index bfa7326..e933f1f 100644 (file)
  */
 class ResourceLoaderUserTokensModule extends ResourceLoaderModule {
 
-       /* Protected Members */
-
        protected $origin = self::ORIGIN_CORE_INDIVIDUAL;
 
        protected $targets = [ 'desktop', 'mobile' ];
 
-       /* Methods */
-
        /**
         * Fetch the tokens for the current user.
         *
index bebc188..6eddfc0 100644 (file)
@@ -183,12 +183,10 @@ class ResourceLoaderWikiModule extends ResourceLoaderModule {
         * @return Content|null
         */
        protected function getContentObj( Title $title ) {
-               $revision = Revision::newKnownCurrent( wfGetDB( DB_REPLICA ), $title->getArticleID(),
-                       $title->getLatestRevID() );
+               $revision = Revision::newKnownCurrent( wfGetDB( DB_REPLICA ), $title );
                if ( !$revision ) {
                        return null;
                }
-               $revision->setTitle( $title );
                $content = $revision->getContent( Revision::RAW );
                if ( !$content ) {
                        wfDebugLog( 'resourceloader', __METHOD__ . ': failed to load content of JS/CSS page!' );
index 0e99ba9..2687c8e 100644 (file)
@@ -100,7 +100,7 @@ class SearchExactMatchRescorer {
         * @return array redirect target prefixedText to index of title in titles
         *   that is a redirect to it.
         */
-       private function redirectTargetsToRedirect( $titles ) {
+       private function redirectTargetsToRedirect( array $titles ) {
                $result = [];
                foreach ( $titles as $key => $titleText ) {
                        $title = Title::newFromText( $titleText );
@@ -122,7 +122,7 @@ class SearchExactMatchRescorer {
         * @param int $key key to pull to the front
         * @return array $array with the item at $key pulled to the front
         */
-       private function pullFront( $key, $array ) {
+       private function pullFront( $key, array $array ) {
                $cut = array_splice( $array, $key, 1 );
                array_unshift( $array, $cut[0] );
                return $array;
index 998b3ed..f887ada 100644 (file)
@@ -36,7 +36,7 @@ class Command {
        use LoggerAwareTrait;
 
        /** @var string */
-       private $command = '';
+       protected $command = '';
 
        /** @var array */
        private $limits = [
@@ -269,9 +269,10 @@ class Command {
         * String together all the options and build the final command
         * to execute
         *
+        * @param string $command Already-escaped command to run
         * @return array [ command, whether to use log pipe ]
         */
-       protected function buildFinalCommand() {
+       protected function buildFinalCommand( $command ) {
                $envcmd = '';
                foreach ( $this->env as $k => $v ) {
                        if ( wfIsWindows() ) {
@@ -291,7 +292,7 @@ class Command {
                }
 
                $useLogPipe = false;
-               $cmd = $envcmd . trim( $this->command );
+               $cmd = $envcmd . trim( $command );
 
                if ( is_executable( '/bin/bash' ) ) {
                        $time = intval( $this->limits['time'] );
@@ -335,7 +336,7 @@ class Command {
 
                $profileMethod = $this->method ?: wfGetCaller();
 
-               list( $cmd, $useLogPipe ) = $this->buildFinalCommand();
+               list( $cmd, $useLogPipe ) = $this->buildFinalCommand( $this->command );
 
                $this->logger->debug( __METHOD__ . ": $cmd" );
 
@@ -405,14 +406,12 @@ class Command {
                        // TODO replace with clear_last_error when requirements are bumped to PHP7
                        set_error_handler( function () {
                        }, 0 );
-                       // @codingStandardsIgnoreStart Generic.PHP.NoSilencedErrors.Discouraged
+                       // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
                        @trigger_error( '' );
-                       // @codingStandardsIgnoreEnd
                        restore_error_handler();
 
-                       // @codingStandardsIgnoreStart Generic.PHP.NoSilencedErrors.Discouraged
+                       // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
                        $numReadyPipes = @stream_select( $readyPipes, $emptyArray, $emptyArray, $timeout );
-                       // @codingStandardsIgnoreEnd
                        if ( $numReadyPipes === false ) {
                                $error = error_get_last();
                                if ( strncmp( $error['message'], $eintrMessage, strlen( $eintrMessage ) ) == 0 ) {
index 79f679d..a71b376 100644 (file)
@@ -59,10 +59,15 @@ class FirejailCommand extends Command {
        /**
         * @inheritDoc
         */
-       protected function buildFinalCommand() {
+       protected function buildFinalCommand( $command ) {
                // If there are no restrictions, don't use firejail
                if ( $this->restrictions === 0 ) {
-                       return parent::buildFinalCommand();
+                       $splitCommand = explode( ' ', $command, 2 );
+                       $this->logger->debug(
+                               "firejail: Command {$splitCommand[0]} {params} has no restrictions",
+                               [ 'params' => isset( $splitCommand[1] ) ? $splitCommand[1] : '' ]
+                       );
+                       return parent::buildFinalCommand( $command );
                }
 
                if ( $this->firejail === false ) {
@@ -110,6 +115,10 @@ class FirejailCommand extends Command {
                        }
                }
 
+               if ( $this->hasRestriction( Shell::NO_LOCALSETTINGS ) ) {
+                       $cmd[] = '--blacklist=' . realpath( MW_CONFIG_FILE );
+               }
+
                if ( $this->hasRestriction( Shell::NO_ROOT ) ) {
                        $cmd[] = '--noroot';
                }
@@ -122,6 +131,10 @@ class FirejailCommand extends Command {
 
                if ( $this->hasRestriction( Shell::NO_EXECVE ) ) {
                        $seccomp[] = 'execve';
+                       // Normally firejail will run commands in a bash shell,
+                       // but that won't work if we ban the execve syscall, so
+                       // run the command without a shell.
+                       $cmd[] = '--shell=none';
                }
 
                if ( $seccomp ) {
@@ -136,11 +149,10 @@ class FirejailCommand extends Command {
                        $cmd[] = '--net=none';
                }
 
-               list( $fullCommand, $useLogPipe ) = parent::buildFinalCommand();
-
                $builtCmd = implode( ' ', $cmd );
 
-               return [ "$builtCmd -- $fullCommand", $useLogPipe ];
+               // Prefix the firejail command in front of the wanted command
+               return parent::buildFinalCommand( "$builtCmd -- {$command}" );
        }
 
 }
index 084e10e..05463db 100644 (file)
@@ -45,13 +45,13 @@ class Shell {
         * Apply a default set of restrictions for improved
         * security out of the box.
         *
-        * Equal to NO_ROOT | SECCOMP | PRIVATE_DEV
+        * Equal to NO_ROOT | SECCOMP | PRIVATE_DEV | NO_LOCALSETTINGS
         *
         * @note This value will change over time to provide increased security
         *       by default, and is not guaranteed to be backwards-compatible.
         * @since 1.31
         */
-       const RESTRICT_DEFAULT = 7;
+       const RESTRICT_DEFAULT = 39;
 
        /**
         * Disallow any root access. Any setuid binaries
@@ -92,6 +92,13 @@ class Shell {
         */
        const NO_EXECVE = 16;
 
+       /**
+        * Deny access to LocalSettings.php (MW_CONFIG_FILE)
+        *
+        * @since 1.31
+        */
+       const NO_LOCALSETTINGS = 32;
+
        /**
         * Returns a new instance of Command class
         *
index 1ad1ab0..bd02fa3 100644 (file)
@@ -26,8 +26,7 @@ class SkinFallbackTemplate extends BaseTemplate {
 
                // Filter out skins that aren't installed
                $possibleSkins = array_filter( $possibleSkins, function ( $skinDir ) use ( $styleDirectory ) {
-                       return
-                               is_file( "$styleDirectory/$skinDir/skin.json" )
+                       return is_file( "$styleDirectory/$skinDir/skin.json" )
                                || is_file( "$styleDirectory/$skinDir/$skinDir.php" );
                } );
 
index 65a03eb..303184d 100644 (file)
@@ -553,7 +553,7 @@ abstract class ChangesListSpecialPage extends SpecialPage {
        public function execute( $subpage ) {
                $this->rcSubpage = $subpage;
 
-               $this->considerActionsForDefaultSavedQuery();
+               $this->considerActionsForDefaultSavedQuery( $subpage );
 
                $opts = $this->getOptions();
                try {
@@ -629,8 +629,10 @@ abstract class ChangesListSpecialPage extends SpecialPage {
         * Check whether or not the page should load defaults, and if so, whether
         * a default saved query is relevant to be redirected to. If it is relevant,
         * redirect properly with all necessary query parameters.
+        *
+        * @param string $subpage
         */
-       protected function considerActionsForDefaultSavedQuery() {
+       protected function considerActionsForDefaultSavedQuery( $subpage ) {
                if ( !$this->isStructuredFilterUiEnabled() || $this->including() ) {
                        return;
                }
@@ -677,7 +679,7 @@ abstract class ChangesListSpecialPage extends SpecialPage {
                                        // but are still valid and requested in the URL
                                        $query = array_merge( $this->getRequest()->getValues(), $query );
                                        unset( $query[ 'title' ] );
-                                       $this->getOutput()->redirect( $this->getPageTitle()->getCanonicalURL( $query ) );
+                                       $this->getOutput()->redirect( $this->getPageTitle( $subpage )->getCanonicalURL( $query ) );
                                } else {
                                        // There's a default, but the version is not 2, and the server can't
                                        // actually recognize the query itself. This happens if it is before
index 73b8128..33b9ccb 100644 (file)
@@ -700,9 +700,8 @@ abstract class QueryPage extends SpecialPage {
 
                        # $res might contain the whole 1,000 rows, so we read up to
                        # $num [should update this to use a Pager]
-                       // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+                       // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                        for ( $i = 0; $i < $num && $row = $res->fetchObject(); $i++ ) {
-                               // @codingStandardsIgnoreEnd
                                $line = $this->formatResult( $skin, $row );
                                if ( $line ) {
                                        $html[] = $this->listoutput
index eb0f0aa..9623953 100644 (file)
@@ -222,9 +222,8 @@ class SpecialEditTags extends UnlistedSpecialPage {
                $numRevisions = 0;
                // Live revisions...
                $list = $this->getList();
-               // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $list->reset(); $list->current(); $list->next() ) {
-                       // @codingStandardsIgnoreEnd
                        $item = $list->current();
                        $numRevisions++;
                        $out->addHTML( $item->getHTML() );
@@ -310,9 +309,8 @@ class SpecialEditTags extends UnlistedSpecialPage {
                        // Otherwise, use a multi-select field for adding tags, and a list of
                        // checkboxes for removing them
 
-                       // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+                       // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                        for ( $list->reset(); $list->current(); $list->next() ) {
-                               // @codingStandardsIgnoreEnd
                                $currentTags = $list->current()->getTags();
                                if ( $currentTags ) {
                                        $tags = array_merge( $tags, explode( ',', $currentTags ) );
index 560d75a..35344aa 100644 (file)
@@ -172,6 +172,11 @@ class SpecialExpandTemplates extends SpecialPage {
                                'rows' => 10,
                                'default' => $input,
                                'id' => 'input',
+                               // The following classes can be used here:
+                               // * mw-editfont-monospace
+                               // * mw-editfont-sans-serif
+                               // * mw-editfont-serif
+                               'cssclass' => 'mw-editfont-' . $this->getUser()->getOption( 'editfont' ),
                        ],
                        'removecomments' => [
                                'type' => 'check',
@@ -203,6 +208,8 @@ class SpecialExpandTemplates extends SpecialPage {
                        ],
                ];
 
+               $this->getOutput()->addModuleStyles( 'mediawiki.editfont.styles' );
+
                $form = HTMLForm::factory( 'ooui', $fields, $this->getContext() );
                $form
                        ->setSubmitTextMsg( 'expand_templates_ok' )
@@ -226,7 +233,11 @@ class SpecialExpandTemplates extends SpecialPage {
                        $output,
                        10,
                        10,
-                       [ 'id' => 'output', 'readonly' => 'readonly' ]
+                       [
+                               'id' => 'output',
+                               'readonly' => 'readonly',
+                               'class' => 'mw-editfont-' . $this->getUser()->getOption( 'editfont' )
+                       ]
                );
 
                return $out;
index eb7be51..78f9253 100644 (file)
@@ -533,9 +533,7 @@ class SpecialExport extends SpecialPage {
         * @return array
         */
        private function getPageLinks( $inputPages, $pageSet, $depth ) {
-               // @codingStandardsIgnoreStart Squiz.WhiteSpace.SemicolonSpacing.Incorrect
                for ( ; $depth > 0; --$depth ) {
-                       // @codingStandardsIgnoreEnd
                        $pageSet = $this->getLinks(
                                $inputPages, $pageSet, 'pagelinks',
                                [ 'namespace' => 'pl_namespace', 'title' => 'pl_title' ],
index 671ab6f..1639386 100644 (file)
@@ -290,15 +290,16 @@ class SpecialNewpages extends IncludableSpecialPage {
 
        /**
         * @param stdClass $result Result row from recent changes
-        * @return Revision|bool
+        * @param Title $title
+        * @return bool|Revision
         */
-       protected function revisionFromRcResult( stdClass $result ) {
+       protected function revisionFromRcResult( stdClass $result, Title $title ) {
                return new Revision( [
                        'comment' => CommentStore::newKey( 'rc_comment' )->getComment( $result )->text,
                        'deleted' => $result->rc_deleted,
                        'user_text' => $result->rc_user_text,
                        'user' => $result->rc_user,
-               ] );
+               ], 0, $title );
        }
 
        /**
@@ -313,8 +314,7 @@ class SpecialNewpages extends IncludableSpecialPage {
 
                // Revision deletion works on revisions,
                // so cast our recent change row to a revision row.
-               $rev = $this->revisionFromRcResult( $result );
-               $rev->setTitle( $title );
+               $rev = $this->revisionFromRcResult( $result, $title );
 
                $classes = [];
                $attribs = [ 'data-mw-revid' => $result->rev_id ];
index 8e20d88..2ef9eaf 100644 (file)
@@ -42,7 +42,7 @@ class SpecialProtectedpages extends SpecialPage {
                $request = $this->getRequest();
                $type = $request->getVal( $this->IdType );
                $level = $request->getVal( $this->IdLevel );
-               $sizetype = $request->getVal( 'sizetype' );
+               $sizetype = $request->getVal( 'size-mode' );
                $size = $request->getIntOrNull( 'size' );
                $ns = $request->getIntOrNull( 'namespace' );
                $indefOnly = $request->getBool( 'indefonly' ) ? 1 : 0;
@@ -95,121 +95,57 @@ class SpecialProtectedpages extends SpecialPage {
        protected function showOptions( $namespace, $type = 'edit', $level, $sizetype,
                $size, $indefOnly, $cascadeOnly, $noRedirect
        ) {
-               $title = $this->getPageTitle();
-
-               return Xml::openElement( 'form', [ 'method' => 'get', 'action' => wfScript() ] ) .
-                       Xml::openElement( 'fieldset' ) .
-                       Xml::element( 'legend', [], $this->msg( 'protectedpages' )->text() ) .
-                       Html::hidden( 'title', $title->getPrefixedDBkey() ) . "\n" .
-                       $this->getNamespaceMenu( $namespace ) . "\n" .
-                       $this->getTypeMenu( $type ) . "\n" .
-                       $this->getLevelMenu( $level ) . "\n" .
-                       "<br />\n" .
-                       $this->getExpiryCheck( $indefOnly ) . "\n" .
-                       $this->getCascadeCheck( $cascadeOnly ) . "\n" .
-                       $this->getRedirectCheck( $noRedirect ) . "\n" .
-                       "<br />\n" .
-                       $this->getSizeLimit( $sizetype, $size ) . "\n" .
-                       Xml::submitButton( $this->msg( 'protectedpages-submit' )->text() ) . "\n" .
-                       Xml::closeElement( 'fieldset' ) .
-                       Xml::closeElement( 'form' );
-       }
-
-       /**
-        * Prepare the namespace filter drop-down; standard namespace
-        * selector, sans the MediaWiki namespace
-        *
-        * @param string|null $namespace Pre-select namespace
-        * @return string
-        */
-       protected function getNamespaceMenu( $namespace = null ) {
-               return Html::rawElement( 'span', [ 'class' => 'mw-input-with-label' ],
-                       Html::namespaceSelector(
-                               [
-                                       'selected' => $namespace,
-                                       'all' => '',
-                                       'label' => $this->msg( 'namespace' )->text()
-                               ], [
-                                       'name' => 'namespace',
-                                       'id' => 'namespace',
-                                       'class' => 'namespaceselector',
-                               ]
-                       )
-               );
-       }
-
-       /**
-        * @param bool $indefOnly
-        * @return string Formatted HTML
-        */
-       protected function getExpiryCheck( $indefOnly ) {
-               return '<span class="mw-input-with-label">' . Xml::checkLabel(
-                       $this->msg( 'protectedpages-indef' )->text(),
-                       'indefonly',
-                       'indefonly',
-                       $indefOnly
-               ) . "</span>\n";
-       }
-
-       /**
-        * @param bool $cascadeOnly
-        * @return string Formatted HTML
-        */
-       protected function getCascadeCheck( $cascadeOnly ) {
-               return '<span class="mw-input-with-label">' . Xml::checkLabel(
-                       $this->msg( 'protectedpages-cascade' )->text(),
-                       'cascadeonly',
-                       'cascadeonly',
-                       $cascadeOnly
-               ) . "</span>\n";
-       }
-
-       /**
-        * @param bool $noRedirect
-        * @return string Formatted HTML
-        */
-       protected function getRedirectCheck( $noRedirect ) {
-               return '<span class="mw-input-with-label">' . Xml::checkLabel(
-                       $this->msg( 'protectedpages-noredirect' )->text(),
-                       'noredirect',
-                       'noredirect',
-                       $noRedirect
-               ) . "</span>\n";
-       }
-
-       /**
-        * @param string $sizetype "min" or "max"
-        * @param mixed $size
-        * @return string Formatted HTML
-        */
-       protected function getSizeLimit( $sizetype, $size ) {
-               $max = $sizetype === 'max';
-
-               return '<span class="mw-input-with-label">' . Xml::radioLabel(
-                       $this->msg( 'minimum-size' )->text(),
-                       'sizetype',
-                       'min',
-                       'wpmin',
-                       !$max
-               ) .
-                       ' ' .
-                       Xml::radioLabel(
-                               $this->msg( 'maximum-size' )->text(),
-                               'sizetype',
-                               'max',
-                               'wpmax',
-                               $max
-                       ) .
-                       ' ' .
-                       Xml::input( 'size', 9, $size, [ 'id' => 'wpsize' ] ) .
-                       ' ' .
-                       Xml::label( $this->msg( 'pagesize' )->text(), 'wpsize' ) . "</span>\n";
+               $formDescriptor = [
+                       'namespace' => [
+                               'class' => 'HTMLSelectNamespace',
+                               'name' => 'namespace',
+                               'id' => 'namespace',
+                               'cssclass' => 'namespaceselector',
+                               'selected' => $namespace,
+                               'all' => '',
+                               'label' => $this->msg( 'namespace' )->text(),
+                       ],
+                       'typemenu' => $this->getTypeMenu( $type ),
+                       'levelmenu' => $this->getLevelMenu( $level ),
+                       'expirycheck' => [
+                               'type' => 'check',
+                               'label' => $this->msg( 'protectedpages-indef' )->text(),
+                               'name' => 'indefonly',
+                               'id' => 'indefonly',
+                               'value' => $indefOnly
+                       ],
+                       'cascadecheck' => [
+                               'type' => 'check',
+                               'label' => $this->msg( 'protectedpages-cascade' )->text(),
+                               'name' => 'cascadeonly',
+                               'id' => 'cascadeonly',
+                               'value' => $cascadeOnly
+                       ],
+                       'redirectcheck' => [
+                               'type' => 'check',
+                               'label' => $this->msg( 'protectedpages-noredirect' )->text(),
+                               'name' => 'noredirect',
+                               'id' => 'noredirect',
+                               'value' => $noRedirect,
+                       ],
+                       'sizelimit' => [
+                               'class' => 'HTMLSizeFilterField',
+                               'name' => 'size',
+                       ]
+               ];
+               $htmlForm = new HTMLForm( $formDescriptor, $this->getContext() );
+               $htmlForm
+                       ->setMethod( 'get' )
+                       ->setWrapperLegendMsg( 'protectedpages' )
+                       ->setSubmitText( $this->msg( 'protectedpages-submit' )->text() );
+
+               return $htmlForm->prepareForm()->getHTML( false );
        }
 
        /**
         * Creates the input label of the restriction type
         * @param string $pr_type Protection type
-        * @return string Formatted HTML
+        * @return array
         */
        protected function getTypeMenu( $pr_type ) {
                $m = []; // Temporary array
@@ -224,21 +160,23 @@ class SpecialProtectedpages extends SpecialPage {
 
                // Third pass generates sorted XHTML content
                foreach ( $m as $text => $type ) {
-                       $selected = ( $type == $pr_type );
-                       $options[] = Xml::option( $text, $type, $selected ) . "\n";
+                       $options[$text] = $type;
                }
 
-               return '<span class="mw-input-with-label">' .
-                       Xml::label( $this->msg( 'restriction-type' )->text(), $this->IdType ) . ' ' .
-                       Xml::tags( 'select',
-                               [ 'id' => $this->IdType, 'name' => $this->IdType ],
-                               implode( "\n", $options ) ) . "</span>";
+               return [
+                       'type' => 'select',
+                       'options' => $options,
+                       'value' => $pr_type,
+                       'label' => $this->msg( 'restriction-type' )->text(),
+                       'name' => $this->IdType,
+                       'id' => $this->IdType,
+               ];
        }
 
        /**
         * Creates the input label of the restriction level
         * @param string $pr_level Protection level
-        * @return string Formatted HTML
+        * @return array
         */
        protected function getLevelMenu( $pr_level ) {
                // Temporary array
@@ -256,15 +194,17 @@ class SpecialProtectedpages extends SpecialPage {
 
                // Third pass generates sorted XHTML content
                foreach ( $m as $text => $type ) {
-                       $selected = ( $type == $pr_level );
-                       $options[] = Xml::option( $text, $type, $selected );
+                       $options[$text] = $type;
                }
 
-               return '<span class="mw-input-with-label">' .
-                       Xml::label( $this->msg( 'restriction-level' )->text(), $this->IdLevel ) . ' ' .
-                       Xml::tags( 'select',
-                               [ 'id' => $this->IdLevel, 'name' => $this->IdLevel ],
-                               implode( "\n", $options ) ) . "</span>";
+               return [
+                       'type' => 'select',
+                       'options' => $options,
+                       'value' => $pr_level,
+                       'label' => $this->msg( 'restriction-level' )->text(),
+                       'name' => $this->IdLevel,
+                       'id' => $this->IdLevel
+               ];
        }
 
        protected function getGroupName() {
index 32204f8..3559c99 100644 (file)
@@ -38,7 +38,6 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
 
        private $watchlistFilterGroupDefinition;
 
-       // @codingStandardsIgnoreStart Needed "useless" override to change parameters.
        public function __construct( $name = 'Recentchanges', $restriction = '' ) {
                parent::__construct( $name, $restriction );
 
@@ -134,7 +133,6 @@ class SpecialRecentChanges extends ChangesListSpecialPage {
                        }
                ];
        }
-       // @codingStandardsIgnoreEnd
 
        /**
         * Main execution point
index 9e0daf5..d4aef6c 100644 (file)
@@ -30,8 +30,6 @@ class SpecialRecentChangesLinked extends SpecialRecentChanges {
        /** @var bool|Title */
        protected $rclTargetTitle;
 
-       protected $rclTarget;
-
        function __construct() {
                parent::__construct( 'Recentchangeslinked' );
        }
@@ -46,7 +44,6 @@ class SpecialRecentChangesLinked extends SpecialRecentChanges {
 
        public function parseParameters( $par, FormOptions $opts ) {
                $opts['target'] = $par;
-               $this->rclTarget = $par;
        }
 
        /**
@@ -297,20 +294,6 @@ class SpecialRecentChangesLinked extends SpecialRecentChanges {
                return $this->prefixSearchString( $search, $limit, $offset );
        }
 
-       /**
-        * Get a self-referential title object
-        * with consideration to the given subpage.
-        *
-        * @param string|bool $subpage
-        * @return Title
-        * @since 1.23
-        */
-       public function getPageTitle( $subpage = false ) {
-               $subpage = $subpage ? $subpage : $this->rclTarget;
-
-               return parent::getPageTitle( $subpage );
-       }
-
        protected function outputNoResults() {
                if ( $this->getTargetTitle() === false ) {
                        $this->getOutput()->addHTML(
index 8edebf2..aec21dc 100644 (file)
@@ -388,9 +388,8 @@ class SpecialRevisionDelete extends UnlistedSpecialPage {
                $numRevisions = 0;
                // Live revisions...
                $list = $this->getList();
-               // @codingStandardsIgnoreStart Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $list->reset(); $list->current(); $list->next() ) {
-                       // @codingStandardsIgnoreEnd
                        $item = $list->current();
 
                        if ( !$item->canView() ) {
index 5ff9e04..2dcb77f 100644 (file)
@@ -60,7 +60,7 @@ class UncategorizedCategoriesPage extends UncategorizedPagesPage {
                                        $title = Title::makeTitleSafe( NS_CATEGORY, $titleStr );
                                }
                                if ( $title ) {
-                                       $this->exceptionList[] = $title->getDBKey();
+                                       $this->exceptionList[] = $title->getDBkey();
                                }
                        }
                }
index a5f9ab3..fd066ac 100644 (file)
@@ -761,7 +761,7 @@ class UserrightsPage extends SpecialPage {
        /**
         * Adds a table with checkboxes where you can select what groups to add/remove
         *
-        * @param array $usergroups Associative array of (group name as string =>
+        * @param UserGroupMembership[] $usergroups Associative array of (group name as string =>
         *   UserGroupMembership object) for groups the user belongs to
         * @param User $user
         * @return Array with 2 elements: the XHTML table element with checkxboes, and
index 85faddc..c3fa2b1 100644 (file)
@@ -634,7 +634,7 @@ class ContribsPager extends RangeChronologicalPager {
         * @param array $opts Options array
         * @return array Options array with processed start and end date filter options
         */
-       public static function processDateFilter( $opts ) {
+       public static function processDateFilter( array $opts ) {
                $start = isset( $opts['start'] ) ? $opts['start'] : '';
                $end = isset( $opts['end'] ) ? $opts['end'] : '';
                $year = isset( $opts['year'] ) ? $opts['year'] : '';
index 008573b..d80946a 100644 (file)
@@ -380,16 +380,12 @@ class ImageListPager extends TablePager {
                        }
                }
 
-               // @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();
                }
index 1587abc..af04703 100644 (file)
  * @ingroup Pager
  */
 
-use \MediaWiki\Linker\LinkRenderer;
+use MediaWiki\Linker\LinkRenderer;
 
-/**
- * @todo document
- */
 class ProtectedPagesPager extends TablePager {
+
        public $mForm, $mConds;
        private $type, $level, $namespace, $sizetype, $size, $indefonly, $cascadeonly, $noredirect;
 
index a68fe66..45d9a7f 100644 (file)
@@ -33,7 +33,7 @@
 class UsersPager extends AlphabeticPager {
 
        /**
-        * @var array A array with user ids as key and a array of groups as value
+        * @var array[] A array with user ids as key and a array of groups as value
         */
        protected $userGroupCache;
 
@@ -391,8 +391,8 @@ class UsersPager extends AlphabeticPager {
         * and the relevant UserGroupMembership objects
         *
         * @param int $uid User id
-        * @param array|null $cache
-        * @return array (group name => UserGroupMembership object)
+        * @param array[]|null $cache
+        * @return UserGroupMembership[] (group name => UserGroupMembership object)
         */
        protected static function getGroupMemberships( $uid, $cache = null ) {
                if ( $cache === null ) {
index e570633..fa89c1a 100644 (file)
  * @since 1.27
  * @author C. Scott Ananian, 2016
  */
+
 namespace MediaWiki\Tidy;
 
+use ExplodeIterator;
+use IteratorAggregate;
+use ReverseArrayIterator;
+use Sanitizer;
 use Wikimedia\Assert\Assert;
 use Wikimedia\Assert\ParameterAssertionException;
-use \ExplodeIterator;
-use \IteratorAggregate;
-use \ReverseArrayIterator;
-use \Sanitizer;
 
 // A note for future librarization[1] -- this file is a good candidate
 // for splitting into an independent library, except that it is currently
index f5c8ee0..ddb4bba 100644 (file)
@@ -1663,9 +1663,8 @@ abstract class UploadBase {
                        # image/svg, text/xml, application/xml, and text/html, which can contain scripts
                        if ( $stripped == 'href' && strncasecmp( 'data:', $value, 5 ) === 0 ) {
                                // rfc2397 parameters. This is only slightly slower than (;[\w;]+)*.
-                               // @codingStandardsIgnoreStart Generic.Files.LineLength
+                               // phpcs:ignore Generic.Files.LineLength
                                $parameters = '(?>;[a-zA-Z0-9\!#$&\'*+.^_`{|}~-]+=(?>[a-zA-Z0-9\!#$&\'*+.^_`{|}~-]+|"(?>[\0-\x0c\x0e-\x21\x23-\x5b\x5d-\x7f]+|\\\\[\0-\x7f])*"))*(?:;base64)?';
-                               // @codingStandardsIgnoreEnd
 
                                if ( !preg_match( "!^data:\s*image/(gif|jpeg|jpg|png)$parameters,!i", $value ) ) {
                                        wfDebug( __METHOD__ . ": Found href to unwhitelisted data: uri "
index a4dfb2b..0d8ef89 100644 (file)
@@ -234,7 +234,7 @@ class User implements IDBAccessObject, UserIdentity {
         * @deprecated since 1.29
         */
        private $mGroups;
-       /** @var array Associative array of (group name => UserGroupMembership object) */
+       /** @var UserGroupMembership[] Associative array of (group name => UserGroupMembership object) */
        protected $mGroupMemberships;
        /** @var array */
        protected $mOptionOverrides;
@@ -3317,7 +3317,7 @@ class User implements IDBAccessObject, UserIdentity {
         * Get the list of explicit group memberships this user has, stored as
         * UserGroupMembership objects. Implicit groups are not included.
         *
-        * @return array Associative array of (group name as string => UserGroupMembership object)
+        * @return UserGroupMembership[] Associative array of (group name => UserGroupMembership object)
         * @since 1.29
         */
        public function getGroupMemberships() {
index a06be83..f771f42 100644 (file)
@@ -276,7 +276,7 @@ class UserGroupMembership {
         *
         * @param int $userId ID of the user to search for
         * @param IDatabase|null $db Optional database connection
-        * @return array Associative array of (group name => UserGroupMembership object)
+        * @return UserGroupMembership[] Associative array of (group name => UserGroupMembership object)
         */
        public static function getMembershipsForUser( $userId, IDatabase $db = null ) {
                if ( !$db ) {
index d12531b..a6783b0 100644 (file)
@@ -236,11 +236,10 @@ class AutoloadGenerator {
                }
 
                $output = implode( "\n\t", $content );
-               return
-                       <<<EOD
+               return <<<EOD
 <?php
 // This file is generated by $commandName, do not adjust manually
-// @codingStandardsIgnoreFile
+// phpcs:ignoreFile Generic.Files.LineLength
 global \${$this->variableName};
 
 \${$this->variableName} {$op} [
index 59dcbd6..c146e96 100644 (file)
@@ -20,8 +20,9 @@
  * @file
  * @ingroup Maintenance
  */
+
+use MediaWiki\MediaWikiServices;
 use Wikimedia\Rdbms\IDatabase;
-use \MediaWiki\MediaWikiServices;
 
 class BatchRowWriter {
        /**
index d3ada03..1d83f51 100644 (file)
@@ -51,7 +51,6 @@ class ComplexNamespaceInputWidget extends \OOUI\Widget {
                        $config
                );
 
-               // Parent constructor
                parent::__construct( $config );
 
                // Properties
index a9e8042..912537a 100644 (file)
@@ -33,7 +33,6 @@ class ComplexTitleInputWidget extends \OOUI\Widget {
                        $config
                );
 
-               // Parent constructor
                parent::__construct( $config );
 
                // Properties
index 507dab6..b516331 100644 (file)
@@ -109,7 +109,6 @@ class DateInputWidget extends \OOUI\TextInputWidget {
                        'placeholder' => $placeholder,
                ], $config );
 
-               // Parent constructor
                parent::__construct( $config );
 
                // Calculate min/max attributes (which are skipped by TextInputWidget) and add to <input>
index f0d5cdb..4c41212 100644 (file)
@@ -34,7 +34,6 @@ class DateTimeInputWidget extends \OOUI\InputWidget {
                        throw new \InvalidArgumentException( '$config[\'type\'] must be specified' );
                }
 
-               // Parent constructor
                parent::__construct( $config );
 
                // Properties, which are ignored in PHP and just shipped back to JS
index 3e913b0..5fdc710 100644 (file)
@@ -24,7 +24,6 @@ class NamespaceInputWidget extends \OOUI\DropdownInputWidget {
                // Configuration initialization
                $config['options'] = $this->getNamespaceDropdownOptions( $config );
 
-               // Parent constructor
                parent::__construct( $config );
 
                // Properties
index 773c291..70b0dcc 100644 (file)
@@ -34,7 +34,6 @@ class SearchInputWidget extends TitleInputWidget {
                        'icon' => 'search',
                ], $config );
 
-               // Parent constructor
                parent::__construct( $config );
 
                // Properties, which are ignored in PHP and just shipped back to JS
index d2dda75..3abfbd0 100644 (file)
@@ -38,7 +38,6 @@ class SelectWithInputWidget extends \OOUI\Widget {
                        $config
                );
 
-               // Parent constructor
                parent::__construct( $config );
 
                // Properties
index da2e94b..a29c3dc 100644 (file)
@@ -30,7 +30,6 @@ class TitleInputWidget extends \OOUI\TextInputWidget {
         *  be a valid title (default: true)
         */
        public function __construct( array $config = [] ) {
-               // Parent constructor
                parent::__construct(
                        array_merge( [ 'maxLength' => 255 ], $config )
                );
index d591ad1..a058ab6 100644 (file)
@@ -16,7 +16,6 @@ class UserInputWidget extends \OOUI\TextInputWidget {
         * @param array $config Configuration options
         */
        public function __construct( array $config = [] ) {
-               // Parent constructor
                parent::__construct( $config );
 
                // Initialization
index bf59fe9..e236640 100644 (file)
@@ -107,10 +107,9 @@ class BasicSearchResultSetWidget {
         * @return string HTML
         */
        protected function header( Message $msg ) {
-               return
-                       "<h2>" .
-                               "<span class='mw-headline'>" . $msg->escaped() . "</span>" .
-                       "</h2>";
+               return "<h2>" .
+                       "<span class='mw-headline'>" . $msg->escaped() . "</span>" .
+               "</h2>";
        }
 
        /**
index 008ed19..2c88563 100644 (file)
@@ -153,10 +153,9 @@ class SearchFormWidget {
                        );
                }
 
-               return
-                               "<div class='search-types'>" .
-                                       "<ul>" . implode( '', $items ) . "</ul>" .
-                               "</div>";
+               return "<div class='search-types'>" .
+                       "<ul>" . implode( '', $items ) . "</ul>" .
+               "</div>";
        }
 
        /**
@@ -298,19 +297,18 @@ class SearchFormWidget {
                        );
                }
 
-               return
-                       "<fieldset id='mw-searchoptions'>" .
-                               "<legend>" . $this->specialSearch->msg( 'powersearch-legend' )->escaped() . '</legend>' .
-                               "<h4>" . $this->specialSearch->msg( 'powersearch-ns' )->parse() . '</h4>' .
-                               // populated by js if available
-                               "<div id='mw-search-togglebox'></div>" .
-                               $divider .
-                               implode(
-                                       $divider,
-                                       $showSections
-                               ) .
-                               $hidden .
-                               $remember .
-                       "</fieldset>";
+               return "<fieldset id='mw-searchoptions'>" .
+                       "<legend>" . $this->specialSearch->msg( 'powersearch-legend' )->escaped() . '</legend>' .
+                       "<h4>" . $this->specialSearch->msg( 'powersearch-ns' )->parse() . '</h4>' .
+                       // populated by js if available
+                       "<div id='mw-search-togglebox'></div>" .
+                       $divider .
+                       implode(
+                               $divider,
+                               $showSections
+                       ) .
+                       $hidden .
+                       $remember .
+               "</fieldset>";
        }
 }
index 4df2eb5..d6583a3 100644 (file)
@@ -74,13 +74,12 @@ class SimpleSearchResultSetWidget implements SearchResultSetWidget {
                        $out .= "</ul>";
                }
 
-               return
-                       "<div id='mw-search-interwiki'>" .
-                               "<div id='mw-search-interwiki-caption'>" .
-                                       $this->specialSearch->msg( 'search-interwiki-caption' )->parse() .
-                               '</div>' .
-                               $out .
-                       "</div>";
+               return "<div id='mw-search-interwiki'>" .
+                       "<div id='mw-search-interwiki-caption'>" .
+                               $this->specialSearch->msg( 'search-interwiki-caption' )->parse() .
+                       '</div>' .
+                       $out .
+               "</div>";
        }
 
        /**
@@ -108,10 +107,9 @@ class SimpleSearchResultSetWidget implements SearchResultSetWidget {
                        $this->specialSearch->msg( 'search-interwiki-more' )->escaped()
                );
 
-               return
-                       "<div class='mw-search-interwiki-project'>" .
-                               "<span class='mw-search-interwiki-more'>{$searchLink}</span>" .
-                               $caption .
+               return "<div class='mw-search-interwiki-project'>" .
+                       "<span class='mw-search-interwiki-more'>{$searchLink}</span>" .
+                       $caption .
                "</div>";
        }
 
index 743f77b..791ffb1 100644 (file)
--- a/index.php
+++ b/index.php
@@ -32,9 +32,8 @@
 
 // Bail on old versions of PHP, or if composer has not been run yet to install
 // dependencies. Using dirname( __FILE__ ) here because __DIR__ is PHP5.3+.
-// @codingStandardsIgnoreStart MediaWiki.Usage.DirUsage.FunctionFound
+// phpcs:ignore MediaWiki.Usage.DirUsage.FunctionFound
 require_once dirname( __FILE__ ) . '/includes/PHPVersionCheck.php';
-// @codingStandardsIgnoreEnd
 wfEntryPointCheck( 'index.php' );
 
 require __DIR__ . '/includes/WebStart.php';
index 467dc78..fdf2d05 100644 (file)
@@ -169,11 +169,10 @@ class Language {
         * Generated by UnicodeJS (see tools/strongDir) from the UCD; see
         * https://phabricator.wikimedia.org/diffusion/GUJS/ .
         */
-       // @codingStandardsIgnoreStart
        // @codeCoverageIgnoreStart
+       // phpcs:ignore Generic.Files.LineLength
        static private $strongDirRegex = '/(?:([\x{41}-\x{5a}\x{61}-\x{7a}\x{aa}\x{b5}\x{ba}\x{c0}-\x{d6}\x{d8}-\x{f6}\x{f8}-\x{2b8}\x{2bb}-\x{2c1}\x{2d0}\x{2d1}\x{2e0}-\x{2e4}\x{2ee}\x{370}-\x{373}\x{376}\x{377}\x{37a}-\x{37d}\x{37f}\x{386}\x{388}-\x{38a}\x{38c}\x{38e}-\x{3a1}\x{3a3}-\x{3f5}\x{3f7}-\x{482}\x{48a}-\x{52f}\x{531}-\x{556}\x{559}-\x{55f}\x{561}-\x{587}\x{589}\x{903}-\x{939}\x{93b}\x{93d}-\x{940}\x{949}-\x{94c}\x{94e}-\x{950}\x{958}-\x{961}\x{964}-\x{980}\x{982}\x{983}\x{985}-\x{98c}\x{98f}\x{990}\x{993}-\x{9a8}\x{9aa}-\x{9b0}\x{9b2}\x{9b6}-\x{9b9}\x{9bd}-\x{9c0}\x{9c7}\x{9c8}\x{9cb}\x{9cc}\x{9ce}\x{9d7}\x{9dc}\x{9dd}\x{9df}-\x{9e1}\x{9e6}-\x{9f1}\x{9f4}-\x{9fa}\x{a03}\x{a05}-\x{a0a}\x{a0f}\x{a10}\x{a13}-\x{a28}\x{a2a}-\x{a30}\x{a32}\x{a33}\x{a35}\x{a36}\x{a38}\x{a39}\x{a3e}-\x{a40}\x{a59}-\x{a5c}\x{a5e}\x{a66}-\x{a6f}\x{a72}-\x{a74}\x{a83}\x{a85}-\x{a8d}\x{a8f}-\x{a91}\x{a93}-\x{aa8}\x{aaa}-\x{ab0}\x{ab2}\x{ab3}\x{ab5}-\x{ab9}\x{abd}-\x{ac0}\x{ac9}\x{acb}\x{acc}\x{ad0}\x{ae0}\x{ae1}\x{ae6}-\x{af0}\x{af9}\x{b02}\x{b03}\x{b05}-\x{b0c}\x{b0f}\x{b10}\x{b13}-\x{b28}\x{b2a}-\x{b30}\x{b32}\x{b33}\x{b35}-\x{b39}\x{b3d}\x{b3e}\x{b40}\x{b47}\x{b48}\x{b4b}\x{b4c}\x{b57}\x{b5c}\x{b5d}\x{b5f}-\x{b61}\x{b66}-\x{b77}\x{b83}\x{b85}-\x{b8a}\x{b8e}-\x{b90}\x{b92}-\x{b95}\x{b99}\x{b9a}\x{b9c}\x{b9e}\x{b9f}\x{ba3}\x{ba4}\x{ba8}-\x{baa}\x{bae}-\x{bb9}\x{bbe}\x{bbf}\x{bc1}\x{bc2}\x{bc6}-\x{bc8}\x{bca}-\x{bcc}\x{bd0}\x{bd7}\x{be6}-\x{bf2}\x{c01}-\x{c03}\x{c05}-\x{c0c}\x{c0e}-\x{c10}\x{c12}-\x{c28}\x{c2a}-\x{c39}\x{c3d}\x{c41}-\x{c44}\x{c58}-\x{c5a}\x{c60}\x{c61}\x{c66}-\x{c6f}\x{c7f}\x{c82}\x{c83}\x{c85}-\x{c8c}\x{c8e}-\x{c90}\x{c92}-\x{ca8}\x{caa}-\x{cb3}\x{cb5}-\x{cb9}\x{cbd}-\x{cc4}\x{cc6}-\x{cc8}\x{cca}\x{ccb}\x{cd5}\x{cd6}\x{cde}\x{ce0}\x{ce1}\x{ce6}-\x{cef}\x{cf1}\x{cf2}\x{d02}\x{d03}\x{d05}-\x{d0c}\x{d0e}-\x{d10}\x{d12}-\x{d3a}\x{d3d}-\x{d40}\x{d46}-\x{d48}\x{d4a}-\x{d4c}\x{d4e}\x{d57}\x{d5f}-\x{d61}\x{d66}-\x{d75}\x{d79}-\x{d7f}\x{d82}\x{d83}\x{d85}-\x{d96}\x{d9a}-\x{db1}\x{db3}-\x{dbb}\x{dbd}\x{dc0}-\x{dc6}\x{dcf}-\x{dd1}\x{dd8}-\x{ddf}\x{de6}-\x{def}\x{df2}-\x{df4}\x{e01}-\x{e30}\x{e32}\x{e33}\x{e40}-\x{e46}\x{e4f}-\x{e5b}\x{e81}\x{e82}\x{e84}\x{e87}\x{e88}\x{e8a}\x{e8d}\x{e94}-\x{e97}\x{e99}-\x{e9f}\x{ea1}-\x{ea3}\x{ea5}\x{ea7}\x{eaa}\x{eab}\x{ead}-\x{eb0}\x{eb2}\x{eb3}\x{ebd}\x{ec0}-\x{ec4}\x{ec6}\x{ed0}-\x{ed9}\x{edc}-\x{edf}\x{f00}-\x{f17}\x{f1a}-\x{f34}\x{f36}\x{f38}\x{f3e}-\x{f47}\x{f49}-\x{f6c}\x{f7f}\x{f85}\x{f88}-\x{f8c}\x{fbe}-\x{fc5}\x{fc7}-\x{fcc}\x{fce}-\x{fda}\x{1000}-\x{102c}\x{1031}\x{1038}\x{103b}\x{103c}\x{103f}-\x{1057}\x{105a}-\x{105d}\x{1061}-\x{1070}\x{1075}-\x{1081}\x{1083}\x{1084}\x{1087}-\x{108c}\x{108e}-\x{109c}\x{109e}-\x{10c5}\x{10c7}\x{10cd}\x{10d0}-\x{1248}\x{124a}-\x{124d}\x{1250}-\x{1256}\x{1258}\x{125a}-\x{125d}\x{1260}-\x{1288}\x{128a}-\x{128d}\x{1290}-\x{12b0}\x{12b2}-\x{12b5}\x{12b8}-\x{12be}\x{12c0}\x{12c2}-\x{12c5}\x{12c8}-\x{12d6}\x{12d8}-\x{1310}\x{1312}-\x{1315}\x{1318}-\x{135a}\x{1360}-\x{137c}\x{1380}-\x{138f}\x{13a0}-\x{13f5}\x{13f8}-\x{13fd}\x{1401}-\x{167f}\x{1681}-\x{169a}\x{16a0}-\x{16f8}\x{1700}-\x{170c}\x{170e}-\x{1711}\x{1720}-\x{1731}\x{1735}\x{1736}\x{1740}-\x{1751}\x{1760}-\x{176c}\x{176e}-\x{1770}\x{1780}-\x{17b3}\x{17b6}\x{17be}-\x{17c5}\x{17c7}\x{17c8}\x{17d4}-\x{17da}\x{17dc}\x{17e0}-\x{17e9}\x{1810}-\x{1819}\x{1820}-\x{1877}\x{1880}-\x{18a8}\x{18aa}\x{18b0}-\x{18f5}\x{1900}-\x{191e}\x{1923}-\x{1926}\x{1929}-\x{192b}\x{1930}\x{1931}\x{1933}-\x{1938}\x{1946}-\x{196d}\x{1970}-\x{1974}\x{1980}-\x{19ab}\x{19b0}-\x{19c9}\x{19d0}-\x{19da}\x{1a00}-\x{1a16}\x{1a19}\x{1a1a}\x{1a1e}-\x{1a55}\x{1a57}\x{1a61}\x{1a63}\x{1a64}\x{1a6d}-\x{1a72}\x{1a80}-\x{1a89}\x{1a90}-\x{1a99}\x{1aa0}-\x{1aad}\x{1b04}-\x{1b33}\x{1b35}\x{1b3b}\x{1b3d}-\x{1b41}\x{1b43}-\x{1b4b}\x{1b50}-\x{1b6a}\x{1b74}-\x{1b7c}\x{1b82}-\x{1ba1}\x{1ba6}\x{1ba7}\x{1baa}\x{1bae}-\x{1be5}\x{1be7}\x{1bea}-\x{1bec}\x{1bee}\x{1bf2}\x{1bf3}\x{1bfc}-\x{1c2b}\x{1c34}\x{1c35}\x{1c3b}-\x{1c49}\x{1c4d}-\x{1c7f}\x{1cc0}-\x{1cc7}\x{1cd3}\x{1ce1}\x{1ce9}-\x{1cec}\x{1cee}-\x{1cf3}\x{1cf5}\x{1cf6}\x{1d00}-\x{1dbf}\x{1e00}-\x{1f15}\x{1f18}-\x{1f1d}\x{1f20}-\x{1f45}\x{1f48}-\x{1f4d}\x{1f50}-\x{1f57}\x{1f59}\x{1f5b}\x{1f5d}\x{1f5f}-\x{1f7d}\x{1f80}-\x{1fb4}\x{1fb6}-\x{1fbc}\x{1fbe}\x{1fc2}-\x{1fc4}\x{1fc6}-\x{1fcc}\x{1fd0}-\x{1fd3}\x{1fd6}-\x{1fdb}\x{1fe0}-\x{1fec}\x{1ff2}-\x{1ff4}\x{1ff6}-\x{1ffc}\x{200e}\x{2071}\x{207f}\x{2090}-\x{209c}\x{2102}\x{2107}\x{210a}-\x{2113}\x{2115}\x{2119}-\x{211d}\x{2124}\x{2126}\x{2128}\x{212a}-\x{212d}\x{212f}-\x{2139}\x{213c}-\x{213f}\x{2145}-\x{2149}\x{214e}\x{214f}\x{2160}-\x{2188}\x{2336}-\x{237a}\x{2395}\x{249c}-\x{24e9}\x{26ac}\x{2800}-\x{28ff}\x{2c00}-\x{2c2e}\x{2c30}-\x{2c5e}\x{2c60}-\x{2ce4}\x{2ceb}-\x{2cee}\x{2cf2}\x{2cf3}\x{2d00}-\x{2d25}\x{2d27}\x{2d2d}\x{2d30}-\x{2d67}\x{2d6f}\x{2d70}\x{2d80}-\x{2d96}\x{2da0}-\x{2da6}\x{2da8}-\x{2dae}\x{2db0}-\x{2db6}\x{2db8}-\x{2dbe}\x{2dc0}-\x{2dc6}\x{2dc8}-\x{2dce}\x{2dd0}-\x{2dd6}\x{2dd8}-\x{2dde}\x{3005}-\x{3007}\x{3021}-\x{3029}\x{302e}\x{302f}\x{3031}-\x{3035}\x{3038}-\x{303c}\x{3041}-\x{3096}\x{309d}-\x{309f}\x{30a1}-\x{30fa}\x{30fc}-\x{30ff}\x{3105}-\x{312d}\x{3131}-\x{318e}\x{3190}-\x{31ba}\x{31f0}-\x{321c}\x{3220}-\x{324f}\x{3260}-\x{327b}\x{327f}-\x{32b0}\x{32c0}-\x{32cb}\x{32d0}-\x{32fe}\x{3300}-\x{3376}\x{337b}-\x{33dd}\x{33e0}-\x{33fe}\x{3400}-\x{4db5}\x{4e00}-\x{9fd5}\x{a000}-\x{a48c}\x{a4d0}-\x{a60c}\x{a610}-\x{a62b}\x{a640}-\x{a66e}\x{a680}-\x{a69d}\x{a6a0}-\x{a6ef}\x{a6f2}-\x{a6f7}\x{a722}-\x{a787}\x{a789}-\x{a7ad}\x{a7b0}-\x{a7b7}\x{a7f7}-\x{a801}\x{a803}-\x{a805}\x{a807}-\x{a80a}\x{a80c}-\x{a824}\x{a827}\x{a830}-\x{a837}\x{a840}-\x{a873}\x{a880}-\x{a8c3}\x{a8ce}-\x{a8d9}\x{a8f2}-\x{a8fd}\x{a900}-\x{a925}\x{a92e}-\x{a946}\x{a952}\x{a953}\x{a95f}-\x{a97c}\x{a983}-\x{a9b2}\x{a9b4}\x{a9b5}\x{a9ba}\x{a9bb}\x{a9bd}-\x{a9cd}\x{a9cf}-\x{a9d9}\x{a9de}-\x{a9e4}\x{a9e6}-\x{a9fe}\x{aa00}-\x{aa28}\x{aa2f}\x{aa30}\x{aa33}\x{aa34}\x{aa40}-\x{aa42}\x{aa44}-\x{aa4b}\x{aa4d}\x{aa50}-\x{aa59}\x{aa5c}-\x{aa7b}\x{aa7d}-\x{aaaf}\x{aab1}\x{aab5}\x{aab6}\x{aab9}-\x{aabd}\x{aac0}\x{aac2}\x{aadb}-\x{aaeb}\x{aaee}-\x{aaf5}\x{ab01}-\x{ab06}\x{ab09}-\x{ab0e}\x{ab11}-\x{ab16}\x{ab20}-\x{ab26}\x{ab28}-\x{ab2e}\x{ab30}-\x{ab65}\x{ab70}-\x{abe4}\x{abe6}\x{abe7}\x{abe9}-\x{abec}\x{abf0}-\x{abf9}\x{ac00}-\x{d7a3}\x{d7b0}-\x{d7c6}\x{d7cb}-\x{d7fb}\x{e000}-\x{fa6d}\x{fa70}-\x{fad9}\x{fb00}-\x{fb06}\x{fb13}-\x{fb17}\x{ff21}-\x{ff3a}\x{ff41}-\x{ff5a}\x{ff66}-\x{ffbe}\x{ffc2}-\x{ffc7}\x{ffca}-\x{ffcf}\x{ffd2}-\x{ffd7}\x{ffda}-\x{ffdc}\x{10000}-\x{1000b}\x{1000d}-\x{10026}\x{10028}-\x{1003a}\x{1003c}\x{1003d}\x{1003f}-\x{1004d}\x{10050}-\x{1005d}\x{10080}-\x{100fa}\x{10100}\x{10102}\x{10107}-\x{10133}\x{10137}-\x{1013f}\x{101d0}-\x{101fc}\x{10280}-\x{1029c}\x{102a0}-\x{102d0}\x{10300}-\x{10323}\x{10330}-\x{1034a}\x{10350}-\x{10375}\x{10380}-\x{1039d}\x{1039f}-\x{103c3}\x{103c8}-\x{103d5}\x{10400}-\x{1049d}\x{104a0}-\x{104a9}\x{10500}-\x{10527}\x{10530}-\x{10563}\x{1056f}\x{10600}-\x{10736}\x{10740}-\x{10755}\x{10760}-\x{10767}\x{11000}\x{11002}-\x{11037}\x{11047}-\x{1104d}\x{11066}-\x{1106f}\x{11082}-\x{110b2}\x{110b7}\x{110b8}\x{110bb}-\x{110c1}\x{110d0}-\x{110e8}\x{110f0}-\x{110f9}\x{11103}-\x{11126}\x{1112c}\x{11136}-\x{11143}\x{11150}-\x{11172}\x{11174}-\x{11176}\x{11182}-\x{111b5}\x{111bf}-\x{111c9}\x{111cd}\x{111d0}-\x{111df}\x{111e1}-\x{111f4}\x{11200}-\x{11211}\x{11213}-\x{1122e}\x{11232}\x{11233}\x{11235}\x{11238}-\x{1123d}\x{11280}-\x{11286}\x{11288}\x{1128a}-\x{1128d}\x{1128f}-\x{1129d}\x{1129f}-\x{112a9}\x{112b0}-\x{112de}\x{112e0}-\x{112e2}\x{112f0}-\x{112f9}\x{11302}\x{11303}\x{11305}-\x{1130c}\x{1130f}\x{11310}\x{11313}-\x{11328}\x{1132a}-\x{11330}\x{11332}\x{11333}\x{11335}-\x{11339}\x{1133d}-\x{1133f}\x{11341}-\x{11344}\x{11347}\x{11348}\x{1134b}-\x{1134d}\x{11350}\x{11357}\x{1135d}-\x{11363}\x{11480}-\x{114b2}\x{114b9}\x{114bb}-\x{114be}\x{114c1}\x{114c4}-\x{114c7}\x{114d0}-\x{114d9}\x{11580}-\x{115b1}\x{115b8}-\x{115bb}\x{115be}\x{115c1}-\x{115db}\x{11600}-\x{11632}\x{1163b}\x{1163c}\x{1163e}\x{11641}-\x{11644}\x{11650}-\x{11659}\x{11680}-\x{116aa}\x{116ac}\x{116ae}\x{116af}\x{116b6}\x{116c0}-\x{116c9}\x{11700}-\x{11719}\x{11720}\x{11721}\x{11726}\x{11730}-\x{1173f}\x{118a0}-\x{118f2}\x{118ff}\x{11ac0}-\x{11af8}\x{12000}-\x{12399}\x{12400}-\x{1246e}\x{12470}-\x{12474}\x{12480}-\x{12543}\x{13000}-\x{1342e}\x{14400}-\x{14646}\x{16800}-\x{16a38}\x{16a40}-\x{16a5e}\x{16a60}-\x{16a69}\x{16a6e}\x{16a6f}\x{16ad0}-\x{16aed}\x{16af5}\x{16b00}-\x{16b2f}\x{16b37}-\x{16b45}\x{16b50}-\x{16b59}\x{16b5b}-\x{16b61}\x{16b63}-\x{16b77}\x{16b7d}-\x{16b8f}\x{16f00}-\x{16f44}\x{16f50}-\x{16f7e}\x{16f93}-\x{16f9f}\x{1b000}\x{1b001}\x{1bc00}-\x{1bc6a}\x{1bc70}-\x{1bc7c}\x{1bc80}-\x{1bc88}\x{1bc90}-\x{1bc99}\x{1bc9c}\x{1bc9f}\x{1d000}-\x{1d0f5}\x{1d100}-\x{1d126}\x{1d129}-\x{1d166}\x{1d16a}-\x{1d172}\x{1d183}\x{1d184}\x{1d18c}-\x{1d1a9}\x{1d1ae}-\x{1d1e8}\x{1d360}-\x{1d371}\x{1d400}-\x{1d454}\x{1d456}-\x{1d49c}\x{1d49e}\x{1d49f}\x{1d4a2}\x{1d4a5}\x{1d4a6}\x{1d4a9}-\x{1d4ac}\x{1d4ae}-\x{1d4b9}\x{1d4bb}\x{1d4bd}-\x{1d4c3}\x{1d4c5}-\x{1d505}\x{1d507}-\x{1d50a}\x{1d50d}-\x{1d514}\x{1d516}-\x{1d51c}\x{1d51e}-\x{1d539}\x{1d53b}-\x{1d53e}\x{1d540}-\x{1d544}\x{1d546}\x{1d54a}-\x{1d550}\x{1d552}-\x{1d6a5}\x{1d6a8}-\x{1d6da}\x{1d6dc}-\x{1d714}\x{1d716}-\x{1d74e}\x{1d750}-\x{1d788}\x{1d78a}-\x{1d7c2}\x{1d7c4}-\x{1d7cb}\x{1d800}-\x{1d9ff}\x{1da37}-\x{1da3a}\x{1da6d}-\x{1da74}\x{1da76}-\x{1da83}\x{1da85}-\x{1da8b}\x{1f110}-\x{1f12e}\x{1f130}-\x{1f169}\x{1f170}-\x{1f19a}\x{1f1e6}-\x{1f202}\x{1f210}-\x{1f23a}\x{1f240}-\x{1f248}\x{1f250}\x{1f251}\x{20000}-\x{2a6d6}\x{2a700}-\x{2b734}\x{2b740}-\x{2b81d}\x{2b820}-\x{2cea1}\x{2f800}-\x{2fa1d}\x{f0000}-\x{ffffd}\x{100000}-\x{10fffd}])|([\x{590}\x{5be}\x{5c0}\x{5c3}\x{5c6}\x{5c8}-\x{5ff}\x{7c0}-\x{7ea}\x{7f4}\x{7f5}\x{7fa}-\x{815}\x{81a}\x{824}\x{828}\x{82e}-\x{858}\x{85c}-\x{89f}\x{200f}\x{fb1d}\x{fb1f}-\x{fb28}\x{fb2a}-\x{fb4f}\x{10800}-\x{1091e}\x{10920}-\x{10a00}\x{10a04}\x{10a07}-\x{10a0b}\x{10a10}-\x{10a37}\x{10a3b}-\x{10a3e}\x{10a40}-\x{10ae4}\x{10ae7}-\x{10b38}\x{10b40}-\x{10e5f}\x{10e7f}-\x{10fff}\x{1e800}-\x{1e8cf}\x{1e8d7}-\x{1edff}\x{1ef00}-\x{1efff}\x{608}\x{60b}\x{60d}\x{61b}-\x{64a}\x{66d}-\x{66f}\x{671}-\x{6d5}\x{6e5}\x{6e6}\x{6ee}\x{6ef}\x{6fa}-\x{710}\x{712}-\x{72f}\x{74b}-\x{7a5}\x{7b1}-\x{7bf}\x{8a0}-\x{8e2}\x{fb50}-\x{fd3d}\x{fd40}-\x{fdcf}\x{fdf0}-\x{fdfc}\x{fdfe}\x{fdff}\x{fe70}-\x{fefe}\x{1ee00}-\x{1eeef}\x{1eef2}-\x{1eeff}]))/u';
        // @codeCoverageIgnoreEnd
-       // @codingStandardsIgnoreEnd
 
        /**
         * Get a cached or new language object for a given language code
@@ -3314,12 +3313,25 @@ class Language {
         */
        function commafy( $number ) {
                $digitGroupingPattern = $this->digitGroupingPattern();
+               $minimumGroupingDigits = $this->minimumGroupingDigits();
                if ( $number === null ) {
                        return '';
                }
 
                if ( !$digitGroupingPattern || $digitGroupingPattern === "###,###,###" ) {
-                       // default grouping is at thousands,  use the same for ###,###,### pattern too.
+                       // Default grouping is at thousands, use the same for ###,###,### pattern too.
+                       // In some languages it's conventional not to insert a thousands separator
+                       // in numbers that are four digits long (1000-9999).
+                       if ( $minimumGroupingDigits ) {
+                               // Number of '#' characters after last comma in the grouping pattern.
+                               // The pattern is hardcoded here, but this would vary for different patterns.
+                               $primaryGroupingSize = 3;
+                               // Maximum length of a number to suppress digit grouping for.
+                               $maximumLength = $minimumGroupingDigits + $primaryGroupingSize - 1;
+                               if ( preg_match( '/^\-?\d{1,' . $maximumLength . '}(\.\d+)?$/', $number ) ) {
+                                       return $number;
+                               }
+                       }
                        return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $number ) ) );
                } else {
                        // Ref: http://cldr.unicode.org/translation/number-patterns
@@ -3382,6 +3394,13 @@ class Language {
                return self::$dataCache->getItem( $this->mCode, 'separatorTransformTable' );
        }
 
+       /**
+        * @return int|null
+        */
+       function minimumGroupingDigits() {
+               return self::$dataCache->getItem( $this->mCode, 'minimumGroupingDigits' );
+       }
+
        /**
         * Take a list of strings and build a locale-friendly comma-separated
         * list, using the local comma-separator message.
@@ -4732,8 +4751,7 @@ class Language {
                }
 
                $dirmark = ( $oppositedm ? $this->getDirMark( true ) : '' ) . $this->getDirMark();
-               return
-                       $page .
+               return $page .
                        $dirmark .
                        $this->msg( 'word-separator' )->escaped() .
                        $this->msg( 'parentheses' )->rawParams( $details )->escaped();
index a84c4b8..f9631a1 100644 (file)
@@ -680,9 +680,8 @@ class LanguageConverter {
 
                $noScript = '<script.*?>.*?<\/script>(*SKIP)(*FAIL)';
                $noStyle = '<style.*?>.*?<\/style>(*SKIP)(*FAIL)';
-               // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
+               // phpcs:ignore Generic.Files.LineLength
                $noHtml = '<(?:[^>=]*+(?>[^>=]*+=\s*+(?:"[^"]*"|\'[^\']*\'|[^\'">\s]*+))*+[^>=]*+>|.*+)(*SKIP)(*FAIL)';
-               // @codingStandardsIgnoreEnd
                while ( $startPos < $length && $continue ) {
                        $continue = preg_match(
                                // Only match -{ outside of html.
index 6007bb4..1f9b767 100644 (file)
@@ -30,9 +30,8 @@
  * @ingroup Language
  * @see http://be-x-old.wikipedia.org/wiki/Project_talk:LanguageBe_tarask.php
  */
-// @codingStandardsIgnoreStart Ignore class name is not in camel caps format error
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class LanguageBe_tarask extends Language {
-       // @codingStandardsIgnoreEnd
        /**
         * The Belarusian language uses apostrophe sign,
         * but the characters used for this could be both U+0027 and U+2019.
@@ -54,20 +53,4 @@ class LanguageBe_tarask extends Language {
 
                return $s;
        }
-
-       /**
-        * Four-digit number should be without group commas (spaces)
-        * So "1 234 567", "12 345" but "1234"
-        *
-        * @param string $_
-        *
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( preg_match( '/^-?\d{1,4}(\.\d*)?$/', $_ ) ) {
-                       return $_;
-               } else {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               }
-       }
 }
diff --git a/languages/classes/LanguageBg.php b/languages/classes/LanguageBg.php
deleted file mode 100644 (file)
index a592d02..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<?php
-/**
- * Bulgarian (Български) specific code.
- *
- * 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 Language
- */
-
-/**
- * Bulgarian (Български)
- *
- * @ingroup Language
- */
-class LanguageBg extends Language {
-       /**
-        * ISO number formatting: 123 456 789,99.
-        * Avoid tripple grouping by numbers with whole part up to 4 digits.
-        *
-        * @param string $_
-        *
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               } else {
-                       return $_;
-               }
-       }
-}
diff --git a/languages/classes/LanguageEs.php b/languages/classes/LanguageEs.php
deleted file mode 100644 (file)
index 098148f..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-/**
- * Spanish (español) specific code.
- *
- * 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 Language
- */
-
-/**
- * Spanish (español)
- *
- * @ingroup Language
- */
-class LanguageEs extends Language {
-
-       /**
-        * @param string $_
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( !preg_match( '/^-?\d{1,4}(\.\d+)?$/', $_ ) ) {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               } else {
-                       return $_;
-               }
-       }
-}
diff --git a/languages/classes/LanguageEt.php b/languages/classes/LanguageEt.php
deleted file mode 100644 (file)
index 759531b..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<?php
-/**
- * Estonian (eesti) specific code.
- *
- * 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 Language
- */
-
-/**
- * Estonian (eesti)
- *
- * @ingroup Language
- */
-class LanguageEt extends Language {
-       /**
-        * Avoid grouping whole numbers between -9999 to 9999
-        * @param string $_
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( !preg_match( '/^\-?\d{1,4}(\.\d+)?$/', $_ ) ) {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               } else {
-                       return $_;
-               }
-       }
-}
index 05b0ebe..602a589 100644 (file)
@@ -78,19 +78,4 @@ class LanguageHy extends Language {
                }
                return $word;
        }
-
-       /**
-        * Armenian numeric format is "12 345,67" but "1234,56"
-        *
-        * @param string $_
-        *
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               } else {
-                       return $_;
-               }
-       }
 }
index 30abe25..57f9529 100644 (file)
@@ -75,19 +75,4 @@ class LanguageKaa extends Language {
                return parent::lcfirst( $string );
        }
 
-       /**
-        * Avoid grouping whole numbers between 0 to 9999
-        *
-        * @param string $_
-        *
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               } else {
-                       return $_;
-               }
-       }
-
 }
index 39d19e7..7353a82 100644 (file)
@@ -26,9 +26,8 @@
  *
  * @ingroup Language
  */
-// @codingStandardsIgnoreStart Ignore class name is not in camel caps format error
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class LanguageKk_cyrl extends Language {
-       // @codingStandardsIgnoreEnd
        # Convert from the nominative form of a noun to some other case
        # Invoked with {{GRAMMAR:case|word}}
        /**
@@ -774,19 +773,4 @@ class LanguageKk_cyrl extends Language {
 
                return $lastLetter;
        }
-
-       /**
-        * Avoid grouping whole numbers between 0 to 9999
-        *
-        * @param string $_
-        *
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               } else {
-                       return $_;
-               }
-       }
 }
index 9ef53e5..0185a03 100644 (file)
@@ -163,21 +163,6 @@ class LanguageKsh extends Language {
                return $word;
        }
 
-       /**
-        * Avoid grouping whole numbers between 0 to 9999
-        *
-        * @param string $_
-        *
-        * @return string
-        */
-       public function commafy( $_ ) {
-               if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               } else {
-                       return $_;
-               }
-       }
-
        /**
         * Handle cases of (1, other, 0) or (1, other)
         *
index c837409..ef77775 100644 (file)
@@ -227,7 +227,7 @@ class KuConverter extends LanguageConverter {
  *
  * @ingroup Language
  */
-class LanguageKu extends LanguageKu_ku {
+class LanguageKu extends Language {
 
        function __construct() {
                parent::__construct();
diff --git a/languages/classes/LanguageKu_ku.php b/languages/classes/LanguageKu_ku.php
deleted file mode 100644 (file)
index 4e9c365..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-<?php
-/**
- * Kurdish specific code.
- *
- * 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 Language
- */
-
-/**
- * Kurdish
- *
- * @ingroup Language
- */
-// @codingStandardsIgnoreStart Ignore class name is not in camel caps format error
-class LanguageKu_ku extends Language {
-       // @codingStandardsIgnoreEnd
-       /**
-        * Avoid grouping whole numbers between 0 to 9999
-        *
-        * @param string $_
-        *
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( !preg_match( '/^\d{1,4}$/', $_ ) ) {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               } else {
-                       return $_;
-               }
-       }
-}
diff --git a/languages/classes/LanguagePl.php b/languages/classes/LanguagePl.php
deleted file mode 100644 (file)
index e0bf069..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?php
-/**
- * Polish (polski) specific code.
- *
- * 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 Language
- */
-
-/**
- * Polish (polski)
- *
- * @ingroup Language
- */
-class LanguagePl extends Language {
-       /**
-        * @param string $_
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( !preg_match( '/^\-?\d{1,4}(\.\d+)?$/', $_ ) ) {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               } else {
-                       return $_;
-               }
-       }
-}
diff --git a/languages/classes/LanguageRu.php b/languages/classes/LanguageRu.php
deleted file mode 100644 (file)
index 7b15721..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-/**
- * Russian (русский язык) specific code.
- *
- * 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 Language
- */
-
-/**
- * Russian (русский язык)
- *
- * You can contact:
- * Alexander Sigachov (alexander.sigachov at Googgle Mail)
- * Amir E. Aharoni (amir.aharoni@mail.huji.ac.il)
- *
- * @ingroup Language
- */
-class LanguageRu extends Language {
-       /**
-        * Four-digit number should be without group commas (spaces)
-        * See manual of style at https://ru.wikipedia.org/wiki/Википедия:Оформление_статей
-        * So "1 234 567", "12 345" but "1234"
-        *
-        * @param string $_
-        *
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( preg_match( '/^-?\d{1,4}(\.\d*)?$/', $_ ) ) {
-                       return $_;
-               } else {
-                       return strrev( (string)preg_replace( '/(\d{3})(?=\d)(?!\d*\.)/', '$1,', strrev( $_ ) ) );
-               }
-       }
-}
diff --git a/languages/classes/LanguageUk.php b/languages/classes/LanguageUk.php
deleted file mode 100644 (file)
index a155d03..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-<?php
-/**
- * Ukrainian (українська мова) specific code.
- *
- * 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 Language
- */
-
-/**
- * Ukrainian (українська мова)
- *
- * @ingroup Language
- */
-class LanguageUk extends Language {
-       /**
-        * Ukrainian numeric format is "12 345,67" but "1234,56"
-        *
-        * @param string $_
-        *
-        * @return string
-        */
-       function commafy( $_ ) {
-               if ( !preg_match( '/^\-?\d{1,4}(\.\d+)?$/', $_ ) ) {
-                       return strrev( (string)preg_replace(
-                               '/(\d{3})(?=\d)(?!\d*\.)/',
-                               '$1,',
-                               strrev( $_ )
-                       ) );
-               } else {
-                       return $_;
-               }
-       }
-}
index 9d81c21..19c2d3a 100644 (file)
@@ -26,9 +26,8 @@
  *
  * @ingroup Language
  */
-// @codingStandardsIgnoreStart Ignore class name is not in camel caps format error
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class LanguageZh_hans extends Language {
-       // @codingStandardsIgnoreEnd
        /**
         * @return bool
         */
index dc4b1ef..d656528 100644 (file)
@@ -9,7 +9,7 @@
 
 namespace MediaWiki\Languages\Data;
 
-use \CrhConverter as Crh;
+use CrhConverter as Crh;
 
 class CrhExceptions {
 
index 41bdba4..6633df2 100644 (file)
@@ -4904,21 +4904,15 @@ public static $zh2Hant = [
 '峇里海' => '峇里海',
 '峰回' => '峰迴',
 '峻岭' => '峻岭',
-'崑剧' => '崑劇',
 '昆剧' => '崑劇',
-'崑山' => '崑山',
 '昆山' => '崑山',
 '昆冈' => '崑岡',
 '昆仑' => '崑崙',
 '昆嵛' => '崑嵛',
 '昆承湖' => '崑承湖',
-'崑曲' => '崑曲',
 '昆曲' => '崑曲',
-'崑腔' => '崑腔',
 '昆腔' => '崑腔',
-'崑苏' => '崑蘇',
 '昆苏' => '崑蘇',
-'崑调' => '崑調',
 '昆调' => '崑調',
 '崖广' => '崖广',
 '嶒棱' => '嶒稜',
@@ -4949,6 +4943,7 @@ public static $zh2Hant = [
 '希伯来历史' => '希伯來歷史',
 '帘子' => '帘子',
 '帘布' => '帘布',
+'帛尸梨' => '帛尸梨',
 '帝后台' => '帝后臺',
 '帝后臺' => '帝后臺',
 '师范' => '師範',
@@ -7465,6 +7460,7 @@ public static $zh2Hant = [
 '姜茶' => '薑茶',
 '姜蓉' => '薑蓉',
 '姜还是老的辣' => '薑還是老的辣',
+'姜酮' => '薑酮',
 '姜饼' => '薑餅',
 '姜黄' => '薑黃',
 '薙发' => '薙髮',
@@ -7498,7 +7494,6 @@ public static $zh2Hant = [
 '藤制' => '藤製',
 '药签' => '藥籤',
 '药面儿' => '藥麵兒',
-'苏崑' => '蘇崑',
 '苏昆' => '蘇崑',
 '苹婆' => '蘋婆',
 '苹果' => '蘋果',
@@ -7588,6 +7583,7 @@ public static $zh2Hant = [
 '冲头阵' => '衝頭陣',
 '冲风' => '衝風',
 '衡鉴' => '衡鑑',
+'表征' => '表徵',
 '表面包' => '表面包',
 '袋杆' => '袋桿',
 '袋里' => '袋裡',
@@ -8979,7 +8975,6 @@ public static $zh2Hant = [
 '松脆' => '鬆脆',
 '松脱' => '鬆脫',
 '松蛋' => '鬆蛋',
-'松起' => '鬆起',
 '松软' => '鬆軟',
 '松通' => '鬆通',
 '松开' => '鬆開',
@@ -9874,7 +9869,9 @@ public static $zh2Hans = [
 '島' => '岛',
 '峽' => '峡',
 '崍' => '崃',
+'崑' => '昆',
 '崗' => '岗',
+'崙' => '仑',
 '崢' => '峥',
 '崬' => '岽',
 '嵐' => '岚',
@@ -13454,7 +13451,6 @@ public static $zh2Hans = [
 '拚搏' => '拚搏',
 '拚死' => '拚死',
 '拾瀋' => '拾渖',
-'拿破崙' => '拿破仑',
 '挨剋' => '挨剋',
 '提昇' => '提升',
 '蒐錄' => '搜录',
@@ -13506,14 +13502,6 @@ public static $zh2Hans = [
 '旋乾转坤' => '旋乾转坤',
 '無言不讎' => '无言不雠',
 '曠若發矇' => '旷若发矇',
-'崑崙' => '昆仑',
-'崑劇' => '昆剧',
-'崑山' => '昆山',
-'崑島' => '昆岛',
-'崑曲' => '昆曲',
-'崑腔' => '昆腔',
-'崑蘇' => '昆苏',
-'崑調' => '昆调',
 '易·乾' => '易·乾',
 '易經·乾' => '易经·乾',
 '易经·乾' => '易经·乾',
@@ -13830,6 +13818,8 @@ public static $zh2TW = [
 '前波美拉尼亚' => '前波莫瑞',
 '前波美拉尼亞' => '前波莫瑞',
 '加蓬' => '加彭',
+'加泰罗尼亚' => '加泰隆尼亞',
+'加泰羅尼亞' => '加泰隆尼亞',
 '加沙地带' => '加薩走廊',
 '加沙地帶' => '加薩走廊',
 '包豪斯' => '包浩斯',
@@ -15015,6 +15005,7 @@ public static $zh2HK = [
 '击剑' => '劍擊',
 '擊劍' => '劍擊',
 '加薩走廊' => '加沙地帶',
+'加泰隆尼亞' => '加泰羅尼亞',
 '迦納' => '加納',
 '加彭' => '加蓬',
 '努力著' => '努力着',
@@ -15250,6 +15241,7 @@ public static $zh2HK = [
 '衣索匹亞' => '埃塞俄比亚',
 '衣索比亞' => '埃塞俄比亞',
 '葉里溫' => '埃里溫',
+'埋著' => '埋着',
 '城市里' => '城市裏',
 '城里' => '城裏',
 '域里' => '域裏',
@@ -15968,7 +15960,6 @@ public static $zh2HK = [
 '朝著者' => '朝著者',
 '朝著述' => '朝著述',
 '朝著錄' => '朝著錄',
-'板球' => '木球',
 '賓·拉登' => '本·拉登',
 '班傑明' => '本傑明',
 '賓拉登' => '本拉登',
@@ -16018,7 +16009,6 @@ public static $zh2HK = [
 '台球' => '桌球',
 '撞球' => '桌球',
 '梅鐸' => '梅鐸',
-'默多克' => '梅鐸',
 '条文里' => '條文裏',
 '梳著' => '梳着',
 '梳著作' => '梳著作',
@@ -16584,8 +16574,6 @@ public static $zh2HK = [
 '箱里' => '箱裏',
 '节目里' => '節目裏',
 '簽著' => '簽着',
-'篮板球' => '籃板球',
-'籃板球' => '籃板球',
 '迈克尔' => '米高',
 '麦克尔' => '米高',
 '迈克尔·欧文' => '米高·奧雲',
@@ -16635,10 +16623,7 @@ public static $zh2HK = [
 '彩球' => '綵球',
 '彩綢' => '綵綢',
 '彩绸' => '綵綢',
-'彩线' => '綵綫',
-'彩線' => '綵線',
 '彩船' => '綵船',
-'彩衣' => '綵衣',
 '线图里' => '線圖裏',
 '緝凶' => '緝兇',
 '县里' => '縣裏',
@@ -17852,7 +17837,6 @@ public static $zh2CN = [
 '偷著者' => '偷著者',
 '偷著述' => '偷著述',
 '傅利葉' => '傅里叶',
-'母音' => '元音',
 '光著' => '光着',
 '光著書' => '光著书',
 '光著作' => '光著作',
@@ -17975,6 +17959,7 @@ public static $zh2CN = [
 '辦著者' => '办著者',
 '辦著述' => '办著述',
 '加薩走廊' => '加沙地带',
+'加泰隆尼亞' => '加泰罗尼亚',
 '迦納' => '加纳',
 '加彭' => '加蓬',
 '動著' => '动着',
@@ -18237,6 +18222,7 @@ public static $zh2CN = [
 '衣索比亞' => '埃塞俄比亚',
 '艾菲爾' => '埃菲尔',
 '葉里溫' => '埃里温',
+'埋著' => '埋着',
 '功能變數名稱' => '域名',
 '網域名稱' => '域名',
 '吉里巴斯' => '基里巴斯',
index 3ba0b96..fcb22d6 100644 (file)
        "category-subcat-count-limited": "هذا التصنيف يحوي {{PLURAL:$1||التصنيف الفرعي التالي|التصنيفين الفرعيين التاليين|التصنيفات الفرعية $1  التالية}}.",
        "category-article-count": "{{PLURAL:$2|لا صفحات بهذا التصنيف سوى التالية.|{{PLURAL:$1||الصفحة التالية مصنّفة|الصفحتان التاليتان مصنّفتان|الصفحات $1 التالية مصنّفة}} بهذا التصنيف، من إجمالي $2.}}",
        "category-article-count-limited": "{{PLURAL:$1||الصفحة التالية|الصفحتان التاليتان|الصفحات $1 التالية}} مصنّفة بهذا التصنيف.",
-       "category-file-count": "{{PLURAL:$2|لا ملفات مصنّفة بهذا التصنيف سوى التالي.|{{PLURAL:$1||الملف التالي مصنّف|الملفان التاليان مصنّفان|الملفات $1 التالية مصنّفة}} بهذا التصنيف من إجمالي $2.}}",
+       "category-file-count": "هذا التصنيف مصنّف عليه الملف{{PLURAL:$2| التالي.|{{PLURAL:$1|| التالي|ان التاليان|ات $1 التالية}}، من إجمالي $2.}}",
        "category-file-count-limited": "{{PLURAL:$1|الملف التالي مصنّف|الملفان التاليان مصنّفان|الملفات $1 التالية مصنّفة}} بهذا التصنيف.",
        "listingcontinuesabbrev": "(تابع)",
        "index-category": "صفحات مفهرسة",
        "history_short": "التاريخ",
        "history_small": "تاريخ",
        "updatedmarker": "عُدلت منذ زيارتي الأخيرة",
-       "printableversion": "نسخة للطباعة",
+       "printableversion": "بتنسق للطباعة",
        "permalink": "رابط دائم",
        "print": "اطبع",
        "view": "مطالعة",
-       "view-foreign": "اعرض Ø¹Ù\84Ù\89 $1",
+       "view-foreign": "استعرضÙ\87 Ù\81Ù\8a $1",
        "edit": "عدل",
        "edit-local": "تعديل الوصف المحلي",
        "create": "أنشئ",
        "aboutsite": "عن {{SITENAME}}",
        "aboutpage": "Project:عن",
        "copyright": "المحتوى منشور وفق $1 إن لم يرد خلاف ذلك.",
-       "copyrightpage": "{{ns:project}}:حقوق التأليف و النشر",
+       "copyrightpage": "{{ns:project}}:حقوق التأليف و&nbsp;الطبع",
        "currentevents": "الأحداث الجارية",
        "currentevents-url": "Project:الأحداث الجارية",
        "disclaimers": "إخلاء مسؤولية",
        "image_tip": "ملف مدرج",
        "media_tip": "وصلة ملف",
        "sig_tip": "توقيعك مع الساعة والتاريخ",
-       "hr_tip": "خط Ø£Ù\81Ù\82Ù\8a (تجÙ\86ب Ø§Ù\84استخداÙ\85 Ø¨Ù\83ثرة)",
+       "hr_tip": "خط Ø£Ù\81Ù\82Ù\8a (تجÙ\86ب Ø§Ù\84Ø¥Ù\81راط)",
        "summary": "ملخص:",
        "subject": "موضوع/عنوان:",
        "minoredit": "هذا تعديل طفيف",
        "publishchanges": "نشر التغييرات",
        "preview": "عرض مسبق",
        "showpreview": "أظهر معاينة",
-       "showdiff": "عرض التغييرات",
+       "showdiff": "استعرض Ø§Ù\84تغÙ\8aÙ\8aرات",
        "blankarticle": "<strong>تنبيه:</strong> الصفحة التي تريد إنشاءها فارغة. إذا نقرت \"$1\" ثانية فستنشأ الصفحة بدون محتوى.",
        "anoneditwarning": "<strong>تحذير:</strong> أنت غير مسجل الدخول. عنوان الأيبي الخاص بك سيكون معروضا بشكل علني لو قمت بأي تعديلات. لو أنك <strong>[$1 سجلت الدخول]</strong> أو <strong>[$2 أنشأت حسابا]</strong>، فتعديلاتك ستنسب لاسم المستخدم الخاص بك، بالإضافة إلى فوائد أخرى.",
        "anonpreviewwarning": "''أنت غير مسجل الدخول. الحفظ سيسجل عنوان الأيبي الخاص بك في تاريخ هذه الصفحة.''",
        "newarticle": "(جديد)",
        "newarticletext": "لقد تبعت وصلة لصفحة لم يتم إنشائها بعد.\nلإنشاء هذه الصفحة ابدأ الكتابة في الصندوق بالأسفل (انظر في [$1 صفحة المساعدة] للمزيد من المعلومات).\nإذا كانت زيارتك لهذه الصفحة بالخطأ، اضغط على زر ''رجوع'' في متصفح الإنترنت لديك.",
        "anontalkpagetext": "----\n<em>هذه صفحة نقاش لمستخدم مجهول لم يقم بإنشاء حساب بعد أو لا يستعمل ذلك الحساب.</em>\nلذا فيجب علينا استعمال رقم الأيبي للتعرف عليه/عليها.\nمثل هذا العنوان يمكن أن يشترك فيه عدة مستخدمين.\nلو كنت مستخدما مجهولا وتشعر بأن تعليقات لا تخصك تم توجيهها إليك، من فضلك [[Special:CreateAccount|أنشئ حسابا]] أو [[Special:UserLogin|سجل الدخول]] لتجنب الارتباك المستقبلي مع مستخدمين مجهولين آخرين.",
-       "noarticletext": "الصفحة خالية. يمكنك [[Special:Search/{{PAGENAME}}|البحث عن عنوانها]] في الصفحات الأخرى أو\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} البحث في السجلات] (لتعرف إذا حذفت)،\nأو '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} إنشاؤها بنفسك]'''</span>.",
-       "noarticletext-nopermission": "لا يوجد حاليا أي نص في هذه الصفحة.\nيمكنك [[Special:Search/{{PAGENAME}}|البحث عن عنوان هذه الصفحة]] في الصفحات الأخرى، أو <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} البحث في السجلات المتعلقة بها]</span>، لكنك لست مخولاً لإنشاء هذه الصفحة.",
+       "noarticletext": "هذه الصفحة خالية حاليا. يمكنك [[Special:Search/{{PAGENAME}}|البحث عن عنوانها]] في الصفحات الأخرى أو\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} البحث في السجلات] (لتعرف إن كانت قد حُذِفَت)،\nأو '''[{{fullurl:{{FULLPAGENAME}}|action=edit}} إنشاؤها]'''</span>.",
+       "noarticletext-nopermission": "لا يوجد حاليا أي نص في هذه الصفحة.\nيمكنك [[Special:Search/{{PAGENAME}}|البحث عن عنوان هذه الصفحة]] في الصفحات الأخرى، أو <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} البحث في السجلات]</span>، لكن ليست لك صلاحية إنشاء هذه الصفحة.",
        "missing-revision": "المراجعة #$1 من الصفحة المسماة \"{{FULLPAGENAME}}\" غير موجودة.\n\nهذا يحدث عادة عن طريق اتباع وصلة تاريخ قديمة لصفحة تم حذفها.\nالتفاصيل يمكن إيجادها في [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} سجل الحذف].",
        "userpage-userdoesnotexist": "حساب المستخدم \"<nowiki>$1</nowiki>\" غير مسجل.\nمن فضلك تأكد أنك تريد إنشاء/تعديل هذه الصفحة.",
        "userpage-userdoesnotexist-view": "حساب المستخدم \"$1\" غير مسجل.",
        "templatesused": "{{PLURAL:$1||القالب المستخدم|القالبان المستخدمان|القوالب المستخدمة}} في هذه الصفحة:",
        "templatesusedpreview": "{{PLURAL:$1||القالب المستخدم|القالبان المستخدمان|القوالب المستخدمة}} في هذه المعاينة:",
        "templatesusedsection": "{{PLURAL:$1||القالب المستخدم|القالبان المستخدمان|القوالب المستخدمة}} في هذا القسم:",
-       "template-protected": "(حماية كاملة)",
-       "template-semiprotected": "(حماية جزئية)",
+       "template-protected": "(محميّة)",
+       "template-semiprotected": "(محمية جزئيا)",
        "hiddencategories": "{{PLURAL:$1|هذه الصفحة غير موجودة في أي تصنايف مخفية|هذه الصفحة موجودة في تصنيف مخفي واحد|هذه الصفحة موجودة في تصنيفين مخفيين|هذه الصفحة موجودة في $1 تصانيف مخفية|هذه الصفحة موجودة في $1 تصنيفا مخفيا|هذه الصفحة موجودة في $1 تصنيف مخفي}}:",
-       "edittools": "<!-- النص هنا سيظهر تحت صندوق التحرير واستمارة رفع الصور. -->",
+       "edittools": "<!-- هذا النص سيظهر تحت حقل تحرير المتن و&nbsp;استمارة رفع الملفات. -->",
        "nocreatetext": "قام {{SITENAME}} بتحديد القدرة على إنشاء صفحات جديدة.\nيمكنك العودة وتحرير صفحة موجودة بالفعل، أو [[Special:UserLogin|الدخول أو تسجيل حساب]].",
        "nocreate-loggedin": "أنت لا تمتلك الصلاحية لإنشاء صفحات جديدة.",
        "sectioneditnotsupported-title": "تعديل الأقسام غير مدعوم",
        "sectioneditnotsupported-text": "تعديل الأقسام غير مدعوم في هذه الصفحة",
        "permissionserrors": "خطأ في السماح",
        "permissionserrorstext": "لا تمتلك الصلاحية لفعل هذا، {{PLURAL:$1||للسبب التالي|للسببين التاليين|للأسباب التالية}}:",
-       "permissionserrorstext-withaction": "لا تملك الصلاحيات ل$2، لل{{PLURAL:$1||سبب التالي|سببين التاليين|أسباب التالية}}:",
+       "permissionserrorstext-withaction": "ليست لك الصلاحية ل$2، لل{{PLURAL:$1||سبب التالي|سببين التاليين|أسباب التالية}}:",
        "contentmodelediterror": "أنت لا يمكنك تعديل هذه المراجعة لأن موديل محتواها هو  <code>$1</code>، والذي يختلف عن موديل المحتوى الحالي للصفحة  <code>$2</code>.",
        "recreate-moveddeleted-warn": "'''تحذير: أنت تعيد إنشاء صفحة سبق حذفها.'''\n\nيجب عليك التيقن من أن الاستمرار بتحرير هذه الصفحة ملائم.\nسجلا الحذف والنقل لهذه الصفحة معروضان هنا للتيسير:",
        "moveddeleted-notice": "هذه الصفحة تم حذفها.\nسجلا حذف ونقل الصفحة معروضان بالأسفل كمرجع.",
        "currentrev": "المراجعة الحالية",
        "currentrev-asof": "المراجعة الحالية بتاريخ $1",
        "revisionasof": "مراجعة $1",
-       "revision-info": "Ù\86سخة $1 Ù\84Ù\84Ù\85ستخدÙ\85 {{GENDER:$6|$2}}$7",
+       "revision-info": "Ù\85راجعة $1 Ø¨Ù\88اسطة {{GENDER:$6|$2}}$7",
        "previousrevision": "→ مراجعة أقدم",
        "nextrevision": "مراجعة أحدث ←",
        "currentrevisionlink": "المراجعة الحالية",
        "shown-title": "عرض $1 {{PLURAL:$1|نتيجة|نتيجة}} لكل صفحة",
        "viewprevnext": "عرض ($1 {{int:pipe-separator}} $2) ($3).",
        "searchmenu-exists": "'''توجد صفحة اسمها \"[[:$1]]\" على هذه الويكي.''' {{PLURAL:$2|0=|انظر ايضا نتائج البحث الأخرى.}}",
-       "searchmenu-new": "<strong>أنشئ الصفحة \"[[:$1]]\" على هذه الويكي!</strong>  {{PLURAL:$2|0=|انظر أيضا الصفحة التي تم العثور عليها من بحثك.|انظر ايضا نتائج البحث.}}",
+       "searchmenu-new": "<strong>أنشئ الصفحة \"[[:$1]]\" في هذه الويكي. انظر أيضا </strong> {{PLURAL:$2|0=|الصفحة التي وجدت بالبحث.|نتائج البحث.}}",
        "searchprofile-articles": "صفحات المحتوى",
        "searchprofile-images": "الوسائط المتعددة",
        "searchprofile-everything": "الكل",
        "recentchanges-label-minor": "هذا تعديل طفيف",
        "recentchanges-label-bot": "تعديل أجراه بوت",
        "recentchanges-label-unpatrolled": "لم يراجع هذا التعديل إلى الآن",
-       "recentchanges-label-plusminus": "حجم الصفحة تغير بهذا العدد من وحدات البايت",
+       "recentchanges-label-plusminus": "حجم الصفحة تغير بهذا العدد من البايتات",
        "recentchanges-legend-heading": "<strong>شرح:</strong>",
-       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (راجع Ø£Ù\8aضا [[Special:NewPages|قائمة الصفحات الجديدة]])",
+       "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (طاÙ\84ع Ù\83Ø°Ù\84Ù\83 [[Special:NewPages|قائمة الصفحات الجديدة]])",
        "recentchanges-submit": "أظهر",
        "rcfilters-tag-remove": "أزل '$1'",
        "rcfilters-legend-heading": "<strong>قائمة الاختصارات:</strong>",
        "rcfilters-preference-label": "أخف النسخة المحسنة من أحدث التغييرات",
        "rcfilters-preference-help": "يسترجع عملية إعادة تصميم الواجهة لعام 2017 وكل الأدوات التي أضيفت منذ ذلك الوقت.",
        "rcfilters-filter-showlinkedfrom-label": "عرض التغييرات في الصفحات الموصولة من",
-       "rcfilters-filter-showlinkedfrom-option-label": "عرض التغييرات في الصفحات الموصولة <strong>من</strong> صفحة",
-       "rcfilters-filter-showlinkedto-label": "أظÙ\87ر التغييرات في الصفحات الموصولة بصفحة",
-       "rcfilters-filter-showlinkedto-option-label": "عرض التغييرات في الصفحات الموصولة <strong>إلى</strong> صفحة",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>الصفحات الموصولة من</strong> الصفحة المختارة",
+       "rcfilters-filter-showlinkedto-label": "عرض التغييرات في الصفحات الموصولة بصفحة",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>الصفحات الموصولة إلى</strong> الصفحة المختارة",
        "rcfilters-target-page-placeholder": "أدخل اسم صفحة",
        "rcnotefrom": "بالأسفل {{PLURAL:$5|التغيير|التغييرات}} منذ <strong>$2</strong> (إلى <strong>$1</strong> معروضة).",
        "rclistfromreset": "إعادة ضبط خيار التاريخ",
-       "rclistfrom": "أظهر التغييرات بدء من $3 $2",
+       "rclistfrom": "أظهر التغييرات بدءًا من $3 $2",
        "rcshowhideminor": "$1 التعديلات الطفيفة",
        "rcshowhideminor-show": "أظهر",
        "rcshowhideminor-hide": "أخف",
        "recentchangeslinked-feed": "تغييرات ذات علاقة",
        "recentchangeslinked-toolbox": "تغييرات ذات علاقة",
        "recentchangeslinked-title": "التغييرات المرتبطة بصفحة «$1»",
-       "recentchangeslinked-summary": "أدخل اسم صفحة لرؤية التغييرات في الصفحات الموصولة من أو إلى تلك الصفحة. (لرؤية أعضاء تصنيف، أدخل تصنيف:الاسم الخاص بالتصنيف). التغييرات في الصفحات في [[Special:Watchlist|قائمة مراقبتك]] <strong>عريضة</strong>.",
+       "recentchangeslinked-summary": "أدخل اسم صفحة لمطالعة التغييرات في الصفحات التي تربط إلى أو من هذه الصفحة. (لمطالعة أعضاء تصنيف، أدخل تصنيف:اسم التصنيف). التغييرات في الصفحات ضمن [[Special:Watchlist|قائمة مراقبتك]] <strong>بخط داكن</strong>.",
        "recentchangeslinked-page": "اسم الصفحة:",
        "recentchangeslinked-to": "أظهر التغييرات للصفحات الموصولة للصفحة المعطاة عوضاً عن ذلك",
        "recentchanges-page-added-to-category": "[[:$1]] أضيفت إلى التصنيف",
        "duplicatesoffile": "{{PLURAL:$1|الملف التالي مكرر|ال$1 ملف التالي مكررات}} لهذا الملف\n([[Special:FileDuplicateSearch/$2|المزيد من التفاصيل]]):",
        "sharedupload": "هذا الملف من $1 ويمكن استخدامه بواسطة المشاريع الأخرى.",
        "sharedupload-desc-there": "هذا الملف من $1 ويمكن استخدامه بواسطة المشاريع الأخرى.\nمن فضلك انظر [$2 صفحة وصف الملف] لمزيد من المعلومات.",
-       "sharedupload-desc-here": "هذا الملف من $1 ويمكن استخدامه بواسطة المشاريع الأخرى.\nالوصف على [$2 صفحة وصف الملف] هناك معروض بالأسفل.",
+       "sharedupload-desc-here": "هذا الملف من $1 ويمكن للمشروعات الأخرى استعماله.\nالوصف من [$2 صفحة وصف الملف] هناك معروض فيما يلي.",
        "sharedupload-desc-edit": "هذا ملف من $1 وقد يكون مستخدما في مشاريع أخرى.\nيمكن لك أن تعدل وصف الملف في [$2  صفحته] هناك.",
        "sharedupload-desc-create": "هذا ملف من $1 وقد يكون مستخدما في مشاريع أخرى.\nيمكن لك أن تعدل وصف الملف في [$2  صفحته] هناك.",
        "filepage-nofile": "لا ملف موجود بهذا الاسم.",
        "shared-repo": "مستودع مشترك",
        "shared-repo-name-wikimediacommons": "ويكيميديا كومنز",
        "filepage.css": "/* CSS المعروض هنا سيضمن في صفحات وصف الملفات، أيضا على الويكيات الأجنبية */",
-       "upload-disallowed-here": "Ù\84ا Ù\8aÙ\85Ù\83Ù\86Ù\83 ØªØ¹Ø¯Ù\8aÙ\84 Ù\87Ø°Ù\87 Ø§Ù\84صÙ\88رة.",
+       "upload-disallowed-here": "Ù\84ا Ù\8aÙ\85Ù\83Ù\86Ù\83 Ø§Ø³ØªØ¨Ø¯Ø§Ù\84 Ù\87ذا Ø§Ù\84Ù\85Ù\84Ù\81.",
        "filerevert": "استرجع $1",
        "filerevert-legend": "استرجع الملف",
        "filerevert-intro": "أنت تسترجع '''[[Media:$1|$1]]''' [$4 لنسخة بتاريخ $2، $3].",
        "nopagetitle": "لا توجد صفحة هدف كهذه",
        "nopagetext": "صفحة الهدف التي حددتها غير موجودة.",
        "pager-newer-n": "{{PLURAL:$1|أجدد 1|أجدد $1}}",
-       "pager-older-n": "{{PLURAL:$1|أقدم 1|أقدم $1}}",
+       "pager-older-n": "{{PLURAL:$1|$1 أقدم}}",
        "suppress": "أوفرسايت",
        "querypage-disabled": "تم تعطيل هذه الصفحة الخاصة لأسباب تتعلق بالأداء.",
        "apihelp": "مساعدة API",
        "undelete-show-file-submit": "نعم",
        "namespace": "النطاق:",
        "invert": "اعكس الاختيار",
-       "tooltip-invert": "عÙ\84Ù\85 Ø¹Ù\84Ù\89 Ù\87ذا Ø§Ù\84صÙ\86دÙ\88Ù\82 Ù\84إخÙ\81اء Ø§Ù\84تغÙ\8aÙ\8aرات Ù\84Ù\84صÙ\81حات Ù\81Ù\8a Ø§Ù\84Ù\86طاÙ\82 Ø§Ù\84Ù\85ختار (Ù\88اÙ\84Ù\86طاÙ\82 Ø§Ù\84Ù\85صاحب Ù\84Ù\88 Ù\85عÙ\84Ù\85 Ø¹Ù\84Ù\8aÙ\87ا)",
+       "tooltip-invert": "أشÙ\90Ù\91ر Ù\87ذا Ø§Ù\84Ø®Ù\8aار Ù\84إخÙ\81اء Ø§Ù\84تغÙ\8aÙ\8aرات Ù\81Ù\8a Ø§Ù\84صÙ\81حات Ù\81Ù\8a Ø§Ù\84Ù\86طاÙ\82 Ø§Ù\84Ù\85ختار (Ù\88اÙ\84Ù\86طاÙ\82 Ø§Ù\84Ù\85Ù\82ترÙ\86 Ø¨Ù\87 Ø¥Ø°Ø§ Ø£Ù\8fØ´Ù\90Ù\91ر Ø¹Ù\84Ù\8aÙ\87)",
        "tooltip-whatlinkshere-invert": "قم بتعليم هذا الخيار لإخفاء الروابط من الصفحات التي تم تعليم نطاقاتها.",
        "namespace_association": "النطاق المقترن",
-       "tooltip-namespace_association": "عÙ\84Ù\85 Ø¹Ù\84Ù\89 Ù\87ذا Ø§Ù\84صÙ\86دÙ\88Ù\82 Ù\84تضÙ\85Ù\8aÙ\86 Ù\86طاÙ\82 Ø§Ù\84Ù\86Ù\82اش Ø£Ù\88 Ø§Ù\84Ù\85Ù\88ضÙ\88ع Ø§Ù\84Ù\85صاحب Ù\84لنطاق المختار",
+       "tooltip-namespace_association": "أشÙ\90Ù\91ر Ù\87ذا Ø§Ù\84Ø®Ù\8aار Ù\84تضÙ\85Ù\8aÙ\86 Ù\86طاÙ\82 Ø§Ù\84Ù\86Ù\82اش Ø£Ù\88 Ø§Ù\84Ù\85Ù\88ضÙ\88ع Ø§Ù\84Ù\85Ù\82ترÙ\86 Ø¨Ø§لنطاق المختار",
        "blanknamespace": "(رئيسي)",
        "contributions": "مساهمات {{GENDER:$1|المستخدم|المستخدمة}}",
        "contributions-title": "مساهمات {{GENDER:$1|المستخدم|المستخدمة}} $1",
        "tooltip-ca-talk": "نقاش عن صفحة المحتوى",
        "tooltip-ca-edit": "تعديل هذه الصفحة",
        "tooltip-ca-addsection": "ابدأ قسما جديدا",
-       "tooltip-ca-viewsource": "هذه الصفحة محمية.\nيمكنك رؤية مصدرها.",
+       "tooltip-ca-viewsource": "هذه الصفحة محمية.\nيمكنك مطالعة مصدرها.",
        "tooltip-ca-history": "النسخ السابقة لهذه الصفحة",
        "tooltip-ca-protect": "احم هذه الصفحة",
        "tooltip-ca-unprotect": "غير حماية هذه الصفحة",
        "tooltip-p-logo": "زُر الصفحة الرئيسية",
        "tooltip-n-mainpage": "زر الصفحة الرئيسية",
        "tooltip-n-mainpage-description": "زر الصفحة الرئيسية",
-       "tooltip-n-portal": "Ø­Ù\88Ù\84 Ø§Ù\84Ù\85شرÙ\88عØ\8c Ù\85اذا Ù\8aÙ\85Ù\83Ù\86 Ø£Ù\86 ØªÙ\81عÙ\84Ø\8c Ø£Ù\8aÙ\86 Ù\8aÙ\85Ù\83Ù\86 Ø£ن تجد ما تحتاجه",
+       "tooltip-n-portal": "Ø­Ù\88Ù\84 Ø§Ù\84Ù\85شرÙ\88عØ\8c Ù\88&nbsp;Ù\85ا Ù\8aÙ\85Ù\83Ù\86 Ù\81عÙ\84Ù\87Ø\8c Ù\88&nbsp;Ø£Ù\8aن تجد ما تحتاجه",
        "tooltip-n-currentevents": "مطالعة سريعة لأهم الأحداث الجارية",
        "tooltip-n-recentchanges": "قائمة أحدث التغييرات في الويكي.",
        "tooltip-n-randompage": "حمل صفحة عشوائية",
        "tooltip-save": "احفظ تغييراتك",
        "tooltip-publish": "انشر تغييراتك",
        "tooltip-preview": "اعرض تغييراتك، من فضلك استخدم هذا قبل الحفظ!",
-       "tooltip-diff": "اعرض Ø§Ù\84تغÙ\8aÙ\8aرات Ø§Ù\84تÙ\8a Ù\82Ù\85ت Ø¨Ù\87ا Ù\84لنص.",
+       "tooltip-diff": "استعرض Ø§Ù\84تغÙ\8aÙ\8aرات Ø§Ù\84تÙ\8a Ø£Ø¬Ø±Ù\8aتÙ\87ا Ø¹Ù\84Ù\89 Ø§لنص.",
        "tooltip-compareselectedversions": "شاهد الفروق بين النسختين المختارتين من هذه الصفحة.",
        "tooltip-watch": "أضف هذه الصفحة إلى قائمة مراقبتك",
        "tooltip-watchlistedit-normal-submit": "أزل العناوين",
        "tooltip-watchlistedit-raw-submit": "حدث قائمة المراقبة",
        "tooltip-recreate": "أعد إنشاء الصفحة رغم كونها حذفت",
        "tooltip-upload": "ابدأ الرفع",
-       "tooltip-rollback": "\"استرجاع\" ØªØ³ØªØ±Ø¬Ø¹ Ø§Ù\84تعدÙ\8aÙ\84 (اÙ\84تعدÙ\8aÙ\84ات)  Ù\81Ù\8a Ù\87Ø°Ù\87 Ø§Ù\84صÙ\81حة Ù\84Ù\84Ù\85ساÙ\87Ù\85 Ø§Ù\84أخÙ\8aر بضغطة واحدة.",
+       "tooltip-rollback": "\"استرجاع\" ØªØ³ØªØ±Ø¬Ø¹ ØªØ¹Ø¯Ù\8aÙ\84ات Ø¢Ø®Ø± Ù\85حرÙ\91ر Ù\84Ù\87Ø°Ù\87 Ø§Ù\84صÙ\81حة بضغطة واحدة.",
        "tooltip-undo": "\"رجوع\" تسترجع هذا التعديل وتفتح نافذة التعديل في نمط العرض المسبق. تسمح بإضافة سبب في الملخص.",
        "tooltip-preferences-save": "احفظ التغييرات",
        "tooltip-summary": "أدخل ملخصا قصيرا",
        "spam_reverting": "استرجاع آخر نسخة ليس بها وصلات إلى $1",
        "spam_blanking": "كل النسخ احتوت على وصلات ل $1، إفراغ",
        "spam_deleting": "جميع النسخ تحوي رابطا إلى $1، يتم الحذف",
-       "simpleantispam-label": "اختبار ضد السبام.\n<strong>لا</strong> تملأ هذا!",
+       "simpleantispam-label": "اختبار ضد السُّخام.\n<strong>لا</strong> تملأ هذا!",
        "pageinfo-title": "المعلومات عن «$1»",
        "pageinfo-not-current": "عذرا، لا يمكن عرض تلك المعلومات للنسخ القديمة.",
        "pageinfo-header-basic": "المعلومات الأساسية",
        "exif-referenceblackwhite": "زوج من قيم المرجع السوداء والبيضاء",
        "exif-datetime": "تاريخ ووقت تغيير الملف",
        "exif-imagedescription": "عنوان الصورة",
-       "exif-make": "مصنع آلة التصوير",
+       "exif-make": "صانع الكاميرا",
        "exif-model": "طراز الكاميرا",
        "exif-software": "البرمجيات المستخدمة",
        "exif-artist": "المؤلف",
        "exif-copyright": "مالك الحقوق",
        "exif-exifversion": "نسخة Exif",
        "exif-flashpixversion": "نسخة Flashpix المدعومة",
-       "exif-colorspace": "فضاء الألوان",
+       "exif-colorspace": "الفضاء اللوني",
        "exif-componentsconfiguration": "معنى كل مكونة",
        "exif-compressedbitsperpixel": "طور ضغط الصورة",
        "exif-pixelxdimension": "عرض الصورة",
        "exif-usercomment": "تعليقات المستخدم",
        "exif-relatedsoundfile": "ملف صوتي مرتبط",
        "exif-datetimeoriginal": "تاريخ ووقت توليد البيانات",
-       "exif-datetimedigitized": "تاريخ ووقت التحويل الرقمي",
+       "exif-datetimedigitized": "تاريخ و&nbsp;وقت الرَّقمنة",
        "exif-subsectime": "وقت تاريخ ثواني فرعية",
        "exif-subsectimeoriginal": "وقت تاريخ أصلي ثواني فرعية",
        "exif-subsectimedigitized": "وقت تاريخ رقمي ثواني فرعية",
        "tag-mw-replace-description": "التعديلات التي أزالت أكثر من 90% من محتوى صفحة",
        "tag-mw-rollback": "استرجاع",
        "tag-mw-rollback-description": "التعديلات التي استرجعت التعديلات السابقة باستخدام وصلة الاسترجاع",
+       "tag-mw-undo": "رجوع",
+       "tag-mw-undo-description": "التعديلات التي ترجع عن التعديلات السابقة باستخدام وصلة رجوع",
        "tags-title": "وسوم",
        "tags-intro": "هذه الصفحة تعرض الوسوم التي ربما يعلم البرنامج تعديلا بها، ومعانيها.",
        "tags-tag": "اسم الوسم",
index 6d2ed73..31c819c 100644 (file)
        "tagline": "De {{SITENAME}}",
        "help": "Ayuda",
        "search": "Buscar",
-       "search-ignored-headings": " #<!-- dexar esta llinia exactamente como ta --> <pre>\n# Testeres que nun se tendrán en cuenta na gueta.\n# Los cambios fechos equí son efeutivos nel momentu que s'indexa la páxina cola testera.\n# Pue forzar el reindexáu d'una páxina faciendo una edición nula.\n# La sintaxis ye la siguiente:\n#   * Tolo qu'hai dende un caráuter \"#\" al fin de llinia ye un comentariu\n#   * Cada llinia nun-balera ye'l títulu exactu a descartar, incluyendo mayúscules y demás\nReferencies\nEnllaces esternos\nVer tamién\n #</pre> <!-- dexar esta llinia exactamente como ta -->",
+       "search-ignored-headings": " #<!-- dexar esta llinia exautamente como ta --> <pre>\n# Testeres que nun se tendrán en cuenta na gueta.\n# Los cambios fechos equí son efeutivos nel momentu que s'indexa la páxina cola testera.\n# Puede forzase'l reindexáu d'una páxina faciendo una edición nula.\n# La sintaxis ye la siguiente:\n#   * Tolo qu'hai dende un caráuter «#» al fin de llinia ye un comentariu\n#   * Cada llinia nun-balera ye'l títulu exautu a descartar, incluyendo mayúscules y too.\nReferencies\nEnllaces esternos\nVer tamién\n #</pre> <!-- dexar esta llinia exautamente como ta -->",
        "searchbutton": "Guetar",
        "go": "Dir",
        "searcharticle": "Dir",
        "resetpass-temp-password": "Contraseña temporal:",
        "resetpass-abort-generic": "Una estensión encaboxó'l cambiu de la contraseña.",
        "resetpass-expired": "La so contraseña caducó. Defina una nueva contraseña p'aniciar sesión.",
-       "resetpass-expired-soft": "La so contraseña caducó y tien de reaniciala. Escueya una contraseña nueva, o calque «{{int:authprovider-resetpass-skip-label}}» pa reaniciala más sero.",
-       "resetpass-validity-soft": "La so contraseña nun ye válida: $1\n\nEscueya una contraseña nueva, o calque «{{int:authprovider-resetpass-skip-label}}» pa reaniciala más sero.",
+       "resetpass-expired-soft": "La contraseña caducó y precisa reaniciase. Escueye agora una contraseña nueva, o pulsia «{{int:authprovider-resetpass-skip-label}}» pa reaniciala sero.",
+       "resetpass-validity-soft": "La contraseña nun ye válida: $1\n\nEscueye agora una contraseña nueva, o pulsia «{{int:authprovider-resetpass-skip-label}}» pa reaniciala sero.",
        "passwordreset": "Reaniciar contraseña",
        "passwordreset-text-one": "Complete esti formulariu pa reaniciar la contraseña.",
        "passwordreset-text-many": "{{PLURAL:$1|Rellene unu de los campos pa recibir una contraseña temporal per corréu.}}",
        "blankarticle": "<strong>Atención:</strong> La páxina que tas a piques de crear ta balera.\nSi vuelves a facer click en «$1», crearáse la páxina ensin conteníu dengún.",
        "anoneditwarning": "<strong>Avisu:</strong> Nun aniciasti sesión. La direición IP sedrá visible en público si faes dalguna edición. Si <strong>[$1 anicies sesión]</strong> o <strong>[$2 crees una cuenta]</strong>, les ediciones atribuiránse al to nome d'usuariu, xunto con otros beneficios.",
        "anonpreviewwarning": "''Nun aniciasti sesión. Al guardar quedará rexistrada la to direición IP nel historial d'edición d'esta páxina.''",
-       "missingsummary": "'''Recordatoriu:''' Nun conseñasti un resume d'edición.\nSi calques nuevamente \"$1\", la to edición guardaráse ensin nengún resume.",
-       "selfredirect": "<strong>Atención:</strong> Tas redirixendo esta páxina a ella mesma.\nSeique conseñaras un oxetivu enquivocáu pa la redireición, o que teas editando una páxina enquivocada. Si vuelves a facer clic en «$1», crearáse la redireición de toles maneres.",
+       "missingsummary": "<strong>Recordatoriu:</strong> Nun conseñasti un resume d'edición.\nSi pulsies nuevamente «$1», la to edición guardaráse ensin resume.",
+       "selfredirect": "<strong>Atención:</strong> Tas redirixendo esta páxina a ella mesma.\nEscurque conseñasti un destín enquivocáu pa la redireición, o que teas editando una páxina enquivocada. Si vuelves a pulsiar en «$1», crearáse la redireición de toles maneres.",
        "missingcommenttext": "Escribi un comentariu.",
        "missingcommentheader": "<strong>Recordatoriu:</strong> Nun conseñasti un asuntu pa esti comentariu.\nSi calques nuevamente «$1», la to edición guardaráse ensin nengunu.",
        "summary-preview": "Vista previa del resume d'edición:",
        "editingsection": "Editando $1 (seición)",
        "editingcomment": "Editando $1 (seición nueva)",
        "editconflict": "Conflictu d'edición: $1",
-       "explainconflict": "Daquién más camudó esta páxina dende qu'empecipiasti a editala.\nL'área de testu d'arriba contien el testu de la páxina como ta nestos momentos.\nLos tos cambios s'amuesen nel área de testu d'abaxo.\nVas tener que fusionar los tos cambios dientro del testu esistente.\n'''Namái''' va guardase'l testu del área d'arriba cuando calques \"$1\".",
+       "explainconflict": "Daquién más camudó esta páxina dende qu'empecipiasti a editala.\nL'área de testu d'arriba contien el testu de la páxina como ta nestos momentos.\nLos tos cambios s'amuesen nel área de testu d'abaxo.\nVas tener que fusionar los tos cambios col testu qu'esiste.\n<strong>Namái</strong> va guardase'l testu del área d'arriba cuando pulsies «$1».",
        "yourtext": "El to testu",
        "storedversion": "Versión almacenada",
        "editingold": "'''AVISU: Tas editando una revisión vieya d'esta páxina. Si la grabes, los cambios que se ficieron dende esta revisión van perdese.'''",
        "undo-summary": "Esfacer la revisión $1 de [[Special:Contributions/$2|$2]] ([[User talk:$2|alderique]])",
        "undo-summary-username-hidden": "Desfacer la revisión $1 d'un usuariu tapecíu",
        "cantcreateaccount-text": "[[User:$3|$3]] bloquió la creación de cuentes dende esta direición IP (<strong>$1</strong>).\n\nEl motivu dau por $3 ye <em>$2</em>",
-       "cantcreateaccount-range-text": "La creación de cuentes dende direiciones IP del rangu <strong>$1</strong>, qu'incluye la so direición IP (<strong>$4</strong>), ta bloquiada pol usuariu [[User:$3|$3]].\n\nLa razón dada por $3 ye <em>$2</em>.",
+       "cantcreateaccount-range-text": "La creación de cuentes dende direiciones IP del rangu <strong>$1</strong>, qu'incluye la to direición IP (<strong>$4</strong>), ta bloquiada pol usuariu [[User:$3|$3]].\n\nLa razón dada por $3 ye <em>$2</em>.",
        "viewpagelogs": "Ver los rexistros d'esta páxina",
        "nohistory": "Nun hay historial d'ediciones pa esta páxina.",
        "currentrev": "Revisión actual",
        "upload-preferred": "{{PLURAL:$2|Tipu de ficheru preferíu|Tipos de ficheros preferíos}}: $1.",
        "upload-prohibited": "{{PLURAL:$2|Tipu de ficheru torgáu|Tipos de ficheros torgaos}}: $1.",
        "uploadlogpage": "Rexistru de xubíes",
-       "uploadlogpagetext": "Abaxo amuésase una llista de les xubíes d'archivos más recientes.\nMira la [[Special:NewFiles|galería d'archivos nuevos]] pa una güeyada más visual.",
+       "uploadlogpagetext": "Abaxo amuésase una llista de les cargues de ficheros más recién.\nMira la [[Special:NewFiles|galería de ficheros nuevos]] pa un resume más visual.",
        "filename": "Nome del ficheru",
        "filedesc": "Resume",
        "fileuploadsummary": "Resume:",
        "filereuploadsummary": "Cambios del ficheru:",
        "filestatus": "Estáu de Copyright:",
        "filesource": "Fonte:",
-       "ignorewarning": "Inorar l'avisu y grabar l'archivu de toes formes",
+       "ignorewarning": "Inorar l'avisu y guardar el ficheru de toles maneres",
        "ignorewarnings": "Inorar tolos avisos",
-       "minlength1": "Los nomes d'archivu han tener a lo menos una lletra.",
+       "minlength1": "Los nomes de ficheru han de tener polo menos una lletra.",
        "illegalfilename": "El nome del ficheru \"$1\" contien caráuteres non permitíos en títulos de páxina. Por favor renoma l'archivu ya intenta xubilu otra vuelta.",
        "filename-toolong": "Los nomes de ficheru nun puen tener más de 240 bytes.",
-       "badfilename": "Nome de la imaxe camudáu a \"$1\".",
+       "badfilename": "El nome del ficheru cambióse a «$1».",
        "filetype-mime-mismatch": "La estensión de ficheru \".$1\" nun casa cola triba MIME detectada del ficheru ($2).",
        "filetype-badmime": "Los ficheros de la triba MIME \"$1\" nun tienen permitida la xubida.",
        "filetype-bad-ie-mime": "Nun se pue xubir esti ficheru porque Internet Explorer detectalu como \"$1\", que nun ta permitíu y pue ser una triba de ficheru peligrosa.",
        "fileexists": "Yá esiste un ficheru con esti nome, por favor comprueba <strong>[[:$1]]</strong> si nun tas {{GENDER:|seguru|segura}} de querer camudalu.\n[[$1|thumb]]",
        "filepageexists": "La páxina de descripción d'esti ficheru creóse yá en <strong>[[:$1]]</strong>, pero anguaño nun esiste nengún ficheru con esti nome.\nEl resume que pongas nun va apaecer na páxina de descripción.\nPa facer que'l to resume apaeza, vas tener qu'editalu manualmente.\n[[$1|thumb]]",
        "fileexists-extension": "Yá esiste un ficheru con un nome asemeyáu: [[$2|thumb]]\n* Nome del ficheru que se quier xubir: <strong>[[:$1]]</strong>\n* Nome del ficheru esistente: <strong>[[:$2]]</strong>\n¿Quies meyor usar un nome más distinguible?",
-       "fileexists-thumbnail-yes": "El ficheru paez ser una imaxe de tamañu menguáu ''(miniatura)''.\n [[$1|thumb]]\nPor favor comprueba el ficheru <strong>[[:$1]]</strong>.\nSi'l ficheru comprobáu tien el mesmu tamañu que la imaxe orixinal, nun ye necesario xubir una miniatura estra.",
-       "file-thumbnail-no": "El ficheru entama con <strong>$1</strong>.\nPaez ser una imaxe de tamañu menguáu ''(miniatura)''.\nSi tienes esta imaxe a resolución completa xúbila; si non, por favor camuda'l nome del ficheru.",
+       "fileexists-thumbnail-yes": "El ficheru paez ser una imaxe de tamañu menguáu <em>(miniatura)</em>.\n [[$1|thumb]]\nRevisa'l ficheru <strong>[[:$1]]</strong>.\nSi'l ficheru revisáu ye la mesma imaxe que la del tamañu orixinal, nun se precisa xubir una miniatura estra.",
+       "file-thumbnail-no": "El nome del ficheru principia por <strong>$1</strong>.\nPaez ser una imaxe de tamañu menguáu <em>(miniatura)</em>.\nSi tienes esta imaxe a resolución completa xúbela; sinón, cambia'l nome del ficheru.",
        "fileexists-forbidden": "Yá esiste un ficheru con esti nome, y nun se pue renomar.\nSi tovía asina quies xubir el ficheru, por favor vuelvi atrás y usa otru nome.\n[[File:$1|thumb|center|$1]]",
        "fileexists-shared-forbidden": "Yá esiste un ficheru con esti nome nel direutoriu de ficheros compartíos.\nSi tovía asina quies xubir el ficheru, por favor vuelvi atrás y usa otru nome.\n[[File:$1|thumb|center|$1]]",
        "fileexists-no-change": "La carga ye un duplicáu exautu de la versión actual de <strong>[[:$1]]</strong>.",
        "uploadvirus": "¡El ficheru tien un virus!\nDetalles: $1",
        "uploadjava": "El ficheru ye un archivu ZIP que contien un ficheru .class de Java.\nXubir ficheros Java nun ta permitío, porque puede facer que se salten les torgues de seguridá.",
        "upload-source": "Ficheru orixe",
-       "sourcefilename": "Nome d'orixe:",
+       "sourcefilename": "Nome del ficheru orixinal:",
        "sourceurl": "URL d'orixe:",
        "destfilename": "Nome de destín:",
        "upload-maxfilesize": "Tamañu máximu del ficheru: $1",
        "filename-bad-prefix": "El nome del ficheru que tas xubiendo entama con '''\"$1\"''', que ye un nome non descriptivu que de vezu conseñen automáticamente les cámares dixitales.\nPor favor escueyi un nome más descriptivu pal to ficheru.",
        "filename-prefix-blacklist": " #<!-- dexa esta llinia exactamente como ta --> <pre>\n# La sintaxis ye la siguiente:\n#   * Lo que va del caráuter \"#\" al fin de llinia ye un comentariu\n#   * Toa llinia non-balera ye un prefixu pa los nomes de ficheru típicos que ponen les cámares dixitales\nCIMG # Casio\nDSC_ # Nikon\nDSCF # Fuji\nDSCN # Nikon\nDUW # dellos teléfonos móviles\nIMG # xenéricu\nJD # Jenoptik\nMGP # Pentax\nPICT # misc.\n #</pre> <!-- dexa esta llinia exactamente como ta -->",
        "upload-proto-error": "Protocolu incorreutu",
-       "upload-proto-error-text": "La xubida remota requier que l'URL entame por <code>http://</code> o <code>ftp://</code>.",
+       "upload-proto-error-text": "La carga remota rique que les URL principien por <code>http://</code> o <code>ftp://</code>.",
        "upload-file-error": "Error internu",
        "upload-file-error-text": "Hebo un error al intentar crear un ficheru temporal nel sirvidor.\nPor favor contauta con un [[Special:ListUsers/sysop|alministrador]] del sistema.",
-       "upload-misc-error": "Error de xubida desconocíu",
+       "upload-misc-error": "Error de carga desconocíu",
        "upload-misc-error-text": "Hebo un error desconocíu na xubida del ficheru.\nPor favor comprueba que l'URL ye válidu y accesible, y inténtalo otra vuelta.\nSi'l problema persiste, contauta con un [[Special:ListUsers/sysop|alministrador]] del sistema.",
        "upload-too-many-redirects": "La URL contenía demasiaes redireiciones",
        "upload-http-error": "Hebo un error HTTP: $1",
        "upload-form-label-infoform-description-tooltip": "Describe de mou curtiu cualquier cosa notable de la obra.\nPa una semeya, cuenta les principales coses qu'apaecen, la ocasión o'l sitiu.",
        "upload-form-label-usage-title": "Usu",
        "upload-form-label-usage-filename": "Nome del ficheru",
-       "upload-form-label-own-work": "Esti ye'l mio propiu trabayu",
+       "upload-form-label-own-work": "Esta ye una obra propia",
        "upload-form-label-infoform-categories": "Categoríes",
        "upload-form-label-infoform-date": "Data",
        "upload-form-label-own-work-message-generic-local": "Confirmo que xubo esti ficheru siguiendo les condiciones de serviciu y les polítiques de llicencies de {{SITENAME}}.",
-       "upload-form-label-not-own-work-message-generic-local": "Si nun puedes xubir esti ficheru baxo les polítiques de {{SITENAME}}, zarra esti diálogu y prueba otru métodu.",
-       "upload-form-label-not-own-work-local-generic-local": "Quiciabes quieras probar tamién [[Special:Upload|la páxina predeterminada de xubíes]].",
+       "upload-form-label-not-own-work-message-generic-local": "Si nun puedes xubir esti ficheru baxo les polítiques de {{SITENAME}}, zarra esti diálogu y tenta otru métodu.",
+       "upload-form-label-not-own-work-local-generic-local": "Quiciabes tamién quieras tentar [[Special:Upload|la páxina de cargues predeterminada]].",
        "upload-form-label-own-work-message-generic-foreign": "Entiendo que toi xubiendo esti ficheru a un depósitu compartíu. Confirmo que toi faciéndolo cumpliendo les condiciones de serviciu y les polítiques de llicencies d'esi sitiu.",
-       "upload-form-label-not-own-work-message-generic-foreign": "Si nun puedes xubir esti ficheru baxo les polítiques del depósitu compartíu, zarra esti diálogu y prueba otru métodu.",
+       "upload-form-label-not-own-work-message-generic-foreign": "Si nun puedes xubir esti ficheru baxo les polítiques del depósitu compartíu, zarra esti diálogu y tenta otru métodu.",
        "upload-form-label-not-own-work-local-generic-foreign": "Tamién pué interesate usar [[Special:Upload|la páxina de carga de {{SITENAME}}]] si esti ficheru pué xubise allí baxo les sos polítiques.",
        "backend-fail-stream": "Nun se pudo tresmitir el ficheru $1.",
        "backend-fail-backup": "Nun se pudo facer copia de seguridá del ficheru $1.",
        "http-curl-error": "Error al baxar la URL: $1",
        "http-bad-status": "Hebo un problema demientres la llamada HTTP: $1 $2",
        "upload-curl-error6": "Nun se pudo acceder a la URL",
-       "upload-curl-error6-text": "Nun se pudo acceder a la URL introducida. Por favor comprueba que la URL ye correuta y que'l sitiu ta activu.",
-       "upload-curl-error28": "Fin del tiempu d'espera de la xubida",
-       "upload-curl-error28-text": "El sitiu tardó demasiáu tiempu en responder. Por favor comprueba que'l sitiu ta activu, espera unos momentos y vuelve a intentalo. Igual ye meyor que lo intentes nun momentu en que tea menos sobrecargáu.",
+       "upload-curl-error6-text": "Nun pudo algamase la URL dada.\nComprueba que la URL ye correuta y que'l sitiu ta activu.",
+       "upload-curl-error28": "Escosó'l tiempu d'espera de la carga",
+       "upload-curl-error28-text": "El sitiu tardó demasiáu tiempu en responder.\nComprueba que'l sitiu ta activu, espera unos momentos y vuelve a tentalo.\nEscurque puedes tentar a una hora con menos sobrecarga.",
        "license": "Llicencia:",
        "license-header": "Llicencia",
        "nolicense": "Nenguna seleicionada",
        "upload_source_file": "(el ficheru qu'escoyisti del to ordenador)",
        "listfiles-delete": "desaniciar",
        "listfiles-summary": "Esta páxina especial amuesa tolos ficheros xubíos.",
-       "listfiles_search_for": "Buscar por nome d'archivu multimedia:",
+       "listfiles_search_for": "Buscar el nome d'un ficheru multimedia:",
        "listfiles-userdoesnotexist": "La cuenta d'usuariu «$1» nun ta rexistrada.",
        "imgfile": "ficheru",
-       "listfiles": "Llista d'imáxenes",
+       "listfiles": "Llista de ficheros",
        "listfiles_thumb": "Miniatura",
        "listfiles_date": "Data",
        "listfiles_name": "Nome",
        "file-anchor-link": "Ficheru",
        "filehist": "Historial del ficheru",
        "filehist-help": "Calca nuna fecha/hora pa ver el ficheru como taba daquella.",
-       "filehist-deleteall": "esborrar too",
+       "filehist-deleteall": "desaniciar too",
        "filehist-deleteone": "desaniciar",
        "filehist-revert": "revertir",
        "filehist-current": "actual",
        "filehist-comment": "Comentariu",
        "imagelinks": "Usu del ficheru",
        "linkstoimage": "{{PLURAL:$1|La páxina siguiente enllacia|Les páxines siguientes enllacien}} a esti ficheru:",
-       "linkstoimage-more": "Más de $1 {{PLURAL:$1|páxina enllacia|páxines enllacien}} a esti archivu.\nLa llista siguiente amuesa{{PLURAL:$1|'l primer enllaz de páxina| los primeros $1 enllaces de páxina}} a esti archivu namái.\nHai disponible una [[Special:WhatLinksHere/$2|llista completa]].",
+       "linkstoimage-more": "Más de $1 {{PLURAL:$1|páxina enllacia|páxines enllacien}} a esti ficheru.\nLa llista siguiente amuesa{{PLURAL:$1|'l primer enllaz de páxina| los primeros $1 enllaces de páxina}} a esti ficheru namái.\nHai disponible una [[Special:WhatLinksHere/$2|llista completa]].",
        "nolinkstoimage": "Nun hai páxines qu'enllacien a esti ficheru.",
-       "morelinkstoimage": "Ver [[Special:WhatLinksHere/$1|más enllaces]] a esti archivu.",
+       "morelinkstoimage": "Ver [[Special:WhatLinksHere/$1|más enllaces]] a esti ficheru.",
        "linkstoimage-redirect": "$1 (redireición de ficheru) $2",
-       "duplicatesoffile": "{{PLURAL:$1|El siguiente archivu ye un duplicáu|Los siguientes $1 archivos son duplicaos}} d'esti archivu ([[Special:FileDuplicateSearch/$2|más detalles]]):",
+       "duplicatesoffile": "{{PLURAL:$1|El siguiente ficheru ye un duplicáu|Los $1 ficheros siguientes son duplicaos}} d'esti ([[Special:FileDuplicateSearch/$2|más detalles]]):",
        "sharedupload": "Esti ficheru ye de $1 y puen usalu otros proyeutos.",
        "sharedupload-desc-there": "Esti ficheru ye de $1 y puen usalu otros proyeutos.\nLlea la [páxina de descripción del ficheru $2] pa más información.",
        "sharedupload-desc-here": "Esti ficheru ye de $1 y puen usalu otros proyeutos.\nLa descripción de la [$2 páxina de descripción del ficheru] s'amuesa darréu.",
        "sharedupload-desc-create": "Esti ficheru ye de $1 y puen usalu otros proyeutos.\nSeique quieras camudar la descripción de la so [páxina de descripción de ficheru $2] allí.",
        "filepage-nofile": "Nun esiste dengún ficheru con esti nome.",
        "filepage-nofile-link": "Nun esiste ficheru dalu con esti nome, pero pues [$1 xubilu].",
-       "uploadnewversion-linktext": "Xubir una nueva versión d'esta imaxe",
+       "uploadnewversion-linktext": "Xubir una versión nueva d'esti ficheru",
        "shared-repo-from": "de $1",
        "shared-repo": "un repositoriu compartíu",
        "filepage.css": "/* El CSS allugáu equí s'incluye na páxina de descripción del ficheru, que tamién s'incluye nes wikis clientes foriates */",
        "upload-disallowed-here": "Nun pues sobrescribir esti ficheru.",
        "filerevert": "Revertir $1",
-       "filerevert-legend": "Revertir archivu",
-       "filerevert-intro": "Tas revirtiendo '''[[Media:$1|$1]]''' a la [$4 versión del $3 a les $2].",
+       "filerevert-legend": "Revertir ficheru",
+       "filerevert-intro": "Tas a piques de revertir el ficheru <strong>[[Media:$1|$1]]</strong> a la [$4 versión del $2, a les $3].",
        "filerevert-comment": "Motivu:",
        "filerevert-defaultcomment": "Revertida a la versión del $1 a les $2 ($3)",
        "filerevert-submit": "Revertir",
-       "filerevert-success": "'''[[Media:$1|$1]]''' foi revertida a la [$4 versión del $3 a les $2].",
-       "filerevert-badversion": "Nun hai nenguna versión llocal previa d'esti archivu cola fecha conseñada.",
+       "filerevert-success": "<strong>[[Media:$1|$1]]</strong> revertióse a la [$4 versión del $2, a les $3].",
+       "filerevert-badversion": "Nun hai nenguna versión llocal anterior d'esti ficheru cola marca de tiempu dada.",
        "filerevert-identical": "La versión actual del ficheru ye igual que la seleicionada.",
        "filedelete": "Desaniciar $1",
-       "filedelete-legend": "Esborrar archivu",
-       "filedelete-intro": "Tas a piques d'esborrar el ficheru '''[[Media:$1|$1]]''' xunto con tol so historial.",
-       "filedelete-intro-old": "Tas esborrando la versión de '''[[Media:$1|$1]]''' del [$4 $3 a les $2].",
+       "filedelete-legend": "Desaniciar ficheru",
+       "filedelete-intro": "Tas a piques de desaniciar el ficheru <strong>[[Media:$1|$1]]</strong> xunto col so historial completu.",
+       "filedelete-intro-old": "Tas desaniciando la versión de <strong>[[Media:$1|$1]]</strong> del [$4 $2, a les $3].",
        "filedelete-comment": "Motivu:",
        "filedelete-submit": "Desaniciar",
        "filedelete-success": "'''$1''' se desanició.",
-       "filedelete-success-old": "Eliminóse la versión de '''[[Media:$1|$1]]''' del $2 a les $3.",
-       "filedelete-nofile": "'''$1''' nun esiste.",
-       "filedelete-nofile-old": "Nun hai nenguna versión archivada de  '''$1''' colos atributos especificaos.",
+       "filedelete-success-old": "Desanicióse la versión de <strong>[[Media:$1|$1]]</strong> del $2, a les $3.",
+       "filedelete-nofile": "<strong>$1</strong> nun esiste.",
+       "filedelete-nofile-old": "Nun hai nenguna versión archivada de  <strong>$1</strong> colos atributos especificaos.",
        "filedelete-otherreason": "Motivu distintu/adicional:",
        "filedelete-reason-otherlist": "Otru motivu",
-       "filedelete-reason-dropdown": "*Motivos comunes d'esborráu\n** Violación de Copyright\n** Archivu duplicáu",
-       "filedelete-edit-reasonlist": "Editar los motivos d'esborráu",
+       "filedelete-reason-dropdown": "*Motivos habituales pal desaniciu\n** Frayamientu de Copyright\n** Ficheru duplicáu",
+       "filedelete-edit-reasonlist": "Editar los motivos del desaniciu",
        "filedelete-maintenance": "El desaniciu y restauración de ficheros ta desactivao temporalmente mientres ta en mantenimientu.",
        "filedelete-maintenance-title": "Nun se pue desaniciar el ficheru",
        "mimesearch": "Busca MIME",
        "listduplicatedfiles-summary": "Esta ye una llista de ficheros onde la versión más nueva del ficheru ye un duplicáu de la versión más nueva d'algún otru ficheru. Considérense sólo los ficheros llocales.",
        "listduplicatedfiles-entry": "[[:File:$1|$1]] tien [[$3|{{PLURAL:$2|un duplicáu|$2 duplicaos}}]].",
        "unusedtemplates": "Plantíes ensin usu",
-       "unusedtemplatestext": "Esta páxina llista toles páxines del espaciu de nomes {{ns:template}} que nun tán inxeríes n'otres páxines.\nAlcuérdate de comprobar otros enllaces a les plantíes enantes d'esborrales.",
+       "unusedtemplatestext": "Esta páxina recueye toles páxines del espaciu de nomes {{ns:template}} que nun tán inxeríes n'otres páxines.\nAlcuérdate de comprobar otros enllaces a les plantíes enantes de desaniciales.",
        "unusedtemplateswlh": "otros enllaces",
        "randompage": "Páxina al debalu",
        "randompage-nopages": "Nun hai páxines {{PLURAL:$2|nel espaciu|nos espacios}} de nomes darréu: \"$1\".",
        "statistics": "Estadístiques",
        "statistics-header-pages": "Estadístiques de páxines",
        "statistics-header-edits": "Estadístiques d'ediciones",
-       "statistics-header-users": "Estadístiques d'usuariu",
+       "statistics-header-users": "Estadístiques d'usuarios",
        "statistics-header-hooks": "Otres estadístiques",
        "statistics-articles": "Páxines de conteníu",
        "statistics-pages": "Páxines",
        "statistics-pages-desc": "Toles páxines de la wiki, incluyendo páxines d'alderique, redireiciones, etc.",
-       "statistics-files": "Archivos xubíos",
-       "statistics-edits": "Ediciones de páxines dende qu'entamó {{SITENAME}}",
+       "statistics-files": "Ficheros xubíos",
+       "statistics-edits": "Ediciones de páxines dende'l principiu de {{SITENAME}}",
        "statistics-edits-average": "Media d'ediciones por páxina",
        "statistics-users": "[[Special:ListUsers|Usuarios]] rexistraos",
        "statistics-users-active": "Usuarios activos",
-       "statistics-users-active-desc": "Usuarios que realizaron una aición {{PLURAL:$1|nel caberu día|nos caberos $1 díes}}",
+       "statistics-users-active-desc": "Usuarios que ficieron dalguna aición {{PLURAL:$1|nel caberu día|nos caberos $1 díes}}",
        "pageswithprop": "Páxines con una propiedá de páxina",
        "pageswithprop-legend": "Páxines con una propiedá de páxina",
        "pageswithprop-text": "Esta páxina llista les páxines qu'usen una propiedá de páxina determinada.",
        "double-redirect-fixed-move": "[[$1]] treslladóse.\nAnovóse automáticamente y agora redirixe haza [[$2]].",
        "double-redirect-fixed-maintenance": "Iguando automáticamente la doble redireición de [[$1]] a [[$2]] nuna xera de mantenimientu.",
        "double-redirect-fixer": "Iguador de redireiciones",
-       "brokenredirects": "Redireiciones rotes",
-       "brokenredirectstext": "Les siguientes redireiciones enllacien a páxines non esistentes:",
+       "brokenredirects": "Redireiciones frañaes",
+       "brokenredirectstext": "Les redireiciones siguientes enllacien a páxines que nun esisten:",
        "brokenredirects-edit": "editar",
        "brokenredirects-delete": "desaniciar",
-       "withoutinterwiki": "Páxines ensin interwikis",
+       "withoutinterwiki": "Páxines ensin enllaces a otres llingües",
        "withoutinterwiki-summary": "Les páxines siguientes nun enllacien a versiones n'otres llingües:",
        "withoutinterwiki-legend": "Prefixu",
        "withoutinterwiki-submit": "Amosar",
-       "fewestrevisions": "Páxines col menor númberu d'ediciones",
+       "fewestrevisions": "Páxines con menor númberu de revisiones",
        "nbytes": "$1 {{PLURAL:$1|byte|bytes}}",
        "ncategories": "$1 {{PLURAL:$1|categoría|categoríes}}",
        "ninterwikis": "$1 {{PLURAL:$1|interwiki|interwikis}}",
        "nrevisions": "$1 {{PLURAL:$1|revisión|revisiones}}",
        "nimagelinks": "Usao en $1 {{PLURAL:$1|páxina|páxines}}",
        "ntransclusions": "usao en $1 {{PLURAL:$1|páxina|páxines}}",
-       "specialpage-empty": "Nun hai resultaos nestos momentos.",
+       "specialpage-empty": "Nun hai resultaos pa esti informe.",
        "lonelypages": "Páxines güérfanes",
        "lonelypagestext": "Les páxines siguientes nun tán enllaciaes nin trescluyíes dende otres páxines de {{SITENAME}}.",
-       "uncategorizedpages": "Páxines non categorizaes",
-       "uncategorizedcategories": "Categoríes non categorizaes",
-       "uncategorizedimages": "Archivos non categorizaos",
-       "uncategorizedtemplates": "Plantíes non categorizaes",
+       "uncategorizedpages": "Páxines ensin categoríes",
+       "uncategorizedcategories": "Categoríes ensin categoríes",
+       "uncategorizedimages": "Ficheros ensin categoríes",
+       "uncategorizedtemplates": "Plantíes ensin categoríes",
        "uncategorized-categories-exceptionlist": "# Contien una llista de categoríes que nun tendríen d'apaecer en Special:UncategorizedCategories. Una categoría per llinia, empezando por «*». Nun se tienen en cuenta les llinies qu'empiecen con otru caráuter (espacios en blancu incluyíos). Usa «#» p'añadir comentarios.",
-       "unusedcategories": "Categoríes non usaes",
-       "unusedimages": "Imáxenes non usaes",
+       "unusedcategories": "Categoríes ensin usu",
+       "unusedimages": "Imáxenes ensin usu",
        "wantedcategories": "Categoríes buscaes",
        "wantedpages": "Páxines buscaes",
        "wantedpages-summary": "Llista de páxines inesistentes con más enllaces a elles, sacante les páxines que sólo tienen redireiciones qu'enllacen con elles. Pa ver la llista de páxines inesistentes que tienen redireiciones qu'enllacen con elles, ver [[{{#special:BrokenRedirects}}|la llista de redireiciones frañaes]].",
        "wantedpages-badtitle": "Títulu inválidu nel conxuntu de resultaos: $1",
-       "wantedfiles": "Archivos buscaos",
+       "wantedfiles": "Ficheros buscaos",
        "wantedfiletext-cat": "Los ficheros siguientes tan usándose, pero nun esisten. Ye posible qu'apaezan ficheros de repositorios esternos ensin qu'esistan. Cualesquier falsu positivu tará <del>tacháu</del>. Amás, les páxines qu'inxerten ficheros que nun esisten apaecen na llista de [[:$1]].",
        "wantedfiletext-cat-noforeign": "Los ficheros siguientes tán usándose, pero nun existen. Amás, hai una llista de páxines qu'incluyen ficheros que non existen en [[:$1]].",
        "wantedfiletext-nocat": "Los ficheros siguientes tan usándose, pero nun esisten. Ye posible qu'apaezan ficheros de repositorios esternos ensin qu'esistan. Cualesquier falsu positivu tará <del>tacháu</del>.",
        "wantedfiletext-nocat-noforeign": "Los ficheros siguientes tán usándose, pero nun existen.",
-       "wantedtemplates": "Plantíes más buscaes",
+       "wantedtemplates": "Plantíes buscaes",
        "mostlinked": "Páxines más enllaciaes",
        "mostlinkedcategories": "Categoríes más enllaciaes",
        "mostlinkedtemplates": "Páxines más trescluíes",
        "mostcategories": "Páxines con más categoríes",
-       "mostimages": "Archivos más enllaciaos",
+       "mostimages": "Ficheros más enllaciaos",
        "mostinterwikis": "Páxines con más interwikis",
        "mostrevisions": "Páxines con más revisiones",
        "prefixindex": "Toles páxines col prefixu",
        "shortpages": "Páxines curties",
        "longpages": "Páxines llargues",
        "deadendpages": "Páxines ensin salida",
-       "deadendpagestext": "Les páxines siguientes nun enllacien a páxina dala de {{SITENAME}}.",
+       "deadendpagestext": "Les páxines siguientes nun enllacien a otres páxines de {{SITENAME}}.",
        "protectedpages": "Páxines protexíes",
-       "protectedpages-indef": "Namái les proteiciones permanentes",
+       "protectedpages-indef": "Namái les proteiciones indefiníes",
        "protectedpages-summary": "Esta páxina amuesa la llista de páxines esistentes que tan protexíes actualmente. Pa la llista de títulos que tienen torgada la creación, ver [[{{#special:ProtectedTitles}}|{{int:protectedtitles}}]].",
        "protectedpages-cascade": "Namái proteiciones en cascada",
        "protectedpages-noredirect": "Anubrir redireiciones",
        "move": "Treslladar",
        "movethispage": "Treslladar esta páxina",
        "unusedimagestext": "Los ficheros darréu esisten pero nun tan inxertaos en páxina dala.\nDate cuenta de qu'otros sitios web puen enllazar a un ficheru con una URL direuta, polo que seique tean tovía llistaos equí, magar que tean n'usu activu.",
-       "unusedcategoriestext": "Les siguientes categoríes esisten magar que nengún artículu o categoría faiga usu d'elles.",
-       "notargettitle": "Nun hai oxetivu",
-       "notargettext": "Nun especificasti una páxina oxetivu o un usuariu sobre los que realizar esta función.",
-       "nopagetitle": "Nun esiste la páxina oxetivu",
-       "nopagetext": "La páxina oxetivu qu'especificasti nun esiste.",
+       "unusedcategoriestext": "Les siguientes páxines de categoría esisten, anque nengún artículu o categoría fai usu d'elles.",
+       "notargettitle": "Nun hai destín",
+       "notargettext": "Nun especificasti qué páxina o usuariu ye'l destín pa executar esta aición.",
+       "nopagetitle": "Nun esiste la páxina de destín",
+       "nopagetext": "La páxina de destín qu'especificasti nun esiste.",
        "pager-newer-n": "{{PLURAL:$1|1 siguiente|$1 siguientes}}",
        "pager-older-n": "{{PLURAL:$1|1 anterior|$1 anteriores}}",
        "suppress": "Supresor",
        "booksources-search-legend": "Busca de fontes de llibros",
        "booksources-search": "Buscar",
        "booksources-text": "Esta ye una llista d'enllaces a otros sitios que vienden llibros nuevos y usaos, y que puen tener más información sobre los llibros que ta buscando:",
-       "booksources-invalid-isbn": "El códigu ISBN que puxisti nun paez que valga; mira que te vien copiáu de la fonte orixinal.",
+       "booksources-invalid-isbn": "El códigu ISBN dau nun paez válidu; comprueba si hai errores al copiar de la fonte orixinal.",
        "magiclink-tracking-rfc": "Páxines que usen enllaces máxicos RFC",
        "magiclink-tracking-rfc-desc": "Esta páxina utiliza enllaces máxicos RFC. Consulta [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] pa saber como facer la migración.",
        "magiclink-tracking-pmid": "Páxines qu'usen enllaces máxicos PMID",
        "log": "Rexistros",
        "logeventslist-submit": "Amosar",
        "all-logs-page": "Tolos rexistros públicos",
-       "alllogstext": "Visualización combinada de tolos rexistros disponibles de {{SITENAME}}.\nPues filtrar la visualización seleicionando una mena de rexistru, el nome d'usuariu (teniendo en cuenta les mayúscules y minúscules) o la páxina afectada (teniendo en cuenta tamién les mayúscules y minúscules).",
+       "alllogstext": "Vista combinada de tolos rexistros disponibles de {{SITENAME}}.\nPues filtrar la vista seleicionando una triba de rexistru, el nome d'usuariu (sensible a mayúscules y minúscules), o la páxina afeutada (tamién sensible a mayúscules y minúscules).",
        "logempty": "Nun hai coincidencies nel rexistru.",
-       "log-title-wildcard": "Buscar títulos qu'emprimen con esti testu",
+       "log-title-wildcard": "Buscar títulos que principien por esti testu",
        "showhideselectedlogentries": "Amosar/anubrir les entraes del rexistru seleicionaes",
        "log-edit-tags": "Editar les etiquetes de les entraes del rexistru seleicionaes",
        "checkbox-select": "Seleicionar: $1",
        "allpages": "Toles páxines",
        "nextpage": "Páxina siguiente ($1)",
        "prevpage": "Páxina anterior ($1)",
-       "allpagesfrom": "Amosar páxines qu'entamen por:",
-       "allpagesto": "Amosar páxines que finen por:",
+       "allpagesfrom": "Amosar páxines qu'empiecen por:",
+       "allpagesto": "Amosar páxines terminaes con:",
        "allarticles": "Toles páxines",
        "allinnamespace": "Toles páxines (espaciu de nomes $1)",
        "allpagessubmit": "Dir",
        "allpagesprefix": "Amosar páxines col prefixu:",
-       "allpagesbadtitle": "El títulu dau a esta páxina nun yera válidu o tenía un prefixu d'enllaz interllingua o interwiki. Pue contener ún o más carauteres que nun se puen usar nos títulos.",
+       "allpagesbadtitle": "El títulu dau a esta páxina nun ye válidu o tenía un prefixu d'enllaz interllingua o interwiki.\nPuede contener ún caráuter o más que nun puede usase nos títulos.",
        "allpages-bad-ns": "{{SITENAME}} nun tien l'espaciu de nomes \"$1\".",
        "allpages-hide-redirects": "Anubrir redireiciones",
        "cachedspecial-viewing-cached-ttl": "Tas viendo una versión en caché d'esta páxina, que pue llegar a tener $1 d'antigüedá.",
        "categories": "Categoríes",
        "categories-submit": "Amosar",
        "categoriespagetext": "{{PLURAL:$1|La siguiente categoría contién|Les siguientes categoríes contienen}} páxines o ficheros multimedia.\nLes [[Special:UnusedCategories|categoríes nun usaes]] nun s'amuesen equí.\nVer tamién les [[Special:WantedCategories|categoríes más buscaes]].",
-       "categoriesfrom": "Amosar categoríes qu'emprimen por:",
-       "deletedcontributions": "Contribuciones d'usuariu esborraes",
+       "categoriesfrom": "Amosar les categoríes qu'empiecen por:",
+       "deletedcontributions": "Contribuciones d'usuariu desaniciaes",
        "deletedcontributions-title": "Contribuciones d'usuariu desaniciaes",
        "sp-deletedcontributions-contribs": "collaboraciones",
        "linksearch": "Busca d'enllaces esternos",
        "linksearch-pat": "Patrón de busca:",
        "linksearch-ns": "Espaciu de nomes:",
        "linksearch-ok": "Buscar",
-       "linksearch-text": "Se puen usar comodinos como \"*.wikipedia.org\".\nNecesita polo menos un dominiu de primer nivel, como \"*.org\".<br />\n{{PLURAL:$2|Protocolu almitíu|Protocolos almitíos}}: $1 (el predetermináu ye http:// si nun se conseña dengún protocolu).",
+       "linksearch-text": "Pueden usase comodinos como «*.wikipedia.org».\nPrecisa polo menos un dominiu de primer nivel, como «*.org».<br />\n{{PLURAL:$2|Protocolu almitíu|Protocolos almitíos}}: $1 (el predetermináu ye http:// si nun se conseña nengún protocolu).",
        "linksearch-line": "$1 enllaciáu dende $2",
-       "linksearch-error": "Los comodinos namái puen apaecer al entamu del nome del güéspede.",
-       "listusersfrom": "Amosar usuarios emprimando dende:",
+       "linksearch-error": "Los comodinos namái pueden apaecer al principiu del nome de sirvidor.",
+       "listusersfrom": "Amosar usuarios qu'empiecen por:",
        "listusers-submit": "Amosar",
-       "listusers-noresult": "Nun s'atoparon usuarios.",
+       "listusers-noresult": "Nun s'alcontraron usuarios.",
        "listusers-blocked": "(bloquiau)",
        "activeusers": "Llista d'usuarios activos",
        "activeusers-intro": "Esta ye una llista d'usuarios que tuvieron alguna mena d'actividá hai menos de $1 {{PLURAL:$1|día|díes}}.",
        "activeusers-excludegroups": "Excluir a los usuarios que pertenezan a los grupos:",
        "activeusers-noresult": "Nun s'alcontraron usuarios.",
        "activeusers-submit": "Amosar los usuarios activos",
-       "listgrouprights": "Drechos de los grupos d'usuariu",
-       "listgrouprights-summary": "La siguiente ye una llista de grupos d'usuariu definíos nesta wiki, colos sos drechos d'accesu asociaos.\nPue haber [[{{MediaWiki:Listgrouprights-helppage}}|información adicional]] tocante a drechos individuales.",
+       "listgrouprights": "Permisos del grupu d'usuarios",
+       "listgrouprights-summary": "La siguiente ye una llista de grupos d'usuarios definíos nesta wiki, colos permisos d'accesu asociaos.\nPuede haber [[{{MediaWiki:Listgrouprights-helppage}}|más información]] tocante a permisos individuales.",
        "listgrouprights-key": "Lleenda:\n* <span class=\"listgrouprights-granted\">Permisu concedíu</span>\n* <span class=\"listgrouprights-revoked\">Permisu retiráu</span>",
        "listgrouprights-group": "Grupu",
-       "listgrouprights-rights": "Drechos",
-       "listgrouprights-helppage": "Help:Drechos de grupu",
+       "listgrouprights-rights": "Permisos",
+       "listgrouprights-helppage": "Help:Permisos de grupu",
        "listgrouprights-members": "(llista de miembros)",
-       "listgrouprights-addgroup": "Pue añader {{PLURAL:$2|grupu|grupos}}: $1",
-       "listgrouprights-removegroup": "Pue quitar {{PLURAL:$2|grupu|grupos}}: $1",
-       "listgrouprights-addgroup-all": "Pue añader tolos grupos",
-       "listgrouprights-removegroup-all": "Pue quitar tolos grupos",
+       "listgrouprights-addgroup": "Añadir {{PLURAL:$2|grupu|grupos}}: $1",
+       "listgrouprights-removegroup": "Desaniciar {{PLURAL:$2|grupu|grupos}}: $1",
+       "listgrouprights-addgroup-all": "Añadir tolos grupos",
+       "listgrouprights-removegroup-all": "Desaniciar tolos grupos",
        "listgrouprights-addgroup-self": "Aamestar {{PLURAL:$2|grupu|grupos}} a la cuenta propia: $1",
        "listgrouprights-removegroup-self": "Desaniciar {{PLURAL:$2|grupu|grupos}} de la cuenta propia: $1",
        "listgrouprights-addgroup-self-all": "Amestar tolos grupos a la cuenta propia",
        "emailmessage": "Mensaxe:",
        "emailsend": "Unviar",
        "emailccme": "Unviame per corréu una copia del mio mensaxe.",
-       "emailccsubject": "Copia del to mensaxe a $1: $2",
+       "emailccsubject": "Copia del mensaxe a $1: $2",
        "emailsent": "Corréu unviáu",
        "emailsenttext": "Unviose'l to mensaxe de corréu.",
        "emailuserfooter": "Esti corréu electrónicu {{GENDER:$1|unviólu}} $1 a {{GENDER:$2|$2}} per aciu de la función «{{int:emailuser}}» de {{SITENAME}}. Si {{GENDER:$2|contestes}} a esti corréu, el {{GENDER:$2|to}} corréu unviaráse direutamente {{GENDER:$1|al remitente|a la remitente}} orixinal, {{GENDER:$1|revelando-y}} la {{GENDER:$2|to}} direición de corréu.",
        "watchlistfor2": "Pa $1 $2",
        "nowatchlist": "La to llista de siguimientu ta vacia.",
        "watchlistanontext": "Por favor, anicia sesión pa ver o editar entraes de la to llista de siguimientu.",
-       "watchnologin": "Non identificáu",
+       "watchnologin": "Nun aniciasti sesión",
        "addwatch": "Amestar a la llista de siguimientu",
        "addedwatchtext": "«[[:$1]]» y la so páxina d'alderique amestáronse a la to [[Special:Watchlist|llista de siguimientu]].",
        "addedwatchtext-talk": "«[[:$1]]» y la so páxina asociada amestáronse a la to [[Special:Watchlist|llista de siguimientu]].",
        "watchthispage": "Vixilar esta páxina",
        "unwatch": "Dexar de vixilar",
        "unwatchthispage": "Dexar de vixilar",
-       "notanarticle": "Nun ye un artículu",
-       "notvisiblerev": "Esborróse la revisión",
+       "notanarticle": "Nun ye una páxina de conteníu",
+       "notvisiblerev": "Desanicióse la última revisión d'un usuariu distintu",
        "watchlist-details": "{{PLURAL:$1|$1 páxina ta|$1 páxines tán}} na to llista de siguimientu (más les páxines d'alderique).",
        "wlheader-enotif": "La notificación per corréu electrónicu ta activada.",
        "wlheader-showupdated": "Les páxines que camudaron dende que les visitasti anteriormente amuesense en '''negrina'''",
        "enotif_minoredit": "Esta ye una edición menor",
        "created": "creada",
        "changed": "camudada",
-       "deletepage": "Esborrar páxina",
+       "deletepage": "Desaniciar páxina",
        "confirm": "Confirmar",
-       "excontent": "el conteníu yera: '$1'",
+       "excontent": "el conteníu yera: «$1»",
        "excontentauthor": "el conteníu yera: «$1», y l'únicu autor yera «[[Special:Contributions/$2|$2]]» ([[User talk:$2|alderique]])",
-       "exbeforeblank": "el conteníu enantes de dexar en blanco yera: '$1'",
+       "exbeforeblank": "el conteníu enantes de dexar en blancu yera: «$1»",
        "delete-confirm": "Desaniciar «$1»",
        "delete-legend": "Desaniciar",
        "historywarning": "<strong>Avisu:</strong> La páxina que vas desaniciar tien un historial con $1 {{PLURAL:$1|revisión|revisiones}}:",
        "confirmdeletetext": "Tas a piques d'esborrar una páxina xunto con tol so historial.\nPor favor confirma que ye lo que quies facer, qu'entiendes les consecuencies, y que lo tas faciendo acordies coles [[{{MediaWiki:Policy-url}}|polítiques]].",
        "actioncomplete": "Aición completada",
        "actionfailed": "Falló l'aición",
-       "deletedtext": "Esborróse \"$1\".\nMira en $2 la llista de les últimes páxines esborraes.",
+       "deletedtext": "Desanicióse «$1».\nVer en $2 el rexistru de desanicios recién.",
        "dellogpage": "Rexistru de desanicios",
-       "dellogpagetext": "Abaxo amuésase una llista de los artículos esborraos más recién.",
+       "dellogpagetext": "Más abaxo ta la llista de los desanicios más recién.",
        "deletionlog": "rexistru de desanicios",
        "reverted": "Revertida a una revisión anterior",
        "deletecomment": "Motivu:",
        "deleteotherreason": "Motivu distintu/adicional:",
        "deletereasonotherlist": "Otru motivu",
        "deletereason-dropdown": "*Motivos comunes d'esborráu\n** Puxarra\n** Vandalismu\n** Violación de drechos d'autor\n** A pidimientu del autor\n** Redireición frañada",
-       "delete-edit-reasonlist": "Editar los motivos d'esborráu",
-       "delete-toobig": "Esta páxina tien un historial d'ediciones grande, más de $1 {{PLURAL:$1|revisión|revisiones}}.\nRestrinxóse l'esborráu d'estes páxines pa evitar perturbaciones accidentales de {{SITENAME}}.",
-       "delete-warning-toobig": "Esta páxina tien un historial d'ediciones grande, más de $1 {{PLURAL:$1|revisión|revisiones}}.\nEsborralu pue perturbar les operaciones de la base de datos de {{SITENAME}};\nobra con precaución.",
+       "delete-edit-reasonlist": "Editar los motivos de desaniciu",
+       "delete-toobig": "Esta páxina tien un historial d'ediciones grande, más de $1 {{PLURAL:$1|revisión|revisiones}}.\nTorgóse'l desaniciu d'estes páxines pa prevenir problemes accidentales en {{SITENAME}}.",
+       "delete-warning-toobig": "Esta páxina tien un historial d'ediciones grande, más de $1 {{PLURAL:$1|revisión|revisiones}}.\nDesanicialu puede afeutar a les operaciones de la base de datos de {{SITENAME}}.\nActúa con procuru.",
        "deleteprotected": "Nun pues desaniciar esta páxina porque ta protexida.",
        "deleting-backlinks-warning": "<strong>Avisu:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Otres páxines]] enllacen a, o trescluyen de, la páxina que tas a piques de desaniciar.",
        "deleting-subpages-warning": "<strong>Avisu:</strong> La páxina que vas desaniciar tien [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|una subpáxina|$1 subpáxines|51=más de 50 subpáxines}}]].",
        "rollbackfailed": "Falló la reversión",
        "rollback-missingparam": "Faltan parámetros riquíos na solicitú.",
        "rollback-missingrevision": "Nun pueden cargase los datos de la revisión.",
-       "cantrollback": "Nun se pue revertir la edición; el postrer collaborador ye l'únicu autor d'esta páxina.",
-       "alreadyrolled": "Nun se pue revertir la postrer edición de [[:$1]] fecha por [[User:$2|$2]] ([[User talk:$2|alderique]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\ndaquién más yá editó o revirtió la páxina.\n\nLa postrer edición foi fecha por [[User:$3|$3]] ([[User talk:$3|alderique]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
+       "cantrollback": "Nun puede revertise la edición;\nl'últimu collaborador ye l'únicu autor d'esta páxina.",
+       "alreadyrolled": "Nun puede revertise la última edición de [[:$1]] fecha por [[User:$2|$2]] ([[User talk:$2|alderique]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]);\ndalguién más yá editó o revertió la páxina.\n\nLa última edición foi de [[User:$3|$3]] ([[User talk:$3|alderique]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "El resume de la edición yera: <em>$1</em>.",
        "revertpage": "Revertíes les ediciones de [[Special:Contributions/$2|$2]] ([[User talk:$2|alderique]]) hasta la cabera versión de [[User:$1|$1]]",
        "revertpage-nouser": "Revertíes les ediciones de (usuariu desaniciáu) a la cabera revisión de {{GENDER:$1|[[User:$1|$1]]}}",
        "rollback-success": "Revertíes les ediciones de {{GENDER:$3|$1}}; devueltu a la última revisión de {{GENDER:$4|$2}}.",
        "rollback-success-notify": "Revertíes les ediciones de $1 a la última revisión de $2. [$3 Ver cambeos]",
        "sessionfailure-title": "Fallu de sesión",
-       "sessionfailure": "Paez qu'hai un problema cola to sesión; por precaución\ncancelóse l'aición que pidisti. Da-y al botón \"Atrás\" del\nnavegador pa cargar otra vuelta la páxina y vuelve a intentalo.",
+       "sessionfailure": "Paez qu'hai un problema col aniciu de sesión;\natayóse esta aición por precaución escontra secuestru de sesiones.\nTorna a la páxina anterior, recarga esa páxina y vuelve a tentalo.",
        "changecontentmodel": "Cambiar el modelu de conteníu d'una páxina",
        "changecontentmodel-legend": "Cambiar el modelu de conteníu",
        "changecontentmodel-title-label": "Títulu de la páxina",
        "protectedarticle-comment": "{{GENDER:$2|Protexó}} «[[$1]]»",
        "modifiedarticleprotection-comment": "{{GENDER:$2|Cambió'l nivel de protección}} pa «[[$1]]»",
        "unprotectedarticle-comment": "{{GENDER:$2|Quitó la protección}} de «[[$1]]»",
-       "protect-title": "Protexendo \"$1\"",
+       "protect-title": "Cambiar el nivel de proteición de «$1»",
        "protect-title-notallowed": "Ver el nivel de proteición de «$1»",
        "prot_1movedto2": "[[$1]] treslladáu a [[$2]]",
        "protect-badnamespace-title": "Espaciu de nomes non protexible",
        "protect-legend": "Confirmar proteición",
        "protectcomment": "Motivu:",
        "protectexpiry": "Caduca:",
-       "protect_expiry_invalid": "Caducidá non válida.",
-       "protect_expiry_old": "La fecha de caducidá ta pasada.",
+       "protect_expiry_invalid": "La hora de caducidá nun ye válida.",
+       "protect_expiry_old": "La hora de caducidá  ta nel pasáu.",
        "protect-unchain-permissions": "Desbloquiar les demás opciones de protección",
-       "protect-text": "Equí pues ver y camudar el nivel de proteición de la páxina '''$1'''.",
-       "protect-locked-blocked": "Nun pues camudar los niveles de proteición mentes teas bloquiáu. Esta\nye la configuración actual de la páxina '''$1''':",
-       "protect-locked-dblock": "Los niveles de proteición nun puen ser camudaos pol mor d'un candáu activu de\nla base de datos. Esta ye la configuración actual de la páxina '''$1''':",
-       "protect-locked-access": "La to cuenta nun tien permisu pa camudar los niveles de proteición de páxina.\nEsta ye la configuración actual pa la páxina '''$1''':",
+       "protect-text": "Equí puedes ver y camudar el nivel de proteición de la páxina <strong>$1</strong>.",
+       "protect-locked-blocked": "Nun puedes camudar los niveles de proteición mentanto tea bloquiada.\nEsta ye la configuración actual de la páxina <strong>$1</strong>:",
+       "protect-locked-dblock": "Los niveles de proteición nun pueden camudase por causa d'un bloquéu activu de la base de datos.\nEsta ye la configuración actual de la páxina <strong>$1</strong>:",
+       "protect-locked-access": "La to cuenta nun tien permisu pa camudar los niveles de proteición de páxina.\nEsta ye la configuración actual de la páxina <strong>$1</strong>:",
        "protect-cascadeon": "Esta páxina ta protexida nestos momentos porque ta trescluída {{PLURAL:$1|na siguiente páxina, que tien|nes siguientes páxines, que tienen}} activada la proteición en cascada.\nLos cambios nel nivel de proteición d'esta páxina nun afeutarán a la proteición en cascada.",
        "protect-default": "Permitir tolos usuarios",
        "protect-fallback": "Permitir namái usuarios con permisu \"$1\"",
        "protect-existing-expiry-infinity": "Tiempu de caducidá esistente: infinitu",
        "protect-otherreason": "Motivu distintu/adicional:",
        "protect-otherreason-op": "Otru motivu",
-       "protect-dropdown": "*Motivos comunes de proteición\n** Vandalismu escomanáu\n** Spamming escesivu\n** Guerra d'ediciones contraproducente\n** Páxina de tráficu altu",
+       "protect-dropdown": "*Motivos habituales de proteición\n** Vandalismu descomanáu\n** Spamming escesivu\n** Guerra d'ediciones contraproducente\n** Páxina de tráficu altu",
        "protect-edit-reasonlist": "Editar los motivos de proteición",
        "protect-expiry-options": "1 hora:1 hour,1 día:1 day,1 selmana:1 week,2 selmanes:2 weeks,1 mes:1 month,3 meses:3 months,6 meses:6 months,1 añu:1 year,pa siempre:infinite",
        "restriction-type": "Permisu:",
        "restriction-level-sysop": "totalmente protexida",
        "restriction-level-autoconfirmed": "semiprotexida",
        "restriction-level-all": "cualesquier nivel",
-       "undelete": "Ver páxines esborraes",
-       "undeletepage": "Ver y restaurar páxines esborraes",
-       "undeletepagetitle": "'''Les siguientes son les revisiones esborraes de [[:$1]]'''.",
-       "viewdeletedpage": "Ver páxines esborraes",
-       "undeletepagetext": "{{PLURAL:$1|La siguiente páxina foi esborrada pero tovía ta nel archivu y pue ser restauráu|Les $1 páxines siguientes foron esborraes pero tovía tán nel archivu y puen ser restauraes}}. L'archivu pue ser purgáu periódicamente.",
+       "undelete": "Ver páxines desaniciaes",
+       "undeletepage": "Ver y restaurar páxines desaniciaes",
+       "undeletepagetitle": "<strong>Les siguientes son les revisiones desaniciaes de [[:$1]]</strong>.",
+       "viewdeletedpage": "Ver páxines desaniciaes",
+       "undeletepagetext": "{{PLURAL:$1|La siguiente páxina desanicióse, pero tovía ta nel archivu y puede|Les $1 páxines siguientes \ndesaniciáronse, pero tovía tán nel archivu y pueden}} restaurase. L'archivu puede llimpiase periódicamente.",
        "undelete-fieldset-title": "Restaurar revisiones",
        "undeleteextrahelp": "Pa restaurar l'historial ensembre de la páxina, desmarca toles caxelles y calca en '''''{{int:undeletebtn}}'''''.\nPa realizar una restauración selectiva, seleiciona les caxelles de la revisión que quies restaurar y calca en '''''{{int:undeletebtn}}'''''.",
        "undeleterevisions": "$1 {{PLURAL:$1|revisión desaniciada|revisiones desaniciaes}}",
-       "undeletehistory": "Si restaures la páxina, restauraránse toles revisiones al historial.\nSi se creó una páxina col mesmu nome dende que fuera esborrada, les revisiones restauraes van apaecer nel historial anterior.",
-       "undeleterevdel": "Nun se fadrá la restauración si ésta provoca un esborráu parcial de la páxina cimera o de la revisión\ndel archivu. Nestos casos, tienes que desmarcar o amosar les revisiones esborraes más recién.",
-       "undeletehistorynoadmin": "Esta páxina foi esborrada. El motivu del esborráu amuésase\nnel resume d'embaxo, amás de detalles de los usuarios qu'editaron esta páxina enantes\nde ser esborrada. El testu actual d'estes revisiones esborraes ta disponible namái pa los alministradores.",
-       "undelete-revision": "Revisión esborrada de $1 ($4, a les $5) fecha por $3:",
-       "undeleterevision-missing": "Falta la revisión o nun ye válida. Sieque l'enllaz nun seya correutu, o que la\nrevisión fuera restaurada o eliminada del archivu.",
+       "undeletehistory": "Si restaures la páxina, restauraránse toles revisiones al historial.\nSi se creó una páxina nueva col mesmu nome desque se desanició, les revisiones restauraes apaecerán nel historial anterior.",
+       "undeleterevdel": "La restauración nun va facese si ésta provoca un desaniciu parcial de la última revisión de la páxina o\ndel ficheru.\nNestos casos, tienes de desmarcar o amosar la revisión desaniciada más recién.",
+       "undeletehistorynoadmin": "Esta páxina desanicióse.\nEl motivu del desaniciu amuésase\nnel resume de más abaxo, xunto colos detalles de los usuarios qu'editaron esta páxina enantes de desaniciase.\nEl testu real d'estes revisiones desaniciaes ta disponible namái pa los alministradores.",
+       "undelete-revision": "Revisión desaniciada de $1 (del $4, a les $5) fecha por $3:",
+       "undeleterevision-missing": "Falta la revisión o nun ye válida. Seique l'enllaz nun seya correutu, o que la revisión restauróse o desanicióse del archivu.",
        "undeleterevision-duplicate-revid": "{{PLURAL:$1|Una revisión nun pudo|$1 revisiones nun pudieron}} restaurase porque {{PLURAL:$1|taba usándose la so|taben usándose les sos}} <code>rev_id</code>.",
-       "undelete-nodiff": "Nun s'atopó revisión previa.",
+       "undelete-nodiff": "Nun s'alcontró nenguna revisión anterior.",
        "undeletebtn": "Restaurar",
        "undeletelink": "ver/restaurar",
        "undeleteviewlink": "ver",
        "undeleteinvert": "Invertir seleición",
        "undeletecomment": "Motivu:",
        "cannotundelete": "Falló total o parcialmente la restauración:\n$1",
-       "undeletedpage": "'''Restauróse $1'''\n\nConsulta'l [[Special:Log/delete|rexistru d'esborraos]] pa ver los esborraos y restauraciones de recién.",
-       "undelete-header": "Mira nel [[Special:Log/delete|rexistru d'esborraos]] les páxines esborraes recién.",
+       "undeletedpage": "<strong>Restauróse $1</strong>\n\nConsulta'l [[Special:Log/delete|rexistru de desanicios]] pa ver los desanicios y restauraciones recién.",
+       "undelete-header": "Mira nel [[Special:Log/delete|rexistru de desanicios]] les páxines desaniciaes recién.",
        "undelete-search-title": "Buscar páxines desaniciaes",
        "undelete-search-box": "Buscar páxines desaniciaes",
-       "undelete-search-prefix": "Amosar páxines qu'empecipien por:",
+       "undelete-search-prefix": "Amosar les páxines qu'empecipien por:",
        "undelete-search-full": "Amosar títulos de páxina que contengan:",
        "undelete-search-submit": "Guetar",
-       "undelete-no-results": "Nun s'atoparon páxines afechisques a la busca nel archivu d'esborraos.",
-       "undelete-filename-mismatch": "Nun se pue restaurar la revisión del archivu con fecha $1: el nome d'archivu nun concuaya",
-       "undelete-bad-store-key": "Nun se pue restaurar la revisión del archivu con fecha $1: yá nun esistía l'archivu nel momentu d'esborralu.",
-       "undelete-cleanup-error": "Error al esborrar l'archivu non usáu \"$1\".",
+       "undelete-no-results": "Nun s'atoparon páxines afechisques nel archivu de desaniciaos.",
+       "undelete-filename-mismatch": "Nun puede restaurase la revisión del ficheru de fecha $1: El nome de ficheru nun concuaya.",
+       "undelete-bad-store-key": "Nun puede restaurase la revisión del ficheru de fecha $1:: El ficheru faltaba antes del desaniciu.",
+       "undelete-cleanup-error": "Error al desaniciar el ficheru non usáu «$1».",
        "undelete-missing-filearchive": "Nun se pue restaurar l'archivu col númberu d'identificación $1 porque nun ta na base de datos. Seique yá fuera restauráu.",
        "undelete-error": "Error al restaurar la páxina",
        "undelete-error-short": "Error al restaurar l'archivu: $1",
        "tag-mw-replace-description": "Ediciones que desanicien más del 90% del conteníu d'una páxina",
        "tag-mw-rollback": "Reversión",
        "tag-mw-rollback-description": "Ediciones que desfaen anteriores ediciones usando l'enllaz de desfacer",
+       "tag-mw-undo": "Desfacer",
+       "tag-mw-undo-description": "Ediciones que desfaen ediciones anteriores usando l'enllaz «Desfacer»",
        "tags-title": "Etiquetes",
        "tags-intro": "Esta páxina llista les etiquetes coles que'l software pue marcar una edición, y el so significáu.",
        "tags-tag": "Nome d'etiqueta",
index 379c774..1a46a3f 100644 (file)
        "rcfilters-activefilters": "Aktiv filtrlər",
        "rcfilters-advancedfilters": "Geniş filtr",
        "rcfilters-limit-title": "Göstərilməli dəyişikliklər",
+       "rcfilters-limit-and-date-label": "{{PLURAL:$1|redaktə|redaktə}}, $2",
+       "rcfilters-date-popup-title": "Axtarış üçün vaxt aralığı",
        "rcfilters-days-title": "Son günlər",
        "rcfilters-hours-title": "Son saatlar",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|gün|gün}}",
index 0307b13..5fdb581 100644 (file)
        "gender-unknown": "Калі вы будзеце згадвацца, праграмнае забесьпячэньне будзе кожны раз пры магчымасьці ўжываць гендэрна нэўтральныя словы",
        "gender-male": "Ён рэдагуе вікістаронкі",
        "gender-female": "Яна рэдагуе вікістаронкі",
-       "prefs-help-gender": "Ð\92Ñ\8bзнаÑ\87аÑ\86Ñ\8c Ð³Ñ\8dÑ\82а Ð½ÐµÐ°Ð±Ð°Ð²Ñ\8fзкова.\nÐ\90пÑ\80агÑ\80амаваньне выкарыстоўвае гэтае значэньне толькі для граматычна карэктнага звароту да вас.\nГэтая інфармацыя будзе агульнадаступнай.",
+       "prefs-help-gender": "Ð\92Ñ\8bзнаÑ\87аÑ\86Ñ\8c Ð³Ñ\8dÑ\82а Ð½ÐµÐ°Ð±Ð°Ð²Ñ\8fзкова.\nÐ\9fÑ\80агÑ\80амнае Ð·Ð°Ð±ÐµÑ\81Ñ\8cпÑ\8fÑ\87Ñ\8dньне выкарыстоўвае гэтае значэньне толькі для граматычна карэктнага звароту да вас.\nГэтая інфармацыя будзе агульнадаступнай.",
        "email": "Электронная пошта",
        "prefs-help-realname": "Сапраўднае імя паведамляць неабавязковае.\nКалі Вы яго пазначыце, яно можа быць выкарыстанае для пазначэньня Вашай працы.",
-       "prefs-help-email": "Ð\90дÑ\80аÑ\81 Ñ\8dлекÑ\82Ñ\80оннай Ð¿Ð¾Ñ\88Ñ\82Ñ\8b Ð½ÐµÐ°Ð±Ð°Ð²Ñ\8fзковÑ\8b, Ð°Ð»Ðµ Ñ\91н Ð´Ð°Ðµ Ð¼Ð°Ð³Ñ\87Ñ\8bмаÑ\81Ñ\8cÑ\86Ñ\8c Ð´Ð°Ñ\81лаÑ\86Ñ\8c Ð\92ам Ð¿Ð°Ñ\80олÑ\8c, ÐºÐ°Ð»Ñ\96 Ð\92Ñ\8b Ð·Ð°Ð±Ñ\8bлÑ\96 яго.",
-       "prefs-help-email-others": "Ð\92Ñ\8b Ð¼Ð¾Ð¶Ð°Ñ\86е Ñ\82акÑ\81ама Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ñ\96нÑ\88Ñ\8bм Ñ\83дзелÑ\8cнÑ\96кам ÐºÐ°Ð½Ñ\82акÑ\82аваÑ\86Ñ\8c Ð· Ð\92амÑ\96 Ð¿Ñ\80аз Ð\92аÑ\88Ñ\83Ñ\8e Ð°Ñ\81абÑ\96Ñ\81Ñ\82Ñ\83Ñ\8e Ñ\81Ñ\82аÑ\80онкÑ\83 Ð³Ñ\83Ñ\82аÑ\80ак Ð±ÐµÐ·Ñ\8c Ð½ÐµÐ°Ð±Ñ\85однаÑ\81Ñ\8cÑ\86Ñ\96 Ñ\80аÑ\81кÑ\80Ñ\8bÑ\86Ñ\8cÑ\86Ñ\8f Ð°Ð´Ñ\80аÑ\81Ñ\83 Ñ\8dлекÑ\82Ñ\80оннай Ð¿Ð¾Ñ\88Ñ\82Ñ\8b.",
+       "prefs-help-email": "Ð\90дÑ\80аÑ\81 Ñ\8dлекÑ\82Ñ\80оннай Ð¿Ð¾Ñ\88Ñ\82Ñ\8b Ð½ÐµÐ°Ð±Ð°Ð²Ñ\8fзковÑ\8b, Ð°Ð»Ðµ Ñ\91н Ð½ÐµÐ°Ð±Ñ\85однÑ\8b Ð´Ð»Ñ\8f Ñ\81кÑ\96данÑ\8cнÑ\8f Ð¿Ð°Ñ\80олÑ\8e, ÐºÐ°Ð»Ñ\96 Ð²Ñ\8b Ð·Ð°Ð±Ñ\83дзеÑ\86е яго.",
+       "prefs-help-email-others": "Ð\92Ñ\8b Ð¼Ð¾Ð¶Ð°Ñ\86е Ñ\82акÑ\81ама Ð´Ð°Ð·Ð²Ð¾Ð»Ñ\96Ñ\86Ñ\8c Ñ\96нÑ\88Ñ\8bм Ñ\83дзелÑ\8cнÑ\96кам ÐºÐ°Ð½Ñ\82акÑ\82аваÑ\86Ñ\8c Ð· Ð²Ð°Ð¼Ñ\96 Ð¿Ñ\80аз Ñ\8dлекÑ\82Ñ\80оннÑ\83Ñ\8e Ð¿Ð¾Ñ\88Ñ\82Ñ\83 Ð¿Ð° Ñ\81паÑ\81Ñ\8bлÑ\86Ñ\8b Ð½Ð° Ð²Ð°Ñ\88ай Ñ\81Ñ\82аÑ\80онÑ\86Ñ\8b Ñ\86Ñ\96 Ñ\81Ñ\82аÑ\80онÑ\86Ñ\8b Ð³Ñ\83Ñ\82аÑ\80ак.\nÐ\92аÑ\88 Ð°Ð´Ñ\80аÑ\81 Ñ\8dлекÑ\82Ñ\80оннай Ð¿Ð¾Ñ\88Ñ\82Ñ\8b Ð½Ñ\8f Ð±Ñ\83дзе Ð¿Ð°ÐºÐ°Ð·Ð°Ð½Ñ\8b Ñ\96нÑ\88Ñ\8bм Ñ\83дзелÑ\8cнÑ\96кам Ð¿Ñ\80Ñ\8b ÐºÐ°Ð½Ñ\82акÑ\82аванÑ\8cнÑ\96.",
        "prefs-help-email-required": "Патрабуецца адрас электроннай пошты.",
        "prefs-info": "Асноўныя зьвесткі",
        "prefs-i18n": "Інтэрнацыяналізацыя",
        "imported-log-entries": "{{PLURAL:$1|Імпартаваны $1 запіс журнала|Імпартаваныя $1 запісы журнала|Імпартаваныя $1 запісаў журнала}}.",
        "importfailed": "Немагчыма імпартаваць: $1",
        "importunknownsource": "Невядомы тып крыніцы імпарту",
+       "importnoprefix": "Не пададзены прэфікс інтэрвікі",
        "importcantopen": "Немагчыма адкрыць файл імпарту",
        "importbadinterwiki": "Няслушная спасылка на іншую моўную вэрсію",
        "importsuccess": "Імпартаваньне скончанае!",
        "autosumm-blank": "Выдалены ўвесь зьмест старонкі",
        "autosumm-replace": "Старонка замененая на '$1'",
        "autoredircomment": "Перанакіроўвае на [[$1]]",
+       "autosumm-removed-redirect": "Выдаленае перанакіраваньне на [[$1]]",
+       "autosumm-changed-redirect-target": "Перанакіраваньне зьмененае з [[$1]] на [[$2]]",
        "autosumm-new": "Створана старонка са зьместам '$1'",
        "autosumm-newblank": "Створаная пустая старонка",
        "size-bytes": "$1 б",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|1=Метка|Меткі}}]]: $2)",
        "tag-mw-contentmodelchange": "зьмена мадэлі зьместу",
        "tag-mw-contentmodelchange-description": "Рэдагаваньні, якія [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel зьмяняюць мадэль зьместу] старонкі",
+       "tag-mw-new-redirect": "Новае перанакіраваньне",
+       "tag-mw-new-redirect-description": "Рэдагаваньні, якія ствараюць новае перанакіраваньне ці зьмяняюць старонку на перанакіраваньне",
+       "tag-mw-removed-redirect": "Выдаленае перанакіраваньне",
+       "tag-mw-removed-redirect-description": "Праўкі, якія зьмяняюць існае перанакіраваньне на не перанакіраваньне",
+       "tag-mw-changed-redirect-target": "Зьмененая мэта перанакіраваньня",
+       "tag-mw-changed-redirect-target-description": "Праўкі, якія зьмяняюць мэту перанакіраваньня",
+       "tag-mw-blank": "Ачыстка",
+       "tag-mw-blank-description": "Праўкі, якія робяць старонку пустой",
+       "tag-mw-replace": "Заменена",
+       "tag-mw-replace-description": "Праўкі, якія выдаляюць больш за 90% зьместу старонкі",
        "tags-title": "Меткі",
        "tags-intro": "На гэтай старонцы знаходзіцца сьпіс метак, якімі праграмнае забесьпячэньне можа пазначыць рэдагаваньне, і іх значэньне.",
        "tags-tag": "Назва меткі",
index 570f869..639733c 100644 (file)
        "permalink": "Постоянна препратка",
        "print": "Печат",
        "view": "Преглед",
-       "view-foreign": "Ð\9fÑ\80еглед Ð½Ð° $1",
+       "view-foreign": "Ð\9fÑ\80еглед Ð² $1",
        "edit": "Редактиране",
        "edit-local": "Редактиране на локалното описание",
        "create": "Създаване",
        "botpasswords-label-delete": "Изтриване",
        "botpasswords-label-resetpassword": "Възстановяване на парола",
        "botpasswords-label-grants": "Приложими разрешения:",
+       "botpasswords-label-grants-column": "Дадено",
        "botpasswords-bad-appid": "Името на бота „$1“ не е валидно.",
        "botpasswords-insert-failed": "Неуспешно добавяне на име на бота „$1“. Дали не е добавяно вече?",
        "botpasswords-update-failed": "Неуспешно подновяване на името на бота „$1“. Дали не е изтрито?",
        "rcfilters-restore-default-filters": "Възстановяване на филтрите по подразбиране",
        "rcfilters-clear-all-filters": "Изчистване на всички филтри",
        "rcfilters-show-new-changes": "Преглед на най-новите промени",
-       "rcfilters-search-placeholder": "Филтриране на последните промени (изберете или започнете да въвеждате)",
+       "rcfilters-search-placeholder": "Филтриране на промените (използвайте менюто или търсете по име на филтър)",
        "rcfilters-invalid-filter": "Невалиден филтър",
        "rcfilters-empty-filter": "Няма активни филтри. Показани са всички редакции.",
        "rcfilters-filterlist-title": "Филтри",
        "rcfilters-filterlist-whatsthis": "Как работи това?",
-       "rcfilters-filterlist-feedbacklink": "Ð\9eÑ\81Ñ\82авеÑ\82е ÐºÐ¾Ð¼ÐµÐ½Ñ\82аÑ\80 Ð·Ð° Ð½Ð¾Ð²Ð¸Ñ\82е (беÑ\82а) Ñ\84илÑ\82Ñ\80и",
+       "rcfilters-filterlist-feedbacklink": "СподелеÑ\82е ÐºÐ°ÐºÐ²Ð¾ Ð¼Ð¸Ñ\81лиÑ\82е Ð·Ð° Ñ\82ези (нови) Ð¸Ð½Ñ\81Ñ\82Ñ\80Ñ\83менÑ\82и Ð·Ð° Ñ\84илÑ\82Ñ\80иÑ\80ане",
        "rcfilters-highlightbutton-title": "Отбелязване на резултатите",
        "rcfilters-highlightmenu-title": "Изберете цвят",
        "rcfilters-highlightmenu-help": "Изберете цвят за отбелязване на свойството",
        "rcfilters-filter-editsbyself-description": "Ваши редакции.",
        "rcfilters-filter-editsbyother-label": "Чужди редакции",
        "rcfilters-filter-editsbyother-description": "Всички редакции с изключение на вашите собствени.",
-       "rcfilters-filtergroup-userExpLevel": "Ð\9dиво Ð½Ð° Ð¾Ð¿Ð¸Ñ\82а (Ñ\81амо Ð·Ð° Ñ\80егиÑ\81Ñ\82Ñ\80иÑ\80ани Ð¿Ð¾Ñ\82Ñ\80ебиÑ\82ели)",
+       "rcfilters-filtergroup-userExpLevel": "РегиÑ\81Ñ\82Ñ\80аÑ\86иÑ\8f Ð½Ð° Ð¿Ð¾Ñ\82Ñ\80ебиÑ\82елÑ\8f Ð¸ Ð¾Ð¿Ð¸Ñ\82",
        "rcfilters-filter-user-experience-level-registered-label": "Регистрирани",
        "rcfilters-filter-user-experience-level-registered-description": "Влезли в системата редактори.",
        "rcfilters-filter-user-experience-level-unregistered-label": "Нерегистрирани",
        "rcfilters-filter-user-experience-level-unregistered-description": "Редактори, които не са влезли в системата.",
        "rcfilters-filter-user-experience-level-newcomer-label": "Новодошли",
-       "rcfilters-filter-user-experience-level-newcomer-description": "Ð\9fо-малко Ð¾Ñ\82 10 Ñ\80едакÑ\86ии Ð¸ 5 дни активност.",
+       "rcfilters-filter-user-experience-level-newcomer-description": "РегиÑ\81Ñ\82Ñ\80иÑ\80ани Ñ\80едакÑ\82оÑ\80и Ñ\81 Ð¿Ð¾-малко Ð¾Ñ\82 10 Ñ\80едакÑ\86ии Ð¸Ð»Ð¸ 4 дни активност.",
        "rcfilters-filter-user-experience-level-learner-label": "Учещи се",
-       "rcfilters-filter-user-experience-level-learner-description": "Ð\9fовеÑ\87е Ð¾Ð¿Ð¸Ñ\82 Ð¾Ñ\82 â\80\9eÐ\9dоводоÑ\88лиâ\80\9c, Ð½Ð¾ Ð¿Ð¾-малко Ð¾Ñ\82 „Опитни потребители“.",
+       "rcfilters-filter-user-experience-level-learner-description": "РегиÑ\81Ñ\82Ñ\80иÑ\80ани Ð¿Ð¾Ñ\82Ñ\80ебиÑ\82ели Ñ\81 Ð¾Ð¿Ð¸Ñ\82 Ð¾Ñ\82 â\80\9eÐ\9dоводоÑ\88лиâ\80\9c Ð´Ð¾ „Опитни потребители“.",
        "rcfilters-filter-user-experience-level-experienced-label": "Опитни потребители",
-       "rcfilters-filter-user-experience-level-experienced-description": "Ð\9fовеÑ\87е Ð¾Ñ\82 30 Ð´Ð½Ð¸ Ð°ÐºÑ\82ивноÑ\81Ñ\82 Ð¸ 500 Ñ\80едакÑ\86ии.",
+       "rcfilters-filter-user-experience-level-experienced-description": "РегиÑ\81Ñ\82Ñ\80иÑ\80ани Ñ\80едакÑ\82оÑ\80и Ñ\81 Ð¿Ð¾Ð²ÐµÑ\87е Ð¾Ñ\82 500 Ñ\80едакÑ\86ии Ð¸ 30 Ð´Ð½Ð¸ Ð°ÐºÑ\82ивноÑ\81Ñ\82.",
        "rcfilters-filtergroup-automated": "Автоматизирани редакции",
        "rcfilters-filter-bots-label": "Бот",
        "rcfilters-filter-bots-description": "Редакции, направени с помощта на автоматизирани инструменти.",
        "rcfilters-filter-logactions-description": "Административни действия, създавания на сметки, изтривания на страници, качвания...",
        "rcfilters-filtergroup-lastRevision": "Текущи версии",
        "rcfilters-filter-lastrevision-label": "Текуща версия",
-       "rcfilters-filter-lastrevision-description": "Ð\9fоследната промяна на страница.",
+       "rcfilters-filter-lastrevision-description": "Само Ð¿оследната промяна на страница.",
        "rcfilters-filter-previousrevision-label": "Не последната версия",
        "rcfilters-filter-previousrevision-description": "Всички редакции, които не са „последната версия“.",
        "rcfilters-filter-excluded": "Изключени",
        "backend-fail-create": "Файлът „$1“ не може да бъде съхранен.",
        "backend-fail-maxsize": "Файлът „$1“ не може да бъде съхранен, тъй като размерът му надвишава {{PLURAL:$2|един байт|$2 байт}}.",
        "backend-fail-connect": "Не е възможно свързването към бекенда за съхранение „$1“.",
-       "backend-fail-internal": "Възникна неизвестна грешка в бекенда за съхранение „1“.",
+       "backend-fail-internal": "Възникна неизвестна грешка в бекенда за съхранение „$1“.",
        "zip-file-open-error": "Възникна грешка при отваряне на файла за проверка на ZIP.",
        "zip-wrong-format": "Указаният файл не е ZIP файл.",
        "zip-bad": "Файлът е повреден или е нечетим ZIP файл.\nСигурността му не може да бъде проверена.",
        "contributions-userdoesnotexist": "Няма регистрирана потребителска сметка за „$1“.",
        "nocontribs": "Не са намерени промени, отговарящи на критерия.",
        "uctop": "(текуща)",
-       "month": "Ð\9cеÑ\81еÑ\86:",
-       "year": "Ð\93одина:",
+       "month": "Ð\9eÑ\82 Ð¼ÐµÑ\81еÑ\86 (и Ð¿Ð¾-Ñ\80ано):",
+       "year": "Ð\9eÑ\82 Ð³Ð¾Ð´Ð¸Ð½Ð° (и Ð¿Ð¾-Ñ\80ано):",
        "sp-contributions-newbies": "Показване само на приносите на нови потребители",
        "sp-contributions-newbies-sub": "на нови потребители",
        "sp-contributions-newbies-title": "Потребителски приноси за нови сметки",
        "whatlinkshere-title": "Страници, които сочат към „$1“",
        "whatlinkshere-page": "Страница:",
        "linkshere": "Следните страници сочат към <strong>[[:$1]]</strong>:",
-       "nolinkshere": "Няма страници, сочещи към '''[[:$1]]'''.",
+       "nolinkshere": "Няма страници, сочещи към <strong>[[:$1]]</strong>.",
        "nolinkshere-ns": "Няма страници, сочещи към [[:$1]] в избраното именно пространство.",
        "isredirect": "пренасочваща страница",
        "istemplate": "включване",
        "delete_and_move_text": "Целевата страница „[[:$1]]“ вече съществува.\nИскате ли да я изтриете, за да освободите място за преместването?",
        "delete_and_move_confirm": "Да, искам да изтрия тази страница",
        "delete_and_move_reason": "Изтрита, за да се освободи място за преместване от „[[$1]]“",
-       "selfmove": "СÑ\82Ñ\80аниÑ\86аÑ\82а Ð½Ðµ Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ð±Ñ\8aде Ð¿Ñ\80емеÑ\81Ñ\82ена, Ñ\82Ñ\8aй ÐºÐ°Ñ\82о Ñ\86елевоÑ\82о Ð¸Ð¼Ðµ Ñ\81Ñ\8aвпада Ñ\81 Ð¿Ñ\8aÑ\80вонаÑ\87алноÑ\82о Ñ\9d Ð·Ð°Ð³Ð»Ð°Ð²Ð¸Ðµ.",
+       "selfmove": "Ð\97аглавиеÑ\82о Ñ\81Ñ\8aвпада;\nÑ\81Ñ\82Ñ\80аниÑ\86аÑ\82а Ð½Ðµ Ð¼Ð¾Ð¶Ðµ Ð´Ð° Ð±Ñ\8aде Ð¿Ñ\80емеÑ\81Ñ\82ена Ð²Ñ\8aÑ\80Ñ\85Ñ\83 Ñ\81амаÑ\82а Ð½ÐµÑ\8f.",
        "immobile-source-namespace": "Не могат да се местят страници в именно пространство „$1“",
        "immobile-target-namespace": "Не могат да се местят страници в именно пространство „$1“.",
        "immobile-target-namespace-iw": "Страницата не може да бъде преместена под заглавие, оформено като междууики препратка.",
        "tooltip-ca-undelete": "Възстановяване на изтрити редакции на страницата",
        "tooltip-ca-move": "Преместване на страницата",
        "tooltip-ca-watch": "Добавяне на страницата към списъка Ви за наблюдение",
-       "tooltip-ca-unwatch": "Ð\9fÑ\80емаÑ\85ване Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86аÑ\82а Ð¾Ñ\82 Ñ\81пиÑ\81Ñ\8aка Ð²и за наблюдение",
+       "tooltip-ca-unwatch": "Ð\9fÑ\80емаÑ\85ване Ð½Ð° Ñ\81Ñ\82Ñ\80аниÑ\86аÑ\82а Ð¾Ñ\82 Ñ\81пиÑ\81Ñ\8aка Ð\92и за наблюдение",
        "tooltip-search": "Претърсване на {{SITENAME}}",
        "tooltip-search-go": "Отиване на страницата, ако тя съществува с точно това име",
        "tooltip-search-fulltext": "Търсене в страниците за този текст",
        "autosumm-blank": "Премахване на цялото съдържание на страницата",
        "autosumm-replace": "Заместване на съдържанието на страницата с „$1“",
        "autoredircomment": "Пренасочване към [[$1]]",
+       "autosumm-changed-redirect-target": "Промяна на целта на пренасочване от [[$1]] на [[$2]]",
        "autosumm-new": "Нова страница: „$1“",
        "autosumm-newblank": "Създаване на празна страница",
        "lag-warn-normal": "Промените от {{PLURAL:$1|последната $1 секунда|последните $1 секунди}} вероятно не са показани в списъка.",
        "redirect-submit": "Отваряне",
        "redirect-lookup": "Параметър:",
        "redirect-value": "Стойност:",
-       "redirect-user": "Ð\9fоÑ\82Ñ\80ебиÑ\82елÑ\81ки Ð½Ð¾Ð¼Ðµр",
+       "redirect-user": "Ð\9fоÑ\82Ñ\80ебиÑ\82елÑ\81ки Ð¸Ð´ÐµÐ½Ñ\82иÑ\84икаÑ\82ор",
        "redirect-page": "Номер на страницата",
        "redirect-revision": "Версия на страницата",
        "redirect-file": "Име на файл",
        "tag-filter-submit": "Филтриране",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Етикет|Етикети}}]]: $2)",
        "tag-mw-contentmodelchange": "промяна на модела на съдържание",
+       "tag-mw-undo": "Отмяна",
        "tags-title": "Етикети",
        "tags-intro": "Тук са изброени всички етикети, които могат да се ползват за отбелязване на редакциите, както и тяхното значение.",
        "tags-tag": "Име на етикета",
index f0cbb13..9ce3d2c 100644 (file)
        "recentchangeslinked-feed": "संबंधित बदलाव",
        "recentchangeslinked-toolbox": "संबंधित बदलाव",
        "recentchangeslinked-title": "\"$1\" संबंधी बदलाव",
-       "recentchangeslinked-summary": "à¤\88 à¤\8fà¤\97à¥\8b à¤ªà¤¨à¥\8dना à¤¬à¤¿à¤¸à¥\87स à¤¸à¥\87 (या à¤\8fà¤\97à¥\8b à¤¶à¥\8dरà¥\87णà¥\80 à¤¬à¤¿à¤¸à¥\87स à¤\95à¥\80 à¤¸à¤¦à¤¸à¥\8dय à¤¸à¥\87) à¤\9cà¥\81ड़ल à¤ªà¤¨à¥\8dनवन à¤®à¥\87à¤\82 à¤¹à¤¾à¤² à¤®à¥\87à¤\82 à¤­à¤\87ल à¤¬à¤¦à¤²à¤¾à¤µ à¤\95à¥\87 à¤\8fà¤\97à¥\8b à¤²à¤¿à¤¸à¥\8dà¤\9f à¤¹à¤µà¥\87। \n[[Special:Watchlist|à¤\86पà¤\95à¥\80 à¤§à¤¿à¤¯à¤¾à¤¨à¤¸à¥\82à¤\9aà¥\80]] à¤\95à¥\87 à¤ªà¤¨à¥\8dना à¤¸à¤¬ <strong>मोट अच्छर में</strong> लउकत बाने।",
+       "recentchangeslinked-summary": "à¤\95à¥\8cनà¥\8bà¤\82 à¤ªà¤¨à¥\8dना à¤ªà¤° à¤¯à¤¾ à¤«à¤¿à¤° à¤\93à¤\95रा à¤¸à¥\87 à¤\9cà¥\81ड़à¥\87 à¤µà¤¾à¤²à¤¾ à¤ªà¤¨à¥\8dना à¤¸à¤­ à¤®à¥\87à¤\82 à¤­à¤\87ल à¤¬à¤¦à¤²à¤¾à¤µ à¤¦à¥\87à¤\96à¥\87 à¤\96ातà¥\80 à¤ªà¤¨à¥\8dना à¤\95à¥\87 à¤¨à¤¾à¤\81व à¤¦à¥\80à¤\82। (à¤\95à¥\8cनà¥\8bà¤\82 à¤¶à¥\8dरà¥\87णà¥\80 à¤®à¥\87à¤\82 à¤\86वà¥\87 à¤µà¤¾à¤²à¤¾ à¤ªà¤¨à¥\8dना à¤¸à¤­ à¤\96ातà¥\80, à¤¶à¥\8dरà¥\87णà¥\80:शà¥\8dरà¥\87णà¥\80 à¤\95à¥\87 à¤¨à¤¾à¤\81व à¤¡à¤¾à¤²à¥\80à¤\82)। [[Special:Watchlist|राà¤\89र à¤§à¤¿à¤¯à¤¾à¤¨à¤¸à¥\82à¤\9aà¥\80]] à¤®à¥\87à¤\82 à¤¶à¤¾à¤®à¤¿à¤² à¤ªà¤¨à¥\8dना à¤¸à¤­ à¤\95à¥\87 à¤¬à¤¦à¤²à¤¾à¤µ <strong>मोट अच्छर में</strong> लउकत बाने।",
        "recentchangeslinked-page": "पन्ना नाँव:",
        "recentchangeslinked-to": "एकरे बजाय ए पन्ना से जुड़ल पन्नवन मे भइल बदलाव देखावल जाय",
        "recentchanges-page-added-to-category": "[[:$1]] श्रेणी में जोड़ल गइल",
        "booksources-search-legend": "किताबी स्रोत के खोज",
        "booksources-search": "खोज",
        "log": "सगरी लॉग",
+       "all-logs-page": "सगरी पब्लिक लॉग",
        "allpages": "सगरी पन्ना",
        "nextpage": "अगिला पन्ना ($1)",
        "prevpage": "पछिला पन्ना ($1)",
        "trackingcategories-name": "संदेस नाँव",
        "emailuser": "ई प्रयोगकर्ता के ईमेल करीं",
        "emailusername": "प्रयोगकर्तानाँव:",
+       "usermessage-editor": "सिस्टम मसेंजर",
        "watchlist": "धियानसूची",
        "mywatchlist": "धियानसूची",
        "watch": "धियानसूची में डालीं",
        "protectlogpage": "सुरक्षा लॉग",
        "protectlogtext": "नीचे पन्ना सुरक्षा में भइल बदलावकुल के सूची बा।\nहाल में सुरक्षित पन्नन के सूची खातिर [[Special:ProtectedPages|सुरक्षित पन्नन के सूची]] देखीं।",
        "protectedarticle": "\"[[$1]]\" सुरक्षित कइल गइल",
+       "protect-default": "सगरी प्रयोगकर्ता लोग के एलाऊ करीं",
+       "restriction-edit": "संपादन करीं",
        "restriction-move": "स्थानांतरण",
        "restriction-create": "बनावे पर",
        "restriction-upload": "अपलोड",
        "sp-contributions-blocked-notice": "ई प्रयोगकर्ता के ई समय निष्क्रीय करल गईल बा।\nनविनतम नष्ट लौग प्रविष्टी उद्धरण खातिर निचे दिहल बा:",
        "sp-contributions-search": "योगदान खातिर खोज करीं",
        "sp-contributions-username": "आइपी पता भा प्रयोगकर्तानाँव:",
+       "sp-contributions-toponly": "खाली उहे संपादन देखीं जवन सभसे नया होखें",
        "sp-contributions-newonly": "खाली उहे संपादन देखीं जेकरा से नया पन्ना बनल होखे",
        "sp-contributions-submit": "खोजीं",
        "whatlinkshere": "इहाँ का जुड़ल बा",
        "change-blocklink": "ब्लॉक बदलीं",
        "contribslink": "योगदान",
        "blocklogpage": "निष्क्रिय खाता",
+       "blocklogentry": "[[$1]] के ब्लॉक कइल गइल, समाप्ती के अवधि $2 $3",
        "movepagebtn": "पन्ना स्थांतरण करीं",
        "movelogpage": "स्थानांतरण लॉग",
        "revertmove": "पिछलका स्थिति",
        "tooltip-save": "जवन बदलाव कइलीं ओकरा के सहेजीं",
        "tooltip-preview": "जवन बदलाव कइलीं ओकर झलक देखीं। सहेजे से पहिले एकर इस्तेमाल करे के आगरह बा।",
        "tooltip-diff": "देखीं कि पाठ में आप का बदलाव कइले बानी",
+       "tooltip-compareselectedversions": "एह पन्ना के चुनल गइल दू गो रिवीजन सभ में अंतर देखीं",
        "tooltip-rollback": "\"रोलबैक\" एह पन्ना पर सभसे अंतिम संपादन करे वाला संपादक के कइल बदलाव(सभ) एकही क्लिक में वापस लवटा देला",
        "tooltip-undo": "\"वापस लीं\" ए संपादन के पलट देला आ संपादन फार्म के झलक देखावे वाला मोड में खोलेला। ई छोट सारांश में कारण जोड़े के मोका देला।",
        "tooltip-summary": "संछेप में एगो सारांश लिखीं",
        "simpleantispam-label": "स्पैम-बिरोधी रोक (Anti-spam check)\nएके <strong>मत</strong> भरीं!",
+       "pageinfo-header-edits": "संपादन इतिहास",
        "pageinfo-length": "पन्ना लंबाई (बाइट में)",
+       "pageinfo-article-id": "पन्ना आइडी",
        "pageinfo-subpages-name": "एह पन्ना के उपपन्ना संख्या",
+       "pageinfo-firstuser": "पन्ना बनावेवाला",
+       "pageinfo-firsttime": "पन्ना बनावे के तारीख",
+       "pageinfo-lastuser": "अंतिम संपादक",
+       "pageinfo-lasttime": "सभसे नया संपादन के तारीख",
+       "pageinfo-edits": "कुल संपादन गिनती",
+       "pageinfo-authors": "कुल अलग-अलग संपादकन के गिनती",
        "pageinfo-magic-words": "जादुई शब्द {{{{PLURAL:$1||शब्द|शब्द}}}} ($1)",
        "pageinfo-toolboxlink": "पन्ना से जुड़ल जानकारी",
        "previousdiff": "← पुरान संपादन",
        "logentry-newusers-create": "खाता $1 {{GENDER:$2|बनावल गइल}}",
        "logentry-upload-upload": "$1 {{GENDER:$2|अपलोड कइलें}} $3",
        "searchsuggest-search": "{{SITENAME}} में खोजीं",
+       "duration-days": "$1 दिन",
        "expandtemplates": "टेम्पलेट बिस्तार",
        "mediastatistics": "मीडिया सांख्यिकी"
 }
index 21f66a7..9037116 100644 (file)
        "contentmodelediterror": "আপনি এই পুনর্বিবেচনা সম্পাদনা করতে পারবেন না কারণ এর বিষয়বস্তু মডেল <code>$1</code>, যা বর্তমান বিষয়বস্তু মডেল <code>$2</code>-এর থেকে ভিন্ন।",
        "recreate-moveddeleted-warn": "'''সতর্কীকরণ: আপনি এমন একটি পাতা পুনরায় তৈরি করছেন যা পূর্বে অপসারণ করা হয়েছিল।'''\n\nআপনি পাতাটি সম্পাদনা চালিয়ে যাওয়া ঠিক হবে কিনা, তা বিবেচনা করুন।\nআপনার সুবিধার্থে পাতাটির অপলুপ্তি লগ এখানে দেয়া হলো:",
        "moveddeleted-notice": "এই পাতাটি অপসারণ করা হয়েছে।\nসূত্র হিসেবে নিচে এই পাতার অপসারণ, সুরক্ষা ও স্থানান্তর লগ দেওয়া হলো।",
-       "moveddeleted-notice-recent": "দà§\81à¦\83à¦\96িত, à¦\8fà¦\87 à¦ªà¦¾à¦¤à¦¾à¦\9fি à¦¸à¦¾à¦®à§\8dপà§\8dরতি à¦\85পসারিত à¦¹à¦¯à¦¼à§\87à¦\9bà§\87 (সরà§\8dবশà§\87ষ à§¨à§ª à¦\98ণà§\8dà¦\9fায়)।\nসà§\82তà§\8dর à¦¹à¦¿à¦¸à§\87বà§\87 à¦¨à¦¿à¦\9aà§\87 à¦\8fà¦\87 à¦ªà¦¾à¦¤à¦¾ অপসারণ, সুরক্ষা ও স্থানান্তর লগ দেয়া হয়েছে।",
+       "moveddeleted-notice-recent": "দà§\81à¦\83à¦\96িত, à¦\8fà¦\87 à¦ªà¦¾à¦¤à¦¾à¦\9fি à¦¸à¦®à§\8dপà§\8dরতি à¦\85পসারিত à¦¹à¦¯à¦¼à§\87à¦\9bà§\87 (সরà§\8dবশà§\87ষ à§¨à§ª à¦\98ণà§\8dà¦\9fায়)।\nসà§\82তà§\8dর à¦¹à¦¿à¦¸à§\87বà§\87 à¦¨à¦¿à¦\9aà§\87 à¦\8fà¦\87 à¦ªà¦¾à¦¤à¦¾à¦° অপসারণ, সুরক্ষা ও স্থানান্তর লগ দেয়া হয়েছে।",
        "log-fulllog": "সম্পূর্ণ লগ দেখুন",
        "edit-hook-aborted": "হূক দ্বারা সম্পাদনা পরিত্যক্ত হয়েছে।\nএর কোন ব্যাখ্যা নাই।",
        "edit-gone-missing": "পাতাটি হালনাগাদ হয়নি।\nসম্ভবতঃ পাতাটি মুছে ফেলা হয়েছে।",
        "tag-mw-replace-description": "সম্পাদনাগুলি যা একটি পাতার বিষয়বস্তুর ৯০ ভাগের বেশী সরিয়ে ফেলে",
        "tag-mw-rollback": "পুনর্বহাল",
        "tag-mw-rollback-description": "সম্পাদনাগুলি যা রোলব্যাক সংযোগ ব্যবহার করে পূর্বের সম্পাদনায় ফেরত নেয়",
+       "tag-mw-undo": "পূর্বাবস্থায় ফেরত",
        "tags-title": "ট্যাগসমূহ",
        "tags-intro": "এই পাতায় সফটওয়্যারটি একটি সম্পাদনা চিহ্নিত করার জন্য যে সকল ট্যাগ ব্যবহার করে তার তালিকা ও বর্ণনা রয়েছে।",
        "tags-tag": "ট্যাগ নাম",
index 312b20c..125c4a8 100644 (file)
        "tooltip-t-specialpages": "Spisak svih posebnih stranica",
        "tooltip-t-print": "Verzija ove stranice za štampanje",
        "tooltip-t-permalink": "Trajni link ove verzije stranice",
-       "tooltip-ca-nstab-main": "Pogledajte stranicu sa sadržajem",
+       "tooltip-ca-nstab-main": "Prikaži stranicu sa sadržajem",
        "tooltip-ca-nstab-user": "Pogledajte korisničku stranicu",
        "tooltip-ca-nstab-media": "Pogledajte medija fajl",
        "tooltip-ca-nstab-special": "Ovo je posebna stranica, te se ne može zasebno uređivati",
index 8e9cc41..18a0e94 100644 (file)
        "undo-summary-username-hidden": "Desfés la revisió $1 d'un usuari ocult",
        "cantcreateaccount-text": "[[User:$3|$3]] ha blocat la creació de comptes des d'aquesta adreça IP ('''$1''').\n\nEl motiu donat per $3 és ''$2''",
        "cantcreateaccount-range-text": "La creació de comptes des de les adreces IP en el rang <strong>$1</strong>, que inclou la vostra adreça IP (<strong>$4</strong>), ha estat blocada per [[User:$3|$3]].\n\nEl motiu donat per $3 és <em>$2</em>",
-       "viewpagelogs": "Visualitza els registres d'aquesta pàgina",
+       "viewpagelogs": "Visualitza els registres daquesta pàgina",
        "nohistory": "No hi ha un historial de revisions per a aquesta pàgina.",
        "currentrev": "Revisió actual",
        "currentrev-asof": "Revisió de $1",
        "rcfilters-group-results-by-page": "Agrupa els resultats per pàgina",
        "rcfilters-activefilters": "Filtres actius",
        "rcfilters-advancedfilters": "Filtres avançats",
-       "rcfilters-limit-title": "Canvis a mostrar",
+       "rcfilters-limit-title": "Resultats a mostrar",
+       "rcfilters-limit-and-date-label": "{{PLURAL:$1|canvi|$1 canvis}}, $2",
        "rcfilters-date-popup-title": "Període de temps per cercar",
        "rcfilters-days-title": "Darrers dies",
        "rcfilters-hours-title": "Hores recents",
        "rcfilters-liveupdates-button-title-off": "Mostra els nous canvis al moment",
        "rcfilters-watchlist-markseen-button": "Marca tots els canvis com a vistos",
        "rcfilters-watchlist-edit-watchlist-button": "Editeu la vostra llista de pàgines seguides",
+       "rcfilters-preference-label": "Amaga la versió millorada de Canvis recents",
        "rcfilters-target-page-placeholder": "Escriviu el nom d’una pàgina",
        "rcnotefrom": "A sota hi ha {{PLURAL:$5|el canvi|els canvis}} a partir de <strong>$3, $4</strong> (fins a <strong>$1</strong>).",
        "rclistfromreset": "Reinicialitza la selecció de data",
        "uploadstash-bad-path": "El camí no existeix.",
        "uploadstash-bad-path-invalid": "El camí no és vàlid.",
        "uploadstash-bad-path-unknown-type": "El tipus «$1» és desconegut.",
+       "uploadstash-no-extension": "L’extensió és nul·la.",
        "invalid-chunk-offset": "El desplaçament del fragment no és vàlid",
        "img-auth-accessdenied": "Accés denegat",
        "img-auth-nopathinfo": "Hi manca PATH_INFO.\nEl servidor no està configurat per passar aquesta informació.\nPot estar basat en CGI i no ser compatible amb img_auth.\nConsulteu https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization",
        "apisandbox-reset": "Neteja",
        "apisandbox-retry": "Torna a provar",
        "apisandbox-loading": "S'està carregant la informació del mòdul d'API «$1»...",
+       "apisandbox-load-error": "S’ha produït un error en carregar la informació del mòdul «$1» de l’API: $2",
        "apisandbox-no-parameters": "Aquest mòdul API no té paràmetres.",
        "apisandbox-helpurls": "Enllaços d'ajuda",
        "apisandbox-examples": "Exemples",
        "unblocked-id": "S'ha eliminat el blocatge de $1",
        "unblocked-ip": "[[Special:Contributions/$1|$1]] ha estat desblocat.",
        "blocklist": "Usuaris blocats",
+       "autoblocklist": "Blocatges automàtics",
        "autoblocklist-submit": "Cerca",
+       "autoblocklist-localblocks": "{{PLURAL:$1|Blocatge automàtic local|Blocatges automàtics locals}}",
+       "autoblocklist-total-autoblocks": "Nombre total de blocatges automàtics: $1",
+       "autoblocklist-empty": "La llista de blocatges automàtics és buida.",
        "ipblocklist": "Usuaris blocats",
        "ipblocklist-legend": "Cerca un usuari blocat",
        "blocklist-userblocks": "Amaga blocatges de compte",
        "fileduplicatesearch-noresults": "No s'ha trobat cap fitxer anomenat «$1».",
        "specialpages": "Pàgines especials",
        "specialpages-note-top": "Llegenda",
+       "specialpages-note-restricted": "* Pàgines especials normals.\n* <span class=\"mw-specialpagerestricted\">Pàgines especials restringides.</span>",
        "specialpages-group-maintenance": "Informes de manteniment",
        "specialpages-group-other": "Altres pàgines especials",
        "specialpages-group-login": "Iniciar sessió / Crear un compte",
        "tag-filter-submit": "Filtra",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Etiqueta|Etiquetes}}]]: $2)",
        "tag-mw-contentmodelchange": "canvi de model de contingut",
+       "tag-mw-new-redirect": "Redirecció nova",
+       "tag-mw-blank": "Buidament",
+       "tag-mw-replace": "Substitució",
        "tags-title": "Etiquetes",
        "tags-intro": "Aquesta pàgina llista les etiquetes amb què el programari pot marcar una modificació, i el seu significat.",
        "tags-tag": "Nom de l'etiqueta",
        "logentry-delete-delete": "$1 {{GENDER:$2|ha esborrat}} la pàgina $3",
        "logentry-delete-delete_redir": "$1 {{GENDER:$2|ha esborrat}} la redirecció $3 sobreescrivint-la",
        "logentry-delete-restore": "$1 {{GENDER:$2|ha restaurat}} la pàgina $3 ($4)",
+       "restore-count-revisions": "{{PLURAL:$1|Una revisió|$1 revisions}}",
+       "restore-count-files": "{{PLURAL:$1|Un fitxer|$1 fitxers}}",
        "logentry-delete-event": "$1 {{GENDER:$2|ha canviat}} la visibilitat {{PLURAL:$5|d'un esdeveniment al registre|de $5 esdeveniments al registre}} de $3: $4",
        "logentry-delete-revision": "$1 {{GENDER:$2|ha canviat}} la visibilitat {{PLURAL:$5|d'una revisió|de $5 revisions}} a la pàgina $3: $4",
        "logentry-delete-event-legacy": "$1 {{GENDER:$2|ha canviat}} la visibilitat d'esdeveniments al registre de $3",
        "mediastatistics": "Estadístiques dels multimèdia",
        "mediastatistics-summary": "Les estadístiques sobre els tipus de fitxers pujats. Això només inclou la versió més recent d'un fitxer. S'exclouen les versions antigues o eliminades dels fitxers.",
        "mediastatistics-nbytes": "{{PLURAL:$1|$1 byte|$1 bytes}} ($2; $3%)",
+       "mediastatistics-bytespertype": "Mida de fitxer total d’aquesta secció: {{PLURAL:$1|$1 byte|$1 bytes}} ($2; $3 %).",
        "mediastatistics-allbytes": "Mida de fitxer total de tots els fitxers {{PLURAL:$1|$1 byte|$1 bytes}} ($2).",
        "mediastatistics-table-mimetype": "Tipus MIME",
        "mediastatistics-table-extensions": "Extensions possibles",
        "special-characters-group-thai": "Tailandès",
        "special-characters-group-lao": "Laosià",
        "special-characters-group-khmer": "Khmer",
+       "special-characters-group-canadianaboriginal": "Sil·labaris canadencs",
        "special-characters-title-endash": "guió curt",
        "special-characters-title-emdash": "guió llarg",
        "special-characters-title-minus": "signe menys",
        "restrictionsfield-label": "Intervals d'IP permesos:",
        "revid": "revisió $1",
        "pageid": "ID de pàgina $1",
+       "gotointerwiki": "A punt d’abandonar {{SITENAME}}",
        "gotointerwiki-invalid": "El títol especificat no és vàlid.",
+       "gotointerwiki-external": "Esteu a punt d’abandonar {{SITENAME}} per a visitar [[$2]], un lloc web diferent.\n\n'''[$1 Continua a $1]'''",
+       "undelete-cantedit": "Com que no podeu editar aquesta pàgina, no en podeu desfer la supressió.",
        "pagedata-title": "Dades de la pàgina",
        "pagedata-bad-title": "Títol no vàlid: $1"
 }
index 46c8b60..86c34dc 100644 (file)
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|де}}",
        "rcfilters-days-show-hours": "$1 {{PLURAL:$1|сахьт}}",
        "rcfilters-quickfilters": "Ӏалашдина литтарш",
+       "rcfilters-quickfilters-placeholder-title": "Ӏалашдина литтарш дац",
        "rcfilters-quickfilters-placeholder-description": "Литтаран буламаш (хьайна) Ӏалашбан лаахь а, йуха уьш лелабан лаахь а, тӀетаӀйе \"жигара литтаран\" уллера хьаьрка.",
        "rcfilters-savedqueries-defaultlabel": "Ӏалашдина литтарш",
        "rcfilters-savedqueries-rename": "ЦӀе хийцар",
        "rcfilters-liveupdates-button": "Авто-карлаяккха",
        "rcfilters-liveupdates-button-title-off": "Керла хийцамаш ма-бинехь гайта",
        "rcfilters-preference-label": "Керла хийцамийн дика кечйина верси къайлаяккха",
+       "rcfilters-preference-help": "2017 шеран интерфейсан редизайн а, оцу хенахь дуьйна тӀетоьхна гӀирсаш а къайлайоху.",
        "rcnotefrom": "Лахахь гайтина тӀера <strong>$2</strong> (хийцамаш <strong>$1</strong> кӀезиг).",
        "rclistfromreset": "Терахь харжар дӀадаккха",
        "rclistfrom": "Гайта хийцам {{CURRENTYEAR}} шеран {{CURRENTDAY}} {{CURRENTMONTHNAMEGEN}} {{CURRENTTIME}} бина болу",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|1=Билгало|Билгалонаш}}]]: $2)",
        "tag-mw-new-redirect": "Керла дӀасахьажорг",
        "tag-mw-rollback": "Юхаяккха",
+       "tag-mw-undo": "цаоьшу",
        "tags-title": "Билгалонаш",
        "tags-intro": "ХӀокху агӀона чохь гойтуш бу билгалонийн могӀам царца программин латторо билгал доху нисдарш, кхин билгалонийн маьӀна а.",
        "tags-tag": "Билгалона цӀе",
index 9d62dbb..aea4564 100644 (file)
        "tag-mw-replace-description": "Editace, které odstraňují více než 90 % obsahu stránky",
        "tag-mw-rollback": "Rychlý revert",
        "tag-mw-rollback-description": "Editace, jimiž byly předchozí editace vráceny zpět pomocí rychlého revertu",
+       "tag-mw-undo": "Vrácení zpět",
+       "tag-mw-undo-description": "Editace, jimiž se ruší předchozí editace pomocí odkazu „zrušit editaci“",
        "tags-title": "Značky",
        "tags-intro": "Tato stránka obsahuje seznam značek, kterými může software označovat jednotlivé editace, a jejich významy.",
        "tags-tag": "Název značky",
        "logentry-newusers-autocreate": "Automaticky byl {{GENDER:$2|založen}} účet $1",
        "logentry-protect-move_prot": "$1 {{GENDER:$2|přesunul|přesunula}} nastavení zámků ze stránky $4 na stránku $3",
        "logentry-protect-unprotect": "$1 {{GENDER:$2|odemknul|odemknula}} stránku $3",
-       "logentry-protect-protect": "$1 {{GENDER:$2|zamknul|zamknula}} stránku $3 $4",
-       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|zamknul|zamknula}} stránku $3 $4 [kaskádovým zámkem]",
+       "logentry-protect-protect": "$1 {{GENDER:$2|zamkl|zamkla|zamkl(a)}} stránku $3 $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|zamkl|zamkla|zamkl(a)}} stránku $3 $4 [kaskádovým zámkem]",
        "logentry-protect-modify": "$1 {{GENDER:$2|změnil|změnila}} úroveň ochrany stránky $3 $4",
        "logentry-protect-modify-cascade": "$1 {{GENDER:$2|změnil|změnila}} úroveň ochrany stránky $3 $4 [kaskádový zámek]",
        "logentry-rights-rights": "$1 {{GENDER:$2|změnil|změnila}} členství {{GENDER:$6|uživatele|uživatelky}} $3 ve skupinách z $4 na $5",
index 37f7e83..cce61a4 100644 (file)
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag|Tags}}]]: $2)",
        "tag-mw-new-redirect": "Ny omdirigering",
        "tag-mw-removed-redirect": "Fjernede omdirigering",
+       "tag-mw-changed-redirect-target": "Omdigeringsmål ændret",
        "tag-mw-blank": "Sidetømning",
        "tag-mw-replace": "Erstattet",
        "tag-mw-rollback": "Tilbagerulning",
index 8935e33..f2fc49b 100644 (file)
        "tog-watchlisthideminor": "Kleine Bearbeitungen in der Beobachtungsliste ausblenden",
        "tog-watchlisthideliu": "Bearbeitungen angemeldeter Benutzer in der Beobachtungsliste ausblenden",
        "tog-watchlistreloadautomatically": "Sofern ein Filter geändert wurde, die Beobachtungsliste automatisch neu laden (erfordert JavaScript)",
-       "tog-watchlistunwatchlinks": "Direkte Links zum (Ent-)Beobachten bei Einträgen in der Beobachtungsliste hinzufügen (für diese Funktion ist JavaScript erforderlich)",
+       "tog-watchlistunwatchlinks": "Direkte Links zum Beobachten/Nicht beobachten bei den Einträgen in der Beobachtungsliste hinzufügen (erfordert JavaScript)",
        "tog-watchlisthideanons": "Bearbeitungen anonymer Benutzer (IP-Adressen) in der Beobachtungsliste ausblenden",
        "tog-watchlisthidepatrolled": "Kontrollierte Änderungen in der Beobachtungsliste ausblenden",
        "tog-watchlisthidecategorization": "Kategorisierungen von Seiten in der Beobachtungsliste ausblenden",
        "tog-showhiddencats": "Versteckte Kategorien anzeigen",
        "tog-norollbackdiff": "Unterschiede nach dem Zurücksetzen nicht anzeigen",
        "tog-useeditwarning": "Warnen, sofern eine zur Bearbeitung geöffnete Seite verlassen wird, die nicht gespeicherte Änderungen enthält",
-       "tog-prefershttps": "Während angemeldet, immer eine sichere Verbindung benutzen.",
+       "tog-prefershttps": "Stets eine sichere Verbindung benutzen, solange ich angemeldet bin",
        "underline-always": "immer",
        "underline-never": "nie",
        "underline-default": "abhängig von der Benutzeroberfläche oder Browsereinstellung",
        "newwindow": "(wird in einem neuen Fenster geöffnet)",
        "cancel": "Abbrechen",
        "moredotdotdot": "Mehr …",
-       "morenotlisted": "Diese Liste könnte nicht vollständig sein.",
+       "morenotlisted": "Diese Liste könnte unvollständig sein.",
        "mypage": "Eigene Seite",
        "mytalk": "Diskussion",
        "anontalk": "Diskussionsseite",
        "tool-link-userrights-readonly": "{{GENDER:$1|Benutzergruppen}} ansehen",
        "tool-link-emailuser": "E-Mail an {{GENDER:$1|diesen Benutzer|diese Benutzerin}} senden",
        "imagepage": "Dateiseite anzeigen",
-       "mediawikipage": "Meldungsseite anzeigen",
+       "mediawikipage": "Systemnachricht ansehen",
        "templatepage": "Vorlagenseite anzeigen",
        "viewhelppage": "Hilfeseite anzeigen",
        "categorypage": "Kategorieseite anzeigen",
        "jumpto": "Wechseln zu:",
        "jumptonavigation": "Navigation",
        "jumptosearch": "Suche",
-       "view-pool-error": "Entschuldigung, die Server sind im Moment überlastet.\nZu viele Benutzer versuchen, diese Seite zu besuchen.\nBitte warte einige Minuten, bevor du es noch einmal versuchst.\n\n$1",
-       "generic-pool-error": "Leider sind die Server derzeit überlastet.\nZu viele Benutzer wollen diese Ressource ansehen.\nBitte warte einen Moment, bevor du sie erneut aufrufst.",
+       "view-pool-error": "Entschuldige bitte, dass die Server im Moment überlastet sind.\nZu viele Benutzer versuchen, diese Seite zu besuchen.\nBitte warte einige Minuten, bevor du es noch einmal versuchst.\n\n$1",
+       "generic-pool-error": "Entschuldige bitte, dass die Server im Moment überlastet sind.\nZu viele Benutzer wollen diese Ressource ansehen.\nBitte warte einen Moment, bevor du sie erneut aufrufst.",
        "pool-timeout": "Zeitablauf während des Wartens auf die Sperrung",
        "pool-queuefull": "Poolwarteschlange ist voll",
        "pool-errorunknown": "Unbekannter Fehler",
        "pool-servererror": "Der Poolzählerdienst ist nicht verfügbar ($1).",
-       "poolcounter-usage-error": "Verwendungsfehler: $1",
+       "poolcounter-usage-error": "Anwendungsfehler: $1",
        "aboutsite": "Über {{SITENAME}}",
        "aboutpage": "Project:Über_{{SITENAME}}",
        "copyright": "Der Inhalt ist verfügbar unter der Lizenz $1, sofern nicht anders angegeben.",
        "tag-mw-replace-description": "Bearbeitungen, die mehr als 90 % des Inhalts einer Seite entfernen.",
        "tag-mw-rollback": "Zurücksetzung",
        "tag-mw-rollback-description": "Bearbeitungen, die frühere Bearbeitungen mithilfe des Zurücksetzen-Links rückgängig machen.",
+       "tag-mw-undo": "Rückgängigmachung",
+       "tag-mw-undo-description": "Bearbeitungen, die frühere Versionen mit dem Link „Rückgängig machen“ zurücksetzen",
        "tags-title": "Markierungen",
        "tags-intro": "Diese Seite zeigt alle Markierungen, die für Bearbeitungen verwendet wurden, sowie deren Bedeutung. \n\nBei entsprechender Einstellung können die Missbrauchfilter beliebige Markierungen in die Versionsgeschichte setzen. Man kann die Versionsgeschichte dann nach den Markierungen filtern.",
        "tags-tag": "Markierungsname",
index 301408f..18c546d 100644 (file)
        "limitreport-expensivefunctioncount": "Expensive parser function count",
        "limitreport-expensivefunctioncount-value": "$1/$2",
        "expandtemplates": "Expand templates",
-       "expand_templates_intro": "This special page takes text and expands all templates in it recursively.\nIt also expands supported parser functions like\n<code><nowiki>{{</nowiki>#language:…}}</code> and variables like\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.\nIn fact, it expands pretty much everything in double-braces.",
+       "expand_templates_intro": "This special page takes wikitext and expands all templates in it recursively.\nIt also expands supported parser functions like\n<code><nowiki>{{</nowiki>#language:…}}</code> and variables like\n<code><nowiki>{{</nowiki>CURRENTDAY}}</code>.\nIn fact, it expands pretty much everything in double-braces.",
        "expand_templates_title": "Context title, for {{FULLPAGENAME}}, etc.:",
-       "expand_templates_input": "Input text:",
+       "expand_templates_input": "Input wikitext:",
        "expand_templates_output": "Result",
        "expand_templates_xml_output": "XML output",
        "expand_templates_html_output": "Raw HTML output",
        "expand_templates_preview": "Preview",
        "expand_templates_preview_fail_html": "<em>Because {{SITENAME}} has raw HTML enabled and there was a loss of session data, the preview is hidden as a precaution against JavaScript attacks.</em>\n\n<strong>If this is a legitimate preview attempt, please try again.</strong>\nIf it still does not work, try [[Special:UserLogout|logging out]] and logging back in, and check that your browser allows cookies from this site.",
        "expand_templates_preview_fail_html_anon": "<em>Because {{SITENAME}} has raw HTML enabled and you are not logged in, the preview is hidden as a precaution against JavaScript attacks.</em>\n\n<strong>If this is a legitimate preview attempt, please [[Special:UserLogin|log in]] and try again.</strong>",
-       "expand_templates_input_missing": "You need to provide at least some input text.",
+       "expand_templates_input_missing": "You need to provide at least some input wikitext.",
        "pagelanguage": "Change page language",
        "pagelang-name": "Page",
        "pagelang-language": "Language",
index b7407e1..856319f 100644 (file)
                        "Luisangelrg",
                        "Pierpao",
                        "Ohlila",
-                       "KATRINE1992"
+                       "KATRINE1992",
+                       "Athena in Wonderland"
                ]
        },
        "tog-underline": "Subrayar los enlaces:",
        "content-json-empty-object": "Objeto vacío",
        "content-json-empty-array": "Matriz vacía",
        "deprecated-self-close-category": "Páginas que utilizan etiquetas HTML autocerradas no válidas",
-       "deprecated-self-close-category-desc": "Esta página contiene etiquetas HTML de autocierre no válidas, tales como <code>&lt;b/></code> o <code>&lt;span/></code>. El comportamiento de estas cambiará pronto para ser consistente con la especificación de HTML5, por lo que su utilización en el wikitexto está obsoleta.",
+       "deprecated-self-close-category-desc": "Esta página contiene etiquetas HTML autocerradas no válidas, tales como <code>&lt;b/></code> o <code>&lt;span/></code>. El comportamiento de estas cambiará pronto para ser coherente con la especificación de HTML5, por lo que su utilización en el wikitexto está obsoleta.",
        "duplicate-args-warning": "<strong>Aviso:</strong> [[:$1]] llama a [[:$2]] con más de un valor para el parámetro «$3». Se usará solo el último valor proporcionado.",
        "duplicate-args-category": "Páginas que usan argumentos duplicados en invocaciones de plantillas",
        "duplicate-args-category-desc": "La página contiene invocaciones de plantillas que utilizan argumentos duplicados, como <code><nowiki>{{foo|bar=1|bar=2}}</nowiki></code> o <code><nowiki>{{foo|bar|1=baz}}</nowiki></code>.",
        "recentchangesdays-max": "Máximo {{PLURAL:$1|un día|$1 días}}",
        "recentchangescount": "N.º de ediciones que mostrar de manera predeterminada:",
        "prefs-help-recentchangescount": "Esto incluye cambios recientes, historiales de páginas y registros.",
-       "prefs-help-watchlist-token2": "Esta es la clave secreta del canal de suscripción de tu lista de seguimiento.\nCualquier persona que la conozca podría leer tu lista, así que no la compartas.\n[[Special:ResetTokens|Pulsa aquí si necesitas restablecerla]].",
+       "prefs-help-watchlist-token2": "Esta es la clave secreta del suministro web de tu lista de seguimiento.\nCualquiera que la conozca podrá consultar la lista, así que no la compartas.\n[[Special:ResetTokens|Puedes restablecerla si lo necesitas]].",
        "savedprefs": "Se han guardado tus preferencias.",
        "savedrights": "Se han guardado los grupos de {{GENDER:$1|usuario|usuaria}} de $1.",
        "timezonelegend": "Huso horario:",
        "uploadstash-bad-path": "La ruta no existe.",
        "uploadstash-bad-path-invalid": "La ruta no es válida.",
        "uploadstash-bad-path-unknown-type": "El tipo «$1» es desconocido.",
+       "uploadstash-bad-path-unrecognized-thumb-name": "No se reconoce el nombre de la miniatura.",
        "uploadstash-bad-path-no-handler": "No se encontró ningún manejador para el MIME $1 del archivo $2.",
        "uploadstash-bad-path-bad-format": "El formato de la clave «$1» es incorrecto.",
        "uploadstash-file-not-found-no-thumb": "No se pudo obtener la miniatura.",
        "uploadstash-wrong-owner": "Este archivo ($1) no pertenece al usuario actual.",
        "uploadstash-no-such-key": "No existe esta clave ($1); no se puede eliminar.",
        "uploadstash-no-extension": "No hay ninguna extension",
-       "uploadstash-zero-length": "El fichero esta vacio",
+       "uploadstash-zero-length": "El archivo está vacío.",
        "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.",
        "apisandbox-reset": "Limpiar",
        "apisandbox-retry": "Reintentar",
        "apisandbox-loading": "Cargando la información para el módulo API \"$1\"...",
-       "apisandbox-load-error": "Ocurrió un error al cargar la información para el módulo API \"$1\": $2",
+       "apisandbox-load-error": "Ocurrió un error al cargar la información del módulo «$1» de la API: $2",
        "apisandbox-no-parameters": "Este módulo API no tiene parámetros.",
        "apisandbox-helpurls": "Enlaces de ayuda",
        "apisandbox-examples": "Ejemplos",
        "exif-gpsdop-moderate": "Moderado ($1)",
        "exif-gpsdop-fair": "Pasable ($1)",
        "exif-gpsdop-poor": "Pobre ( $1 )",
-       "exif-objectcycle-a": "Sólo por la mañana",
-       "exif-objectcycle-p": "Sólo por el atardecer",
+       "exif-objectcycle-a": "Por la mañana únicamente",
+       "exif-objectcycle-p": "Por el atardecer únicamente",
        "exif-objectcycle-b": "Tanto por la mañana y por la tarde",
        "exif-gpsdirection-t": "Dirección real",
        "exif-gpsdirection-m": "Dirección magnética",
        "tag-mw-replace-description": "Ediciones que eliminan más del 90 % del contenido de una página",
        "tag-mw-rollback": "Reversión",
        "tag-mw-rollback-description": "Ediciones que deshacen modificaciones previas usando la herramienta de reversor",
+       "tag-mw-undo": "Deshacer",
+       "tag-mw-undo-description": "Ediciones que deshacen modificaciones anteriores mediante el enlace «Deshacer»",
        "tags-title": "Etiquetas",
        "tags-intro": "Esta página lista las etiquetas con las que el software puede marcar una edición y su significado.",
        "tags-tag": "Nombre de etiqueta",
        "mediastatistics-summary": "Estadísticas sobre los tipos de archivos cargados. Solo se tiene en cuenta la versión más reciente de cada archivo. Los archivos antiguos o eliminados están excluidos.",
        "mediastatistics-nfiles": "$1 ($2 %)",
        "mediastatistics-nbytes": "{{PLURAL:$1|$1 ''byte''|$1 ''bytes''}} ($2; $3 %)",
-       "mediastatistics-bytespertype": "Tamaño de archivo total para esta sección: {{PLURAL:$1|$1 byte|$1 bytes}} ($2; $3%).",
+       "mediastatistics-bytespertype": "Tamaño de archivo total de esta sección: {{PLURAL:$1|$1 byte|$1 bytes}} ($2; $3 %).",
        "mediastatistics-allbytes": "Tamaño de archivo total para todos los archivos: {{PLURAL:$1|$1 byte|$1 bytes}} ($2).",
        "mediastatistics-table-mimetype": "Tipo MIME",
        "mediastatistics-table-extensions": "Extensiones posibles",
index ef98e7a..86a9236 100644 (file)
        "timezoneregion-indian": "India ookean",
        "timezoneregion-pacific": "Vaikne ookean",
        "allowemail": "Luba teistel kasutajatel mulle e-kirju saata",
+       "email-allow-new-users-label": "Luba e-kirjad tuliuutelt kasutajatelt",
        "email-blacklist-label": "Keela neil kasutajatel mulle e-kirju saata:",
        "prefs-searchoptions": "Otsimine",
        "prefs-namespaces": "Nimeruumid",
        "right-siteadmin": "Panna lukku ja lukust lahti teha andmebaasi",
        "right-override-export-depth": "Eksportida lehekülgi, kaasates viidatud leheküljed kuni viienda tasemeni",
        "right-sendemail": "Saata teistele kasutajatele e-kirju",
+       "right-sendemail-new-users": "Saata e-kirju logitud toiminguteta kasutajatele",
        "right-managechangetags": "Koostada ja (in)aktiveerida [[Special:Tags|märgiseid]]",
        "right-applychangetags": "Rakendada [[Special:Tags|märgiseid]] enda muudatuste suhtes",
        "right-changetags": "Lisada ja eemaldada käsitsi rakendatavaid [[Special:Tags|märgiseid]] üksikute redaktsioonide ja logisissekannete juures",
        "rcfilters-preference-label": "Peida viimaste muudatuste täiustatud versioon",
        "rcfilters-preference-help": "Pöörab tagasi 2017. aastast alates tehtud muudatused kujunduses ja lisatud tööriistad.",
        "rcfilters-filter-showlinkedfrom-label": "Näita muudatusi lehekülgedel, millele viidatakse leheküljelt:",
-       "rcfilters-filter-showlinkedfrom-option-label": "Näita muudatusi lehekülgedel, millele viidatakse <strong>leheküljelt</strong>",
-       "rcfilters-filter-showlinkedto-label": "Näita muudatusi lehekülgedel, millel viidatakse leheküljele:",
-       "rcfilters-filter-showlinkedto-option-label": "Näita muudatusi lehekülgedel, mis viitavad <strong>leheküljele</strong>",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Leheküljed, millele viidatakse</strong> valitud leheküljel",
+       "rcfilters-filter-showlinkedto-label": "Näita muudatusi lehekülgedel, millel viidatakse leheküljele",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Leheküljed, mis viitavad</strong> valitud leheküljele",
        "rcfilters-target-page-placeholder": "Sisesta lehekülje pealkiri",
        "rcnotefrom": "Allpool on toodud {{PLURAL:$5|muudatus|muudatused}} alates: <strong>$3, kell $4</strong> (näidatakse kuni <strong>$1</strong> muudatust)",
        "rclistfromreset": "Lähtesta kuupäeva valik",
        "tag-mw-replace-description": "Muudatused, millega asendatakse lehekülje sisust enam kui 90%",
        "tag-mw-rollback": "Tühistamine",
        "tag-mw-rollback-description": "Muudatused, millega eelmised muudatused pööratakse tagasi, kasutades tühistuslinki",
+       "tag-mw-undo": "Eemaldamine",
+       "tag-mw-undo-description": "Muudatused, millega eelmised muudatused pööratakse tagasi, kasutades eemaldamislinki",
        "tags-title": "Märgised",
        "tags-intro": "See lehekülg loetleb märgised, millega tarkvara võib muudatused märgistada, ja nende kirjeldused.",
        "tags-tag": "Märgise nimi",
index 569d2c0..e8307df 100644 (file)
        "botpasswords-insert-failed": "Ezin izan da bot \"$1\" izen hori gehitu. Dagoeneko gehituta zegoen?",
        "botpasswords-update-failed": "\"$1\" Errobota ezin eguneratu. Ezabatua izan al da?",
        "botpasswords-created-title": "Botaren pasahitza sortu da",
-       "botpasswords-created-body": "$2 erabiltzailearen $1 errobot izenarentzako pasahitza sortu egin da.",
+       "botpasswords-created-body": "$2 erabiltzailearen $1 bot izenarentzako pasahitza sortu egin da.",
        "botpasswords-updated-title": "Botaren pasahitza eguneratu da",
        "botpasswords-updated-body": "$2 erabiltzailearen $1 errobot izenarentzako pasahitza gaurkotua izan da.",
        "botpasswords-deleted-title": "Botaren pasahitza ezabatu da",
        "content-model-css": "CSS",
        "content-json-empty-object": "Objetu hustua",
        "content-json-empty-array": "Matrize hutsa",
-       "deprecated-self-close-category": "HTML etiketa automatikoak ez diren balioak erabiltzen ari diren oriialdeak",
+       "deprecated-self-close-category": "HTML etiketen itxiera propio ez-baliagarria erabiltzen duten orrialdeak",
        "deprecated-self-close-category-desc": "Orriak HTML etiketa autoitxi baliogabeak dauzka, adibidez <code>&lt;b/></code> edo <code>&lt;span/></code>. Hauen jarrera HTML5 zehaztapenekin bat egiteko goiz aldatuko dira, zaharkiturik geratzen direla wikitestuan.",
        "duplicate-args-warning": "<strong>Oharra:</strong> [[:$1]]k [[:$2]] \"$3\" parametroarentzako balio bat baino gehiagorekin deitzen ari da. Emandako azken balioa bakarrik erabiliko da.",
        "duplicate-args-category": "Txantiloi-deietan argumentu bikoiztuak erabiltzen dituzten orrialdeak",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Etiketa|Etiketak}}]]: $2)",
        "tag-mw-contentmodelchange": "Eduki eredu aldaketa",
        "tag-mw-contentmodelchange-description": "Orri baten [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel change the content model] aldaketak",
+       "tag-mw-new-redirect": "Birbideratze berria",
        "tag-mw-blank-description": "Orria zuriz jartzen duten aldaketak",
        "tag-mw-replace": "Ordezkatuta",
        "tag-mw-replace-description": "Orrialde baten edukiaren %90a baino gehiagok ezabatzen duten aldaketak",
index 004c740..873c74f 100644 (file)
        "tags-activate": "فعال‌سازی",
        "tags-deactivate": "غیرفعال کردن",
        "tags-hitcount": "$1 {{PLURAL:$1|تغییر|تغییر}}",
-       "tags-manage-no-permission": "Ø´Ù\85ا Ø§Ø¬Ø§Ø²Ù\87 Ù\85دÛ\8cرÛ\8cت ØªØºÛ\8cÛ\8cر ØªÚ¯‌ها را ندارید.",
+       "tags-manage-no-permission": "Ø´Ù\85ا Ø§Ø¬Ø§Ø²Ù\87 Ù\85دÛ\8cرÛ\8cت ØªØºÛ\8cÛ\8cر Ø¨Ø±Ú\86سب‌ها را ندارید.",
        "tags-manage-blocked": "امکان تغییر برچسب‌ها را در زمان بسته‌بودن {{GENDER:$1|ندارید}}",
        "tags-create-heading": "ایجاد یک برچسب جدید",
        "tags-create-explanation": "به طور پیش‌فرض، تگ‌های تازه ایجاد شده برای استفاده کاربران و ربات‌ها در دسترس قرار می‌گیرند.",
        "tags-create-tag-name": "نام برچسب:",
        "tags-create-reason": "دلیل:",
        "tags-create-submit": "ایجاد",
-       "tags-create-no-name": "Ù\86اÙ\85 ØªÚ¯ باید مشخص شود.",
+       "tags-create-no-name": "Ù\86اÙ\85 Ø¨Ø±Ú\86سب باید مشخص شود.",
        "tags-create-invalid-chars": "نام برچسب‌ها نباید حاوی کاما (<code>,</code>) یا خط مورب (<code>/</code>) باشد.",
-       "tags-create-invalid-title-chars": "Ù\86اÙ\85 ØªÚ¯‌ها نباید شامل حروفی شود که نمی‌توان از آن‌ها در عنوان صفحات استفاده کرد.",
-       "tags-create-already-exists": "تگ \"$1\" هم‌اکنون موجود است.",
-       "tags-create-warnings-above": "در Ù\87Ù\86گاÙ\85 Ø§Û\8cجاد ØªÚ¯ \"$1\" با {{PLURAL:$2|هشدار|هشدارهای}} زیر پیش آمد:",
-       "tags-create-warnings-below": "Ø¢Û\8cا Ù\85اÛ\8cÙ\84 Ø¨Ù\87 Ø§Ø¯Ø§Ù\85Ù\87 Ø§Û\8cجاد ØªÚ¯ هستید؟",
+       "tags-create-invalid-title-chars": "Ù\86اÙ\85 Ø¨Ø±Ú\86سب‌ها نباید شامل حروفی شود که نمی‌توان از آن‌ها در عنوان صفحات استفاده کرد.",
+       "tags-create-already-exists": "برÚ\86سب \"$1\" هم‌اکنون موجود است.",
+       "tags-create-warnings-above": "در Ù\87Ù\86گاÙ\85 Ø§Û\8cجاد Ø¨Ø±Ú\86سب \"$1\" با {{PLURAL:$2|هشدار|هشدارهای}} زیر پیش آمد:",
+       "tags-create-warnings-below": "Ø¢Û\8cا Ù\85اÛ\8cÙ\84 Ø¨Ù\87 Ø§Ø¯Ø§Ù\85Ù\87 Ø§Û\8cجاد Ø¨Ø±Ú\86سب هستید؟",
        "tags-delete-title": "حذف برچسب",
-       "tags-delete-explanation-initial": "Ø´Ù\85ا Ø¯Ø± Ø­Ø§Ù\84 Ø­Ø°Ù\81 ØªÚ¯ «$1» از پایگاه داده هستید.",
+       "tags-delete-explanation-initial": "Ø´Ù\85ا Ø¯Ø± Ø­Ø§Ù\84 Ø­Ø°Ù\81 Ø¨Ø±Ú\86سب «$1» از پایگاه داده هستید.",
        "tags-delete-explanation-in-use": "این از {{PLURAL:$2|$2 ویرایش یا ورودی سیاهه|همهٔ $2 ویرایش و/یا ورودی سیاهه}} حذف خواهد شد با وجودی که الان تائید شده‌است.",
        "tags-delete-explanation-warning": "این عمل <strong>غیر قابل بازگشت</strong> است، حتی توسط مدیران پایگاه داده. مطمئن باشید که این همان تگی است که می‌خواهید آن‌را حذف کنید.",
        "tags-delete-explanation-active": "<strong>برچسب \"$1\" هنوز فعال است و در آینده اعمال خواهد شد.</strong> برای جلوگیری از این اتفاق، به قسمت(‌هایی) که برچسب فعال شده رفته و از آنجا غیرفعالش کنید.",
        "tags-delete-reason": "دلیل:",
-       "tags-delete-submit": "اÛ\8cÙ\86 ØªÚ¯ را به‌صورت غیرقابل بازگشت حذف کن",
+       "tags-delete-submit": "اÛ\8cÙ\86 Ø¨Ø±Ú\86سب را به‌صورت غیرقابل بازگشت حذف کن",
        "tags-delete-not-allowed": "برچسب‌هایی که در یک افزونه تعریف می‌شوند قابل حذف نیستند، مگر اینکه آن افزونه در این مورد خاص این قابلیت را بدهد.",
-       "tags-delete-not-found": "تگ «$1» وجود ندارد.",
+       "tags-delete-not-found": "برÚ\86سب «$1» وجود ندارد.",
        "tags-delete-too-many-uses": "برچسب \"$1\" در بیش از $2 نسخه اعمال شده است و نمی‌توان آن را حذف نمود.",
        "tags-delete-warnings-after-delete": "برچسب \"$1\" حذف شد، اما با {{PLURAL:$2|خطای|خطاهای}} زیر همراه بود:",
        "tags-delete-no-permission": "شما اجازهٔ حذف برچسب‌های تغییر را ندارید.",
        "tags-activate-title": "فعال‌سازی برچسب",
-       "tags-activate-question": "Ø´Ù\85ا Ø¯Ø± Ø­Ø§Ù\84 Ù\81عاÙ\84â\80\8cسازÛ\8c ØªÚ¯ «$1» هستید.",
+       "tags-activate-question": "Ø´Ù\85ا Ø¯Ø± Ø­Ø§Ù\84 Ù\81عاÙ\84â\80\8cسازÛ\8c Ø¨Ø±Ú\86سب «$1» هستید.",
        "tags-activate-reason": "دلیل:",
-       "tags-activate-not-allowed": "Ù\81عاÙ\84â\80\8cسازÛ\8c ØªÚ¯ «$1» ممکن نیست.",
-       "tags-activate-not-found": "تگ «$1» وجود ندارد.",
+       "tags-activate-not-allowed": "Ù\81عاÙ\84â\80\8cسازÛ\8c Ø¨Ø±Ú\86سب «$1» ممکن نیست.",
+       "tags-activate-not-found": "برÚ\86سب «$1» وجود ندارد.",
        "tags-activate-submit": "فعال‌سازی",
        "tags-deactivate-title": "غیرفعال‌سازی برچسب",
-       "tags-deactivate-question": "Ø´Ù\85ا Ø¯Ø± Ø­Ø§Ù\84 ØºÛ\8cرÙ\81عاÙ\84â\80\8cسازÛ\8c ØªÚ¯ «$1» هستید.",
+       "tags-deactivate-question": "Ø´Ù\85ا Ø¯Ø± Ø­Ø§Ù\84 ØºÛ\8cرÙ\81عاÙ\84â\80\8cسازÛ\8c Ø¨Ø±Ú\86سب «$1» هستید.",
        "tags-deactivate-reason": "دلیل:",
-       "tags-deactivate-not-allowed": "غÛ\8cرÙ\81عاÙ\84â\80\8cسازÛ\8c ØªÚ¯ «$1» ممکن نیست.",
+       "tags-deactivate-not-allowed": "غÛ\8cرÙ\81عاÙ\84â\80\8cسازÛ\8c Ø¨Ø±Ú\86سب «$1» ممکن نیست.",
        "tags-deactivate-submit": "غیرفعال‌سازی",
        "tags-apply-no-permission": "دسترسی برای تغییر برچسب تغییراتتان را ندارید.",
        "tags-apply-blocked": "در زمان بسته‌بودن امکان اعمال تغییراتتان بر روی برچسب‌ها را {{GENDER:$1|ندارید}}.",
        "logentry-upload-upload": "$1 $3 را {{GENDER:$2|بارگذاری کرد}}",
        "logentry-upload-overwrite": "$1 نسخهٔ تازه‌ای از $3 را {{GENDER:$2|بارگذاری کرد}}",
        "logentry-upload-revert": "$1 {{GENDER:$2|بارگذاری کرد}} $3",
-       "log-name-managetags": "تارÛ\8cØ®Ú\86Ù\87 Ù\85دÛ\8cرÛ\8cت ØªÚ¯",
+       "log-name-managetags": "تارÛ\8cØ®Ú\86Ù\87 Ù\85دÛ\8cرÛ\8cت Ø¨Ø±Ú\86سب",
        "log-description-managetags": "این صفحه امور مدیریتی مربوط به [[Special:Tags|برچسب‌ها]] را فهرست می‌کند. سیاهه فقط حاوی فعالیت‌هایی است که توسط یک مدیر به صورت دستی انجام شده‌اند؛ برچسب‌ها ممکن است توسط نرم‌افزار ویکی ساخته یا حذف بشوند بدون اینکه هیچ ورودی در این سیاهه ثبت گردد.",
        "logentry-managetags-create": "$1 برچسب «$4» را {{GENDER:$2|ایجاد کرد}}",
        "logentry-managetags-delete": "$1 برچسب را از \"$4\" {{GENDER:$2|حذف کرد}} (حذف شده از $5 {{PLURAL:$5|نسخه یا ورودی سیاهه|نسخه یا/و ورودی سیاهه}})",
        "log-action-filter-delete-revision": "حذف ویرایش",
        "log-action-filter-import-interwiki": "ورودی ترانسویکی",
        "log-action-filter-import-upload": "درون‌ریزی به کمک بارگذاری XML",
-       "log-action-filter-managetags-create": "اÛ\8cجاد ØªÚ¯",
-       "log-action-filter-managetags-delete": "حذÙ\81 Ú©Ø±Ø¯Ù\86 ØªÚ¯",
-       "log-action-filter-managetags-activate": "Ù\81عاÙ\84سازÛ\8c ØªÚ¯",
-       "log-action-filter-managetags-deactivate": "تغÛ\8cÛ\8cر ØªÚ¯",
+       "log-action-filter-managetags-create": "اÛ\8cجاد Ø¨Ø±Ú\86سب",
+       "log-action-filter-managetags-delete": "حذÙ\81 Ú©Ø±Ø¯Ù\86 Ø¨Ø±Ú\86سب",
+       "log-action-filter-managetags-activate": "Ù\81عاÙ\84سازÛ\8c Ø¨Ø±Ú\86سب",
+       "log-action-filter-managetags-deactivate": "تغÛ\8cÛ\8cر Ø¨Ø±Ú\86سب",
        "log-action-filter-move-move": "انتقال بدون بازنویسی تغییر مسیرها",
        "log-action-filter-move-move_redir": "انتقال با بازنویسی تغییر مسیرها",
        "log-action-filter-newusers-create": "ایجاد شده توسط کاربر ناشناس",
index b0ad41e..bf75153 100644 (file)
        "recentchangesdays-max": "Enintään $1 {{PLURAL:$1|päivä|päivää}}",
        "recentchangescount": "Näytettävien muutoksien määrä oletuksena",
        "prefs-help-recentchangescount": "Tämä sisältää tuoreet muutokset, muutoshistoriat ja lokit.",
-       "prefs-help-watchlist-token2": "Tämä on salainen avain tarkkailulistasi verkkosyötteeseen.\nKuka tahansa, joka tietää sen voi lukea tarkkailulistaasi, joten älä paljasta sitä.\n[[Special:ResetTokens|Napsauta tästä, jos sinun pitää uudistaa se]].",
+       "prefs-help-watchlist-token2": "Tämä on salainen avain tarkkailulistasi verkkosyötteeseen.\nKuka tahansa, joka tietää sen voi lukea tarkkailulistaasi, joten älä paljasta sitä.\nJos sinun täytyy, [[Special:ResetTokens|voit uudistaa sen]].",
        "savedprefs": "Asetuksesi on tallennettu.",
        "savedrights": "Käyttäjän {{GENDER:$1|$1}} käyttäjäryhmät on tallennettu.",
        "timezonelegend": "Aikavyöhyke",
        "timezoneregion-indian": "Intian valtameri",
        "timezoneregion-pacific": "Tyynimeri",
        "allowemail": "Salli muiden käyttäjien lähettää minulle sähköpostia",
+       "email-allow-new-users-label": "Salli sähköpostit uusilta käyttäjiltä",
        "email-blacklist-label": "Estä näitä käyttäjiä lähettämästä minulle sähköpostia:",
        "prefs-searchoptions": "Haku",
        "prefs-namespaces": "Nimiavaruudet",
        "rcfilters-advancedfilters": "Kehittyneet suodattimet",
        "rcfilters-limit-title": "Näytettävät tulokset",
        "rcfilters-limit-and-date-label": "{{PLURAL:$1|muutos|$1 muutosta}}, $2",
+       "rcfilters-date-popup-title": "Aikajakso hakua varten",
        "rcfilters-days-title": "Viimeisimmät päivät",
        "rcfilters-hours-title": "Viimeisimmät tunnit",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|päivä|päivää}}",
        "rcfilters-filter-watchlist-notwatched-description": "Kaikki paitsi muutokset tarkkailulistallasi oleviin sivuihin.",
        "rcfilters-filtergroup-watchlistactivity": "Tarkkailulistan aktiivisuus",
        "rcfilters-filter-watchlistactivity-unseen-label": "Näkemättömät muutokset",
+       "rcfilters-filter-watchlistactivity-unseen-description": "Muutokset sivuihin, joilla et ole käynyt muutosten jälkeen.",
        "rcfilters-filter-watchlistactivity-seen-label": "Nähdyt muutokset",
+       "rcfilters-filter-watchlistactivity-seen-description": "Muutokset sivuihin, joilla olet käynyt muutosten jälkeen.",
        "rcfilters-filtergroup-changetype": "Muutoksen tyyppi",
        "rcfilters-filter-pageedits-label": "Sivun muokkaukset",
        "rcfilters-filter-pageedits-description": "Muokkaukset wikin sisältöön, keskusteluihin, luokkakuvauksiin…",
        "rcfilters-watchlist-showupdated": "Muutokset sivuihin, joilla et ole vieraillut sen jälkeen kun muutokset on tehty, on <strong>lihavoitu</strong> ja värimerkitty.",
        "rcfilters-preference-label": "Piilota tuoreiden muutosten parannettu versio",
        "rcfilters-preference-help": "Peruuttaa vuoden 2017 käyttöliittymän uudistuksen ja kaikki sen jälkeen lisätyt työkalut.",
+       "rcfilters-target-page-placeholder": "Anna sivun nimi",
        "rcnotefrom": "Alla ovat muutokset <strong>$3, $4</strong> lähtien. (Enintään <strong>$1</strong> näytetään.)",
        "rclistfromreset": "Tyhjennä ajankohdan valinta",
        "rclistfrom": "Näytä uudet muutokset $3 kello $2 alkaen",
        "uploadstash-errclear": "Tiedostojen tyhjentäminen epäonnistui.",
        "uploadstash-refresh": "Päivitä tiedostoluettelo",
        "uploadstash-thumbnail": "näytä pienoiskuva",
+       "uploadstash-bad-path": "\nPolkua ei ole.",
+       "uploadstash-bad-path-invalid": "Polku ei kelpaa.",
+       "uploadstash-not-logged-in": "Käyttäjää ei ole kirjautunut sisään, tiedostojen on kuuluttava käyttäjille.",
+       "uploadstash-no-extension": "Laajennus on tyhjä.",
        "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.",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Merkkaus|Merkkaukset}}]]: $2)",
        "tag-mw-contentmodelchange": "sisältömallin muutos",
        "tag-mw-contentmodelchange-description": "Muokkaukset, jotka [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel muuttavat sivun sisältömallia]",
+       "tag-mw-new-redirect": "Uusi uudelleenohjaus",
+       "tag-mw-new-redirect-description": "Muokkaukset, jotka luovat uuden uudelleenohjauksen tai muuttavat sivun uudelleenohjaukseksi",
        "tag-mw-removed-redirect": "Ohjaus on poistettu",
+       "tag-mw-removed-redirect-description": "Muokkaukset, jotka muuttavat olemassa olevan uudelleenohjauksen ei-uudelleenohjaukseksi",
+       "tag-mw-changed-redirect-target": "Uudelleenohjauksen kohde muutettu",
+       "tag-mw-changed-redirect-target-description": "Muokkaukset, jotka muuttavat uudelleenohjauksen kohdetta",
+       "tag-mw-blank-description": "Muokkaukset, jotka tyhjentävät sivun",
+       "tag-mw-replace": "Korvattu",
+       "tag-mw-replace-description": "Muokkaukset, jotka poistavat yli 90% sivun sisällöstä",
+       "tag-mw-rollback": "Palautus",
+       "tag-mw-rollback-description": "Muokkaukset, jotka palauttavat edelliset muokkaukset takaisinvetolinkillä",
+       "tag-mw-undo": "Kumoa",
+       "tag-mw-undo-description": "Muokkaukset, jotka kumoavat edelliset muokkaukset kumoamislinkillä",
        "tags-title": "Merkkaukset",
        "tags-intro": "Tämä sivu luetteloi ne merkkaukset (''engl.'' tags), joilla ohjelmisto voi merkitä muokkauksia, ja mitä ne tarkoittavat.",
        "tags-tag": "Merkkauksen nimi",
        "special-characters-group-thai": "Thai",
        "special-characters-group-lao": "Lao",
        "special-characters-group-khmer": "Khmer",
+       "special-characters-group-canadianaboriginal": "Kanadalainen aboriginaali",
        "special-characters-title-endash": "ajatusviiva",
        "special-characters-title-emdash": "pitkä ajatusviiva",
        "special-characters-title-minus": "miinusmerkki",
        "authmanager-userlogin-remembermypassword-help": "Tulisiko salasana muistaa istunnon kestoa pidempään.",
        "authmanager-username-help": "Käyttäjänimi varmentamiseen.",
        "authmanager-password-help": "Salasana varmentamiseen.",
+       "authmanager-domain-help": "Verkkonimi ulkoiselle todennukselle.",
        "authmanager-retype-help": "Salasana uudelleen vahvistaaksesi.",
        "authmanager-email-label": "Sähköposti",
        "authmanager-email-help": "Sähköpostiosoite",
        "authprovider-confirmlink-request-label": "Tunnukset, jotka tulisi yhdistää",
        "authprovider-confirmlink-success-line": "$1: Linkitetty onnistuneesti.",
        "authprovider-confirmlink-failed": "Tunnuksen linkitys ei onnistunut täysin: $1",
+       "authprovider-confirmlink-ok-help": "Jatka yhteydenottohäiriöilmoitusten näyttämisen jälkeen.",
        "authprovider-resetpass-skip-label": "Ohita",
        "authprovider-resetpass-skip-help": "Ohita salasanan palautus.",
        "authform-nosession-login": "Varmennus onnistui, mutta selaimesi ei pysty \"muistamaan\" sisäänkirjautumista.\n\n$1",
index ae0b09a..ace1bc7 100644 (file)
        "youremail": "Courriel :",
        "username": "{{GENDER:$1|Nom d'utilisateur|Nom d'utilisatrice}} :",
        "prefs-memberingroups": "{{GENDER:$2|Membre}} {{PLURAL:$1|du groupe|des groupes}} :",
+       "prefs-memberingroups-type": "$1",
        "group-membership-link-with-expiry": "$1 (jusqu'à $2)",
        "prefs-registration": "Date d'inscription :",
+       "prefs-registration-date-time": "$1",
        "yourrealname": "Nom réel :",
        "yourlanguage": "Langue :",
        "yourvariant": "Variante de la langue du contenu :",
        "rcfilters-advancedfilters": "Filtres avancés",
        "rcfilters-limit-title": "Résultats à afficher",
        "rcfilters-limit-and-date-label": "{{PLURAL:$1|modification|$1 modifications}}, $2",
-       "rcfilters-date-popup-title": "Periode de temps pour chercher",
+       "rcfilters-date-popup-title": "Période de temps à rechercher",
        "rcfilters-days-title": "Derniers jours",
        "rcfilters-hours-title": "Dernières heures",
        "rcfilters-days-show-days": "$1 {{PLURAL:$1|jour|jours}}",
        "rcfilters-liveupdates-button-title-off": "Afficher les nouveaux changements dès qu'ils se produisent",
        "rcfilters-watchlist-markseen-button": "Marquer toutes les modifications comme vues",
        "rcfilters-watchlist-edit-watchlist-button": "Modifier votre liste de pages suivies",
-       "rcfilters-watchlist-showupdated": "Les modifications faites aux pages que vous n’avez pas visitées depuis qu’elles ont été modifiées sont en <strong>gras</strong>, avec des balises unies.",
+       "rcfilters-watchlist-showupdated": "Les modifications faites aux pages que vous n’avez pas visitées depuis qu’elles ont été modifiées sont en <strong>gras</strong>, avec des puces pleines.",
        "rcfilters-preference-label": "Masquer la version améliorée des modifications récentes",
        "rcfilters-preference-help": "Désactive la version 2017 de l'interface ainsi que de tous les outils ajoutés alors et depuis.",
        "rcfilters-filter-showlinkedfrom-label": "Montrer les modifications des pages liées depuis",
        "apisandbox-request-selectformat-label": "Afficher les données de la requête comme :",
        "apisandbox-request-format-url-label": "Chaîne de requête de l’URL",
        "apisandbox-request-url-label": "Requête URL :",
+       "apisandbox-request-format-json-label": "JSON",
        "apisandbox-request-json-label": "Demander du JSON :",
        "apisandbox-request-time": "Durée de la demande: {{PLURAL:$1|$1 ms}}",
        "apisandbox-results-fixtoken": "Corrigez le jeton et renvoyez",
        "listgrants-summary": "Voici une liste des droits avec leur accès associé aux droits utilisateur. Les utilisateurs peuvent autoriser les applications à utiliser leur compte, mais avec des droits limités d’après les droits que l’utilisateur a donnés à l’application. Un application agissant au nom d’un utilisateur ne peut toutefois pas, de fait, utiliser des droits que l’utilisateur ne possède pas.\nIl peut y avoir [[{{MediaWiki:Listgrouprights-helppage}}|plus d’information]] sur les droits individuels.",
        "listgrants-grant": "Accorder",
        "listgrants-rights": "Droits",
+       "listgrants-grant-display": "$1 <code>($2)</code>",
        "trackingcategories": "Catégories de suivi",
        "trackingcategories-summary": "Cette page liste les catégories de suivi qui sont remplies automatiquement par [[MediaWiki]]. Leurs noms peuvent être changés en modifiant les messages systèmes correspondants dans l’espace de noms {{ns:8}}.",
        "trackingcategories-msg": "Catégorie de suivi",
        "imported-log-entries": "$1 {{PLURAL:$1|entrée|entrées}} du journal {{PLURAL:$1|importée|importées}}.",
        "importfailed": "Échec de l'importation : <nowiki>$1</nowiki>",
        "importunknownsource": "Type inconnu de la source à importer",
-       "importnoprefix": "Aucun prefixe de interwiki n'a ete fourni",
+       "importnoprefix": "Aucun prefixe interwiki n’a été fourni",
        "importcantopen": "Impossible d'ouvrir le fichier à importer",
        "importbadinterwiki": "Mauvais lien inter-wiki",
        "importsuccess": "L'importation a réussi !",
        "watchlistedit-clear-removed": "{{PLURAL:$1|Un titre a été|$1 titres ont été}} retirés :",
        "watchlistedit-too-many": "Il y a trop de pages à afficher ici.",
        "watchlisttools-clear": "Effacer la liste de suivi",
-       "watchlisttools-view": "Voir les changements intervenus",
+       "watchlisttools-view": "Voir les changements correspondants",
        "watchlisttools-edit": "Voir et modifier la liste de suivi",
        "watchlisttools-raw": "Modifier la liste de suivi en mode brut",
        "iranian-calendar-m1": "Farvardin",
        "tag-mw-contentmodelchange": "modification du modèle de contenu",
        "tag-mw-contentmodelchange-description": "Modifications qui [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel changent le modèle de contenu] d'une page",
        "tag-mw-new-redirect": "Nouvelle redirection",
-       "tag-mw-new-redirect-description": "Editions qui vont creer une nouvelle redirection ou modifier una page vers une redirection",
+       "tag-mw-new-redirect-description": "Modifications qui créent une nouvelle redirection ou transforment une page en redirection",
        "tag-mw-removed-redirect": "Redirection supprimée",
-       "tag-mw-removed-redirect-description": "Les editions qui vont changer la redirection courante a une non redirection",
-       "tag-mw-changed-redirect-target": "La destination de redirection a ete modifiee",
+       "tag-mw-removed-redirect-description": "Modifications qui remplacent une redirection existante par une page sans redirection",
+       "tag-mw-changed-redirect-target": "La destination de redirection a été modifiée",
        "tag-mw-changed-redirect-target-description": "Modifications qui modifient la cible d’une redirection",
        "tag-mw-blank": "Blanchiment",
        "tag-mw-blank-description": "Modifications qui suppriment le contenu des pages",
        "tag-mw-replace-description": "Modifications qui enlèvent plus de 90% du contenu des pages",
        "tag-mw-rollback": "Révocation",
        "tag-mw-rollback-description": "Modifications qui annulent des modifications existantes en utilisant le lien de révocation (''rollback'')",
+       "tag-mw-undo": "Annuler",
+       "tag-mw-undo-description": "Modifications qui annulent les précédentes en utilisant le lien annuler",
        "tags-title": "Balises",
        "tags-intro": "Cette page liste les balises que le logiciel peut utiliser pour marquer une modification et la signification de chacune d’elles.",
        "tags-tag": "Nom de la balise",
index a02c743..3c5c93a 100644 (file)
        "recentchanges-legend-heading": "<strong>Ferklaarang:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (luke uk bi't [[Special:NewPages|list mä nei sidjen]])",
        "recentchanges-legend-plusminus": "(''±123'')",
+       "rcfilters-preference-label": "Det nei werjuun faan a Leetst Feranrangen versteeg",
        "rcnotefrom": "Diar {{PLURAL:$5|woort det feranrang|wurd a feranrangen}} sant <strong>$3,$4</strong>uunwiset (ei muar üs <strong>$1</strong> feranrangen).",
        "rclistfrom": "Bluas feranrangen sant $3 $2 wise",
        "rcshowhideminor": "$1 letj feranrangen",
        "autosumm-blank": "Det sidj as leesag maaget wurden.",
        "autosumm-replace": "Di tekst as ütjbütjet wurden mä \"$1\"",
        "autoredircomment": "Sidj tu [[$1]] widjerfeerd",
+       "autosumm-changed-redirect-target": "Widjerfeerang feranert faan [[$1]] tu [[$2]]",
        "autosumm-new": "Det sidj as nei uunlaanj wurden: \"$1\"",
        "autosumm-newblank": "En leesag sidj maaget",
        "lag-warn-normal": "Feranrangen faan {{PLURAL:$1|at leetst sekund|a leetst $1 sekunden}} kön noch ei uunwiset wurd.",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Kääntiaken|Kääntiakens}}]]: $2)",
        "tag-mw-new-redirect": "Nei widjerfeerang",
        "tag-mw-new-redirect-description": "Feranrangen, diar en nei widjerfeerang iinracht.",
+       "tag-mw-removed-redirect": "Widjerfeerang wechnimen",
+       "tag-mw-changed-redirect-target": "Widjerfeerang feranert",
        "tags-title": "Kääntiaken",
        "tags-intro": "Det sidj wiset kääntiaken, diar för't bewerkin brükt wurd, an wat jo men.",
        "tags-tag": "Kääntiaken-nööm",
index e8ae7e6..a530e16 100644 (file)
@@ -24,7 +24,8 @@
                        "Banjo",
                        "Josep Maria Roca Peña",
                        "Luan",
-                       "Hamilton Abreu"
+                       "Hamilton Abreu",
+                       "Athena in Wonderland"
                ]
        },
        "tog-underline": "Subliñar as ligazóns:",
        "rcfilters-preference-label": "Ocultar a versión mellorada de cambios recentes",
        "rcfilters-preference-help": "Reverte o redeseño da interface de 2017 e tódalas ferramentas engadidas dende entón.",
        "rcfilters-filter-showlinkedfrom-label": "Amosar os cambios en páxinas ligadas desde",
-       "rcfilters-filter-showlinkedfrom-option-label": "Amosar os cambios en páxinas ligadas <strong>DESDE</strong> unha páxina",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Páxinas ligadas desde</strong> a páxina seleccionada",
        "rcfilters-filter-showlinkedto-label": "Amosar os cambios en páxinas que ligan con",
-       "rcfilters-filter-showlinkedto-option-label": "Amosar os cambios en páxinas que ligan <strong>CON</strong> unha páxina",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Páxinas que ligan</strong> para a páxina seleccionada",
        "rcfilters-target-page-placeholder": "Insire un nome de páxina",
        "rcnotefrom": "A continuación {{PLURAL:$5|móstrase o cambio feito|móstranse os cambios feitos}} desde o <strong>$3</strong> ás <strong>$4</strong> (móstranse <strong>$1</strong> como máximo).",
        "rclistfromreset": "Reinicializar a selección da data",
        "tag-mw-replace-description": "Edicións que eliminan máis do 90% do contido dunha páxina",
        "tag-mw-rollback": "Desfacer",
        "tag-mw-rollback-description": "Edicións que desfán modificacións previas usando a ligazón de desfacer",
+       "tag-mw-undo": "Desfacer",
        "tags-title": "Etiquetas",
        "tags-intro": "Esta páxina lista as etiquetas coas que o software pode marcar unha edición, e mailos seus significados.",
        "tags-tag": "Nome da etiqueta",
index 0e521b3..cf76e44 100644 (file)
        "tag-mw-replace-description": "עריכות שמסירות יותר מ־90% מהתוכן של דף",
        "tag-mw-rollback": "שחזור",
        "tag-mw-rollback-description": "עריכות שמשחזרות עריכות קודמות בעזרת קישור השחזור",
+       "tag-mw-undo": "ביטול",
+       "tag-mw-undo-description": "עריכות שמבטלות עריכות קודמות בעזרת קישור הביטול",
        "tags-title": "תגיות",
        "tags-intro": "דף זה מכיל רשימה של תגיות שהתוכנה יכולה לסמן איתן עריכה, ומשמעויותיהן.",
        "tags-tag": "שם התגית",
index 0822003..981706c 100644 (file)
@@ -86,7 +86,8 @@
                        "Sachinkatiyar",
                        "Rishi.Singh",
                        "Clockery",
-                       "Rajatkatiyar10"
+                       "Rajatkatiyar10",
+                       "Dcljr"
                ]
        },
        "tog-underline": "लिंक रेखांकित करें:",
        "tog-watchdefault": "मेरे द्वारा सम्पादित पृष्ठों और फ़ाइलों को मेरी ध्यानसूची में जोड़ें",
        "tog-watchmoves": "मेरे द्वारा स्थानांतरित पृष्ठों एवं फ़ाइलों को मेरी ध्यानसूची में जोड़ें",
        "tog-watchdeletion": "मेरे द्वारा हटाए गए पृष्ठों एवं फ़ाइलों को मेरी ध्यानसूची में जोड़ें",
-       "tog-watchuploads": "मà¥\87रà¥\87 à¤¨à¤\8f à¤«à¤¼à¤¾à¤\87लà¥\8bà¤\82 à¤\95à¥\8b à¤®à¥\87रà¥\87 à¤§à¥\8dयानसà¥\82à¤\9aà¥\80 à¤®à¥\87à¤\82 à¤¡à¤¾à¤²à¥\87à¤\82।",
+       "tog-watchuploads": "मà¥\87रà¥\80 à¤§à¥\8dयानसà¥\82à¤\9aà¥\80 à¤®à¥\87à¤\82 à¤®à¥\87रà¥\80 à¤\85पलà¥\8bड à¤\95रनà¥\87 à¤µà¤¾à¤²à¥\80 à¤¨à¤\88 à¤«à¤¼à¤¾à¤\87लà¥\87à¤\82 à¤¡à¤¾à¤²à¥\87à¤\82|",
        "tog-watchrollback": "मेरे द्वारा प्रत्यापन्न (रोलबैक) किये हुये पृष्ठों को मेरी ध्यानसूची में जोड़ें।",
        "tog-minordefault": "मेरे सभी सम्पादनों को छोटे बदलाव के रूप में चिह्नित करें",
        "tog-previewontop": "सम्पादन सन्दूक से पहले झलक दिखायें",
        "viewdeleted_short": "देखें {{PLURAL:$1|एक हटाया गया सम्पादन|$1 हटाए गए सम्पादन}}",
        "protect": "सुरक्षित करें",
        "protect_change": "बदलें",
-       "unprotect": "à¤\85सà¥\81रà¤\95à¥\8dषित",
+       "unprotect": "सà¥\81रà¤\95à¥\8dषा à¤¬à¤¦à¤²à¥\87à¤\82",
        "newpage": "नया पृष्ठ",
        "talkpagelinktext": "चर्चा",
        "specialpage": "विशेष पृष्ठ",
        "pool-queuefull": "पूल पंक्ति भरी हुई है",
        "pool-errorunknown": "अज्ञात त्रुटि",
        "pool-servererror": "पूल काउंटर सेवा उपलब्ध नहीं है ($1)।",
-       "poolcounter-usage-error": "à¤\89पयोग त्रुटि: $1",
+       "poolcounter-usage-error": "पà¥\8dरयोग त्रुटि: $1",
        "aboutsite": "{{SITENAME}} के बारे में",
-       "aboutpage": "Project:परिà¤\9aय",
+       "aboutpage": "Project:à¤\95à¥\87 à¤¬à¤¾à¤°à¥\87 à¤®à¥\87à¤\82",
        "copyright": "उपलब्ध सामग्री $1 के अधीन है जब तक अलग से उल्लेख ना किया गया हो।",
        "copyrightpage": "{{ns:project}}:कॉपीराइट",
        "currentevents": "हाल की घटनाएँ",
        "enotif_impersonal_salutation": "{{SITENAME}} सदस्य",
        "enotif_subject_deleted": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने हटा दिया है",
        "enotif_subject_created": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने बना दिया है",
-       "enotif_subject_moved": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने स्थानांतरित कर दिया है",
+       "enotif_subject_moved": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|चले गए}} $2 द्वारा चले जा चुका है",
        "enotif_subject_restored": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने पुनर्स्थापित कर दिया है",
        "enotif_subject_changed": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने परिवर्तित किया है",
-       "enotif_body_intro_deleted": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने $PAGEEDITDATE को हटा दिया है, देखें $3।",
+       "enotif_body_intro_deleted": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने $PAGEEDITDATE को हटा दिया है, देखें <$3>।",
        "enotif_body_intro_created": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने $PAGEEDITDATE को बनाया है, वर्तमान अवतरण के लिए $3 देखें।",
        "enotif_body_intro_moved": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने $PAGEEDITDATE को स्थानांतरित किया है, वर्तमान अवतरण के लिए $3 देखें।",
        "enotif_body_intro_restored": "{{SITENAME}} पृष्ठ $1 को {{GENDER:$2|$2}} ने $PAGEEDITDATE को पुनर्स्थापित किया है, वर्तमान अवतरण के लिए $3 देखें।",
        "tag-mw-replace-description": "संपादन जिसने 90% से अधिक पृष्ट की सामग्री को हटा दिया",
        "tag-mw-rollback": "पीछे हटना",
        "tag-mw-rollback-description": "संपादन जो रोलबैक लिंक का उपयोग करके पिछला संपादन वापस रोल करता है",
+       "tag-mw-undo": "किए हुए कार्य को पूर्वत करना",
+       "tag-mw-undo-description": "संपादन जो पिछले लिंक का उपयोग करके पिछले संपादन को पूर्वत करता है",
        "tags-title": "चिप्पियाँ",
        "tags-intro": "यह पृष्ठ अर्थ सहित वह चिप्पियाँ दर्शाता है जिनका कोई तंत्रांश किसी संपादन पर निशान लगाने के लिए इस्तेमाल कर सकता है।",
        "tags-tag": "चिप्पी का नाम",
index d739d97..e18db10 100644 (file)
        "category-empty": "<em>U ovoj kategoriji trenutačno nema članaka ni medija.</em>",
        "hidden-categories": "{{PLURAL:$1|Skrivena kategorija|Skrivene kategorije|Skrivenih kategorija}}",
        "hidden-category-category": "Skrivene kategorije",
-       "category-subcat-count": "Ova kategorija sadrži $2 {{PLURAL:$2|podkategoriju|podkategorije|podkategorija}}, ovaj popis prikazuje $1.",
+       "category-subcat-count": "{{PLURAL:$2|1=Ova kategorija sadržava samo sljedeću potkategoriju.|Ova kategorija ima {{PLURAL:$1|sljedeću $1 potkategoriju|sljedeće $1 potkategorije|sljedećih $1 potkategorija}}, od ukupno $2.}}",
        "category-subcat-count-limited": "Ova kategorija ima {{PLURAL:$1|podkategoriju|$1 podkategorije|$1 podkategorija}}.",
        "category-article-count": "{{PLURAL:$2|Ova kategorija sadrži samo sljedeću stranicu.|{{PLURAL:$1|Prikazana stranica jedina je|Prikazane su $1 stranice su|Prikazano je $1 stranica}} u ovoj kategoriji, od ukupno $2.}}",
        "category-article-count-limited": "{{PLURAL:$1|stranica je|$1 stranice su|$1 stranica je}} u ovoj kategoriji.",
        "passwordreset-emailsentemail": "Ako je ova adresa povezana s Vašim suradničkim računom, na nju će biti poslan podsjetnik na zaporku.",
        "passwordreset-emailsentusername": "Ukoliko je ova adresa povezana s Vašim suradničkim računom, na istu će biti poslan podsjetnik sa zaporkom.",
        "passwordreset-invalidemail": "Nevaljala adresa e-pošte",
+       "passwordreset-nodata": "Niste naveli ni suradničko ime, a niti adresu e-pošte",
        "changeemail": "Promijeni ili izbriši e-mail adresu",
        "changeemail-header": "Ispunite ovaj obrazac da biste promijenili svoju adresu e-pošte. Ukoliko želite ukloniti povezanost svoje adrese e-pošte i suradničkoga računa, prilikom popunjavanja obrasca ostavite prazno polje umjesto upisivanja nove adrese e-pošte.",
        "changeemail-no-info": "Morate biti prijavljeni da biste izravno pristupili ovoj stranici.",
        "blockedtitle": "Suradnik je blokiran",
        "blockedtext": "<strong>Vaše je suradničko ime blokirano ili je Vaša IP adresa blokirana.</strong>\n\nBlokirao Vas je $1.\nRazlog blokiranja je sljedeći: <em>$2</em>.\n\n* Početak blokade: $8\n* Blokada istječe: $6\n* Blokirani suradnik: $7\n\nMožete kontaktirati $1 ili jednog od [[{{MediaWiki:Grouppage-sysop}}|administratora]] kako bi Vam pojasnili razlog blokiranja.\n\nPrimijetite da ne možete koristiti opciju \"Pošalji e-poruku suradnici – suradniku\" ako niste upisali valjanu adresu e-pošte u Vašim [[Special:Preferences|suradničkim postavkama]] i ako niste u tome onemogućeni prilikom blokiranja.\n\nVaša trenutačna IP adresa je $3, a oznaka bloka #$5. Molimo uvrstite sve gore navedene detalje u svaki upit koji napišete.",
        "autoblockedtext": "Vaša IP adresa automatski je blokirana zbog toga što ju je koristio drugi suradnik, kojeg je blokirao $1.\nRazlog blokiranja je sljedeći:\n\n:<em>$2</em>\n\n* Početak blokade: $8\n* Blokada istječe: $6\n* Blokirani suradnik: $7\n\nMožete kontaktirati $1 ili jednog od [[{{MediaWiki:Grouppage-sysop}}|administratora]] kako bi Vam pojasnili razlog blokiranja.\n\nPrimijetite da ne možete rabiti opciju \"Pošalji e-poruku suradnici – suradniku\" ako niste upisali valjanu adresu e-pošte u Vašim [[Special:Preferences|suradničkim postavkama]] i ako niste u tome onemogućeni prilikom blokiranja.\n\nVaša trenutačna IP adresa je $3, a oznaka bloka #$5. Molimo uvrstite sve gore navedene detalje u svaki upit koji napišete.",
+       "systemblockedtext": "MediaWiki je automatski blokirao Vaše suradničko ime ili IP-adresu.\nDano je sljedeće obrazloženje:\n\n:<em>$2</em>\n\n* Početak blokade: $8\n* Istek blokade: $6\n* Blokada je namijenjena za: $7\n\nVaša trenutačna IP-adresa je $3.\nAko imate pitanja u svezi s blokadom, priložite sve pojedinosti koje su prethodno navedene.",
        "blockednoreason": "bez obrazloženja",
        "whitelistedittext": "Za uređivanje stranice molimo $1.",
        "confirmedittext": "Morate potvrditi Vašu adresu e-pošte prije nego što Vam bude omogućeno uređivanje. Molim unesite i ovjerite Vašu adresu e-pošte u [[Special:Preferences|suradničkim postavkama]].",
        "cascadeprotectedwarning": "'''UPOZORENJE:''' Ova stranica je zaključana i mogu je uređivati samo suradnici s administratorskim pravima, jer je uključena u {{PLURAL:$1|slijedeću stranicu|slijedeće stranice}} koje su zaštićene \"prenosivom\" zaštitom:",
        "titleprotectedwarning": "<strong>Upozorenje: Ova je stranica zaključana i samo ju suradnici s [[Special:ListGroupRights|određenim pravima]] mogu stvoriti.</strong>\nPosljednja stavka u evidenciji navedena je niže kao napomena:",
        "templatesused": "{{PLURAL:$1|Predložak koji se rabi|Predlošci koji se rabe}} na ovoj stranici:",
-       "templatesusedpreview": "{{PLURAL:$1|Predložak koji se rabi|Predlošci koji se rabe}} u ovom predpregledu:",
+       "templatesusedpreview": "{{PLURAL:$1|Predložak koji se rabi|Predlošci koji se rabe}} u ovom pretpregledu:",
        "templatesusedsection": "{{PLURAL:$1|Predložak koji se rabi|Predlošci koji se rabe}} u ovom odjeljku:",
        "template-protected": "(zaštićen)",
        "template-semiprotected": "(djelomično zaštićen)",
        "permissionserrors": "Pogrješka u pravima",
        "permissionserrorstext": "Nemate ovlasti za tu radnju iz sljedećih {{PLURAL:$1|razlog|razloga}}:",
        "permissionserrorstext-withaction": "Nemate dopuštenje za $2, iz {{PLURAL:$1|navedenog|navedenih}} razloga:",
-       "recreate-moveddeleted-warn": "<strong>Upozorenje: Ponovo stvarate stranicu koja je prethodno bila izbrisana.</strong>\n\nRazmotrite je li prikladno nastaviti s uređivanje ove stranice.\nZa Vašu informaciju slijedi evidencija brisanja i premještanja ove stranice:",
+       "recreate-moveddeleted-warn": "<strong>Upozorenje: ponovo stvarate stranicu koja je prethodno bila izbrisana.</strong>\n\nRazmotrite je li prikladno nastaviti s uređivanjem ove stranice.\nZa Vašu informaciju slijedi evidencija brisanja i premještanja ove stranice:",
        "moveddeleted-notice": "Ova je stranica izbrisana.\nEvidencije brisanja, zaštićivanja i premještanja za ovu stranicu prikazane su niže za uputu.",
        "moveddeleted-notice-recent": "Žao nam je, ova stranica je izbrisana u prošla 24 sata. \nNiže je navedena evidencija brisanja i premještanja.",
        "log-fulllog": "Prikaži cijelu evidenciju",
        "search-external": "Vanjski pretraživač",
        "searchdisabled": "<p>Oprostite! Pretraga po cjelokupnoj bazi je zbog bržeg rada projekta {{SITENAME}} trenutačno onemogućena. Možete se poslužiti tražilicom Google.</p>",
        "search-error": "Greška prilikom pretrage: $1",
+       "search-warning": "Došlo je do upozorenja prilikom pretraživanja: $1",
        "preferences": "Postavke",
        "mypreferences": "Postavke",
        "prefs-edits": "Broj uređivanja:",
        "timezoneregion-indian": "Indijski ocean",
        "timezoneregion-pacific": "Tihi ocean",
        "allowemail": "Omogući primanje e-maila od drugih suradnika",
+       "email-allow-new-users-label": "Dopusti e-poruke od posve novopridošlih suradnika",
        "email-blacklist-label": "Zabrani sljedećim suradnicima da mi šalju e-poruke:",
        "prefs-searchoptions": "Način traženja",
        "prefs-namespaces": "Imenski prostori",
        "right-siteadmin": "Zaključavanje i otključavanje baze podataka",
        "right-override-export-depth": "Izvezi stranice uključujući i povezane stranice do dubine od 5",
        "right-sendemail": "Slanje e-pošte drugim suradnicima",
+       "right-sendemail-new-users": "Pošalji e-poruku suradnicima bez radnji zabilježenih u evidencijama",
+       "right-managechangetags": "Stvaranje i (de)aktiviranje [[Special:Tags|oznaka]]",
        "grant-generic": "Snop prava »$1«",
        "grant-group-email": "Pošalji e-mail",
+       "grant-group-other": "Raznovrsno djelovanje",
        "grant-blockusers": "Blokiraj i odblokiraj korisnike",
        "grant-createaccount": "Otvori račune",
        "grant-createeditmovepage": "Stvaranje, uređivanje i premještanje stranica",
+       "grant-delete": "Brisanje stranica, izmjena i unosa u evidencijama",
        "grant-editmyoptions": "Uređivanje vlastitih suradničkih postavki",
        "grant-editmywatchlist": "Uređivanje Vašega popisa praćenih stranica",
        "grant-editpage": "Uređivanje postojećih stranica",
        "recentchanges-legend-newpage": "Nova stranica",
        "recentchanges-legend-plusminus": "(<em>±123</em>)",
        "recentchanges-submit": "Prikaži",
+       "rcfilters-tag-remove": "Ukloni »$1«",
        "rcfilters-legend-heading": "<strong>Popis kratica:</strong>",
        "rcfilters-other-review-tools": "Ostali alati za pregledavanje:",
        "rcfilters-group-results-by-page": "Grupiranje rezultata po stranici",
        "rcfilters-days-show-hours": "$1 {{PLURAL:$1|sat|sata|sati}}",
        "rcfilters-highlighted-filters-list": "Istaknuto: $1",
        "rcfilters-quickfilters": "Spremljeni filtri",
-       "rcfilters-quickfilters-placeholder-title": "Još nema spremljenih poveznica",
+       "rcfilters-quickfilters-placeholder-title": "Još nema spremljenih filtara",
        "rcfilters-quickfilters-placeholder-description": "Da biste spremili postavke filtra i rabili ih poslije, kliknite ispod na oznaku dočitnice u polju Aktivni filtri.",
        "rcfilters-savedqueries-defaultlabel": "Spremljeni filteri",
        "rcfilters-savedqueries-rename": "Preimenuj",
        "rcfilters-savedqueries-new-name-label": "Naziv",
        "rcfilters-savedqueries-new-name-placeholder": "Opišite svrhu filtra",
        "rcfilters-savedqueries-apply-label": "Stvori filtar",
+       "rcfilters-savedqueries-apply-and-setdefault-label": "Stvori predodređeni filtar",
        "rcfilters-savedqueries-cancel-label": "Otkaži",
        "rcfilters-savedqueries-add-new-title": "Spremi trenutačne postavke filtra",
        "rcfilters-restore-default-filters": "Vrati zadane filtre",
        "rcfilters-filter-watchlist-watchednew-description": "Izmjene stranica na popisu praćenja koje niste posjetili od vremena učinjenih izmjena.",
        "rcfilters-filter-watchlist-notwatched-label": "Izvan popisa praćenja",
        "rcfilters-filter-watchlist-notwatched-description": "Sve izmjene na stranicama osim onih na popisu praćenja.",
+       "rcfilters-filtergroup-watchlistactivity": "Aktivnost na popisu praćenja",
+       "rcfilters-filter-watchlistactivity-unseen-label": "Nepregledane izmjene",
+       "rcfilters-filter-watchlistactivity-seen-label": "Pregledane izmjene",
+       "rcfilters-filter-watchlistactivity-seen-description": "Izmjene na stranicama koje ste posjetili otkako su načinjene.",
        "rcfilters-filtergroup-changetype": "Vrste promjena",
        "rcfilters-filter-pageedits-label": "Uređivanja stranica",
        "rcfilters-filter-pageedits-description": "Uređivanja wikisadržaja, rasprave, opisi kategorija...",
        "rcfilters-liveupdates-button": "Ažuriranja uživo",
        "rcfilters-liveupdates-button-title-on": "Isključi ažuriranja uživo",
        "rcfilters-liveupdates-button-title-off": "Prikaži nove izmjene uživo",
+       "rcfilters-watchlist-markseen-button": "Označi sve izmjene kao pregledane",
+       "rcfilters-watchlist-edit-watchlist-button": "Izmijeni popis praćenih stranica",
        "rcfilters-preference-label": "Skrij poboljšanu inačicu nedavnih promjena",
        "rcfilters-preference-help": "Vraća natrag stanje prije redizajna sučelja 2017., te svih oruđa dodanih tada i poslije toga.",
        "rcnotefrom": "Ispod {{PLURAL:$5|je izmjena|su izmjene}} od <strong>$3, $4</strong> (prikazano ih do <strong>$1</strong>).",
        "uploadstash-refresh": "Osvježi popis datoteka",
        "uploadstash-thumbnail": "pogledaj kao minijaturu",
        "uploadstash-exception": "Postavljanje u zalihu nije bilo moguće ($1): »$2«.",
+       "uploadstash-bad-path": "Putanja ne postoji.",
+       "uploadstash-bad-path-invalid": "Putanja nije valjana.",
+       "uploadstash-bad-path-unknown-type": "Neprepoznata vrsta »$1«.",
+       "uploadstash-bad-path-unrecognized-thumb-name": "Neprepoznano ime sličice.",
+       "uploadstash-file-not-found-no-thumb": "Ne mogu dobiti minijaturu.",
+       "uploadstash-file-not-found-no-local-path": "Nema lokalne putanje za umanjenu stavku.",
+       "uploadstash-file-not-found-no-object": "Ne mogu načiniti lokalni podatkovni objekt za minijaturu.",
+       "uploadstash-file-not-found-no-remote-thumb": "Dobavljanje minijature nije uspjelo: $1\nURL = $2",
+       "uploadstash-file-not-found-missing-content-type": "Nedostaje zaglavlje za vrstu sadržaja.",
+       "uploadstash-file-not-found-not-exists": "Ne mogu naći putanju ili ovo nije uobičajena datoteka.",
+       "uploadstash-file-too-large": "Ne mogu poslužiti datoteku veću od $1 {{PLURAL:$1|bajta|bajtova}}.",
+       "uploadstash-not-logged-in": "Nije prijavljen ijedan suradnik. Datoteke moraju biti povezane sa suradnicima koji ih postavljaju.",
+       "uploadstash-no-extension": "Nema traženog proširenja.",
+       "uploadstash-zero-length": "Veličina datoteke je nula bajtova.",
        "invalid-chunk-offset": "Nevaljana točka nastavka snimanja",
        "img-auth-accessdenied": "Pristup onemogućen",
        "img-auth-nopathinfo": "Nedostaje PATH_INFO.\nVaš poslužitelj nije postavljen da prosljeđuje ovu informaciju.\nMožda se temelji na CGI skripti i ne može podržavati img_auth.\n[https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:Image_Authorization?uselang=hr Pogledajte stranicu o autorizaciji slika]",
        "pageswithprop-legend": "Stranice s određenim osobinama",
        "pageswithprop-text": "Ovo je popis stranica koje koriste određene osobine stranica.",
        "pageswithprop-prop": "Ime osobine:",
+       "pageswithprop-reverse": "Sortiraj obrnutim redoslijedom",
        "pageswithprop-sortbyvalue": "Sortiraj po vrijednosti svojstva",
        "pageswithprop-submit": "Idi",
        "doubleredirects": "Dvostruka preusmjeravanja",
        "magiclink-tracking-isbn": "Stranice s čarobnim ISBN poveznicama",
        "magiclink-tracking-isbn-desc": "Ova stranica rabi čarobne ISBN poveznice. Za njihovu migraciju vidi [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org].",
        "specialloguserlabel": "Suradnik:",
-       "speciallogtitlelabel": "Cilj (naslov ili suradnik):",
+       "speciallogtitlelabel": "Cilj (naslov ili {{ns:user}}:suradničko ime):",
        "log": "Evidencije",
        "logeventslist-submit": "Prikaži",
        "all-logs-page": "Sve javne evidencije",
        "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 promjene",
        "wlshowhidebots": "botove",
        "wlshowhideliu": "prijavljene suradnike",
        "enotif_body_intro_moved": "Stranicu $1 projekta {{SITENAME}} {{GENDER:$2|premjestio|premjestila}} je dana $PAGEEDITDATE {{GENDER:$2|suradnik|suradnica}} $2, vidi $3 za trenutačnu inačicu stranice.",
        "enotif_body_intro_restored": "Stranica $1 projekta {{SITENAME}} {{GENDER:$2|vratio|vratila}} je dana $PAGEEDITDATE {{GENDER:$2|suradnik|suradnica}} $2, vidi $3 za trenutačnu inačicu stranice.",
        "enotif_body_intro_changed": "Stranica $1 projekta {{SITENAME}} {{GENDER:$2|promijenio|promijenila}} je dana $PAGEEDITDATE {{GENDER:$2|suradnik|suradnica}} $2, vidi $3 za trenutačnu inačicu stranice.",
-       "enotif_lastvisited": "Pogledaj $1 za promjene od zadnjeg posjeta.",
+       "enotif_lastvisited": "Za sve izmjene od Vašega posljednjeg posjeta, pogledajte $1",
        "enotif_lastdiff": "Pogledajte $1 kako biste mogli vidjeti tu izmjenu.",
        "enotif_anon_editor": "neprijavljeni suradnik $1",
        "enotif_body": "Poštovani $WATCHINGUSERNAME,\n\n$PAGEINTRO $NEWPAGE\n\nSažetak uređivača: $PAGESUMMARY $PAGEMINOREDIT\n\nMožete kontaktirati suradnika koji je posljednji uređivao stranicu:\nmail: $PAGEEDITOR_EMAIL\nwiki: $PAGEEDITOR_WIKI\n\nDo Vašega ponovnog posjeta stranici ne ćete dobivati nove obavijesti. Postavke za izvješćivanje možete vratiti na prvobitno zadane za sve praćene stranice Vašega popisa praćenja.\n\nVaš sustav izvješćivanja {{SITENAME}}.\n\n--\nZa promjene postavki izvješćivanja putem e-pošte, posjetite\n{{canonicalurl:{{#special:Preferences}}}}\n\nZa promjene svog popisa praćenja, posjetite\n{{canonicalurl:{{#special:EditWatchlist}}}}\n\nZa brisanje stranica iz svog popisa praćenja, posjetite\n$UNWATCHURL\n\nZa povratne informacije i pomoć posjetite:\n$HELPPAGE",
        "confirmdeletetext": "Zauvijek ćete izbrisati stranicu ili sliku zajedno s prijašnjim inačicama.\nMolim potvrdite svoju namjeru, da razumijete posljedice i da ovo radite u skladu s [[{{MediaWiki:Policy-url}}|pravilima]].",
        "actioncomplete": "Radnja je dovršena",
        "actionfailed": "Radnja nije uspjela",
-       "deletedtext": "\"$1\" je izbrisana.\nVidi $2 za evidenciju nedavnih brisanja.",
+       "deletedtext": "Stranica »$1« je izbrisana.\nVidi pod $2 za zapise nedavnih brisanja.",
        "dellogpage": "Evidencija brisanja",
        "dellogpagetext": "Dolje je popis nedavnih brisanja.\nSva vremena su prema poslužiteljevom vremenu.",
        "deletionlog": "evidencija brisanja",
        "rollbacklinkcount": "ukloni $1 {{PLURAL:$1|uređivanje|uređivanja}}",
        "rollbacklinkcount-morethan": "ukloni više od $1 {{PLURAL:$1|uređivanje|uređivanja}}",
        "rollbackfailed": "Brzo uklanjanje nije uspjelo",
+       "rollback-missingrevision": "Ne mogu učitati podatke o izmjeni.",
        "cantrollback": "Ne mogu ukloniti posljednju promjenu, postoji samo jedna promjena.",
        "alreadyrolled": "Ne mogu ukloniti posljednju promjenu članka [[:$1]] koju je napravio [[User:$2|$2]] ([[User talk:$2|razgovor]]{{int:pipe-separator}}[[Special:Contributions/$2|{{int:contribslink}}]]); netko je već promijenio stranicu ili uklonio promjenu.\n\nPosljednju promjenu napravio je [[User:$3|$3]] ([[User talk:$3|razgovor]]{{int:pipe-separator}}[[Special:Contributions/$3|{{int:contribslink}}]]).",
        "editcomment": "Sažetak promjene je bio: <em>$1</em>.",
        "revertpage": "uklonjena promjena {{GENDER:$2|suradnika|suradnice}} [[Special:Contributions/$2|$2]] ([[User talk:$2|razgovor]]), vraćeno na posljednju inačicu {{GENDER:$1|suradnika|suradnice}} [[User:$1|$1]]",
        "revertpage-nouser": "Vraćene izmjene suradnika (suradničko ime uklonjeno) na posljednju inačicu suradnika [[User:$1|$1]]",
-       "rollback-success": "uklonjeno uređivanje {{GENDER:$1|suradnika|suradnice}} $1\nvraćeno na posljednju inačicu {{GENDER:$2|suradnika|suradnice}} $2.",
+       "rollback-success": "Uklonjeno uređivanje {{GENDER:$3|suradnika|suradnice}} $1; vraćeno na posljednju inačicu {{GENDER:$4|suradnika|suradnice}} $2.",
+       "rollback-success-notify": "Uklonili ste izmjene suradnika $1;\nvraćeno na posljednju izmjenu suradnika $2. [$3 Prikaži izmjene]",
        "sessionfailure-title": "Prekid sesije",
        "sessionfailure": "Izgleda da postoji problem s uspostavom sjednice kod Vašega prijavljivanja; ta radnja otkazana je kao način sprječavanja krađe sjednice. Molimo Vas da se u pregledniku vratite natrag na prethodnu stranicu, ponovo ju učitate i zatim pokušate opet.",
        "changecontentmodel": "Promjena modela sadržaja stranice",
        "changecontentmodel-reason-label": "Razlog:",
        "changecontentmodel-submit": "Promijeni",
        "changecontentmodel-success-title": "Sadržaj modela je promijenjen",
+       "changecontentmodel-success-text": "Model sadržaja stranice [[:$1]] je promijenjen.",
+       "changecontentmodel-cannot-convert": "Model sadržaja stranice [[:$1]] se ne može pretvoriti u vrstu $2.",
+       "changecontentmodel-nodirectediting": "Model sadržaja $1 ne podržava izravno uređivanje",
+       "changecontentmodel-emptymodels-title": "Nema dostupnih modela sadržaja",
+       "changecontentmodel-emptymodels-text": "Model sadržaja stranice [[:$1]] ne može se pretvoriti ni u jednu drugu vrstu.",
        "log-name-contentmodel": "Evidencija promjena modela sadržaja",
+       "log-description-contentmodel": "Ova stranica navodi izmjene modela sadržaja stranica, kao i stranice napravljene s modelom sadržaja koji se razlikuje od predodređenoga.",
+       "logentry-contentmodel-new": "$1 {{GENDER:$2|načinio|načinila}} je stranicu $3 s nestandardnim modelom sadržaja »$5«",
+       "logentry-contentmodel-change": "$1 {{GENDER:$2|promijenio|promijenila}} je model sadržaja stranice $3 iz »$4« u »$5«",
        "logentry-contentmodel-change-revertlink": "vrati",
        "logentry-contentmodel-change-revert": "vraćanje modela",
        "protectlogpage": "Evidencija zaštićivanja",
        "prot_1movedto2": "$1 premješteno na $2",
        "protect-badnamespace-title": "Nezaštitljiv imenski prostor",
        "protect-badnamespace-text": "Stranice u ovom imenskom prostoru ne mogu se zaštititi.",
+       "protect-norestrictiontypes-text": "Ova se stranica ne može zaštititi jer nema dostupnih oblika ograničenja.",
        "protect-norestrictiontypes-title": "Stranicu nije moguće zaštititi",
        "protect-legend": "Potvrda zaštite",
        "protectcomment": "Razlog:",
        "undelete-search-title": "Pretraži obrisane stranice",
        "undelete-search-box": "Pretraži obrisane stranice",
        "undelete-search-prefix": "Pretraži stranice koje počinju s:",
+       "undelete-search-full": "Prikaži naslove koji sadržavaju:",
        "undelete-search-submit": "Pretraži",
        "undelete-no-results": "Nije pronađena odgovarajuća stranica u arhivu brisanja.",
        "undelete-filename-mismatch": "Ne mogu vratiti inačicu datoteke s vremenom i datumom $1: imena se ne slažu (''filename mismatch'')",
        "sp-contributions-newbies-sub": "Za nove suradnike",
        "sp-contributions-newbies-title": "Doprinosi novih suradnika",
        "sp-contributions-blocklog": "evidencija blokiranja",
-       "sp-contributions-deleted": "obrisani suradnički doprinosi",
+       "sp-contributions-suppresslog": "pobrisani {{GENDER:$1|suradnikovi|suradničini}} doprinosi",
+       "sp-contributions-deleted": "pobrisani {{GENDER:$1|suradnikovi|suradničini}} doprinosi",
        "sp-contributions-uploads": "postavljene datoteke",
        "sp-contributions-logs": "evidencije",
        "sp-contributions-talk": "razgovor",
        "articleexists": "Stranica pod tim imenom već postoji ili ime koje ste odabrali nije u skladu s pravilima.\nMolimo odaberite drugo ime.",
        "cantmove-titleprotected": "Ne možete premjestiti ovu stranicu na ovo mjesto, jer je novi naslov zaštićen od kreiranja",
        "movetalk": "Premjesti i njezinu stranicu za razgovor ako je moguće.",
-       "move-subpages": "Premjesti podstranice (na $1)",
+       "move-subpages": "Premjesti podstranice (najviše do $1)",
        "move-talk-subpages": "Premjesti podstranice od stranice za razgovor (na $1)",
        "movepage-page-exists": "Stranica $1 već postoji i ne može biti automatski prepisana",
        "movepage-page-moved": "Stranica $1 je premještena na $2.",
        "logentry-block-reblock": "$1 {{GENDER:$2|promijenio|promijenila}} je postavke blokiranja {{GENDER:$4|suradnika|suradnice}} {{GENDER:$4|$3}} s krajnjim rokom koji ističe $5 $6",
        "logentry-suppress-block": "$1 {{GENDER:$2|blokirao|blokirala}} je {{GENDER:$4|$3}} s krajnjim rokom koji ističe $5 $6",
        "logentry-suppress-reblock": "$1 {{GENDER:$2|promijenio|promijenila}} je postavke blokiranja {{GENDER:$4|suradnika|suradnice}} {{GENDER:$4|$3}} s krajnjim rokom koji ističe $5 $6",
+       "logentry-import-interwiki": "$1 {{GENDER:$2|uvezao|uvezla}} je $3 s drugog wikija",
+       "logentry-import-interwiki-details": "$1 {{GENDER:$2|uvezao|uvezla}} je $3 sa $5 ($4 {{PLURAL:$4|izmjena|izmjene|izmjena}})",
        "logentry-merge-merge": "$1 je {{GENDER:$2|spojio|spojila}} $3 s $4 (izmjene do $5)",
        "logentry-move-move": "$1 je {{GENDER:$2|premjestio|premjestila}} stranicu $3 na $4",
        "logentry-move-move-noredirect": "$1 je {{GENDER:$2|premjestio|premjestila}} stranicu $3 na $4 bez preusmjeravanja",
        "duration-centuries": "$1 {{PLURAL:$1|stoljeće|stoljeća}}",
        "duration-millennia": "$1 {{PLURAL:$1|milenij|milenija}}",
        "rotate-comment": "Sliku je $1 zaokrenuo za {{PLURAL:$1|stupanj|stupnja|stupnjeva}} u smjeru kazaljke na satu.",
+       "limitreport-title": "Podatci profiliranja raščlanjivača:",
        "limitreport-cputime-value": "$1 {{PLURAL:$1|sekunda|sekunde|sekundi}}",
        "limitreport-walltime": "Uporaba u realnom vremenu",
        "limitreport-walltime-value": "$1 {{PLURAL:$1|sekunda|sekunde|sekundi}}",
        "pagelang-submit": "Pošalji",
        "right-pagelang": "Promijeni jezik stranice",
        "log-name-pagelang": "Evidencija mijenjanja jezika",
+       "logentry-pagelang-pagelang": "$1 {{GENDER:$2|promijenio|promijenila}} je jezik stranice $3 iz $4 u $5.",
        "mediastatistics": "Statistika datoteka",
        "mediastatistics-summary": "Slijede statistike postavljenih datoteka koje pokazuju zadnju inačicu datoteke. Starije ili izbrisane inačice nisu prikazane.",
        "mediastatistics-nbytes": "{{PLURAL:$1|$1 bajt|$1 bajta|$1 bajtova}} ($2; $3 %)",
        "authmanager-realname-help": "Pravo ime suradnika",
        "authmanager-provider-password": "Autorizacija zaporkom",
        "authmanager-provider-temporarypassword": "Privremena zaporka",
+       "cannotauth-not-allowed-title": "Pristup odbijen",
+       "cannotauth-not-allowed": "Nije Vam dopušteno rabiti ovu stranicu",
        "changecredentials": "Promjena vjerodajnica",
        "changecredentials-submit": "Promijeni vjerodajnice",
+       "changecredentials-invalidsubpage": "$1 nije valjana vrsta vjerodajnice.",
+       "changecredentials-success": "Vaše su vjerodajnice promijenjene.",
        "removecredentials": "Uklanjanje vjerodajnica",
        "removecredentials-submit": "Ukloni vjerodajnice",
        "credentialsform-provider": "Vrsta vjerodajnica:",
        "credentialsform-account": "Suradnički račun:",
+       "gotointerwiki": "Napuštate projekt {{SITENAME}}",
+       "gotointerwiki-invalid": "Navedeni naslov nije valjan.",
+       "gotointerwiki-external": "Napuštate projekt {{SITENAME}} da biste posjetili zasebno mrežno mjesto [[$2]].\n\n<strong>[$1 Nastavljate na $1]</strong>",
        "pagedata-title": "Podatci o stranici",
        "pagedata-bad-title": "Naslov nije valjan: $1."
 }
index b3855cf..9b8fab5 100644 (file)
        "rcfilters-liveupdates-button-title-off": "A legfrissebb változtatások mutatása, amint megtörténnek",
        "rcfilters-watchlist-markseen-button": "Összes változtatás megjelölése olvasottként",
        "rcfilters-watchlist-edit-watchlist-button": "A figyelőlistád szerkesztése",
-       "rcfilters-watchlist-showupdated": "Az újabb változtatások amiket még nem néztél meg, <strong>vastaggal jelöltük</strong>",
+       "rcfilters-watchlist-showupdated": "Az újabb változtatások, amiket még nem néztél meg, <strong>vastagítva</strong> láthatók, kitöltött jelzőkkel.",
        "rcfilters-preference-label": "A friss változtatások fejlesztett változatának elrejtése",
        "rcfilters-preference-help": "A 2017-es felületátdolgozás és minden azóta hozzáadott eszköz visszaállítása.",
        "rcfilters-filter-showlinkedfrom-label": "A következő lapra hivatkozó lapok változtatásainak megjelenítése",
+       "rcfilters-filter-showlinkedfrom-option-label": "A kiválasztott <strong>lapról</strong> hivatkozott lapok",
        "rcfilters-filter-showlinkedto-label": "A következő lapról hivatkozott lapok változtatásainak megjelenítése",
+       "rcfilters-filter-showlinkedto-option-label": "A kiválasztott <strong>lapra</strong> hivatkozó lapok",
        "rcfilters-target-page-placeholder": "Adj meg egy oldal nevét",
        "rcnotefrom": "Alább a <strong>$3 $4</strong> óta történt változtatások láthatóak (legfeljebb <b>$1</b> db).",
        "rclistfromreset": "Dátumválasztás visszaállítása",
        "recentchangeslinked-feed": "Kapcsolódó változtatások",
        "recentchangeslinked-toolbox": "Kapcsolódó változtatások",
        "recentchangeslinked-title": "A(z) $1 laphoz kapcsolódó változtatások",
-       "recentchangeslinked-summary": "Alább azon lapoknak a legutóbbi változtatásai láthatóak, amelyekre hivatkozik egy megadott lap (vagy tagjai a megadott kategóriának).\nA [[Special:Watchlist|figyelőlistádon]] szereplő lapok '''félkövérrel''' vannak jelölve.",
+       "recentchangeslinked-summary": "Alább azon lapoknak a legutóbbi változtatásai láthatóak, amelyekre hivatkozik egy megadott lap. (Ha egy kategória tagjaira vagy kíváncsi, írd be, hogy Kategória:katerógianév.)\nA [[Special:Watchlist|figyelőlistádon]] szereplő lapok '''félkövérrel''' vannak jelölve.",
        "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",
        "uploadstash-bad-path-unrecognized-thumb-name": "Ismeretlen bélyegképnév.",
        "uploadstash-bad-path-no-handler": "Nem található kezelő a(z) $1 MIME-típusú $2 fájlhoz.",
        "uploadstash-bad-path-bad-format": "A(z) „$1” kulcs nem megfelelő formátumú.",
+       "uploadstash-file-not-found": "A(z) „$1” kulcs nem található a tárolóban.",
        "uploadstash-file-not-found-no-thumb": "A bélyegkép lekérése sikertelen.",
        "uploadstash-file-not-found-no-local-path": "Nincs helyi útvonal az átméretezett elemhez.",
        "uploadstash-file-not-found-no-object": "A bélyegkép helyi fájlobjektumának létrehozása sikertelen.",
        "listfiles_thumb": "Bélyegkép",
        "listfiles_date": "Dátum",
        "listfiles_name": "Név",
-       "listfiles_user": "feltöltő",
+       "listfiles_user": "Feltöltő",
        "listfiles_size": "Méret",
        "listfiles_description": "Leírás",
        "listfiles_count": "Változatok",
        "emailuser-title-target": "E-mail küldése ennek a felhasználónak: $1",
        "emailuser-title-notarget": "E-mail küldése a felhasználónak",
        "emailpagetext": "Ezzel az űrlappal tudsz ennek a {{GENDER:$1|felhasználónak}} e-mailt küldeni.\nFeladóként a [[Special:Preferences|beállításaidnál]] megadott e-mail címed fog szerepelni, így a címzett közvetlenül tud majd válaszolni neked.",
-       "defemailsubject": "{{SITENAME}} e-mail a következő felhasználótól: „$1”",
+       "defemailsubject": "{{SITENAME}}-e-mail a következő felhasználótól: „$1”",
        "usermaildisabled": "Email fogadás letiltva",
        "usermaildisabledtext": "Nem küldhetsz emailt más felhasználóknak ezen a wikin",
        "noemailtitle": "Nincs e-mail-cím",
        "delete-warning-toobig": "Ennek a lapnak a laptörténete több mint {{PLURAL:$1|egy|$1}} változatot őriz. Törlése fennakadásokat okozhat a wiki adatbázis-műveleteiben; óvatosan járj el.",
        "deleteprotected": "Nem tudod törölni a lapot, mivel le van védve.",
        "deleting-backlinks-warning": "<strong>Figyelem:</strong> [[Special:WhatLinksHere/{{FULLPAGENAME}}|Más lapok]] hivatkoznak a törlendő oldalra (vagy beillesztik azt).",
-       "deleting-subpages-warning": "<strong>Figyelem:</strong> A törlésre jelölt lapnak[[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|van allapja|$1 vannak allapjai|51=több mint 50 allapja van}}]].",
+       "deleting-subpages-warning": "<strong>Figyelem:</strong> A törlésre jelölt lapnak [[Special:PrefixIndex/{{FULLPAGENAME}}/|{{PLURAL:$1|van egy allapja|$1 allapja van|51=több mint 50 allapja van}}]].",
        "rollback": "Szerkesztések visszaállítása",
        "rollbacklink": "visszaállítás",
        "rollbacklinkcount": "$1 szerkesztés visszaállítása",
        "ip_range_invalid": "Érvénytelen IP-tartomány.",
        "ip_range_toolarge": "Nem engedélyezettek azok a tartományblokkok, melyek nagyobbak mint /$1.",
        "ip_range_exceeded": "Az IP-cím-tartomány nagyobb a megengedettnél. Engedélyezett tartomány: /$1.",
+       "ip_range_toolow": "IP tartományok ténylegesen nem használhatók.",
        "proxyblocker": "Proxyblokkoló",
        "proxyblockreason": "Az IP-címeden ''nyílt proxy'' üzemel. Amennyiben nem használsz proxyt, vedd fel a kapcsolatot egy informatikussal vagy az internetszolgáltatóddal ezen súlyos biztonsági probléma ügyében.",
        "sorbsreason": "Az IP-címed nyitott proxyként szerepel e webhely által használt DNSBL listán.",
        "tooltip-ca-nstab-media": "A fájlleíró lap megtekintése",
        "tooltip-ca-nstab-special": "Ez egy speciális lap, nem szerkesztheted.",
        "tooltip-ca-nstab-project": "A projektlap megtekintése",
-       "tooltip-ca-nstab-image": "A képleíró lap megtekintése",
+       "tooltip-ca-nstab-image": "A fájlleíró lap megtekintése",
        "tooltip-ca-nstab-mediawiki": "A rendszerüzenet megtekintése",
        "tooltip-ca-nstab-template": "A sablon megtekintése",
        "tooltip-ca-nstab-help": "A súgólap megtekintése",
        "file-no-thumb-animation": "'''Megjegyzés: technikai korlátok miatt a fájl bélyegképe nem lesz animált.'''",
        "file-no-thumb-animation-gif": "'''Megjegyzés: technikai korlátok miatt a nagy felbontású GIF képekből készített bélyegkép nem lesz animált.'''",
        "newimages": "Új fájlok galériája",
-       "imagelisttext": "Lentebb '''{{PLURAL:$1|egy|$1}}''' kép látható, $2 rendezve.",
+       "imagelisttext": "Lentebb <strong>$1</strong> fájl látható $2 rendezve.",
        "newimages-summary": "Ezen a speciális lapon láthatóak a legutóbb feltöltött fájlok.",
        "newimages-legend": "Fájlnév",
        "newimages-label": "Fájlnév (vagy annak részlete):",
        "tag-mw-replace-description": "Szerkesztések, amelyet egy oldal tartalmának több mint 90%-át törölték",
        "tag-mw-rollback": "Visszaállítás",
        "tag-mw-rollback-description": "Szerkesztések, amelyek visszaállítottak szerkesztéseket a „visszavonás” gombra kattintva",
+       "tag-mw-undo": "Visszavonás",
+       "tag-mw-undo-description": "Szerkesztések, amelyek visszaállítottak szerkesztéseket a „visszavonás” linkre kattintva",
        "tags-title": "Címkék",
        "tags-intro": "Ez a lap azokat a címkéket és jelentéseiket tartalmazza, amikkel a szoftver megjelölhet egy szerkesztést.",
        "tags-tag": "Címke neve",
        "log-action-filter-patrol": "Járőrözés típusa:",
        "log-action-filter-protect": "Lapvédelem típusa:",
        "log-action-filter-rights": "Jogosultságváltozás típusa:",
+       "log-action-filter-suppress": "Elrejtés típusa:",
        "log-action-filter-upload": "Feltöltés típusa:",
        "log-action-filter-all": "Mind",
        "log-action-filter-block-block": "Blokk",
        "log-action-filter-protect-move_prot": "Védelem áthelyezése",
        "log-action-filter-rights-rights": "Kézi módosítás",
        "log-action-filter-rights-autopromote": "Automatikus módosítás",
+       "log-action-filter-suppress-event": "Napló elrejtés",
+       "log-action-filter-suppress-revision": "Lapváltozat elrejtés",
+       "log-action-filter-suppress-delete": "Lap elrejtés",
+       "log-action-filter-suppress-block": "Felhasználó elrejtése blokkolással",
+       "log-action-filter-suppress-reblock": "Felhasználó elrejtést újra blokkolással",
        "log-action-filter-upload-upload": "Új feltöltés",
        "log-action-filter-upload-overwrite": "Újrafeltöltés",
        "authmanager-authn-not-in-progress": "Hitelesítés nincs folyamatban, vagy a folyamat adatai elvesztek. Kérjük, indítsd újra az elejétől.",
index 84d0a70..f71620b 100644 (file)
        "tag-mw-replace-description": "Modificationes que elimina plus de 90% del contento de un pagina",
        "tag-mw-rollback": "Revocation",
        "tag-mw-rollback-description": "Modificationes que disface previe modificationes usante le ligamine \"revocar\"",
+       "tag-mw-undo": "Disfacer",
+       "tag-mw-undo-description": "Modificationes que disface previe modificationes usante le ligamine \"disfacer\"",
        "tags-title": "Etiquettas",
        "tags-intro": "Iste pagina lista le etiquettas con le quales le software pote marcar un modification, e lor significato.",
        "tags-tag": "Nomine del etiquetta",
index cc616d4..f7ec581 100644 (file)
        "htmlform-user-not-exists": "<strong>$1</strong> er ekki til.",
        "htmlform-user-not-valid": "<strong>$1</strong> er ekki gilt notandanafn.",
        "logentry-delete-delete": "$1 {{GENDER:$2|eyddi}} síðunni $3",
+       "logentry-delete-delete_redir": "$1 {{GENDER:$2|eyddi}} tilvísun $3 með því að yfirskrifa",
        "logentry-delete-restore": "$1 {{GENDER:$2|endurvakti}} síðu $3 ($4)",
        "logentry-delete-event": "$1 {{GENDER:$2|breytti}} sýnileika {{PLURAL:$5|færslu|$5 færslna}} á $3: $4",
        "logentry-delete-revision": "$1 {{GENDER:$2|breytti}} sýnileika {{PLURAL:$5|útgáfu|$5 útgáfna}} á $3: $4",
index f6fd689..90f4e60 100644 (file)
        "tag-mw-replace-description": "Modifiche che rimuovono oltre il 90% del contenuto di una pagina",
        "tag-mw-rollback": "Rollback",
        "tag-mw-rollback-description": "Modifiche che ripristinano le versioni precedenti utilizzando il collegamento di rollback",
+       "tag-mw-undo": "Annulla",
+       "tag-mw-undo-description": "Modifiche che annullano le modifiche precedenti utilizzando il collegamento \"Annulla\"",
        "tags-title": "Etichette",
        "tags-intro": "Questa pagina elenca le etichette che il software potrebbe associare a una modifica e il loro significato.",
        "tags-tag": "Nome dell'etichetta",
index 72963d6..189b327 100644 (file)
        "userrights-viewusergroup": "{{GENDER:$1|利用者}}グループ",
        "saveusergroups": "{{GENDER:$1|利用者}}グループを保存",
        "userrights-groupsmember": "所属グループ:",
-       "userrights-groupsmember-auto": "秘匿した所属グループ",
+       "userrights-groupsmember-auto": "自動的に所属するグループ:",
        "userrights-groupsmember-type": "$1",
        "userrights-groups-help": "この利用者が属するグループを変更できます。\n* チェックが入っているボックスは、この利用者がそのグループに属していることを意味します。\n* チェックが入っていないボックスは、この利用者がそのグループに属していないことを意味します。\n*「*」はグループに一旦追加した場合に除去 (あるいはその逆) ができないことを示しています。\n*「#」は有効期限の延長のみを行うことができるグループの参加資格を示します; 現在の期限よりも短縮することはできません。",
        "userrights-reason": "理由:",
        "recentchanges-submit": "表示",
        "rcfilters-tag-remove": "「$1」を除去",
        "rcfilters-legend-heading": "<strong>略語のリスト:</strong>",
+       "rcfilters-other-review-tools": "その他の監視ツール",
        "rcfilters-group-results-by-page": "ページごとにまとめて表示",
        "rcfilters-activefilters": "絞り込み",
        "rcfilters-advancedfilters": "詳細フィルター",
        "rcfilters-limit-title": "表示件数の変更",
+       "rcfilters-limit-and-date-label": "$1件の変更、$2",
        "rcfilters-date-popup-title": "検索期間",
        "rcfilters-days-title": "日数",
        "rcfilters-hours-title": "時間",
        "rcfilters-preference-label": "最近の更新の改善版を隠す",
        "rcfilters-preference-help": "2017年のインターフェース更新、当時追加したや以来の新しいツールの使用を断る。",
        "rcfilters-filter-showlinkedfrom-label": "リンク先ページの変更を表示する",
+       "rcfilters-target-page-placeholder": "ページ名を入力",
        "rcnotefrom": "以下は<strong>$3 $4</strong>以降の{{PLURAL:$5|更新です}} (最大 <strong>$1</strong> 件)。",
        "rclistfromreset": "日時指定をリセット",
        "rclistfrom": "$3の$2以降の更新を表示する",
        "tag-mw-contentmodelchange-description": "ページの[https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel コンテンツモデルを変更]する",
        "tag-mw-new-redirect": "新規リダイレクト",
        "tag-mw-new-redirect-description": "新たな転送ページの作成または既存ページの転送化の編集",
+       "tag-mw-removed-redirect": "転送廃止",
        "tag-mw-changed-redirect-target": "転送先変更",
        "tag-mw-changed-redirect-target-description": "転送先を変更する編集",
        "tag-mw-blank": "白紙化",
index 7c4b4f4..d83a5ea 100644 (file)
        "logentry-newusers-byemail": "$1 $3 деген аккаунт {{GENDER:$2|тіркеді}} және құпия сөзі е-пошта арқылы жіберілді",
        "logentry-newusers-autocreate": "$1 қатысушы аккаунтын автоматты түрде {{GENDER:$2|тіркеді}}",
        "logentry-protect-move_prot": "$1 protection settings from $4 дегеннен $3 дегенге қорғалу баптауларын {{GENDER:$2|жылжытты}}",
-       "logentry-protect-unprotect": "$1 $3 бетінің қорғанысын {{GENDER:$2|алыпсады}}",
+       "logentry-protect-unprotect": "$1 $3 бетінің қорғанысын {{GENDER:$2|алып тастады}}",
        "logentry-protect-protect": "$1 $3 бетін {{GENDER:$2|қорғады}}  $4",
        "logentry-protect-modify-cascade": "$1 $3 бетінің қорғалу деңгейін $4 мерзіміне {{GENDER:$2|өзгертті}} [баулы]",
        "logentry-rights-rights": "$1 $3 үшін топ мүшелігін $4 дегеннен $5 дегенге {{GENDER:$2|өзгертті}}",
index 99dfa4e..1ceca05 100644 (file)
        "autosumm-replace": "내용을 \"$1\"(으)로 바꿈",
        "autoredircomment": "[[$1]] 문서로 넘겨주기",
        "autosumm-removed-redirect": "[[$1]]에 대한 넘겨주기를 제거함",
-       "autosumm-changed-redirect-target": "넘겨주기 대상을 [[$1]]에서 [[$2]](으)로 변경했습니다",
+       "autosumm-changed-redirect-target": "넘겨주기 대상을 [[$1]]에서 [[$2]] 문서로 변경했습니다",
        "autosumm-new": "새 문서: $1",
        "autosumm-newblank": "빈 문서를 만듦",
        "size-bytes": "$1 {{PLURAL:$1|바이트}}",
        "tag-mw-replace-description": "문서 내용 중 90% 보다 많은 내용을 제거한 편집",
        "tag-mw-rollback": "되돌리기",
        "tag-mw-rollback-description": "되돌리기 링크를 사용하여 이전 편집을 되돌리는 편집",
+       "tag-mw-undo": "편집 취소",
+       "tag-mw-undo-description": "편집 취소 링크를 사용하여 이전 편집을 취소하는 편집",
        "tags-title": "태그",
        "tags-intro": "이 문서는 소프트웨어에서 편집에 대해 표시하는 태그와 그 의미를 설명하는 목록입니다.",
        "tags-tag": "태그 이름",
index 159d808..25c4d93 100644 (file)
        "versionrequired": "Se nesesite la versyon $1 de MediaWiki",
        "versionrequiredtext": "Se nesesita versyon $1 de MediaWiki para uzar este pajina. Ver [[Special:Version|La pajina de versyon]].",
        "ok": "DE ACORDDO",
-       "retrievedfrom": "Acojido del adresso \"$1\"",
+       "retrievedfrom": "Acojido del aderesso \"$1\"",
        "youhavenewmessages": "{{PLURAL:$3|Tienes}} $1 ($2).",
        "youhavenewmessagesfromusers": "{{PLURAL:$4|Tiene}} $1 de {{PLURAL:$3|otro usuario|$3 usuarios}}($2).",
        "youhavenewmessagesmanyusers": "Tiene $1 de munchos usuarios ($2).",
index 2e93cba..291ded5 100644 (file)
        "tog-showtoolbar": "Ännerungstoolbar weisen",
        "tog-editondblclick": "Säite mat Duebelklick änneren",
        "tog-editsectiononrightclick": "Eenzel Abschnitter mat Rietsklick änneren",
-       "tog-watchcreations": "Säiten déi ech uleeën a Fichieren déi ech eroplueden op meng Iwwerwaachungslëscht derbäisetzen",
-       "tog-watchdefault": "Säiten a Fichieren déi ech änneren op meng Iwwerwaachungslëscht derbäisetzen",
-       "tog-watchmoves": "Säiten a Fichieren déi ech réckelen automatesch op meng Iwwerwaachungslëscht derbäisetzen",
-       "tog-watchdeletion": "Säiten a Fichieren déi ech läschen op meng Iwwerwaachungslëscht derbäisetzen",
+       "tog-watchcreations": "Säiten déi ech uleeën a Fichieren déi ech eroplueden op meng Iwwerwaachungslëscht dobäisetzen",
+       "tog-watchdefault": "Säiten a Fichieren déi ech änneren op meng Iwwerwaachungslëscht dobäisetzen",
+       "tog-watchmoves": "Säiten a Fichieren déi ech réckelen automatesch op meng Iwwerwaachungslëscht dobäisetzen",
+       "tog-watchdeletion": "Säiten a Fichieren déi ech läschen op meng Iwwerwaachungslëscht dobäisetzen",
        "tog-watchuploads": "Nei Fichieren déi ech eroplueden op meng Iwwerwaachungslëscht setzen",
-       "tog-watchrollback": "Säiten déi ech zréckgesat hunn op meng Iwwerwaachungslëscht derbäisetzen",
+       "tog-watchrollback": "Säiten déi ech zréckgesat hunn op meng Iwwerwaachungslëscht dobäisetzen",
        "tog-minordefault": "All Ännerungen automatesch als 'Kleng Ännerungen' markéieren.",
        "tog-previewontop": "Déi ''nach-net gespäichert Versioun'' iwwer der Ännerungsfënster weisen",
        "tog-previewonfirst": "Beim éischten Änneren déi  ''nach net gespäichert Versioun'' weisen.",
        "edit": "Änneren",
        "edit-local": "Lokal Beschreiwung änneren",
        "create": "Uleeën",
-       "create-local": "Lokal Beschreiwung derbäisetzen",
+       "create-local": "Lokal Beschreiwung dobäisetzen",
        "delete": "Läschen",
        "undelete_short": "$1 {{PLURAL:$1|Versioun|Versioune}} restauréieren",
        "viewdeleted_short": "{{PLURAL:$1|Eng geläschte Versioun|$1 geläscht Versioune}} weisen",
        "botpasswords-help-grants": "Berechtegunge ginn Zougang op déi Benotzerrechter déi Äre Benotzerkont schonn huet. D'Aktivéiere vun enger Berechtegung hei gëtt Iech keen Zougang op Rechter déi Äre Benotzerkont net scho souwisou huet. Kuckt d'[[Special:ListGrants|Tabell vun de Berechtigunge]] fir méi Informatiounen.",
        "botpasswords-label-grants-column": "Accordéiert",
        "botpasswords-bad-appid": "Den Numm vum Bot \"$1\" ass net valabel.",
-       "botpasswords-insert-failed": "De Botnumm \"$1\" konnt net dobäigesat ginn. Gouf e schonn derbäigesat?",
+       "botpasswords-insert-failed": "De Botnumm \"$1\" konnt net dobäigesat ginn. Gouf e schonn dobäigesat?",
        "botpasswords-update-failed": "Den Numm vum Bot \"$1\" konnt net aktualiséiert ginn. Gouf e geläscht?",
        "botpasswords-created-title": "Botpasswuert ugeluecht",
        "botpasswords-created-body": "D'Botpasswuert fir de Bot-Numm \"$1\" vum {{GENDER:$2|Benotzer}} ''$2'' gouf ugeluecht.",
        "email": "E-Mail",
        "prefs-help-realname": "De richtegen Numm ass fakultativ.\nWann en ugi gouf, gëtt e benotzt fir Iech Är Kontributiounen zouzeuerdnen.",
        "prefs-help-email": "D'E-Mailadress ass fakultativ, awer si gëtt gebraucht fir Iech Äert Passwuert ze mailen, wann Dir et géift vergiessen.",
-       "prefs-help-email-others": "Dir kënnt Iech och dofir decidéieren datt Anerer Iech iwwer Är Diskussiounssäit kontaktéieren ouni datt Dir derbäi Är Identitéit verrode musst.",
+       "prefs-help-email-others": "Dir kënnt Iech och dofir decidéieren datt Anerer Iech iwwer Är Diskussiounssäit kontaktéieren ouni datt Dir dobäi Är Identitéit verrode musst.",
        "prefs-help-email-required": "Eng gëlteg E-Mail-Adress gëtt heifir gebraucht.",
        "prefs-info": "Grondinformatioun",
        "prefs-i18n": "Internationalisatioun",
        "right-editmyusercss": "Är eegen CSS-Fichieren änneren",
        "right-editmyuserjs": "Är eege JavaScript-Fichieren änneren",
        "right-viewmywatchlist": "Kuckt Är eegen Iwwerwaachungslëscht",
-       "right-editmywatchlist": "Ännert Är eegen Iwwerwaachungslëscht. Denkt drun datt och aner Aktioune Säiten op d'Iwwerwaachungslëscht derbäisetzen.",
+       "right-editmywatchlist": "Ännert Är eegen Iwwerwaachungslëscht. Denkt drun datt och aner Aktioune Säiten op d'Iwwerwaachungslëscht dobäisetzen.",
        "right-viewmyprivateinfo": "Är eege privat Donnéeën (z.Bsp. E-Mail-Adress, richtegen Numm) kucken",
        "right-editmyprivateinfo": "Är eege privat Donnéeën (z.Bsp. E-Mail-Adress, richtegen Numm) änneren",
        "right-editmyoptions": "Ännert Är eegen Astellungen",
        "recentchangeslinked-summary": "Gitt den Numm vun enger Säit a fir Ännerungen Säiten ze gesinn op déi oder vun deene gelinkt gëtt. Ännerungen op Säite vun [[Special:Watchlist|Ärer Iwwerwaachungslëscht]] si <strong>fett</strong> geschriwwen.",
        "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": "[[:$1]] an d'Kategorie dobäigesat",
        "recentchanges-page-added-to-category-bundled": "[[:$1]] an d'Kategorie dobäigesat, [[Special:WhatLinksHere/$1|dës Säit ass an aner Säiten agebonn]]",
        "recentchanges-page-removed-from-category": "[[:$1]] erausgeholl aus der Kategorie",
        "recentchanges-page-removed-from-category-bundled": "[[:$1]] aus der Kategorie erausgeholl, [[Special:WhatLinksHere/$1|dës Säit ass an aner Säiten agebonn]]",
        "upload-dialog-button-upload": "Eroplueden",
        "upload-form-label-infoform-title": "Detailer",
        "upload-form-label-infoform-name": "Numm",
-       "upload-form-label-infoform-name-tooltip": "E kuerzen an uniquen Titel fir de Fichier, deen och als Numm vum Fichier benotzt gëtt. Dir kënnt derbäi Text mat Espace benotzen. D'Erweiderung vum Fichier soll net ugi ginn.",
+       "upload-form-label-infoform-name-tooltip": "E kuerzen an uniquen Titel fir de Fichier, deen och als Numm vum Fichier benotzt gëtt. Dir kënnt dobäi Text mat Espace benotzen. D'Erweiderung vum Fichier soll net ugi ginn.",
        "upload-form-label-infoform-description": "Beschreiwung",
        "upload-form-label-infoform-description-tooltip": "Beschreift w.e.g. kuerz dat Wichtegst vun dësem Wierk.\nFir eng Photo, ernimmt déi Haaptsaachen déi drop sinn, d'Geleeënheet oder d'Plaz.",
        "upload-form-label-usage-title": "Benotzung",
        "apisandbox-helpurls": "Hëllef-Linken",
        "apisandbox-examples": "Beispiller",
        "apisandbox-dynamic-parameters": "Zousätzlech Parameteren",
-       "apisandbox-dynamic-parameters-add-label": "Parameter derbäisetzen:",
+       "apisandbox-dynamic-parameters-add-label": "Parameter dobäisetzen:",
        "apisandbox-dynamic-parameters-add-placeholder": "Numm vum Parameter",
        "apisandbox-dynamic-error-exists": "Et gëtt schonn e Parameter mam Numm \"$1\".",
        "apisandbox-deprecated-parameters": "Vereelst Parameter",
        "listgrouprights-rights": "Rechter",
        "listgrouprights-helppage": "Help:Grupperechter",
        "listgrouprights-members": "(Lëscht vun de Memberen)",
-       "listgrouprights-addgroup": "Dës {{PLURAL:$2|Grupp|Gruppen}} derbäisetzen: $1",
+       "listgrouprights-addgroup": "Dës {{PLURAL:$2|Grupp|Gruppen}} dobäisetzen: $1",
        "listgrouprights-removegroup": "Kann {{PLURAL:$2|dëse Gruppe|dës Gruppen}} ewechhuelen: $1",
-       "listgrouprights-addgroup-all": "Kann all Gruppen derbäisetzen",
+       "listgrouprights-addgroup-all": "Kann all Gruppen dobäisetzen",
        "listgrouprights-removegroup-all": "Ka Benotzer aus alle Gruppen eraushuelen",
-       "listgrouprights-addgroup-self": "Däerf {{PLURAL:$2|de Grupp|d'Gruppe}} bei säin eegene Benotzerkont derbäisetzen: $1",
+       "listgrouprights-addgroup-self": "Däerf {{PLURAL:$2|de Grupp|d'Gruppe}} bei säin eegene Benotzerkont dobäisetzen: $1",
        "listgrouprights-removegroup-self": "Däerf {{PLURAL:$2|de Grupp|d'Gruppe}} vu sengem eegene Benotzerkont ewechhuelen: $1",
-       "listgrouprights-addgroup-self-all": "däerf all Gruppe bei säin eegene Benotzerkont derbäisetzen",
+       "listgrouprights-addgroup-self-all": "däerf all Gruppe bei säin eegene Benotzerkont dobäisetzen",
        "listgrouprights-removegroup-self-all": "Däerf all Gruppe vu sengem eegene Benotzerkont ewechhuelen",
        "listgrouprights-namespaceprotection-header": "Limitatioune vum Nummraum",
        "listgrouprights-namespaceprotection-namespace": "Nummraum",
        "nowatchlist": "Är Iwwerwaachungslëscht ass eidel.",
        "watchlistanontext": "Loggt Iech a fir Elementer op Ärer Iwwerwaachungslëscht ze gesinn oder z'änneren.",
        "watchnologin": "Net ageloggt",
-       "addwatch": "Op d'Iwwerwaachungslëscht derbäisetzen",
+       "addwatch": "Op d'Iwwerwaachungslëscht dobäisetzen",
        "addedwatchtext": "\"[[:$1]]\" a seng Diskussiounssäit goufen op Är [[Special:Watchlist|Iwwerwaachungslëscht]] gesat.",
-       "addedwatchtext-short": "D'Säit \"$1\" gouf op Är Iwwerwaachungslëscht derbäigesat.",
+       "addedwatchtext-short": "D'Säit \"$1\" gouf op Är Iwwerwaachungslëscht dobäigesat.",
        "removewatch": "Vun der Iwwerwaachungslëscht erofhuelen",
        "removedwatchtext": "\"[[:$1]]\" a seng Diskussiounssäit goufe vun Ärer [[Special:Watchlist|Iwwerwaachungslëscht]] erofgeholl.",
        "removedwatchtext-talk": "\"[[:$1]]\" a seng associéiert Säit goufe vun Ärer [[Special:Watchlist|Iwwerwaachungslëscht]] erofgeholl.",
        "exportnohistory": "----\n'''Hiwäis:''' Den Export vu komplette Versiounshistoriquen ass aus Performancegrënn bis op weideres net méiglech.",
        "exportlistauthors": "Fir all Säit eng komplett Lëscht vun deenen déi un der Säit matgeschafft hunn drasetzen",
        "export-submit": "Exportéieren",
-       "export-addcattext": "Säiten aus Kategorie derbäisetzen:",
-       "export-addcat": "Derbäisetzen",
-       "export-addnstext": "Säiten aus Nummraum derbäisetzen:",
-       "export-addns": "Derbäisetzen",
+       "export-addcattext": "Säiten aus Kategorie dobäisetzen:",
+       "export-addcat": "Dobäisetzen",
+       "export-addnstext": "Säiten aus Nummraum dobäisetzen:",
+       "export-addns": "Dobäisetzen",
        "export-download": "Als XML-Datei späicheren",
        "export-templates": "Inklusiv Schablounen",
        "export-pagelinks": "Verlinkte Säiten mat exportéieren, bis zu enger Déift vun:",
-       "export-manual": "Säite manuell derbäisetzen:",
+       "export-manual": "Säite manuell dobäisetzen:",
        "allmessages": "All Systemmessagen",
        "allmessagesname": "Numm",
        "allmessagesdefault": "Standardtext",
        "svg-long-desc-animated": "Animéierten SVG-Fichier, Basisgréisst $1 x $2 Pixel, Gréisst vum Fichier: $3",
        "svg-long-error": "Ongëltegen SVG-Fichier: $1",
        "show-big-image": "Original Fichier",
-       "show-big-image-preview": "Gréisst vun dësem Preview: $1.",
-       "show-big-image-preview-differ": "Gréisst vun dësem $3-Preview vun dësem $2-Fichier: $1.",
+       "show-big-image-preview": "Gréisst vun dëser Duerstellung: $1.",
+       "show-big-image-preview-differ": "Gréisst vun dëser $3-Duerstellung vun dësem $2-Fichier: $1.",
        "show-big-image-other": "Aner {{PLURAL:$2|Opléisung|Opléisungen}}: $1.",
        "show-big-image-size": "$1 × $2 Pixel",
        "file-info-gif-looped": "endlos Schleef",
        "watchlistedit-normal-done": "{{PLURAL:$1|1 Säit gouf|$1 Säite goufe}} vun ärer Iwwerwaachungslëscht erofgeholl:",
        "watchlistedit-raw-title": "Iwwerwaachungslëscht onformatéiert änneren",
        "watchlistedit-raw-legend": "Iwwerwaachungslëscht onformatéiert änneren",
-       "watchlistedit-raw-explain": "D'Säite vun Ärer Iwwerwaachungslëscht ginn hei drënner gewisen a kënne geännert ginn andeems der d'Säiten op d'Lëscht derbäisetze oder erofhuelt; eng Säit pro Linn.\nWann Dir fäerdeg sidd, klickt \"{{int:Watchlistedit-raw-submit}}\".\nDir kënnt och [[Special:EditWatchlist|de Standard Editeur benotzen]].",
+       "watchlistedit-raw-explain": "D'Säite vun Ärer Iwwerwaachungslëscht ginn hei drënner gewisen a kënne geännert ginn andeems Dir d'Säiten op d'Lëscht dobäisetzt oder erofhuelt; eng Säit pro Linn.\nWann Dir fäerdeg sidd, klickt \"{{int:Watchlistedit-raw-submit}}\".\nDir kënnt och [[Special:EditWatchlist|de Standard Editeur benotzen]].",
        "watchlistedit-raw-titles": "Säiten:",
        "watchlistedit-raw-submit": "Iwwerwaachungslëscht aktualiséieren",
        "watchlistedit-raw-done": "Är Iwwerwaachungslëscht gouf aktualiséiert.",
-       "watchlistedit-raw-added": "{{PLURAL:$1|1 Säit gouf|$1 Säite goufen}} derbäigesat:",
+       "watchlistedit-raw-added": "{{PLURAL:$1|1 Säit gouf|$1 Säite goufen}} dobäigesat:",
        "watchlistedit-raw-removed": "{{PLURAL:$1|1 Säit gouf|$1 Säite goufen}} erausgeholl:",
        "watchlistedit-clear-title": "Iwwerwaachungslëscht eidelmaachen",
        "watchlistedit-clear-legend": "Iwwerwaachungslëscht eidelmaachen",
        "tag-mw-blank-description": "Ännerungen déi eng Säit eidelmaachen",
        "tag-mw-replace": "Ersat",
        "tag-mw-rollback": "Zrécksetzen",
+       "tag-mw-undo": "Réckgängeg maachen",
        "tags-title": "Markéierungen",
        "tags-intro": "Op dëser Säit stinn all déi Taggen, déi vun dëser Software fir Ännerungen unzeweise benotzt ginn, an hir Bedeitung.",
        "tags-tag": "Numm vun der Markéierung",
        "tags-deactivate-submit": "Desaktivéieren",
        "tags-apply-not-allowed-one": "D'Markéierung \"$1\" däerf net manuell applizéiert ginn.",
        "tags-update-add-not-allowed-one": "D'Markéierung (tag) \"$1\" däerf net manuell dobäigesat ginn.",
-       "tags-update-add-not-allowed-multi": "Dës {{PLURAL:$2|Markéierung däerf|Markéierungen däerfen}} net manuelle derbäi gesat ginn: $1",
+       "tags-update-add-not-allowed-multi": "Dës {{PLURAL:$2|Markéierung däerf|Markéierungen däerfen}} net manuelle dobäi gesat ginn: $1",
        "tags-update-remove-not-allowed-one": "D'Markéierung (tag) \"$1\" däerf net ewechgeholl ginn.",
        "tags-update-remove-not-allowed-multi": "Dës {{PLURAL:$2|Markéierung däerf|Markéierungen däerfen}} net manuell ewechgeholl ginn: $1",
        "tags-edit-title": "Markéierungen (tags) änneren",
        "htmlform-no": "Neen",
        "htmlform-yes": "Jo",
        "htmlform-chosen-placeholder": "Sicht eng Optioun eraus",
-       "htmlform-cloner-create": "Méi derbäisetzen",
+       "htmlform-cloner-create": "Méi dobäisetzen",
        "htmlform-cloner-delete": "Ewechhuelen",
        "htmlform-cloner-required": "Mindestens ee Wäert ass obligatoresch.",
        "htmlform-date-placeholder": "JJJJ-MM-DD",
        "logentry-import-interwiki-details": "$1 {{GENDER:$2|huet}} $3 vu(n) $5 importéiert ({{PLURAL:$4|Eng Versioun|$4 Versiounen}})",
        "logentry-move-move": "$1 huet d'Säit $3 op $4 {{GENDER:$2|geréckelt}}",
        "logentry-move-move-noredirect": "$1 huet d'Säit $3 op $4 {{GENDER:$2|geréckelt}} ouni eng Viruleedung unzeleeën",
-       "logentry-move-move_redir": "$1 huet d'Säit $3 op $4 {{GENDER:$2|geréckelt}} an derbäi gouf eng Viruleedung iwwerschriwwen",
-       "logentry-move-move_redir-noredirect": "$1 huet d'Säit $3 op $4 {{GENDER:$2|geréckelt}} an derbäi gouf eng Viruleedung iwwerschriwwen an et et gouf keng nei Viruleedung ugeluecht",
+       "logentry-move-move_redir": "$1 huet d'Säit $3 op $4 {{GENDER:$2|geréckelt}} an dobäi gouf eng Viruleedung iwwerschriwwen",
+       "logentry-move-move_redir-noredirect": "$1 huet d'Säit $3 op $4 {{GENDER:$2|geréckelt}} an dobäi gouf eng Viruleedung iwwerschriwwen an et et gouf keng nei Viruleedung ugeluecht",
        "logentry-patrol-patrol": "$1 huet d'Versioun $4 vun der Säit $3 als nogekuckt {{GENDER:$2|markéiert}}",
        "logentry-patrol-patrol-auto": "$1 huet d'Versioun $4 vun der Säit $3 automatesch als nogekuckt  {{GENDER:$2|markéiert}}",
        "logentry-newusers-newusers": "De Benotzerkont $1 gouf {{GENDER:$2|ugeluecht}}",
        "logentry-tag-update-add-revision": "$1 {{GENDER:$2|huet}} d'{{PLURAL:$7|Markéierung|Markéierunge(n)}} $6 op d'Versioun $4 vun der Säit $3 dobäigesat",
        "rightsnone": "(keen)",
        "rightslogentry-temporary-group": "$1 (temporär, bis $2)",
-       "feedback-adding": "Feedback gëtt bei d'Säit derbäigesat...",
+       "feedback-adding": "Feedback gëtt bei d'Säit dobäigesat...",
        "feedback-back": "Zréck",
        "feedback-bugcheck": "Super! Kuckt just no ob et net ee vun de scho [$1 bekannte Feeler] ass.",
        "feedback-bugnew": "Ech hunn et nogekuckt. Den neie Bug mellen",
-       "feedback-bugornote": "Wann Dir bereet sidd fir en technesche Problem am Detail ze beschreiwen da [$1 mellt w.e.g. e Feeler (Bug)].\nSoss kënnt Dir den einfache Formulär hei drënner benotzen. Är Bemierkung gëtt op d'Säit \"[$3 $2]\" derbäigesat, zesumme mat Ärem Benotzernumm an dem Numm vum Browser deen Dir benotzt.",
+       "feedback-bugornote": "Wann Dir bereet sidd fir en technesche Problem am Detail ze beschreiwen da [$1 mellt w.e.g. e Feeler (Bug)].\nSoss kënnt Dir den einfache Formular hei drënner benotzen. Är Bemierkung gëtt op d'Säit \"[$3 $2]\" dobäigesat, zesumme mat Ärem Benotzernumm am Numm vum Browser deen Dir benotzt.",
        "feedback-cancel": "Ofbriechen",
        "feedback-close": "Fäerdeg",
        "feedback-external-bug-report-button": "Eng technesch Aufgab notifizéieren",
        "mw-widgets-mediasearch-noresults": "Näischt fonnt.",
        "mw-widgets-titleinput-description-new-page": "Säit gëtt et nach net",
        "mw-widgets-titleinput-description-redirect": "viruleeden op $1",
-       "mw-widgets-categoryselector-add-category-placeholder": "Eng Kategorie derbäisetzen...",
-       "mw-widgets-usersmultiselect-placeholder": "Méi derbäisetzen...",
+       "mw-widgets-categoryselector-add-category-placeholder": "Eng Kategorie dobäisetzen...",
+       "mw-widgets-usersmultiselect-placeholder": "Méi dobäisetzen...",
        "date-range-from": "Vum (Datum):",
        "date-range-to": "Bis den (Datum):",
        "sessionprovider-generic": "$1-Sessiounen",
index 8ec2530..e2574a8 100644 (file)
@@ -49,7 +49,7 @@
        "tog-usenewrc": "Grupuoti pakeitimas pagal puslapį paskutinių keitimų ir stebėjimo sąrašuose",
        "tog-numberheadings": "Automatiškai numeruoti skyrelius",
        "tog-showtoolbar": "Rodyti redagavimo įrankių juosta",
-       "tog-editondblclick": "Puslapių redagavimas dvigubu spustelėjimu (JavaScript)",
+       "tog-editondblclick": "Puslapių redagavimas dvigubu spustelėjimu",
        "tog-editsectiononrightclick": "Įjungti skyrelių redagavimą paspaudus skyrelio pavadinimą dešiniuoju pelės klavišu (JavaScript)",
        "tog-watchcreations": "Pridėti mano sukuriamus puslapius į stebimųjų sąrašą",
        "tog-watchdefault": "Pridėti puslapius, kuriuos aš redaguoju, į stebimųjų sąrašą",
        "category_header": "Puslapiai kategorijoje „$1“",
        "subcategories": "Subkategorijos",
        "category-media-header": "Daugialypės terpės rinkmenos kategorijoje „$1“",
-       "category-empty": "''Šiuo metu ši kategorija neturi jokių puslapių ar failų.''",
-       "hidden-categories": "{{PLURAL:$1|Paslėpta kategorija|Paslėptos kategorijos}}",
+       "category-empty": "<em>Šiuo metu ši kategorija neturi jokių puslapių ar failų.</em>",
+       "hidden-categories": "{{PLURAL:$1|Paslėpta kategorija|Paslėptos kategorijos|Paslėptų kategorijų}}",
        "hidden-category-category": "Paslėptos kategorijos",
        "category-subcat-count": "{{PLURAL:$2|Šioje kategorijoje yra viena subkategorija.|{{PLURAL:$1|Rodoma|Rodomos|Rodoma}} $1 {{PLURAL:$1|subkategorija|subkategorijos|subkategorijų}} (iš viso yra $2 {{PLURAL:$2|subkategorija|subkategorijos|subkategorijų}}).}}",
        "category-subcat-count-limited": "Šioje kategorijoje yra $1 {{PLURAL:$1|subkategorija|subkategorijos|subkategorijų}}.",
        "permissionserrorstext-withaction": "Jūs neturite leidimo $2 dėl {{PLURAL:$1|šios priežasties|šių priežasčių}}:",
        "contentmodelediterror": "Jūs negalite redaguoti šios versijos, nes jos turinio modelis yra <code>$1</code>, kuris skiriasi nuo dabartinio puslapio turinio modelio, kuris yra <code>$2</code>.",
        "recreate-moveddeleted-warn": "'''Dėmesio: Jūs atkuriate puslapį, kuris anksčiau buvo ištrintas.'''\n\nTurėtumėte nuspręsti, ar reikėtų toliau redaguoti šį puslapį.\nJūsų patogumui čia pateikiamas šio puslapio šalinimų ir perkėlimų sąrašas:",
-       "moveddeleted-notice": "Šis puslapis buvo ištrintas.\nŽemiau pateikiamas puslapio šalinimų ir pervadinimų sąrašas.",
+       "moveddeleted-notice": "Šis puslapis buvo ištrintas.\nŽemiau pateikiamas puslapio šalinimų, apsaugojimų, ir pervadinimų sąrašas.",
        "moveddeleted-notice-recent": "Atsiprašome, šis puslapis neseniai buvo ištrintas (per pastarąsias 24 valandas). Žemiau pateikiama detali puslapio ištrynimo ir perkėlimo istorija.",
        "log-fulllog": "Rodyti visą istoriją",
        "edit-hook-aborted": "Keitimas nutrauktas užlūžimo.\nTam nėra paaiškinimo.",
        "page_last": "pask",
        "histlegend": "Skirtumai tarp versijų: pažymėkite lyginamas versijas ir spustelkite ''Enter'' klavišą arba mygtuką apačioje.<br />\nŽymėjimai: (dab) = palyginimas su naujausia versija,\n(pask) = palyginimas su prieš tai buvusia versija, S = smulkus keitimas.",
        "history-fieldset-title": "Ieškoti versijų",
-       "history-show-deleted": "Tik ištrinti",
+       "history-show-deleted": "Tik ištrintos versijos",
        "histfirst": "seniausi",
        "histlast": "paskutiniai",
        "historysize": "($1 {{PLURAL:$1|baitas|baitai|baitų}})",
        "revdelete-unsuppress": "Šalinti apribojimus atkurtose versijose",
        "revdelete-log": "Priežastis:",
        "revdelete-submit": "Taikyti {{PLURAL:$1|pasirinktai versijai|pasirinktoms versijoms}}",
-       "revdelete-success": "'''Versijos matomumas sėkmingai pakeistas.'''",
+       "revdelete-success": "Versijos matomumas pakeistas.",
        "revdelete-failure": "'''Versijos rodomumas negali būti nustatytas:'''\n$1",
        "logdelete-success": "'''Įvykio matomumas sėkmingai nustatytas.'''",
        "logdelete-failure": "'''Sąrašo rodomumas negali būti nustatytas:'''\n$1",
        "action-deleterevision": "ištrinti revizijas",
        "action-deletelogentry": "trinti žurnalo įrašus",
        "action-deletedhistory": "žiūrėti puslapio ištrintą istoriją",
+       "action-deletedtext": "žiūrėti ištrintą versijos tekstą",
        "action-browsearchive": "ieškoti ištrintų puslapių",
        "action-undelete": "atkurti puslapius",
        "action-suppressrevision": "peržiūrėti ir atkurti paslėptas versijas",
        "recentchanges-legend-heading": "<strong>Paaiškinimai:</strong>",
        "recentchanges-legend-newpage": "{{int:recentchanges-label-newpage}} (taip pat žiūrėkite [[Special:NewPages|naujausių straipsnių sąrašą]])",
        "recentchanges-submit": "Rodyti",
+       "rcfilters-tag-remove": "Pašalinti '$1'",
+       "rcfilters-other-review-tools": "Kiti peržiūros įrankiai",
        "rcfilters-activefilters": "Aktyvūs filtrai",
        "rcfilters-advancedfilters": "Detalūs filtrai",
        "rcfilters-quickfilters": "Išsaugoti filtrai",
        "uploadstash-clear": "Išvalyti stashed failai",
        "uploadstash-nofiles": "Jūs neturite stashed failus.",
        "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-errclear": "Išvalyti failų nepavyko.",
        "uploadstash-refresh": "Atnaujinti failų sąrašą",
        "uploadstash-thumbnail": "rodyti miniatiūrą",
        "invalid-chunk-offset": "Neleistinas segmento poslinkis",
        "apisandbox-alert-field": "Šio lauko reikšmė yra neteisinga.",
        "apisandbox-continue": "Tęsti",
        "apisandbox-continue-clear": "Išvalyti",
+       "apisandbox-multivalue-all-namespaces": "$1 (Visos vardų sritys)",
        "apisandbox-multivalue-all-values": "$1 (Visos reikšmės)",
        "booksources": "Knygų šaltiniai",
        "booksources-search-legend": "Knygų šaltinių paieška",
        "unwatchthispage": "Nustoti stebėti",
        "notanarticle": "Ne turinio puslapis",
        "notvisiblerev": "Versija buvo ištrinta",
-       "watchlist-details": "Stebima {{PLURAL:$1|$1 puslapis|$1 puslapiai|$1 puslapių}}, neskaičiuojant aptarimų puslapių.",
+       "watchlist-details": "Stebima {{PLURAL:$1|$1 puslapis|$1 puslapiai|$1 puslapių}}, (įskaičiuojant aptarimų puslapius).",
        "wlheader-enotif": "El. pašto pranešimai yra įjungti.",
        "wlheader-showupdated": "Puslapiai pakeisti nuo tada, kai paskutinį kartą apsilankėte juose, yra '''paryškinti'''.",
        "wlnote": "{{PLURAL:$1|Rodomas '''$1''' paskutinis pakeitimas, atliktas|Rodomi '''$1''' paskutiniai pakeitimai, atlikti|Rodoma '''$1''' paskutinių pakeitimų, atliktų}} per '''$2''' {{PLURAL:$2|paskutinę valandą|paskutines valandas|paskutinių valandų}}, nuo $3 $4.",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Žyma|Žymos}}]]: $2)",
        "tag-mw-contentmodelchange": "turinio modulio keitimas",
        "tag-mw-contentmodelchange-description": "Pakeitimai, kurie [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel keičia puslapio turinio modelį]",
+       "tag-mw-undo": "Anuliuoti",
        "tags-title": "Žymos",
        "tags-intro": "Šiame puslapyje yra žymų, kuriomis programinė įranga gali pažymėti keitimus, sąrašas bei jų reikšmės.",
        "tags-tag": "Žymos pavadinimas",
index 0b8cc8c..95d230f 100644 (file)
        "htmlform-submit": "呈",
        "htmlform-reset": "復",
        "htmlform-selectorother-other": "他",
+       "logentry-delete-delete": "$1 {{GENDER:$2|已削}} 頁 $3",
        "revdelete-restricted": "應限至有秩",
        "revdelete-unrestricted": "除限自有秩",
        "logentry-newusers-create": "簿$1已{{GENDER:$2|增}}。",
index d835015..7142145 100644 (file)
        "rcfilters-preference-label": "Скриј ја подобрената верзија во Скорешните промени",
        "rcfilters-preference-help": "Го отповикува преуредувањето на околината од 2017 г. и сите алатки додадени оттогаш.",
        "rcfilters-filter-showlinkedfrom-label": "Прикажи промени во страници кои водат од",
-       "rcfilters-filter-showlinkedfrom-option-label": "Прикажи промени во страници кои водат <strong>ОД</strong> страница",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Страници кон кои води</strong> избраната страница",
        "rcfilters-filter-showlinkedto-label": "Прикажи промени во страници кои водат кон",
-       "rcfilters-filter-showlinkedto-option-label": "Прикажи промени во страници кои водат <strong>КОН</strong> страница",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Страници кои води кон</strong> избраната страница",
        "rcfilters-target-page-placeholder": "Внесете страница",
        "rcnotefrom": "Подолу {{PLURAL:$5|е прикажана промената|се прикажани промените}} почнувајќи од <strong>$3, $4</strong>  (се прикажуваат до <b>$1</b>).",
        "rclistfromreset": "Нов избор на датуми",
        "exif-model": "Модел",
        "exif-software": "Користен програм",
        "exif-artist": "Автор",
-       "exif-copyright": "Ð\9dоÑ\81иÑ\82ел Ð½Ð° Ð°Ð²Ñ\82оÑ\80Ñ\81киÑ\82е Ð¿Ñ\80ава",
+       "exif-copyright": "Ð\9fÑ\80аводÑ\80жеÑ\86",
        "exif-exifversion": "Exif-верзија",
        "exif-flashpixversion": "Поддржана верзија на Flashpix",
        "exif-colorspace": "Боен простор",
        "exif-rating": "Оценка (од 5)",
        "exif-rightscertificate": "Уверение за раководство со права",
        "exif-copyrighted": "Авторскоправен статус:",
-       "exif-copyrightowner": "Ð\9dоÑ\81иÑ\82ел Ð½Ð° Ð°Ð²Ñ\82оÑ\80Ñ\81киÑ\82е Ð¿Ñ\80ава",
+       "exif-copyrightowner": "Ð\9fÑ\80аводÑ\80жеÑ\86",
        "exif-usageterms": "Услови на употреба",
        "exif-webstatement": "Изјава за авторското право",
        "exif-originaldocumentid": "Единствена назнака на изворниот документ",
        "tag-mw-replace-description": "Уредувања што отстрануваат преку 90% од содржината на една страница",
        "tag-mw-rollback": "Отповикување",
        "tag-mw-rollback-description": "Уредувања што отповикуваат претходни уредувања користејќи ја соодветната врска",
+       "tag-mw-undo": "Отповикај",
+       "tag-mw-undo-description": "Уредувања што ги отповикуваат претходните уредувања користејќи ја врската за таа намена",
        "tags-title": "Ознаки",
        "tags-intro": "На оваа страница е даден список на ознаки со кои програмската опрема може да ги означи измените и нивното значење.",
        "tags-tag": "Име на ознака",
        "tags-delete-explanation-active": "<strong>Ознаката „$1“ сè уште е активна и во иднина ќе продолжи да се применува.</strong> За да го запрете ова, одете на местото/тата на кои ѝ е зададено да се применува и оневозможете ја таму.",
        "tags-delete-reason": "Причина:",
        "tags-delete-submit": "Неповратно избриши ја ознакава",
-       "tags-delete-not-allowed": "Ð\9eзнакиÑ\82е Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸ Ð¾Ð´ Ð´Ð¾Ð´Ð°Ñ\82ок Ð½Ðµ Ð¼Ð¾Ð¶Ð°Ñ\82 Ð´Ð° Ñ\81е Ð±Ñ\80иÑ\88аÑ\82 Ð¾Ñ\81вен Ð°ÐºÐ¾ Ñ\82оа Ð½Ðµ Ðµ Ð¸Ð·Ñ\80ично дозволено од додатокот.",
+       "tags-delete-not-allowed": "Ð\9eзнакиÑ\82е Ð·Ð°Ð´Ð°Ð´ÐµÐ½Ð¸ Ð¾Ð´ Ð´Ð¾Ð´Ð°Ñ\82ок Ð½Ðµ Ð¼Ð¾Ð¶Ð°Ñ\82 Ð´Ð° Ñ\81е Ð±Ñ\80иÑ\88аÑ\82 Ð¾Ñ\81вен Ð°ÐºÐ¾ Ñ\82оа Ð½Ðµ Ðµ Ð¸Ð·Ñ\80ечно дозволено од додатокот.",
        "tags-delete-not-found": "Ознаката „$1“ не постои.",
        "tags-delete-too-many-uses": "Ознаката „$1“ се применува во повеќе од {{PLURAL:$2|една преработка|$2 преработки}}, што значи дека не може да се избрише.",
        "tags-delete-warnings-after-delete": "Ознаката „$1“ е избришана, но наидов на {{PLURAL:$2|следново предупредување|следниве предупредувања}}:",
index 51db50d..960a589 100644 (file)
@@ -61,7 +61,7 @@
        "tog-shownumberswatching": "ശ്രദ്ധിക്കുന്ന ഉപയോക്താക്കളുടെ എണ്ണം കാണിക്കുക",
        "tog-oldsig": "താങ്കളുടെ നിലവിലുള്ള ഒപ്പ്:",
        "tog-fancysig": "ഒപ്പ് ഒരു വിക്കി എഴുത്തായി പരിഗണിക്കുക (കണ്ണി സ്വയം ചേർക്കേണ്ടതില്ല)",
-       "tog-uselivepreview": "തത്സമയ പ്രിവ്യൂ ഉപയോഗപ്പെടുത്തുക",
+       "tog-uselivepreview": "à´ªàµ\87à´\9càµ\8d à´µàµ\80à´£àµ\8dà´\9fàµ\81à´\82 à´²àµ\8bà´¡àµ\8d à´\9aàµ\86à´¯àµ\8dയാതàµ\86 à´¤à´¤àµ\8dസമയ à´ªàµ\8dà´°à´¿à´µàµ\8dà´¯àµ\82 à´\89പയàµ\8bà´\97à´ªàµ\8dà´ªàµ\86à´\9fàµ\81à´¤àµ\8dà´¤àµ\81à´\95",
        "tog-forceeditsummary": "തിരുത്തുകളുടെ ചുരുക്കം നൽകിയില്ലെങ്കിൽ എന്നെ ഓർമ്മിപ്പിക്കുക",
        "tog-watchlisthideown": "ഞാൻ ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടികയിൽനിന്ന് എന്റെ തിരുത്തുകൾ മറയ്ക്കുക",
        "tog-watchlisthidebots": "ഞാൻ ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടികയിൽനിന്ന് യന്ത്രങ്ങൾ വരുത്തിയ തിരുത്തുകൾ മറയ്ക്കുക",
        "talk": "സംവാദം",
        "views": "ദർശനീയത",
        "toolbox": "ഉപകരണങ്ങൾ",
+       "tool-link-userrights": "{{GENDER:$1|ഉപയോക്തൃസംഘങ്ങളിലെ}} അംഗത്വം പുനഃക്രമീകരിക്കുക",
+       "tool-link-userrights-readonly": "{{GENDER:$1|ഉപയോക്തൃസംഘങ്ങൾ}} കാണുക",
+       "tool-link-emailuser": "ഈ {{GENDER:$1|ഉപയോക്താവിന്}} ഇമെയിൽ അയയ്ക്കുക",
        "imagepage": "പ്രമാണ താൾ കാണുക",
        "mediawikipage": "സന്ദേശങ്ങളുടെ താൾ കാണുക",
        "templatepage": "ഫലകം താൾ കാണുക",
        "createacct-yourpasswordagain-ph": "രഹസ്യവാക്ക് വീണ്ടും നൽകുക",
        "userlogin-remembermypassword": "ഞാൻ പ്രവേശിച്ചതായിത്തന്നെ ഓർത്തിരിക്കുക",
        "userlogin-signwithsecure": "സുരക്ഷിത കണക്ഷൻ ഉപയോഗിക്കുക",
+       "cannotlogin-title": "പ്രവേശിക്കാൻ സാധിക്കുന്നില്ല",
+       "cannotlogin-text": "പ്രവേശനം സാധ്യമല്ല.",
        "cannotloginnow-title": "ഇപ്പോൾ പ്രവേശിക്കാൻ കഴിയില്ല",
        "cannotloginnow-text": "$1 ഉപയോഗിച്ചുകൊണ്ടിരിക്കെ പ്രവേശിക്കാൻ കഴിയില്ല.",
+       "cannotcreateaccount-title": "അംഗത്വം സൃഷ്ടിക്കാൻ സാധിച്ചില്ല",
+       "cannotcreateaccount-text": "നേരിട്ട് അംഗത്വം സൃഷ്ടിക്കുന്നതുള്ള ക്രമീകരണം ഈ വിക്കിയിൽ നിലവിലില്ല.",
        "yourdomainname": "താങ്കളുടെ ഡൊമെയിൻ:",
        "password-change-forbidden": "ഈ വിക്കിയിൽ രഹസ്യവാക്കുകൾ മാറ്റാനാവില്ല.",
        "externaldberror": "ഒന്നുകിൽ ഡേറ്റാബേസ് സാധൂകരണത്തിൽ പ്രശ്നം ഉണ്ടായിരുന്നു അല്ലെങ്കിൽ നവീകരിക്കുവാൻ താങ്കളുടെ ബാഹ്യ അംഗത്വം താങ്കളെ അനുവദിക്കുന്നില്ല.",
        "login": "പ്രവേശിക്കുക",
+       "login-security": "താങ്കളുടെ ഐകാത്മ്യം സ്ഥിരീകരിക്കുക",
        "nav-login-createaccount": "പ്രവേശിക്കുക / അംഗത്വമെടുക്കുക",
        "logout": "ലോഗൗട്ട്",
        "userlogout": "ലോഗൗട്ട്",
        "userlogin-resetpassword-link": "താങ്കൾ രഹസ്യവാക്ക് മറന്നോ?",
        "userlogin-helplink2": "പ്രവേശിക്കാൻ സഹായമാവശ്യമെങ്കിൽ",
        "userlogin-loggedin": "താങ്കൾ ഇപ്പോൾ തന്നെ {{GENDER:$1|$1}} ആയി പ്രവേശിച്ചിരിക്കുന്നു.\nതാഴെ ഉള്ള ഫോം ഉപയോഗിച്ച് മറ്റൊരു ഉപയോക്താവായി പ്രവേശിക്കാവുന്നതാണ്.",
+       "userlogin-reauth": "താങ്കൾ {{GENDER:$1|$1}} തന്നെയെന്ന് സ്ഥിരീകരിക്കാൻ ദയവായി വീണ്ടും ലോഗിൻ ചെയ്യുക.",
        "userlogin-createanother": "മറ്റൊരു അംഗത്വമെടുക്കുക",
        "createacct-emailrequired": "ഇമെയിൽ വിലാസം",
        "createacct-emailoptional": "ഇമെയിൽ വിലാസം (നിർബന്ധമില്ല)",
        "createacct-reason-ph": "താങ്കൾ എന്തുകൊണ്ടാണ് മറ്റൊരു അംഗത്വം എടുക്കുന്നത്",
        "createacct-submit": "താങ്കളുടെ അംഗത്വം സൃഷ്ടിക്കുക",
        "createacct-another-submit": "അംഗത്വമെടുക്കുക",
+       "createacct-continue-submit": "അംഗത്വം സൃഷ്ടിക്കുന്നത് തുടരുക",
+       "createacct-another-continue-submit": "അംഗത്വം സൃഷ്ടിക്കുന്നത് തുടരുക",
        "createacct-benefit-heading": "താങ്കളെപ്പോലെയുള്ളവരാണ്  {{SITENAME}}  പടുത്തുയർത്തിയിരിക്കുന്നത്.",
        "createacct-benefit-body1": "{{PLURAL:$1|തിരുത്ത്|തിരുത്തുകൾ}}",
        "createacct-benefit-body2": "{{PLURAL:$1|താൾ|താളുകൾ}}",
        "nocookiesnew": "ഉപയോക്തൃഅംഗത്വം ഉണ്ടാക്കിയിരിക്കുന്നു. പക്ഷെ താങ്കൾ ലോഗിൻ ചെയ്തിട്ടില്ല. {{SITENAME}} സംരംഭത്തിൽ ലോഗിൻ ചെയ്യാൻ കുക്കികൾ സജ്ജമാക്കിയിരിക്കണം. താങ്കളുടെ കമ്പ്യൂട്ടറിൽ നിലവിൽ കുക്കികൾ പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു. അത് സജ്ജമാക്കിയ ശേഷം താങ്കളുടെ ഉപയോക്തൃനാമവും രഹസ്യവാക്കും ഉപയോഗിച്ച് ലോഗിൻ ചെയ്യൂ.",
        "nocookieslogin": "{{SITENAME}} സംരംഭത്തിൽ ലോഗിൻ ചെയ്യുവാൻ കുക്കികൾ സജ്ജമാക്കിയിരിക്കണം. പക്ഷെ താങ്കൾ കുക്കികൾ സജ്ജമാക്കിയിട്ടില്ല. കുക്കികൾ സജ്ജമാക്കിയതിനു ശേഷം വീണ്ടും ലോഗിൻ ചെയ്യാൻ ശ്രമിക്കൂ.",
        "nocookiesfornew": "ഞങ്ങൾക്ക് ഇതിന്റെ സ്രോതസ് കണ്ടെത്താനാകാതിരുന്നതിനാൽ ഉപയോക്തൃ അംഗത്വം സൃഷ്ടിച്ചിട്ടില്ല.\nകുക്കികൾ സജ്ജമാക്കിയ ശേഷം, താൾ വീണ്ടുമെടുത്ത്, വീണ്ടും ശ്രമിക്കുക.",
+       "createacct-loginerror": "താങ്കളുടെ അംഗത്വം വിജയകരമായി സൃഷ്ടിക്കപ്പെട്ടിരിക്കുന്നു, എന്നാൽ പ്രസ്തുത അംഗത്വമുപയോഗിച്ച് യാന്ത്രികമായി പ്രവേശിക്കാൻ സാധിച്ചില്ല. ദയവായി [[Special:UserLogin|ലോഗിൻ താൾ]] ഉപയോഗിച്ചു പ്രവേശിക്കാൻ ശ്രമിക്കുക.",
        "noname": "താങ്കൾ സാധുവായ ഉപയോക്തൃനാമം സൂചിപ്പിച്ചിട്ടില്ല.",
        "loginsuccesstitle": "സ്വാഗതം! \nതാങ്കൾ വിജയകരമായി പ്രവേശിച്ചിരിക്കുന്നു.",
        "loginsuccess": "'''{{SITENAME}} സംരംഭത്തിൽ \"$1\" എന്ന പേരിൽ താങ്കൾ ലോഗിൻ ചെയ്തിരിക്കുന്നു.'''",
        "nosuchusershort": "\"$1\" എന്ന പേരിൽ ഒരു ഉപയോക്താവ് ഇല്ല. അക്ഷരങ്ങൾ ഒന്നു കൂടി പരിശോധിക്കുക.",
        "nouserspecified": "ഉപയോക്തൃനാമം നിർബന്ധമായും ചേർക്കണം.",
        "login-userblocked": "ഈ ഉപയോക്താവ് തടയപ്പെട്ടിരിക്കുന്നു. പ്രവേശനം അനുവദിക്കുന്നില്ല.",
-       "wrongpassword": "രഹസàµ\8dയവാà´\95àµ\8dà´\95àµ\8d à´¤àµ\86à´±àµ\8dറാണàµ\8d, വീണ്ടും ശ്രമിക്കുക.",
+       "wrongpassword": "താà´\99àµ\8dà´\95ൾ à´¨àµ½à´\95à´¿à´¯ à´\89പയàµ\8bà´\95àµ\8dà´¤àµ\83നാമമàµ\8b à´°à´¹à´¸àµ\8dയവാà´\95àµ\8dà´\95àµ\8b à´¤àµ\86à´±àµ\8dറാണàµ\8d, à´¦à´¯à´µà´¾à´¯à´¿ വീണ്ടും ശ്രമിക്കുക.",
        "wrongpasswordempty": "രഹസ്യവാക്ക് നൽകിയിരുന്നില്ല. വീണ്ടും ശ്രമിക്കുക.",
        "passwordtooshort": "രഹസ്യവാക്കിൽ കുറഞ്ഞതു {{PLURAL:$1|ഒരു അക്ഷരം|$1 അക്ഷരങ്ങൾ}} ഉണ്ടായിരിക്കണം.",
        "passwordtoolong": "രഹസ്യവാക്കിൽ പരമാവധി {{PLURAL:$1|ഒരു അക്ഷരം|$1 അക്ഷരങ്ങൾ}} മാത്രമേ പാടുള്ളു.",
        "eauthentsent": "താങ്കൾ നൽകിയിട്ടുള്ള ഇമെയിൽ വിലാസത്തിലേക്ക് സ്ഥിരീകരണത്തിനായി ഒരു ഇമെയിൽ അയച്ചിട്ടുണ്ട്. ആ വിലാസത്തിലേക്ക് മറ്റൊരു ഇമെയിൽ അയക്കുന്നതിനു മുൻപായി, അംഗത്വം താങ്കളുടേതു തന്നെ എന്നു ഉറപ്പു വരുത്തുന്നതിന്, ഇപ്പോൾ അയച്ചിട്ടുള്ള ഇമെയിലിലെ നിർദ്ദേശങ്ങൾ താങ്കൾ പാലിക്കേണ്ടതാണ്.",
        "throttled-mailpassword": "കഴിഞ്ഞ {{PLURAL:$1|മണിക്കൂറിനുള്ളിൽ |$1 മണിക്കൂറുകൾക്കുള്ളിൽ}} രഹസ്യവാക്ക് പുനർസജ്ജീകരിക്കാനുള്ള ഒരു ഇമെയിൽ അയച്ചിട്ടുണ്ട്. ദുരുപയോഗം ഒഴിവാക്കാൻ {{PLURAL:$1|ഒരു മണിക്കൂറിനുള്ളിൽ |$1 മണിക്കൂറുകൾക്കുള്ളിൽ}} രഹസ്യവാക്ക് പുനർസജ്ജീകരിക്കാനുള്ള ഒരു ഇമെയിൽ മാത്രമേ അയയ്ക്കുകയുള്ളു.",
        "mailerror": "മെയിൽ അയയ്ക്കുന്നതിൽ പിഴവ്: $1",
-       "acct_creation_throttle_hit": "കഴിഞ്ഞ ഒരു ദിവസത്തിനുള്ളിൽ താങ്കളുടെ ഐ.പി. വിലാസത്തിൽ നിന്നുമുള്ള സന്ദർശകർ {{PLURAL:$1|1 അംഗത്വം|$1 അംഗത്വങ്ങൾ}} എടുത്തിട്ടുണ്ട്, പ്രസ്താവിത സമയത്തിനുള്ളിൽ എടുക്കാവുന്ന ഏറ്റവും കൂടിയ പരിധിയാണിത്.\nഅതിന്റെ ഫലമായി, ഈ ഐ.പി.യിൽ നിന്നുള്ള സന്ദർശകർക്ക് ഇപ്പോൾ കൂടുതൽ അംഗത്വമെടുക്കാൻ കഴിയുന്നതല്ല.",
+       "acct_creation_throttle_hit": "കഴിഞ്ഞ $2 സമയത്തിനുള്ളിൽ താങ്കളുടെ ഐ.പി. വിലാസത്തിൽ നിന്നുമുള്ള സന്ദർശകർ {{PLURAL:$1|1 അംഗത്വം|$1 അംഗത്വങ്ങൾ}} എടുത്തിട്ടുണ്ട്, പ്രസ്താവിത സമയത്തിനുള്ളിൽ എടുക്കാവുന്ന ഏറ്റവും കൂടിയ പരിധിയാണിത്.\nഅതിന്റെ ഫലമായി, ഈ ഐ.പി.യിൽ നിന്നുള്ള സന്ദർശകർക്ക് ഇപ്പോൾ കൂടുതൽ അംഗത്വമെടുക്കാൻ കഴിയുന്നതല്ല.",
        "emailauthenticated": "താങ്കൾ ഇമെയിൽ വിലാസം $2, $3-ന് സ്ഥിരീകരിച്ചതാണ്.",
        "emailnotauthenticated": "താങ്കളുടെ ഇമെയിൽ വിലാസം ഇതുവരെ സ്ഥിരീകരിക്കപ്പെട്ടിട്ടില്ല. താഴെപ്പറയുന്നവയ്ക്ക് ഇമെയിലുകൾ അയയ്ക്കാൻ സാദ്ധ്യമല്ല.",
        "noemailprefs": "ഈ ക്രമീകരണങ്ങൾ പ്രവർത്തിക്കുവാൻ സാധുവായ ഒരു ഇമെയിൽ വിലാസം ഉൾപ്പെടുത്തുക.",
        "createacct-another-realname-tip": "താങ്കളുടെ യഥാർത്ഥ പേര്‌ നൽകണമെന്നു നിർബന്ധമില്ല.\n\nഎങ്കിലും അങ്ങനെ ചെയ്താൽ, ഉപയോക്താക്കൾക്ക് അവരരവരുടെ പേരിൽ തന്നെ തങ്ങളുടെ സൃഷ്ടിക്ക് കടപ്പാട് ലഭിക്കുന്നതാണ്.",
        "pt-login": "പ്രവേശിക്കുക",
        "pt-login-button": "പ്രവേശിക്കുക",
+       "pt-login-continue-button": "പ്രവേശനപ്രക്രിയ തുടരുക",
        "pt-createaccount": "അംഗത്വമെടുക്കുക",
        "pt-userlogout": "ലോഗൗട്ട്",
        "php-mail-error-unknown": "പി.എച്ച്.പി.യുടെ main() ഫങ്ഷനിൽ അപരിചിതമായ പിഴവ്",
        "changepassword-success": "താങ്കളുടെ രഹസ്യവാക്ക് വിജയകരമായി മാറ്റിയിരിക്കുന്നു!",
        "changepassword-throttled": "കുറഞ്ഞ സമയത്തിനുള്ളിൽ താങ്കൾ നിരവധി തവണ പ്രവേശിക്കാൻ ശ്രമിച്ചിരിക്കുന്നു.\nവീണ്ടും ശ്രമിക്കുന്നതിനു മുമ്പ് ദയവായി $1 കാത്തിരിക്കുക.",
        "botpasswords": "യന്ത്രത്തിനുള്ള രഹസ്യവാക്കുകൾ",
+       "botpasswords-disabled": "യാന്ത്രിക രഹസ്യവാക്കുകൾ അനുവദനീയമല്ല.",
        "botpasswords-label-appid": "യന്ത്രത്തിന്റെ പേര്:",
        "botpasswords-label-create": "സൃഷ്ടിക്കുക",
        "botpasswords-label-update": "പുതുക്കുക",
        "mergehistory-empty": "സം‌യോജിപ്പിക്കാവുന്ന പതിപ്പുകളൊന്നും ഇല്ല.",
        "mergehistory-done": "$1-ന്റെ {{PLURAL:$3|പതിപ്പ്|പതിപ്പുകൾ}} [[:$2]]-ലേക്കു വിജയകരമായി സം‌യോജിപ്പിച്ചിരിക്കുന്നു.",
        "mergehistory-fail": "താളുകളുടെ നാൾവഴി സം‌യോജനം നടത്താൻ സാദ്ധ്യമല്ല. താളുകളും സമയവിവരങ്ങളും ഒന്നു കൂടി പരിശോധിക്കുക.",
+       "mergehistory-fail-permission": "താങ്കൾക്ക് നാൾവഴികൾ ലയിപ്പിക്കാനുള്ള അനുമതി ഇല്ല.",
+       "mergehistory-fail-self-merge": "സ്രോതസ്സ് - ലക്ഷ്യ താളുകൾക്ക് ഒരേ പേര്‌ ഉണ്ടാകാൻ പാടില്ല.",
        "mergehistory-fail-toobig": "{{PLURAL:$1|ഒരു നാൾപ്പതിപ്പിൽ|$1 നാൾപ്പതിപ്പുകൾ}} മാറ്റണമെന്നതിനാൽ നാൾവഴി ലയിപ്പിക്കാൽ നടത്താനാവില്ല.",
        "mergehistory-no-source": "സ്രോതസ്സ് താളായ $1 നിലവിലില്ല.",
        "mergehistory-no-destination": "ലക്ഷ്യ താളായ $1 നിലവിലില്ല.",
        "search-file-match": "(പ്രമാണ ഉള്ളടക്കവുമായി ഒത്തുപോകുന്നുണ്ട്)",
        "search-suggest": "താങ്കൾ ഉദ്ദേശിച്ചത് $1 എന്നാണോ",
        "search-rewritten": "$1 എന്നതിനുള്ള ഫലങ്ങൾ കാണിക്കുന്നു. പകരം $2 എന്നതിനായി തിരയുക.",
-       "search-interwiki-caption": "സഹോദര സംരംഭങ്ങൾ",
+       "search-interwiki-caption": "സഹàµ\8bദര à´¸à´\82à´°à´\82à´­à´\99àµ\8dà´\99ളിൽനിനàµ\8dà´¨àµ\81à´³àµ\8dà´³ à´«à´²à´\99àµ\8dà´\99ൾ",
        "search-interwiki-default": "$1 വിക്കിയിൽ നിന്നുള്ള ഫലങ്ങൾ:",
        "search-interwiki-more": "(കൂടുതൽ)",
+       "search-interwiki-more-results": "കൂടുതൽ ഫലങ്ങൾ",
        "search-relatedarticle": "ബന്ധപ്പെട്ടവ",
        "searchrelated": "ബന്ധപ്പെട്ടവ",
        "searchall": "എല്ലാം",
        "search-external": "ബാഹ്യ അന്വേഷണം",
        "searchdisabled": "{{SITENAME}} സം‌രംഭത്തിൽ തിരച്ചിൽ ദുർബലപ്പെടുത്തിയിരിക്കുന്നു. താങ്കൾക്ക് ഗൂഗിൾ ഉപയോഗിച്ച് തത്കാലം തിരച്ചിൽ നടത്താവുന്നതാണ്‌. പക്ഷെ ഗൂഗിളിൽ {{SITENAME}} സം‌രംഭത്തിന്റെ സൂചിക കാലഹരണപ്പെട്ടതായിരിക്കാൻ സാദ്ധ്യതയുണ്ട്.",
        "search-error": "തിരയുന്നതിനിടെ ഒരു പിഴവുണ്ടായി: $1",
+       "search-warning": "തിരയുന്നതിനിടെ ഒരു മുന്നറിയിപ്പു ലഭിച്ചു: $1",
        "preferences": "ക്രമീകരണങ്ങൾ",
        "mypreferences": "ക്രമീകരണങ്ങൾ",
        "prefs-edits": "ആകെ തിരുത്തുകൾ:",
        "prefs-editwatchlist-clear": "ശ്രദ്ധിക്കുന്നവയുടെ പട്ടിക ശൂന്യമാക്കുക",
        "prefs-watchlist-days": "ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടികയിൽ പ്രദർശിപ്പിക്കേണ്ട പരമാവധി ദിവസങ്ങൾ:",
        "prefs-watchlist-days-max": "പരമാവധി {{PLURAL:$1|ഒരു ദിവസം|$1 ദിവസങ്ങൾ}}",
-       "prefs-watchlist-edits": "à´¶àµ\8dà´°à´¦àµ\8dധിà´\95àµ\8dà´\95àµ\81à´¨àµ\8dà´¨ à´¤à´¾à´³àµ\81à´\95à´³àµ\81à´\9fàµ\86 à´ªà´\9fàµ\8dà´\9fà´¿à´\95à´¯àµ\81à´\9fàµ\86 à´µà´¿à´\95സിത à´°àµ\82പതàµ\8dതിൽ à´ªàµ\8dരദർശിപàµ\8dപിà´\95àµ\8dà´\95àµ\87à´£àµ\8dà´\9f à´ªà´°à´®à´¾à´µà´§à´¿ à´®à´¾à´±àµ\8dà´±à´\99àµ\8dà´\99ൾ:",
+       "prefs-watchlist-edits": "ശ്രദ്ധിക്കുന്ന താളുകളുടെ പട്ടികയിൽ പ്രദർശിപ്പിക്കേണ്ട പരമാവധി മാറ്റങ്ങൾ:",
        "prefs-watchlist-edits-max": "പരമാവധി 1000 തിരുത്തുകൾ",
        "prefs-watchlist-token": "ശ്രദ്ധിക്കുന്നവയുടെ പട്ടികയ്ക്കുള്ള അടയാളപദം:",
        "prefs-misc": "പലവക",
        "timezoneregion-europe": "യൂറോപ്പ്",
        "timezoneregion-indian": "ഇന്ത്യൻ മഹാസമുദ്രം",
        "timezoneregion-pacific": "ശാന്തസമുദ്രം",
-       "allowemail": "എനിക്ക് എഴുത്തയക്കാൻ മറ്റുള്ളവരെ അനുവദിക്കുക",
+       "allowemail": "എനിക്ക് ഈ-മെയിൽ അയയ്ക്കാൻ മറ്റുള്ളവരെ അനുവദിക്കുക",
+       "email-allow-new-users-label": "എനിക്ക് ഈ-മെയിൽ അയയ്ക്കാൻ പുതിയ ഉപയോക്താക്കളെ അനുവദിക്കുക",
        "email-blacklist-label": "ഈ ഉപയോക്താക്കൾ എനിക്ക് ഇമെയിൽ അയയ്ക്കുന്നത് തടയുക:",
        "prefs-searchoptions": "തിരച്ചിൽ",
        "prefs-namespaces": "നാമമേഖലകൾ",
        "youremail": "ഇമെയിൽ:",
        "username": "{{GENDER:$1|ഉപയോക്തൃനാമം}}:",
        "prefs-memberingroups": "{{GENDER:$2|അംഗത്വമുള്ള}} {{PLURAL:$1|സംഘം|സംഘങ്ങൾ}}:",
+       "group-membership-link-with-expiry": "$1 ($2 വരെ)",
        "prefs-registration": "അംഗത്വം എടുത്തത്:",
        "yourrealname": "യഥാർത്ഥ പേര്‌:",
        "yourlanguage": "ഭാഷ:",
index 44ae5b9..058eb5b 100644 (file)
@@ -24,7 +24,8 @@
                        "Nemo bis",
                        "Mbrt",
                        "Muhdnurhidayat",
-                       "Jeluang Terluang"
+                       "Jeluang Terluang",
+                       "Zulfadli51"
                ]
        },
        "tog-underline": "Garis bawah pautan:",
        "nosuchusershort": "Pengguna \"$1\" tidak wujud. Sila semak ejaan anda.",
        "nouserspecified": "Sila nyatakan nama pengguna.",
        "login-userblocked": "Pengguna ini disekat. Log masuk tidak dibenarkan.",
-       "wrongpassword": "Kata laluan yang dimasukkan adalah salah. Sila cuba lagi.",
+       "wrongpassword": "Dimasukkan nama pengguna atau kata laluan yang salah.\nSila cuba lagi.",
        "wrongpasswordempty": "Kata laluan yang dimasukkan adalah kosong. Sila cuba lagi.",
        "passwordtooshort": "Kata laluan mestilah sekurang-kurangnya {{PLURAL:$1|1 aksara|$1 aksara}}.",
        "passwordtoolong": "Kata laluan tidak boleh melebihi $1 aksara.",
        "botpasswords-insert-failed": "Gagal untuk menambah nama bot \"$1\". Adakah ia telah digunakan?",
        "botpasswords-update-failed": "Gagal untuk mengemas kini nama bot \"$1\". Adakah ia telah dipadam?",
        "botpasswords-created-title": "Kata laluan bot telah dicipta",
-       "botpasswords-created-body": "Kata laluan bot untuk nama bot \"$1\" bagi pengguna \"$2\" telah dicipta.",
+       "botpasswords-created-body": "Kata laluan bot untuk nama bot \"$1\" bagi {{GENDER:$2|pengguna}} \"$2\" telah dicipta.",
        "botpasswords-updated-title": "Kata laluan bot telah dikemaskinikan",
-       "botpasswords-updated-body": "Kata laluan bot untuk nama bot \"$1\" bagi pengguna \"$2\" telah dikemaskini.",
+       "botpasswords-updated-body": "Kata laluan bot untuk nama bot \"$1\" bagi {GENDER:$2|pengguna}} \"$2\" telah dikemaskini.",
        "botpasswords-deleted-title": "Kata laluan bot telah dipadam",
-       "botpasswords-deleted-body": "Kata laluan bot untuk nama bot \"$1\" bagi pengguna \"$2\" telah dipadam.",
+       "botpasswords-deleted-body": "Kata laluan bot untuk nama bot \"$1\" bagi {{GENDER:$2|pengguna}} \"$2\" telah dipadam.",
        "botpasswords-newpassword": "Kata laluan baru untuk log masuk dengan <strong>$1</strong> adalah <strong>$2</strong>. <em>Sila catatkan ini untuk rujukan masa depan.</em> <br> (Untuk bot-bot lama yang memerlukan nama log masuk agar sama dengan nama pengguna akhirnya, anda juga boleh menggunakan <strong>$3</strong> sebagai nama pengguna dan <strong>$4</strong> sebagai kata laluan.)",
        "botpasswords-no-provider": "BotPasswordsSessionProvider tidak tersedia.",
        "botpasswords-restriction-failed": "Bot sekatan kata laluan menghalang log masuk ini.",
        "passwordreset-emailtext-user": "Pengguna $1 telah memohon supaya kata laluan diset semula untuk {{SITENAME}} anda ($4). {{PLURAL:$3|Akaun|Akaun-akaun}} pengguna yang berikut\ndikaitkan dengan alamat e-mel ini:\n\n$2\n\n{{PLURAL:$3|Kata|Kata-kata}} laluan sementara ini akan luput dalam masa $5 hari. Anda harus log masuk dan membuat kata laluan yang baru sekarang. Jika permohonan ini dibuat oleh orang lain, atau jika anda teringat kembali kata laluan asal anda dan anda tidak lagi berhasrat untuk mengubahnya, anda boleh mengabaikan pesanan ini dan terus menggunakan kata laluan lama anda.",
        "passwordreset-emailelement": "Nama pengguna: \n$1\n\nKata laluan sementara: \n$2",
        "passwordreset-emailsentemail": "Jika ini ialah alamat e-mel yang terdaftar untuk akaun anda, maka e-mel set semula kata laluan akan dihantar.",
+       "passwordreset-emailsentusername": "Sekiranya terdapat alamat e-mel yang dikaitkan dengan nama pengguna ini, maka e-mel set semula kata laluan akan dihantar.",
+       "passwordreset-nocaller": "Pemanggil perlu diberikan",
+       "passwordreset-nosuchcaller": "Pemanggil tidak wujud: $1",
+       "passwordreset-ignored": "Reset kata laluan tidak dikendalikan. Mungkin tiada pembekal tidak dikonfigurasikan?",
+       "passwordreset-invalidemail": "Alamat e-mel tidak sah",
+       "passwordreset-nodata": "Tiada nama pengguna atau alamat e-mel dibekalkan",
        "changeemail": "Tukar atau padamkan alamat e-mel",
        "changeemail-header": "Lengkapkan borang ini untuk menukar alamat e-mel anda. Jika anda ingin memutuskan sebarang hubungan alamat e-mel daripada akaun anda, biarkan ruangan alamat e-mel kosong ketika menghantar borang.",
        "changeemail-no-info": "Anda hendaklah log masuk terlebih dahulu untuk mencapai laman ini secara terus.",
        "minoredit": "Ini ialah suntingan kecil",
        "watchthis": "Pantau laman ini",
        "savearticle": "Paparkan Laman",
+       "savechanges": "Simpan perubahan",
        "publishpage": "Terbitkan",
        "publishchanges": "Terbit perubahan",
        "preview": "Pralihat",
        "showpreview": "Paparkan pralihat",
        "showdiff": "Lihat perubahan",
-       "blankarticle": "<strong>Amaran:</strong> Laman yang sedang anda ciptakan adalah kosong.\nJika anda menklik \"$1\" sekali lagi, laman ini akan diciptakan tanpa sebarang kandungan.",
+       "blankarticle": "<strong>Amaran:</strong> Laman yang anda sedang cipta adalah kosong.\nJika anda mengklik \"$1\" sekali lagi, laman ini akan dicipta tanpa sebarang kandungan.",
        "anoneditwarning": "<strong>Amaran:</strong> Anda tidak log masuk. Alamat IP anda akan disiarkan kepada umum jika anda membuat sebarang suntingan. Jika anda <strong>[$1 log masuk]</strong> atau <strong>[$2 membuka akaun]</strong>, suntingan anda akan diatribusikan kepada nama pengguna anda di samping manfaat-manfaat lain.",
        "anonpreviewwarning": "''Anda belum log masuk. Jika anda menyimpan laman ini, alamat IP anda akan direkodkan dalam sejarah penyuntingan laman ini.''",
        "missingsummary": "'''Peringatan:''' Anda tidak menyatakan ringkasan suntingan. Klik '''Simpan''' sekali lagi untuk menyimpan suntingan ini tanpa ringkasan.",
        "selfredirect": "<strong>Amaran:</strong> Anda sedang melencongkan laman ini kepada dirinya sendiri.\nMungkin anda telah menyatakan sasaran yang salah untuk lencongan ini ataupun sedang tersalah menyunting halaman.\nJika anda mengklik \"$1\" semula, maka lencongan tetap akan dihasilkan.",
-       "missingcommenttext": "Sila masukkan komen dalam ruangan di bawah.",
+       "missingcommenttext": "Sila masukkan komen.",
        "missingcommentheader": "<strong>Peringatan:</strong> Anda belum menyatakan tajuk perkara bagi komen ini.\nJika anda klik '''$1''' sekali lagi, suntingan anda akan tersimpan tanpa tajuk.",
-       "summary-preview": "Pralihat ringkasan:",
+       "summary-preview": "Pralihat ringkasan suntingan:",
        "subject-preview": "Pralihat perkara:",
        "previewerrortext": "Ralat berlaku ketika cuba mempratayangkan hasil suntingan anda.",
        "blockedtitle": "Pengguna disekat",
        "blockedtext": "<strong>Nama pengguna atau alamat IP anda telah disekat.</strong>\n\nSekatan ini dilakukan oleh $1.\nSebab yang telah diberikan ialah <em>$2</em>.\n\n* Sekatan mula: $8\n* Sekatan tamat: $6\n* Pengguna sasaran: $7\n\nAnda boleh hubungi $1 atau [[{{MediaWiki:Grouppage-sysop}}|penyelia]] yang lain untuk membincangkan sekatan ini.\n\nSila ambil perhatian bahawa anda tidak boleh menggunakan ciri \"kirim e-mel kepada pengguna ini\" kecuali sekiranya anda telah menetapkan alamat e-mel yang sah dalam [[Special:Preferences|keutamaan pengguna]] anda dan anda tidak disekat daripada menggunakannya.\n\nAlamat IP semasa anda ialah $3, dan ID sekatan ialah #$5.\nSila sertakan maklumat-maklumat di atas dalam sebarang pertanyaan yang anda membuat.",
        "autoblockedtext": "Alamat IP anda telah disekat secara automatik kerana ia digunakan oleh pengguna lain yang disekat oleh $1.\nSebab yang dinyatakan ialah:\n\n:<em>$2</em>\n\n* Sekatan mula: $8\n* Sekatan tamat: $6\n* Pengguna sasaran: $7\n\nAnda boleh menghubungi $1 atau seorang [[{{MediaWiki:Grouppage-sysop}}|penyelia]] yang lain untuk membincangkan sekatan ini.\n\nSila ambil perhatian bahawa anda tidak boleh menggunakan ciri \"kirim e-mel kepada pengguna ini\" kecuali sekiranya anda telah menetapkan alamat e-mel yang sah dalam [[Special:Preferences|keutamaan pengguna]] anda dan anda tidak disekat daripada menggunakannya.\n\nAlamat IP semasa anda ialah $3, dan ID sekatan ialah #$5.\nSila sertakan maklumat-maklumat di atas dalam sebarang pertanyaan yang anda membuat.",
+       "systemblockedtext": "Nama pengguna atau alamat IP anda telah diblok secara automatik oleh MediaWiki. Alasan diberikan ialah:\n\n:<em>$2</em>\n\n* Mula blok: $8\n* Luput blok: $6\n* Yang diblok yang dimaksudkan: $7\n\nAlamat IP anda sekarang ialah $3.\nSila sertakan butiran di atas dalam sebarang pertanyaan yang anda buat.",
        "blockednoreason": "tiada sebab diberikan",
        "whitelistedittext": "Anda hendaklah $1 terlebih dahulu untuk menyunting laman.",
        "confirmedittext": "Anda perlu mengesahkan alamat e-mel anda terlebih dahulu untuk menyunting mana-mana laman. Sila tetapkan dan sahkan alamat e-mel anda melalui [[Special:Preferences|laman keutamaan]].",
        "accmailtext": "Kata laluan janaan rawak untuk [[User talk:$1|$1]] telah dikirim kepada $2. Anda boleh menukarnya di halaman ''[[Special:ChangePassword|tukar kata laluan]]'' sebaik sahaja log masuk.",
        "newarticle": "(Baru)",
        "newarticletext": "Anda telah mengikuti pautan ke laman yang belum wujud.\nUntuk mencipta laman ini, sila taip dalam kotak di bawah\n(lihat [$1 laman bantuan] untuk maklumat lanjut).\nJika anda tiba di sini secara tak sengaja, hanya klik butang '''back''' pada pelayar anda.",
-       "anontalkpagetext": "----''Ini ialah laman perbincangan bagi pengguna tanpa nama yang belum membuka akaun atau tidak log masuk.\nOleh itu, kami terpaksa menggunakan alamat IP untuk mengenal pasti pengguna tersebut. Alamat IP ini boleh dikongsi oleh ramai pengguna.\nSekiranya anda ialah seorang pengguna tanpa nama dan berasa bahawa komen yang tidak kena-mengena telah ditujukan kepada anda, sila [[Special:CreateAccount|buka akaun baru]] atau [[Special:UserLogin|log masuk]] untuk mengelakkan sebarang kekeliruan dengan pengguna tanpa nama yang lain.''",
+       "anontalkpagetext": "<em>Ini ialah laman perbincangan bagi pengguna tanpa nama yang belum membuka akaun atau tidak menggunakannya.</em>\nOleh itu, kami terpaksa menggunakan alamat IP angka untuk mengenal pasti pengguna tersebut. Alamat IP ini boleh dikongsi oleh ramai pengguna.\nSekiranya anda ialah seorang pengguna tanpa nama dan berasa bahawa komen yang tidak relevan telah ditujukan kepada anda, sila [[Special:CreateAccount|buka akaun baru]] atau [[Special:UserLogin|log masuk]] untuk mengelakkan sebarang kekeliruan dengan pengguna tanpa nama yang lain.",
        "noarticletext": "Laman ini buat masa sekarang tidak berteks. Anda boleh [[Special:Search/{{PAGENAME}}|cari tajuk bagi laman ini]] dalam laman-laman lain, <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} cari log-log yang berkaitan], atau [{{fullurl:{{FULLPAGENAME}}|action=edit}} sunting laman ini]</span>.",
        "noarticletext-nopermission": "Tiada teks dalam laman ini ketika ini.\nAnda boleh [[Special:Search/{{PAGENAME}}|mencari tajuk laman ini]] dalam laman lain,\natau <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} mencari log yang berkaitan]</span>.",
        "missing-revision": "Semakan #$1 pada halaman \"{{FULLPAGENAME}}\" tidak wujud.\n\nHal ini biasanya disebabkan oleh pautan sejarah yang lapuk ke halaman yang sudah dihapuskan.\nButirannya boleh didapati di [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} log penghapusan].",
index 33f34cc..cbaa2e5 100644 (file)
        "navigation": "Nabegaçon",
        "and": "&#32;i",
        "faq": "FAQ",
+       "actions": "Açones",
        "namespaces": "Domínios",
        "variants": "Bariadades",
        "navigation-heading": "Menu de nabegaçon",
index aa9636f..79b5551 100644 (file)
        "rcfilters-preference-label": "Skjul den forbedrede versjonen av siste endringer",
        "rcfilters-preference-help": "Fjerner grensesnittendringen fra 2017 og alle verktøyene som ble lagt fra og med da.",
        "rcfilters-filter-showlinkedfrom-label": "Vis endringer på sider som lenkes fra",
-       "rcfilters-filter-showlinkedfrom-option-label": "Vis endringer på sider som lenkes <strong>FRA</strong> en side",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Sider som lenkes fra</strong> den valgte siden",
        "rcfilters-filter-showlinkedto-label": "Vis endringer på sider som lenker til",
-       "rcfilters-filter-showlinkedto-option-label": "Vis endringer på sider som lenker <strong>TIL</strong> en side",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Sider som lenker til</strong> den valgte siden",
        "rcfilters-target-page-placeholder": "Skriv inn et sidenavn",
        "rcnotefrom": "Nedenfor er vist {{PLURAL:$5|endringen|endringene}} som er gjort siden <strong>$3, $4</strong> (frem til <strong>$1</strong>).",
        "rclistfromreset": "Nullstill datovalg",
        "sp-contributions-hideminor": "Skjul mindre endringer",
        "sp-contributions-submit": "Søk",
        "sp-contributions-outofrange": "Kan ikke vise resultater. Det gitte IP-intervallet er større enn CIDR-grensen på /$1.",
-       "whatlinkshere": "Det som lenker hit",
+       "whatlinkshere": "Hva lenker hit",
        "whatlinkshere-title": "Sider som lenker til «$1»",
        "whatlinkshere-page": "Side:",
        "linkshere": "Følgende sider lenker til '''[[:$1]]''':",
        "tag-mw-replace-description": "Redigeringer som fjerner mer enn 90 % av innholdet på en side",
        "tag-mw-rollback": "Tilbakestilling",
        "tag-mw-rollback-description": "Redigeringer som tilbakestiller redigeringer med tilbakestillingsknappen",
+       "tag-mw-undo": "Endringsomgjøring",
+       "tag-mw-undo-description": "Redigeringer som fjerner tidligere redigeringer med lenka «{{int:editundo}}»",
        "tags-title": "Tagger",
        "tags-intro": "Denne siden lister opp taggene programvaren kan merke en endring med, og hva de betyr.",
        "tags-tag": "Taggnavn",
index b8d8b37..75d2fef 100644 (file)
        "rcfilters-preference-label": "Verberg de verbeterde versie van recente wijzigingen",
        "rcfilters-preference-help": "Zet het oude uiterlijk van de recente wijzigingen-pagina terug, inclusief alle hulpmiddelen die sindsdien zijn toegevoegd.",
        "rcfilters-filter-showlinkedfrom-label": "Toon wijzigingen op pagina's gekoppeld aan",
-       "rcfilters-filter-showlinkedfrom-option-label": "Toon wijzigingen op paginas gekoppeld <strong>AAN</strong> een pagina",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Paginas gekoppeld aan</strong> de geselecteerde pagina",
        "rcfilters-filter-showlinkedto-label": "Toon wijzigingen op pagina's gekoppeld naar",
-       "rcfilters-filter-showlinkedto-option-label": "Toon wijzigingen op pagina's gekoppeld <strong>NAAR</strong> een pagina",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Pagina's gekoppeld naar</strong> de geselecteerde pagina",
        "rcfilters-target-page-placeholder": "Voer een paginanaam in",
        "rcnotefrom": "Wijzigingen sinds <strong>$3 om $4</strong> (maximaal <strong>$1</strong> {{PLURAL:$1|wijziging|wijzigingen}}).",
        "rclistfromreset": "Datum selectie opnieuw instellen",
        "tag-mw-replace-description": "Bewerkingen die meer dan 90% van de pagina verwijderen",
        "tag-mw-rollback": "Terugdraaiing",
        "tag-mw-rollback-description": "Bewerkingen die eerdere bewerkingen terugdraaien door middel van de koppeling \"terugdraaien\"",
+       "tag-mw-undo": "Ongedaan maken",
+       "tag-mw-undo-description": "Bewerkingen die vorige bewerkingen door middel van de ongedaan maken koppeling ongedaan maken",
        "tags-title": "Labels",
        "tags-intro": "Op deze pagina staan de labels waarmee de software iedere bewerking kan markeren, en hun betekenis.",
        "tags-tag": "Labelnaam",
index 3c8451c..68bca8a 100644 (file)
        "parser-template-loop-warning": "Wykryto pętlę w szablonie [[$1]]",
        "template-loop-category": "Strony z pętlami szablonów",
        "template-loop-category-desc": "Strona zawiera pętlę szablonów, czyli szablon, który wywołuje sam siebie rekursywnie.",
+       "template-loop-warning": "<strong>Ostrzeżenie:</strong> Ta strona wywołuje [[:$1]], co tworzy pętlę szablonu (nieskończone wywołanie rekurencyjne).",
        "parser-template-recursion-depth-warning": "Przekroczno limit głębokości rekurencji szablonu ($1)",
        "language-converter-depth-warning": "Przekroczono ograniczenie ($1) głębokości zagnieżdżenia konwersji językowej",
        "node-count-exceeded-category": "Strony, gdzie przekroczono liczbę węzłów",
        "uploadbtn": "Prześlij plik",
        "reuploaddesc": "Przerwij wysyłanie i wróć do formularza wysyłki",
        "upload-tryagain": "Zapisz zmieniony opis pliku",
+       "upload-tryagain-nostash": "Prześlij ponownie przesłany plik i zmodyfikowany opis",
        "uploadnologin": "Nie jesteś zalogowany",
        "uploadnologintext": "Musisz $1 przed przesłaniem plików.",
        "upload_directory_missing": "Katalog dla przesyłanych plików ($1) nie istnieje i nie może zostać utworzony przez serwer WWW.",
        "file-deleted-duplicate-notitle": "Plik jest identyczny z plikiem, który został wcześniej usunięty, a jego nazwa została ukryta. Należy poprosić kogoś z możliwością przeglądania ukrytych danych, aby przeanalizował sytuację przed przystąpieniem do jego ponownego przesłania.",
        "uploadwarning": "Ostrzeżenie o przesyłaniu",
        "uploadwarning-text": "Zmień poniższy opis pliku i spróbuj ponownie.",
+       "uploadwarning-text-nostash": "Ponownie prześlij plik, zmodyfikuj poniższy opis i spróbuj ponownie.",
        "savefile": "Zapisz plik",
        "uploaddisabled": "Przesyłanie plików wyłączone",
        "copyuploaddisabled": "Przesyłanie poprzez podanie adres URL jest wyłączone.",
        "uploadstash-exception": "Nie udało się zapisać przesyłanego pliku w magazynie tymczasowym ($1): „$2”.",
        "uploadstash-bad-path": "Ścieżka nie istnieje.",
        "uploadstash-bad-path-invalid": "Ścieżka jest nieprawidłowa.",
+       "uploadstash-bad-path-unknown-type": "Nieznany typ „$1”.",
+       "uploadstash-file-not-found-no-thumb": "Nie można uzyskać miniaturki.",
+       "uploadstash-file-not-found-no-local-path": "Brak lokalnej ścieżki dla skalowanego elementu.",
+       "uploadstash-file-not-found-no-object": "Nie można utworzyć lokalnego obiektu pliku dla miniatury.",
+       "uploadstash-file-not-found-no-remote-thumb": "Nie udało się pobrać miniatury: $1\nURL = $2",
        "uploadstash-file-not-found-missing-content-type": "Brakuje nagłówka content-type.",
+       "uploadstash-file-too-large": "Nie można wyświetlić pliku większego niż $1 bajtów.",
+       "uploadstash-not-logged-in": "Użytkownik nie jest zalogowany, a pliki muszą należeć do użytkowników.",
+       "uploadstash-wrong-owner": "Ten plik ($1) nie należy do bieżącego użytkownika.",
+       "uploadstash-no-extension": "Rozszerzenie ma wartość zerową.",
+       "uploadstash-zero-length": "Plik ma zerowy rozmiar.",
        "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.",
        "sp-contributions-newonly": "Pokazuj tylko edycje tworzące nową stronę",
        "sp-contributions-hideminor": "Ukryj drobne zmiany",
        "sp-contributions-submit": "Szukaj",
+       "sp-contributions-outofrange": "Nie można wyświetlić żadnych wyników. Żądany zakres IP jest większy niż limit CIDR równy /$1.",
        "whatlinkshere": "Linkujące",
        "whatlinkshere-title": "Strony linkujące do „$1”",
        "whatlinkshere-page": "Strona:",
        "ipb_blocked_as_range": "Błąd – adres IP $1 nie został zablokowany bezpośrednio i nie może zostać odblokowany.\nNależy on do zablokowanego zakresu adresów $2. Odblokować można tylko cały zakres.",
        "ip_range_invalid": "Niepoprawny zakres adresów IP.",
        "ip_range_toolarge": "Zakresy IP większe niż /$1 są niedozwolone.",
+       "ip_range_exceeded": "Zakres IP przekracza zakres maksymalny. Dozwolony zakres to /$1.",
        "proxyblocker": "Blokowanie proxy",
        "proxyblockreason": "Twój adres IP został zablokowany, ponieważ jest to adres otwartego proxy.\nO tym poważnym problemie dotyczącym bezpieczeństwa należy poinformować dostawcę Internetu lub pomoc techniczną.",
        "sorbsreason": "Twój adres IP znajduje się na liście serwerów open proxy w DNSBL, używanej przez {{GRAMMAR:B.lp|{{SITENAME}}}}.",
        "newtitle": "Nowy tytuł:",
        "move-watch": "Obserwuj",
        "movepagebtn": "Przenieś stronę",
-       "pagemovedsub": "Przeniesienie się powiodło",
+       "pagemovedsub": "Przeniesienie powiodło się",
        "movepage-moved": "'''„$1” została przeniesiona do „$2”'''",
        "movepage-moved-redirect": "Zostało utworzone przekierowanie.",
        "movepage-moved-noredirect": "Nie zostało utworzone przekierowanie.",
        "tag-mw-replace-description": "Edycja, która usuwa ponad 90% zawartości strony",
        "tag-mw-rollback": "Wycofanie zmian",
        "tag-mw-rollback-description": "Edycja, która przywraca poprzednią wersję przy użyciu funkcji cofania zmian (rollback)",
+       "tag-mw-undo": "Cofnij",
        "tags-title": "Znaczniki",
        "tags-intro": "Na tej stronie znajduje się lista znaczników, którymi oprogramowanie może oznaczyć edycje, oraz ich opisy.",
        "tags-tag": "Nazwa znacznika",
index 079b425..a757afc 100644 (file)
        "anontalkpagetext": "----''دا د يوه ورکنومي کارن چې کارن-نوم نه لري او يا خپل کارن-نوم نه کاروي، د سکالو يوه پاڼه ده. نو د يوه کس د پېژندلو پخاطر موږ د هماغه کارن د انټرنېټ شمېره يا IP پته دلته ثبتوؤ. داسې يوه IP پته د ډېرو کارنانو لخوا هم کارېدلی شي. که تاسې يو ورکنومی کارن ياست او تاسې ته دا څرگندېږي چې تاسې ته نااړونده پېغامونه او تبصرې اشاره شوي، نو د نورو بې نومو کارنانو او ستاسې ترمېنځ د ټکنتوب د مخ نيونې لپاره لطفاً [[Special:CreateAccount|يو گڼون جوړ کړۍ]] او يا هم [[Special:UserLogin|غونډال ته ورننوځۍ]].''",
        "noarticletext": "دم مهال په دې مخ کې څه نشته.\nتاسې کولای شی چې په نورو مخونو کې [[Special:Search/{{PAGENAME}}|د دې مخ د سرليک پلټنه]]،\n<span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} د اړوندو يادښتونو پلټنه] ،\nاو يا [{{fullurl:{{FULLPAGENAME}}|action=edit}} همدا مخ جوړ کړئ]</span>.",
        "noarticletext-nopermission": "دم مهال په دې مخ کې متن نشته.\nتاسې کولای شی چې [[Special:Search/{{PAGENAME}}|همدا سرليک په نورو مخونو کې وپلټۍ]]، يا هم <span class=\"plainlinks\">[{{fullurl:{{#Special:Log}}|page={{FULLPAGENAMEE}}}} اړونده يادښتونه وپلټۍ]</span>، خو تاسې د دې مخ د جوړولو اجازه نه لرۍ.",
+       "missing-revision": "سمون #$1 د «{{FULLPAGENAME}}» څخه شتون نه لري.\n\nدا عموما د ړنگ شوي مخ د تاریخ لپاره د لینک لاندینۍ پيښې سره تړاو لري.\nکولای شي نور معلومات [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} ړنګ شوي] ساحه کې پيدا کړي.",
        "userpage-userdoesnotexist": "د \"<nowiki>$1</nowiki>\" گڼون نه دی ثبت شوی.\nلطفاً ځان ډاډه کړئ چې آيا تاسې په رښتيا همدا مخ جوړول/سمول غواړئ.",
        "userpage-userdoesnotexist-view": "د \"$1\" گڼون نه دی ثبت شوی.",
        "blocked-notice-logextract": "دم مهال په دې کارن بنديز لگېدلی.\nد بنديز يادښت تازه مالومات په لاندې توگه دي:",
        "userjspreview": "'''هېر مو نشي چې دا يوازې ستاسې د کارن د جاوا سکرېپټ آزمېيل/مخليدنه ده.'''\n'''تر اوسه پورې لا ستاسې بدلونونه نه دي خوندي شوي!'''",
        "sitecsspreview": "'''په پام کې دې وي چې دا يوازې ستاسې د CSS مخليدنه ده.'''\n'''تر اوسه پورې لا ستاسې بدلونونه نه دي خوندي شوي!'''",
        "sitejspreview": "'''په پام کې مو اوسه چې تاسې يوازې د دغه جاواسکرېپټ کوډ مخليدنه کوۍ.'''\n'''تر اوسه پورې دا نه دی خوندي شوی!'''",
+       "userinvalidcssjstitle": "<strong>خبرداری:</strong>دلته  هیڅ پوست نشته \"$1\".\nد ګمرکونو .ثي اس اس او .ج س مخونه  کوچني سرلیک استعمالوي، او داسې نور. {{ns:user}}:Foo/vector.css  که مخالف وي نو {{ns:user}}:Foo/Vector.css.",
        "updated": "(تازه)",
        "note": "'''يادونه:'''",
        "previewnote": "'''هېر مو نه شي چې دا يواځې يوه مخليدنه ده.'''\nستاسې لخوا ترسره شوي بدلونونه لا تر اوسه پورې نه دي خوندي شوي!!",
        "continue-editing": "د سمولو سيمې ته ورتلل",
+       "previewconflict": "دا غوښتنه د متن د سمون په سیمه کې متن منعکس کوي ځکه چې دا به هلته ښکاره شي چي تاسو يي د خوندي کولو لپاره غوره کړئ.",
+       "session_fail_preview": "وبخښي! موږ د سیشن ډاټا د ضایع کيدلو له امله ستاسو سمون ندی ترسره کړي..\n\nکېدی شي تاسو د سيسټم څخه وتلي ياست. <strong>لطفا تایید کړئ چې تاسو لا تر اوسه ننوتلي یاست او کړنه بیا ترسره کړئ</strong>.\nکه دا تراوسه لا هم کار نه کوي، نو بيا يو ځل [[Special:UserLogout|د دي ځای څخه ووځي]] او بيرته راننوځي، او ډاډه کړئ چې ستاسو براؤزر اجازه لري چې د دې سایټ څخه کوکیز ترلاسه کړي.",
+       "session_fail_preview_html": "وبخښي! موږ د سیشن ډاټا د ضایع کيدلو له امله ستاسو سمون ندی ترسره کړي..\n\n<em>ځکه د {{SITENAME}} اي ټي ام ال لين بند کړل شوي وو،  وړاندې کول د جاواسکرېپ بریدونو په وړاندې د احتیاط په توګه پټ شوي.</em>\n\n<strong>که دا د قانوني سمونې هڅه وي، لطفا بیا هڅه وکړئ.</strong>\nکه دا تراوسه لا هم کار نه کوي، نو بيا يو ځل [[Special:UserLogout|د دي ځای څخه ووځي]] او بيرته راننوځي، او ډاډه کړئ چې ستاسو براؤزر اجازه لري چې د دې سایټ څخه کوکیز ترلاسه کړي.",
+       "token_suffix_mismatch": "<strong>ستاسو سمون ونه منل شو ځکه چې ستاسو مراجع د تفتیش په نښه کې د تکرار تورو نښې نښانې کړي.</strong>\nدا سمون د پاڼې د ټکو د فساد مخنیولو لپاره ونه منل شوه.\nدا کله پېښ شي چې تاسو د ګوتو ویب سایټ پریمین پراکسي خدمت کاروئ.",
+       "edit_form_incomplete": "<strong>د سمون فورم ځینې برخې وانه وښتي; دوه ځله يي وګورئ چې ستاسو سمونونه پاتي دي او بیا هڅه وکړئ.</strong>",
        "editing": "د $1 سمونه",
        "creating": "$1 جوړېدنې کې دی",
        "editingsection": "$1 (برخه) په سمېدنې کې دی",
        "editingcomment": "د $1 سمون (نوې برخه)",
        "editconflict": "په سمولو کې خنډ: $1",
+       "explainconflict": "بل چا په دې مخ کي هغه وخت سمون راوست چې تاسو هم په سمون اخته وست.\nد مخ په ساحه کې دا  متن شامل دي ځکه چې دا اوس مهال شتون لري.\nستاسو بدلونونه په لاندې متن کې ښودل شوي.\nتاسو باید خپل بدلونونه په موجوده متن کې ضمیمه کړئ..\n<strong>يوازې</strong> د متن په ساحه کې به متن هغه وخت خوندي شي کله چې تاسو دلته  \"$1\" کليک کړي.",
        "yourtext": "ستاسې متن",
        "storedversion": "زېرمه شوې مخکتنه",
        "yourdiff": "توپيرونه",
        "grant-editpage": "شته مخونه سمول",
        "grant-editprotected": "ژغورلي مخونه سمول",
        "grant-highvolume": "د لوړ حجم سمون",
-       "grant-oversight": "د Ú©Ø§Ø±Ù\88Ù\88Ù\86Ú©Ù\88 Ù¾Ù¼Ù\88Ù\84 Ø§Ù\88 Ø¨Û\8cا Ú©ØªÙ\86Ù\87 Ú©Ù\88Ù\84",
+       "grant-oversight": "د Ú©Ø§Ø±Ù\88Ù\88Ù\86Ú©Ù\88 Ù¾Ù¼Ù\88Ù\84 Ø¯ Ù\87غÙ\88Ù\8a Ø¯ Ø³Ù\85Ù\88Ù\86Ù\88 Ø³Ø±Ù\87",
        "grant-patrol": "د مخونو بدلونونه ګزمه کړي",
        "grant-privateinfo": "شخصي معلوماتو ته لاسرسۍ",
+       "grant-protect": "د مخونو ژغورنه او ژغورنه لري کونه",
+       "grant-rollback": "د مخونو بدلونونه راګرځونکي",
        "grant-sendemail": "نورو کارنانو ته برېښليک لېږل",
+       "grant-uploadeditmovefile": "پورته کول، د دوتنو لیږد او بدلونه",
        "grant-uploadfile": "نوې دوتنې پورته کول",
        "grant-basic": "بنسټيزې رښتې",
+       "grant-viewdeleted": "ړنګ شوي دوتنې او مخونه کتونکي",
        "grant-viewmywatchlist": "خپل کتنلړ کتل",
+       "grant-viewrestrictedlogs": "محدود شوي ننوتلي ثبتونې وګورئ",
        "newuserlogpage": "د کارن-نوم د جوړېدو يادښت",
        "newuserlogpagetext": "دا د کارن-نوم د جوړېدو يادښت دی",
        "rightslog": "د کارن رښتو يادښت",
        "apisandbox-request-time": "د غوښتنې وخت: {{PLURAL:$1|$1 م.ث}}",
        "apisandbox-continue": "پرله پورې",
        "apisandbox-continue-clear": "سپينول",
+       "apisandbox-multivalue-all-values": "د $1 (ټول ارزښتونه)",
        "booksources": "د کتاب سرچينې",
        "booksources-search-legend": "د کتابي سرچينو پلټنه",
        "booksources-isbn": "ISBN:",
        "listgrouprights-namespaceprotection-namespace": "نوم-تشيال",
        "listgrouprights-namespaceprotection-restrictedto": "د کارن سمون ترسره کولو رښته(رښتې)",
        "listgrants": "منلې",
+       "listgrants-grant": "منلې",
        "listgrants-rights": "رښتې",
        "trackingcategories": "موندونکې وېشنيزې",
        "trackingcategories-summary": "په دې مخ کې هغه موندونکې وېشنيزې چې په اتوماتيک ډول د مېډياويکي ساوترې لخوا ډکېږي، د لړليک په توگه راغلي. د وېشنيزو نومونه د اړونده غونډال پيغامونو په بدلون سره چې د {{ns:8}} په نومتشيال کې دي، د بدلېدلو وړتيا لري.",
        "rollbacklinkcount": "$1 {{PLURAL:$1|سمون|سمونونه}} پرشابېول",
        "editcomment": "د سمون لنډيز دا وو: \"''$1''\".",
        "changecontentmodel-title-label": "مخ سرليک",
+       "changecontentmodel-model-label": "د نوي مېنځپانگې موډل",
        "changecontentmodel-reason-label": "سبب:",
        "changecontentmodel-submit": "بدلول",
        "logentry-contentmodel-change-revertlink": "په څټ گرځول",
        "whatlinkshere-hideimages": "د دوتنې تړنې $1",
        "whatlinkshere-filters": "چاڼگرونه",
        "whatlinkshere-submit": "ورځه",
+       "autoblockid": "خپلواک بنديز #$1",
        "block": "په کارن بنديز لگول",
        "unblock": "کارن له بنديزه وېستل",
        "blockip": "په {{GENDER:$1|کارن}} بنديز لگول",
        "ipbhidename": "کارن-نوم له سمون او لړليکونو پټول",
        "ipbwatchuser": "د دې کارن د خبرو اترو مخ او کارن مخ کتل",
        "ipb-disableusertalk": "د بنديز لگېدو سره دې د کارن د خبرو اترو مخ د سمولو مخنيوی هم پلي شي",
+       "ipb-change-block": "د کارن څخه بنديز لرې کول ددغو امستنې له لارې",
        "ipb-confirm": "د بنديز تاييد",
        "badipaddress": "ناسمه IP پته",
        "blockipsuccesssub": "بنديز په برياليتوب سره ولگېده",
        "blockipsuccesstext": "په [[Special:Contributions/$1|$1]] بنديز لگېدلی.<br />\nد بنديزونو د څارلو لپاره [[Special:BlockList|بنديز لړليک]] وگورۍ.",
+       "ipb-blockingself": "تاسو پر خپل ځان د بنديز لګولو په حال کې یاست! ایا تاسو ډاډه یاست چې تاسو دا کار کول غواړئ؟",
        "ipb-edit-dropdown": "د بنديز سببونه سمول",
        "ipb-unblock-addr": "له $1 بنديز ليرې کول",
        "ipb-unblock": "له يوه کارن-نوم يا IP پتې بنديز ليري کول",
        "unblocked-range": "له $1 بنديز ليرې شو",
        "unblocked-ip": "له [[Special:Contributions/$1|$1]] څخه بنديز ليرې شو.",
        "blocklist": "بنديز لگېدلي کارنان",
+       "autoblocklist": "خپلواک بنديزونه",
        "autoblocklist-submit": "پلټل",
+       "autoblocklist-legend": "د خپلواک بنديزونو لړليک",
+       "autoblocklist-localblocks": "ځایي {{PLURAL:$1|خپلواک بنديز|خپلواک بنديزونه}}",
+       "autoblocklist-total-autoblocks": "د خپلواک بنديز ټول لړليک: $1",
+       "autoblocklist-empty": "د بنديز لړليک تش دی",
+       "autoblocklist-otherblocks": "نور {{PLURAL:$1|خپلواک بنديز|خپلواک بنديزونه}}",
        "ipblocklist": "بنديز لگېدلي کارنان",
        "ipblocklist-legend": "يو بنديز شوی کارن موندل",
        "blocklist-userblocks": "گڼون بنديزونه پټول",
        "blocklist-tempblocks": "لنډمهاله بنديزونه پټول",
        "blocklist-addressblocks": "يواځې آی پي بنديزونه پټول",
+       "blocklist-rangeblocks": "پټ اندازه بنديزونه",
        "blocklist-timestamp": "وخت ټاپه",
        "blocklist-target": "موخه",
        "blocklist-expiry": "پای نېټه",
        "blocklist-by": "بنديز لگونکی پازوال",
+       "blocklist-params": "بنديز  پاراميټرونه",
        "blocklist-reason": "سبب",
        "ipblocklist-submit": "پلټل",
        "ipblocklist-localblock": "سيمه ايز بنديز",
        "infiniteblock": "نامحدوده",
        "expiringblock": "په $1 نېټه، $2 بجو پای ته رسېږي",
        "anononlyblock": "يواځې ورکنومی",
+       "noautoblockblock": "خپلواک بنديز ترسره نشو",
        "createaccountblock": "په گڼون جوړولو بنديز لگېدلی",
        "emailblock": "پر برېښليک بنديز ولگېد",
        "blocklist-nousertalk": "د خبرواترو خپل مخ نه شی سمولای",
        "ipblocklist-empty": "د بنديز لړليک تش دی",
+       "ipblocklist-no-results": "پر غوښتل شوي آي پي پتې باندې بنديز نه دي لګول شوي.",
        "blocklink": "بنديز لگول",
        "unblocklink": "بنديز لرې کول",
        "change-blocklink": "د بنديز بدلون",
        "unblocklogentry": "بنديز ليرې شو $1",
        "block-log-flags-anononly": "يواځې ورکنومي کارنان",
        "block-log-flags-nocreate": "د گڼون جوړول ناچارن شوی",
+       "block-log-flags-noautoblock": "خپلواک بنديز ترسره نشو",
        "block-log-flags-noemail": "ددې برېښليک مخه نيول شوی",
        "block-log-flags-nousertalk": "خپل د خبرو اترو مخ نه شي سمولای",
        "block-log-flags-hiddenname": "پټ کارن-نوم",
+       "ipb_expiry_invalid": "د پاي ته رسيدو وخت غلط دی.",
+       "ipb_expiry_old": "د پای ته رسېدو وخت په تېرمهال کې دی.",
        "ipb_already_blocked": "پر \"$1\" د پخوا نه بنديز دی",
        "ipb-needreblock": "پر $1 د پخوا نه بنديز لگېدلی.\nآيا تاسې د امستنو بدلول غواړۍ؟",
        "ipb-otherblocks-header": "{{PLURAL:$1|بل بنديز|نور بنديزونه}}",
        "imported-log-entries": "$1 {{PLURAL:$1|يادښتليک راوړل شوی|يادښتليکونه راوړل شوي}}.",
        "importcantopen": "واردونکې دوتنه و نه پرانيستل شوه.",
        "importbadinterwiki": "ناسمه ويکيخپلمنځي تړنه",
+       "importsuccess": "راليږل بشپړ شوه!",
+       "import-noarticle": "د رالېږدولو لپاره مخونه نشته.",
        "import-upload": "د XML اومتوک پورته کول",
-       "import-token-mismatch": "د اومتوک غونډېدنه له لاسه وتلې.\n\nتاسو شاید په نښه شوي وي. لطفا ډاډ ترلاسه کړئ چې ته ننوځئ او بیا بیا هڅه وکړه.\nکه تاسو د سیسټم څخه یو ځل بیا پیغام ترلاسه کړئ چي [[Special:UserLogout|ووځي]]، بيا ننوځي، و از این‌ که او ډاډه کړئ چې ستاسو براؤزر اجازه لري چې د دې سایټ څخه کوکیز ترلاسه کړي.",
+       "import-token-mismatch": "د اومتوک غونډېدنه له لاسه وتلې.\n\nتاسو شاید په نښه شوي وي. لطفا ډاډ ترلاسه کړئ چې ته ننوځئ او بیا بیا هڅه وکړه.\nکه تاسو د سیسټم څخه یو ځل بیا پیغام ترلاسه کړئ چي [[Special:UserLogout|ووځي]]، بيا ننوځي، او ډاډه کړئ چې ستاسو براؤزر اجازه لري چې د دې سایټ څخه کوکیز ترلاسه کړي.",
        "importlogpage": "د واردولو يادښت",
        "import-logentry-upload-detail": "$1 {{PLURAL:$1|بڼه|بڼې}} راولېږدېدې",
        "javascripttest": "د جاوا سکرېپټ آزمېښت",
        "siteuser": "د {{SITENAME}} کارن $1",
        "anonuser": "د {{SITENAME}} ورکنومی کارن $1",
        "lastmodifiedatby": "دا مخ وروستی ځل د $3 لخوا په $2، $1 بدلون موندلی.",
+       "othercontribs": "نور کار پر بنسټ",
        "others": "نور",
        "siteusers": "د {{SITENAME}} {{PLURAL:$2|کارن|کارنان}} $1",
        "anonusers": "د {{SITENAME}} {{PLURAL:$2|ورکنومی کارن|ورکنومي کارنان}} $1",
        "exif-objectname": "لنډ سرليک",
        "exif-headline": "سرليک",
        "exif-source": "سرچينه",
+       "exif-urgency": "بیړنی حالت",
+       "exif-fixtureidentifier": "د ثابتولو نوم",
+       "exif-locationdest": "ځای ښودل شوی",
+       "exif-locationdestcode": "د موقعیت کوډ ښودل شوی",
+       "exif-objectcycle": "د ورځې وخت چې رسنۍ اراده لري",
        "exif-contact": "د اړيکو مالومات",
        "exif-writer": "ليکوال",
        "exif-languagecode": "ژبه",
+       "exif-iimversion": "د IIM بڼه",
        "exif-iimcategory": "وېشنيزه",
+       "exif-iimsupplementalcategory": "ضمیمه وېشنيزه",
        "exif-datetimeexpires": "مه يې کاروۍ وروسته له",
        "exif-datetimereleased": "خپرېدلی په",
        "exif-identifier": "پېژندنه",
        "exif-serialnumber": "د کامرې پرله پسې شمېره",
        "exif-cameraownername": "د کامرې خاوند",
        "exif-label": "نښکه",
+       "exif-rating": "درجه (له ۵ څخه بهر)",
        "exif-copyrighted": "د رښتو دريځ",
        "exif-copyrightowner": "د رښتو خاوند",
        "exif-usageterms": "د کارولو شرايط",
        "exif-pngfilecomment": "د PNG دوتنې تبصره",
        "exif-disclaimer": "ردادعاليک",
+       "exif-contentwarning": "د منځپانګي خبرداری",
        "exif-giffilecomment": "د GIF دوتنې تبصره",
+       "exif-intellectualgenre": "د توکو ډول",
+       "exif-subjectnewscode": "د موضوع کوډ",
+       "exif-scenecode": "د اي پي ثي ټي(IPTC) منظر کوډ",
+       "exif-event": "پيښه ښودل شوي",
+       "exif-organisationinimage": "سازمان ښودل شوي",
        "exif-personinimage": "شخص ښودل شوی",
        "exif-copyrighted-true": "په رښتو سمبال",
        "exif-copyrighted-false": "د خپراوي د رښتو دريځ نه دی ټاکل شوی",
        "exif-photometricinterpretation-1": "تور او سپين (تور 0 دی)",
        "exif-unknowndate": "ناڅرگنده نېټه",
        "exif-orientation-1": "نورمال",
+       "exif-orientation-3": "څرخيدونکي °١٨٠",
+       "exif-orientation-4": "چورليځه اړونه",
+       "exif-orientation-5": "څرخيدونکي °٩٠ CCW او عمودی یې وویشل",
+       "exif-orientation-6": "څرخيدونکي °٩٠ CCW",
        "exif-componentsconfiguration-0": "نشته دی",
        "exif-exposureprogram-1": "لارښوونيز",
        "exif-exposureprogram-2": "نورماله پروگرام",
        "exif-meteringmode-1": "منځالی",
        "exif-meteringmode-3": "سپوټ",
        "exif-meteringmode-5": "مخبېلگه",
+       "exif-meteringmode-6": "برخيز",
        "exif-meteringmode-255": "نور",
        "exif-lightsource-0": "ناجوت",
        "exif-lightsource-1": "د ورځې رڼا",
        "exif-lightsource-9": "ښه هوا",
        "exif-lightsource-10": "ورېځ پوښلې هوا",
        "exif-lightsource-11": "سيوری",
+       "exif-lightsource-12": "ورځنې فلوروسینټ (ډالر ۵۷۰۰ – ۷۱۰۰ زره)",
+       "exif-lightsource-17": "معياري رڼا '''ا'''",
+       "exif-lightsource-18": "معياري رڼا '''ب'''",
+       "exif-lightsource-19": "معياري رڼا '''ث'''",
        "exif-lightsource-255": "د رڼا بله سرچينه",
        "exif-flash-fired-0": "فلش و نه ځلېده",
        "exif-flash-mode-3": "خپلکاره حالت",
        "version-other": "بل",
        "version-hooks": "کونډۍ",
        "version-hook-name": "کونډۍ نوم",
+       "version-hook-subscribedby": "سبسکرايبيدنه لخوا د",
        "version-version": "($1)",
        "version-no-ext-name": "[بې نومه]",
        "version-license": "مېډياويکي منښتليک",
        "version-ext-colheader-description": "څرگندونه",
        "version-ext-colheader-credits": "ليکوالان",
        "version-license-title": "د $1 منښتليک",
+       "version-credits-title": "د کریډیټ د $1 لپاره",
        "version-poweredby-credits": "دا ويکي د '''[https://www.mediawiki.org/ مېډياويکي]''' په سېک چلېږي، ټولې رښتې خوندي دي © 2001-$1 $2.",
        "version-poweredby-others": "نور",
        "version-poweredby-translators": "د translatewiki.net ژباړنان",
        "tag-filter": "[[Special:Tags|نښلن]] چاڼگر:",
        "tag-filter-submit": "چاڼگر",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|نښلن|نښلنونه}}]]: $2)",
+       "tag-mw-blank": "بسته بندي",
+       "tag-mw-replace": "ځايناستول",
+       "tag-mw-rollback": "په شابېول",
+       "tag-mw-undo": "ناکړل",
        "tags-title": "نښلنونه",
        "tags-tag": "نښلن نوم",
        "tags-display-header": "د بدلون په لړليکونو کې ښکارېدنه",
        "tags-deactivate-submit": "نافعالول",
        "tags-edit-title": "نښلنونه سمول",
        "tags-edit-manage-link": "نښلنونه مهارول",
+       "tags-edit-existing-tags": "شته ټګونه:",
        "tags-edit-existing-tags-none": "<em>هېڅ</em>",
        "tags-edit-new-tags": "نوي نښلنونه:",
        "tags-edit-add": "دا نښلنونه ورگډول:",
        "tags-edit-remove-all-tags": "(ټول نښلنونه غورځول)",
        "tags-edit-chosen-placeholder": "ځينې نښلنونه ټاکل",
        "tags-edit-reason": "سبب:",
+       "tags-edit-success": "بدلونونه تطبيق شوي دي.",
+       "tags-edit-failure": "بدلونونه کارول نشي تطبيق کيداي:\n$1",
+       "tags-edit-nooldid-title": "ناباوره پيښنليک ته اشاره",
+       "tags-edit-nooldid-text": "تاسو د کوم هدف بیا کتنه نده مشخصه کړې چې دا فعالیت ترسره کړي، یا مشخصه بیاکتنه شتون نلري.",
+       "tags-edit-none-selected": "مهرباني وکړئ لږترلږه یو ٹیګ غوره یا لرې کړئ.",
        "comparepages": "مخونه پرتلل",
        "compare-page1": "۱ مخ",
        "compare-page2": "۲ مخ",
        "compare-invalid-title": "کوم سرليک مو چې ځانگړی کړی ناسم دی.",
        "compare-title-not-exists": "کوم سرليک مو چې ځانگړی کړی نشته.",
        "compare-revision-not-exists": "کومه مخکتنه مو چې ځانگړې کړې نشته.",
+       "diff-form": "توپيرونه",
+       "diff-form-oldid": "د زړي بیاکتنې پيژندګلوي (اختیاري)",
+       "diff-form-revid": "د بیاکتنې د پيژندګلوي توپیر",
+       "diff-form-submit": "توپيرونه ښکاره کول",
+       "permanentlink": "تلپاتې تړنه",
+       "permanentlink-revid": "د بیاکتنې پيژندګلوي",
+       "permanentlink-submit": "بیاکتنې ته ولاړ شي",
        "dberr-problems": "اوبخښۍ! دم مهال دا وېبپاڼه د تخنيکي ستونزو سره مخامخ شوې.",
        "dberr-usegoogle": "تاسې کولای شی چې هم مهاله د گووگل له لخوا هم د پلټنې هڅه وکړۍ.",
        "htmlform-invalid-input": "ستاسې ځينې ورکړېينې ستونزې لري",
        "htmlform-cloner-create": "نور ورگډول",
        "htmlform-cloner-delete": "غورځول",
        "htmlform-cloner-required": "لږ تر لږه يو ارزښت ته اړتيا شته.",
+       "htmlform-date-placeholder": "کککک-م م-و و",
+       "htmlform-time-placeholder": "HH:MM:SS",
+       "htmlform-datetime-placeholder": "YYYY-MM-DD HH:MM:SS",
+       "htmlform-date-invalid": "هغه ارزښت چې تاسو یې مشخص کړی د پېژندل شوې نیټه ندی. د YYYY-MM-DD بڼه کارولو هڅه وکړئ.",
+       "htmlform-time-invalid": "هغه ارزښت چې تا مشخص کړی د پېژندل شوي وخت ندی. کارولو هڅه وکړي HH:MM:SS .",
+       "htmlform-datetime-invalid": "هغه ارزښت چې تا مشخص شوی د پېژندل شوې نیټې او وخت ندی. د YYYY-MM-DD HH کارولو هڅه وکړئ: MM: SS بڼه.",
+       "htmlform-date-toolow": "هغه ارزښت چې تاسو یې مشخص کړی وي د پیل څخه مخکې د $1 نیټې څخه مخکې وي.",
+       "htmlform-date-toohigh": "هغه ارزښت چې تاسو یې مشخص کړی وي د $1 وروستی نیټې نیټې وروسته دی.",
+       "htmlform-time-toolow": "هغه ارزښت چې تاسو یې مشخص کړی وي د ترټولو ترټولو غوره وخت د $1 وخت دی.",
+       "htmlform-time-toohigh": "هغه ارزښت چې تاسو یې مشخص کړی وي د $1 وروستیو وختونو څخه وروسته وي.",
+       "htmlform-datetime-toolow": "هغه ارزښت چې تاسو یې مشخص کړئ د پیل نیټه او د $1 وخت څخه مخکې وي.",
+       "htmlform-title-badnamespace": "[[:$1]] په \"{{ns:$2}}\" کي نشته.",
+       "htmlform-title-not-creatable": "\"$1\" مخ د جوړېدو وړ سرليک نه دی",
        "htmlform-title-not-exists": "$1 نشته.",
        "htmlform-user-not-exists": "<strong>$1</strong> نشته.",
+       "htmlform-user-not-valid": "<strong>$1</strong> یو باوري کارن نوم نه دی.",
        "logentry-delete-delete": "$1 د $3 مخ {{GENDER:$2|ړنگ کړ}}",
        "logentry-delete-restore": "$1 د $3 مخ $4 ته {{GENDER:$2|ولېږداوه}}",
        "logentry-delete-revision": "$1 {{GENDER:$2|بدل شو}} لیدل د{{PLURAL:$5|a هيسټري|$5 هيسټري}} په مخ کي $3: $4",
        "revdelete-content-hid": "مېنځپانگه پټېدلې",
+       "revdelete-summary-hid": "پټ سمون لنډیز",
        "revdelete-uname-hid": "کارن نوم پټ شوی",
        "revdelete-content-unhid": "مېنځپانگه ښکاره شوی",
+       "revdelete-summary-unhid": "ښکاره سمون لنډیز",
        "revdelete-uname-unhid": "ښکاره کارن-نوم",
+       "revdelete-restricted": "پازوالانو ته پلي شوي محدوديتونه",
+       "revdelete-unrestricted": "د پازوالانو لپاره لیرې شوي بندیزونه",
+       "logentry-block-block": "$1 تر $5 $6 نيټې پورې پر {{GENDER:$4|$3}} باندې {{GENDER:$2|بنديز}} ولګوي",
+       "logentry-block-unblock": "$1 د {{GENDER:$4|$3}} څخه {{GENDER:$2|بنديز}} لري کړ",
+       "logentry-suppress-block": "$1 تر $5 $6 نيټې پورې پر {{GENDER:$4|$3}} باندې {{GENDER:$2|بنديز}} ولګوي",
+       "logentry-suppress-reblock": "$1 تر $5 $6 نيټې پورې پر {{GENDER:$4|$3}} باندې {{GENDER:$2|بنديز}} بدلون وموند",
+       "logentry-import-upload": "$1 $3 د دوتنې اپلوډ له لارې {{GENDER:$2|واردکړ}}",
        "logentry-move-move": "$1 د $3 مخ $4 ته {{GENDER:$2|ولېږداوه}}",
        "logentry-move-move-noredirect": "$1 پرته له دې چې يو مخ گرځونی پرېږدي له $3 څخه $4 ته مخ {{GENDER:$2|ولېږداوه}}",
        "logentry-move-move_redir": "$1 د $3 مخ $4 ته د مخ گرځونې له لارې {{GENDER:$2|ولېږداوه}}.",
        "logentry-newusers-create": "د $1 کارن گڼون {{GENDER:$2|جوړ شو}}",
        "logentry-newusers-autocreate": "د $1 گڼون په اتوماتيک ډول {{GENDER:$2|جوړ شو}}",
        "logentry-protect-unprotect": "$1 له $3 څخه ژغورنه {{GENDER:$2|ليرې کړه}}",
+       "logentry-protect-protect": "$1 د $3 مخ {{GENDER:$2|وژغوره}} $4",
+       "logentry-protect-protect-cascade": "$1 {{GENDER:$2|وژغورل شو}} $3 $4 [کڅوړی]",
+       "logentry-protect-modify": "$1 د $3 د ژغورلو کچه {{GENDER:$2|بدله کړه}} $4",
+       "logentry-protect-modify-cascade": "$1 د $3 ژغورنې په کچه کي {{GENDER:$2|بدلون راوست}} و $4 [کالیډیډنګ]",
        "logentry-rights-rights": "$1 د $3 لپاره د غړيتوب ډله له $4 څخه $5 ته {{GENDER:$2|بدله کړه}}",
        "logentry-rights-rights-legacy": "$1 د $3 لپاره د غړيتوب ډله {{GENDER:$2|بدله کړه}}",
        "logentry-upload-upload": "$1 $3 {{GENDER:$2|ورپورته يې کړ}}",
        "logentry-upload-overwrite": "$1 نوي ويرژن {{GENDER:$2|پورته}} سو $3",
        "logentry-upload-revert": "$1 $3 يې {{GENDER:$2|ورپورته کړه}}",
        "log-name-managetags": "د نښلن مهارولو يادښت",
+       "logentry-managetags-create": "$1 {{GENDER:$2|د}} د ټګ \"$4\" جوړ کړ",
        "log-name-tag": "نښلن يادښت",
        "rightsnone": "(هېڅ)",
        "rightslogentry-temporary-group": "$1 (لنډمهاله، تر $2)",
index 44e8dd5..7bb87c6 100644 (file)
        "tag-mw-replace-description": "Edições que removem mais de 90% do conteúdo de uma página",
        "tag-mw-rollback": "Reverter",
        "tag-mw-rollback-description": "Edições que revertem edições anteriores usando o link de reversão",
+       "tag-mw-undo": "Desfazer",
+       "tag-mw-undo-description": "Edições que desfazem edições anteriores usando o link de desfazer",
        "tags-title": "Etiquetas",
        "tags-intro": "Esta página lista as etiquetas com que o software poderá marcar uma edição, e o seu significado.",
        "tags-tag": "Nome da etiqueta",
index bb12e08..cf2d6e2 100644 (file)
        "tagline": "Da wiki {{SITENAME}}",
        "help": "Ajuda",
        "search": "Pesquisa",
-       "search-ignored-headings": " #<!-- deixe esta linha exatamente como ela está --> <pre>\n# Títulos de página que serão ignorados pela pesquisa.\n# Mudanças a esta lista terão efeito quando a página com o título referido for indexada.\n# Pode forçar a indexação de uma página realizando uma edição nula nessa página.\n# A sintaxe é a seguinte:\n#  * Tudo desde um símbolo de cardinal (#) até ao fim da linha é um comentário\n#  * Cada linha não vazia é o título exato a ignorar, respeitando o uso de maiúsculas\nReferências\nLinks externos\nVer também\n #</pre> <!-- deixe esta linha exatamente como ela está -->",
+       "search-ignored-headings": " #<!-- deixe esta linha exatamente como ela está --> <pre>\n# Títulos de página que serão ignorados pela pesquisa.\n# Mudanças a esta lista terão efeito quando a página com o título referido for indexada.\n# Pode forçar a indexação de uma página realizando uma edição nula nessa página.\n# A sintaxe é a seguinte:\n#  * Tudo desde um símbolo de cardinal (#) até ao fim da linha é um comentário\n#  * Cada linha não vazia é o título exato a ignorar, respeitando o uso de maiúsculas\nReferências\nHiperligações externas\nVer também\n #</pre> <!-- deixe esta linha exatamente como ela está -->",
        "searchbutton": "Pesquisar",
        "go": "Prosseguir",
        "searcharticle": "Ir",
        "title-invalid-magic-tilde": "O título de página solicitado contém uma sequência de tis inválida (<nowiki>~~~</nowiki>).",
        "title-invalid-too-long": "O título de página solicitado é demasiado longo. Não pode exceder $1 {{PLURAL:$1|byte|bytes}} em codificação UTF-8.",
        "title-invalid-leading-colon": "O título de página solicitado contém um sinal de dois pontos (:) inválido no início.",
-       "perfcached": "Os seguintes dados encontram-se armazenados na ''cache'' e podem não estar atualizados. {{PLURAL:$1|Está disponível na ''cache'' um máximo de um resultado|Estão disponíveis na ''cache'' um máximo de $1 resultados}}.",
-       "perfcachedts": "Os seguintes dados encontram-se armazenados na ''cache'' e foram atualizados pela última vez a $1. {{PLURAL:$4|Está disponível na ''cache'' um máximo de um resultado|Estão disponíveis na ''cache'' um máximo de $4 resultados}}.",
+       "perfcached": "Os seguintes dados encontram-se armazenados na cache e podem não estar atualizados. {{PLURAL:$1|Está disponível na cache um máximo de um resultado|Estão disponíveis na cache um máximo de $1 resultados}}.",
+       "perfcachedts": "Os seguintes dados estão na cache e foram atualizados pela última vez a $1. {{PLURAL:$4|Está disponível na cache um máximo de um resultado|Estão disponíveis na cache um máximo de $4 resultados}}.",
        "querypage-no-updates": "As atualizações estão presentemente desativadas para esta página.\nPor enquanto, os dados aqui presentes não poderão ser atualizados.",
        "viewsource": "Ver código-fonte",
        "viewsource-title": "Mostrar código-fonte de $1",
        "right-reupload-own": "Sobrescrever um ficheiro existente carregado pelo mesmo utilizador",
        "right-reupload-shared": "Sobrescrever localmente ficheiros no repositório partilhado de imagens",
        "right-upload_by_url": "Carregar um ficheiro de um endereço URL",
-       "right-purge": "Limpar a ''cache'' de uma página no servidor sem confirmação",
+       "right-purge": "Limpar a cache de uma página no servidor sem confirmação",
        "right-autoconfirmed": "Não ser afetado pelos limites de frequência de edição baseados em endereços IP",
        "right-bot": "Ser tratado como um processo automatizado",
        "right-nominornewtalk": "Não desencadear o aviso de mensagens novas ao fazer edições menores a páginas de discussão",
        "recentchanges-network": "Devido a uma falha técnica, não foi possível carregar nenhum resultado. Tente atualizar a página, por favor.",
        "recentchanges-notargetpage": "Introduza um nome de página acima para ver as alterações relacionadas a essa página.",
        "recentchanges-feed-description": "Acompanhe neste ''feed'' as mudanças mais recentes da wiki.",
-       "recentchanges-label-newpage": "Esta edição criou uma nova página",
+       "recentchanges-label-newpage": "Esta edição criou uma página nova",
        "recentchanges-label-minor": "Esta é uma edição menor",
        "recentchanges-label-bot": "Esta edição foi feita por um robô",
        "recentchanges-label-unpatrolled": "Esta edição ainda não foi patrulhada",
        "rcfilters-preference-label": "Ocultar a versão melhorada das mudanças recentes",
        "rcfilters-preference-help": "Reverte o redesenho da interface de 2017 e todas as ferramentas adicionadas na altura e desde então.",
        "rcfilters-filter-showlinkedfrom-label": "Mostrar mudanças de páginas para as quais esta página contém hiperligações",
-       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Páginas que contêm hiperligações</strong> da página selecionada",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Páginas para as quais</strong> a página selecionada contém hiperligações",
        "rcfilters-filter-showlinkedto-label": "Mostrar mudanças nas páginas que contêm hiperligações para",
        "rcfilters-filter-showlinkedto-option-label": "<strong>Páginas que contêm hiperligações</strong> para a página selecionada",
        "rcfilters-target-page-placeholder": "Introduzir o nome de uma página",
        "mostlinkedtemplates": "Páginas mais transcluídas",
        "mostcategories": "Páginas com mais categorias",
        "mostimages": "Ficheiros com mais afluentes",
-       "mostinterwikis": "Páginas com mais ligações interwikis",
+       "mostinterwikis": "Páginas com mais hiperligações interwikis",
        "mostrevisions": "Páginas com mais revisões",
        "prefixindex": "Todas as páginas iniciadas por",
        "prefixindex-namespace": "Todas as páginas com prefixo (domínio $1)",
        "apisandbox-fullscreen": "Expandir painel",
        "apisandbox-fullscreen-tooltip": "Expandir o painel da página de testes para preencher a janela do navegador.",
        "apisandbox-unfullscreen": "Mostrar página",
-       "apisandbox-unfullscreen-tooltip": "Reduza o painel da área de testes, para que as ligações de navegação estejam disponíveis.",
+       "apisandbox-unfullscreen-tooltip": "Reduza o painel da área de testes, para que as hiperligações de navegação do MediaWiki estejam disponíveis.",
        "apisandbox-submit": "Fazer o pedido",
        "apisandbox-reset": "Limpar",
        "apisandbox-retry": "Tentar novamente",
        "apisandbox-loading": "A carregar a informação do módulo API \"$1\"...",
        "apisandbox-load-error": "Ocorreu um erro ao carregar a informação do módulo API \"$1\": $2",
        "apisandbox-no-parameters": "Este módulo API não tem parâmetros.",
-       "apisandbox-helpurls": "Ligações de ajuda",
+       "apisandbox-helpurls": "Hiperligações de ajuda",
        "apisandbox-examples": "Exemplos",
        "apisandbox-dynamic-parameters": "Parâmetros adicionais",
        "apisandbox-dynamic-parameters-add-label": "Adicionar parâmetro:",
        "booksources": "Fontes bibliográficas",
        "booksources-search-legend": "Pesquisar fontes de livros",
        "booksources-search": "Pesquisar",
-       "booksources-text": "É apresentada abaixo uma lista de ligações para outros sítios na Internet que vendem livros novos e usados e talvez possuam informações adicionais sobre os livros que procura:",
+       "booksources-text": "É apresentada abaixo uma lista de hiperligações para outros sítios na Internet que vendem livros novos e usados e talvez possuam informações adicionais sobre os livros que procura:",
        "booksources-invalid-isbn": "O número ISBN fornecido não parece ser válido; verifique a existência de erros ao copiar da fonte original.",
-       "magiclink-tracking-rfc": "Páginas que usam links mágicos RFC",
-       "magiclink-tracking-rfc-desc": "Esta página usa links mágicos RFC. Consulte a [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] para saber como migrar.",
+       "magiclink-tracking-rfc": "Páginas que usam hiperligações mágicas RFC",
+       "magiclink-tracking-rfc-desc": "Esta página usa hiperligações mágicas RFC. Consulte a [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] para saber como migrar.",
        "magiclink-tracking-pmid": "Páginas que usam links mágicos PMID",
-       "magiclink-tracking-pmid-desc": "Esta página usa links mágicos PMID. Consulte a [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] para saber como migrar.",
+       "magiclink-tracking-pmid-desc": "Esta página usa hiperligações mágicas PMID. Consulte a [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] para saber como migrar.",
        "magiclink-tracking-isbn": "Páginas que usam links mágicos ISBN",
-       "magiclink-tracking-isbn-desc": "Esta página usa links mágicos ISBN. Consulte a [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] para saber como migrar.",
+       "magiclink-tracking-isbn-desc": "Esta página usa hiperligações mágicas ISBN. Consulte a [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:Magic_links mediawiki.org] para saber como migrar.",
        "specialloguserlabel": "Executante:",
        "speciallogtitlelabel": "Alvo (título ou página ou {{ns:user}}:nome de utilizador):",
        "log": "Registos",
        "deletedcontributions": "Edições eliminadas",
        "deletedcontributions-title": "Edições eliminadas",
        "sp-deletedcontributions-contribs": "contribuições",
-       "linksearch": "Pesquisa de ligações externas",
+       "linksearch": "Pesquisa de hiperligações externas",
        "linksearch-pat": "Padrão de pesquisa:",
        "linksearch-ns": "Domínio:",
        "linksearch-ok": "Pesquisar",
        "post-expand-template-inclusion-category-desc": "O tamanho da página é superior a <code>$wgMaxArticleSize</code>, após a expansão de todas as predefinições, pelo que algumas predefinições não foram expandidas.",
        "post-expand-template-argument-category-desc": "O tamanho da página é superior a <code>$wgMaxArticleSize</code>, após a expansão de um argumento de predefinição (algo em chavetas triplas, como <code>{{{Foo}}}</code>).",
        "expensive-parserfunction-category-desc": "A página tem demasiadas funções do analisador custosas (como <code>#ifexist</code>) incluídas. Consulte [https://www.mediawiki.org/wiki/Special:MyLanguage/Manual:$wgExpensiveParserFunctionLimit Manual:$wgExpensiveParserFunctionLimit].",
-       "broken-file-category-desc": "A página contém uma ligação quebrada para um ficheiro (uma ligação para incorporar um ficheiro que não existe).",
-       "hidden-category-category-desc": "Esta é uma categoria com a marca <code><nowiki>__HIDDENCAT__</nowiki></code>, que faz com que ela não apareça na caixa de ligações de categoria nas páginas, por omissão.",
+       "broken-file-category-desc": "A página contém uma hiperligação quebrada para um ficheiro (uma hiperligação para incorporar um ficheiro que não existe).",
+       "hidden-category-category-desc": "Esta é uma categoria com a marca <code><nowiki>__HIDDENCAT__</nowiki></code>, que faz com que ela não apareça na caixa de hiperligações de categoria nas páginas, por omissão.",
        "trackingcategories-nodesc": "Sem descrição disponível.",
        "trackingcategories-disabled": "A categoria está desativada.",
        "mailnologin": "Não existe endereço de envio",
        "undeleterevdel": "O restauro não será efetuado se resulta na remoção parcial da versão mais recente da página ou ficheiro.\nNestes casos, deverá desmarcar ou revelar a versão eliminada mais recente.",
        "undeletehistorynoadmin": "Esta página foi eliminada.\nO motivo de eliminação é apresentado no resumo abaixo, em conjunto com detalhes dos utilizadores que tinham editado esta página antes da sua eliminação.\nO texto atual destas edições eliminadas encontra-se agora apenas disponível para administradores.",
        "undelete-revision": "Edição eliminada da página $1 (das $5 de $4), por $3:",
-       "undeleterevision-missing": "Edição inválida ou não encontrada.\nPode ter usado uma ligação incorreta ou talvez a revisão tenha sido restaurada ou removida do arquivo.",
+       "undeleterevision-missing": "Edição inválida ou não encontrada.\nPode ter usado uma hiperligação incorreta ou talvez a revisão tenha sido restaurada ou removida do arquivo.",
        "undeleterevision-duplicate-revid": "Não foi possível restaurar {{PLURAL:$1|uma revisão|$1 revisões}}, porque {{PLURAL:$1|a sua <code>rev_id</code> já estava a ser usada|as respetivas <code>rev_id</code> já estavam a ser usadas}}.",
        "undelete-nodiff": "Não foram encontradas edições anteriores.",
        "undeletebtn": "Restaurar",
        "nolinkshere-ns": "Não existem afluentes para <strong>[[:$1]]</strong> no espaço nominal selecionado.",
        "isredirect": "página de redirecionamento",
        "istemplate": "inclusão",
-       "isimage": "ligação para ficheiro",
+       "isimage": "hiperligação para ficheiro",
        "whatlinkshere-prev": "{{PLURAL:$1|anterior|$1 anteriores}}",
        "whatlinkshere-next": "{{PLURAL:$1|próximo|próximos $1}}",
        "whatlinkshere-links": "← afluentes",
        "whatlinkshere-hideredirs": "$1 redirecionamentos",
        "whatlinkshere-hidetrans": "$1 transclusões",
-       "whatlinkshere-hidelinks": "$1 ligações",
+       "whatlinkshere-hidelinks": "$1 hiperligações",
        "whatlinkshere-hideimages": "$1 ligações para ficheiros",
        "whatlinkshere-filters": "Filtros",
        "whatlinkshere-submit": "Continuar",
        "selfmove": "O título é o mesmo;\nnão é possível mover uma página para ela mesma.",
        "immobile-source-namespace": "Não é possível mover páginas no domínio \"$1\"",
        "immobile-target-namespace": "Não é possível mover páginas para o domínio \"$1\"",
-       "immobile-target-namespace-iw": "Uma ligação interlíngua não é um destino válido para uma movimentação de página.",
+       "immobile-target-namespace-iw": "Uma hiperligação interwikis não é um destino válido para uma movimentação de página.",
        "immobile-source-page": "Esta página não pode ser movida.",
        "immobile-target-page": "Não é possível mover para esse título de destino.",
        "bad-target-model": "O destino pretendido usa um modelo de conteúdo diferente. Não é possível converter de $1 para $2.",
        "move-over-sharedrepo": "[[:$1]] já existe num repositório partilhado. Mover um ficheiro para o título [[:$1]] irá substituir o ficheiro partilhado.",
        "file-exists-sharedrepo": "O nome de ficheiro que escolheu já é utilizado num repositório partilhado.\nEscolha outro nome, por favor.",
        "export": "Exportar páginas",
-       "exporttext": "Pode exportar o texto e o histórico de edições de uma página em particular para um ficheiro XML. Poderá então importar esse conteúdo noutra wiki que utilize o programa MediaWiki, através da [[Special:Import|página de importações]].\n\nPara exportar páginas, introduza os títulos na caixa de texto abaixo (um título por linha) e selecione se deseja todas as versões, com as linhas de histórico de edições, ou apenas a edição atual e informações sobre a mais recente das edições.\n\nSe desejar, pode utilizar um link (por exemplo, [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] para a [[{{MediaWiki:Mainpage}}]]).",
+       "exporttext": "Pode exportar o texto e o histórico de edições de uma página em particular para um ficheiro XML. Poderá então importar esse conteúdo noutra wiki que utilize o programa MediaWiki, através da [[Special:Import|página de importações]].\n\nPara exportar páginas, introduza os títulos na caixa de texto abaixo (um título por linha) e selecione se deseja todas as versões, com as linhas de histórico de edições, ou apenas a edição atual e informações sobre a mais recente das edições.\n\nSe desejar, pode utilizar uma hiperligação (por exemplo, [[{{#Special:Export}}/{{MediaWiki:Mainpage}}]] para a [[{{MediaWiki:Mainpage}}]]).",
        "exportall": "Exportar todas as páginas",
        "exportcuronly": "Incluir apenas a edição atual, não o histórico completo",
        "exportnohistory": "----\n<strong>Nota:</strong> A exportação do histórico completo de páginas através deste formulário foi desativada por motivos de desempenho.",
        "importunknownsource": "Tipo da fonte de importação desconhecido",
        "importnoprefix": "Não foi fornecido nenhum prefixo interwikis",
        "importcantopen": "Não foi possível abrir o ficheiro a importar",
-       "importbadinterwiki": "Ligação interlíngua incorreta",
+       "importbadinterwiki": "Hiperligação interwikis incorreta",
        "importsuccess": "Importação completa!",
        "importnosources": "Não foram definidas as wikis das quais importar e o carregamento direto de históricos encontra-se desativado.",
        "importnofile": "Não foi carregado nenhum ficheiro de importação.",
        "tooltip-n-randompage": "Carregar página aleatória",
        "tooltip-n-help": "Um local reservado para auxílio.",
        "tooltip-t-whatlinkshere": "Lista de todas as páginas que contêm ligações para esta",
-       "tooltip-t-recentchangeslinked": "Mudanças recentes nas páginas para as quais esta contém ligação",
+       "tooltip-t-recentchangeslinked": "Mudanças recentes nas páginas para as quais esta contém hiperligações",
        "tooltip-feed-rss": "''Feed'' RSS desta página",
        "tooltip-feed-atom": "''Feed'' Atom desta página",
        "tooltip-t-contributions": "Ver as contribuições {{GENDER:$1|deste utilizador|desta utilizadora|deste(a) utilizador(a)}}",
        "tooltip-t-upload": "Carregar ficheiros",
        "tooltip-t-specialpages": "Lista de páginas especiais",
        "tooltip-t-print": "Versão para impressão desta página",
-       "tooltip-t-permalink": "Ligação permanente para esta versão da página",
+       "tooltip-t-permalink": "Hiperligação permanente para esta revisão da página",
        "tooltip-ca-nstab-main": "Ver a página de conteúdo",
        "tooltip-ca-nstab-user": "Ver a página de utilizador",
        "tooltip-ca-nstab-media": "Ver a página de multimédia",
        "creditspage": "Créditos da página",
        "nocredits": "Não há informação disponível sobre os créditos desta página.",
        "spamprotectiontitle": "Filtro de proteção contra spam",
-       "spamprotectiontext": "O texto que desejava gravar foi bloqueado pelo filtro de spam.\nEste bloqueio foi provavelmente causado por um link para um site externo que consta da lista negra.",
+       "spamprotectiontext": "O texto que pretendia gravar foi bloqueado pelo filtro de spam.\nEste bloqueio foi provavelmente causado por uma hiperligação para um ''site'' externo que está na lista negra.",
        "spamprotectionmatch": "O seguinte texto ativou o filtro de <i>spam</i>: $1",
        "spambot_username": "MediaWiki limpeza de spam",
        "spam_reverting": "A reverter para a última revisão que não contém ligação para $1",
-       "spam_blanking": "Todas as revisões continham ligações para $1; a esvaziar",
-       "spam_deleting": "Todas as revisões continham ligações para $1; a eliminar",
+       "spam_blanking": "Todas as revisões continham hiperligações para $1; a esvaziar",
+       "spam_deleting": "Todas as revisões continham hiperligações para $1; a eliminar",
        "simpleantispam-label": "Verificação contra spam.\n<strong>Não</strong> preencha isto!",
        "pageinfo-title": "Informações sobre \"$1\"",
        "pageinfo-not-current": "Desculpe, é impossível fornecer esta informação para revisões antigas.",
        "saturday-at": "Sábado às $1",
        "sunday-at": "Domingo às $1",
        "yesterday-at": "Ontem às $1",
-       "bad_image_list": "O formato é o seguinte:\n\nSó são reconhecidos elementos na forma de lista (linhas começadas por *).\nO primeiro link em cada linha deve apontar para o ficheiro que se pretende bloquear.\nQuaisquer outras ligações nessa mesma linha são considerados excepções (ou seja, páginas de onde se pode aceder ao ficheiro).",
+       "bad_image_list": "O formato é o seguinte:\n\nSó são reconhecidos elementos na forma de lista (linhas começadas por *).\nA primeira hiperligação em cada linha deve apontar para o ficheiro que se pretende bloquear.\nQuaisquer outras hiperligações nessa mesma linha são consideradas exceções (ou seja, páginas de onde se pode aceder ao ficheiro).",
        "metadata": "Metadados",
        "metadata-help": "Este ficheiro contém informação adicional, provavelmente acrescentada pela câmara digital ou pelo digitalizador usados para criá-lo.\nCaso o ficheiro tenha sido modificado a partir do seu estado original, alguns detalhes poderão não refletir completamente as mudanças efetuadas.",
        "metadata-expand": "Mostrar detalhes adicionais",
        "confirmemail_success": "O seu endereço de correio eletrónico foi confirmado.\nPode agora [[Special:UserLogin|autenticar-se]] e desfrutar da wiki.",
        "confirmemail_loggedin": "O seu endereço de correio eletrónico foi confirmado.",
        "confirmemail_subject": "Confirmação de endereço de correio eletrónico da wiki {{SITENAME}}",
-       "confirmemail_body": "Alguém, provavelmente você a partir do endereço IP $1,\nregistou uma conta \"$2\" com este endereço de correio eletrónico na wiki {{SITENAME}}.\n\nPara confirmar que esta conta é realmente sua e ativar\nas funcionalidades de correio eletrónico na wiki {{SITENAME}}, abra a seguinte ligação no seu navegador:\n\n$3\n\nSe a conta *não* é sua, abra a seguinte ligação para cancelar a confirmação do endereço de correio eletrónico:\n\n$5\n\nEste código de confirmação expira a $4.",
-       "confirmemail_body_changed": "Alguém, provavelmente você a partir do endereço IP $1,\nalterou o endereço de correio eletrónico da conta \"$2\" para este endereço, na wiki{{SITENAME}}.\n\nPara confirmar que esta conta é realmente sua e reativar\nas funcionalidades de correio eletrónico na wiki {{SITENAME}},\nabra a seguinte ligação no seu navegador:\n\n$3\n\nCaso a conta *não* lhe pertença, abra a seguinte ligação\npara cancelar a confirmação do endereço de correio eletrónico:\n\n$5\n\nEste código de confirmação expira a $4.",
-       "confirmemail_body_set": "Alguém, provavelmente você a partir do endereço IP $1,\ndefiniu o seu endereço de correio eletrónico como correio da conta \"$2\" na wiki {{SITENAME}}.\n\nPara confirmar que esta conta é realmente sua e reativar\nas funcionalidades de correio eletrónico na wiki {{SITENAME}},\nabra a seguinte ligação no seu navegador:\n\n$3\n\nCaso a conta *não* lhe pertença, abra a seguinte ligação\npara cancelar a confirmação do endereço de correio eletrónico:\n\n$5\n\nEste código de confirmação expira a $4.",
+       "confirmemail_body": "Alguém, provavelmente você a partir do endereço IP $1,\nregistou uma conta \"$2\" com este endereço de correio eletrónico na wiki {{SITENAME}}.\n\nPara confirmar que esta conta é realmente sua e ativar\nas funcionalidades de correio eletrónico na wiki {{SITENAME}}, abra a seguinte hiperligação no seu navegador:\n\n$3\n\nSe a conta *não* é sua, siga a seguinte hiperligação para cancelar a confirmação do endereço de correio eletrónico:\n\n$5\n\nEste código de confirmação expira a $4.",
+       "confirmemail_body_changed": "Alguém, provavelmente você a partir do endereço IP $1,\nalterou o endereço de correio eletrónico da conta \"$2\" para este endereço, na wiki{{SITENAME}}.\n\nPara confirmar que esta conta é realmente sua e reativar\nas funcionalidades de correio eletrónico na wiki {{SITENAME}},\nabra a seguinte hiperligação no seu navegador:\n\n$3\n\nCaso a conta *não* lhe pertença, siga a seguinte hiperligação\npara cancelar a confirmação do endereço de correio eletrónico:\n\n$5\n\nEste código de confirmação expira a $4.",
+       "confirmemail_body_set": "Alguém, provavelmente você a partir do endereço IP $1,\ndefiniu o seu endereço de correio eletrónico como correio da conta \"$2\" na wiki {{SITENAME}}.\n\nPara confirmar que esta conta é realmente sua e reativar\nas funcionalidades de correio eletrónico na wiki {{SITENAME}},\nabra a seguinte hiperligação no seu navegador:\n\n$3\n\nCaso a conta *não* lhe pertença, siga a seguinte hiperligação\npara cancelar a confirmação do endereço de correio eletrónico:\n\n$5\n\nEste código de confirmação expira a $4.",
        "confirmemail_invalidated": "Confirmação de endereço de correio eletrónico cancelada",
        "invalidateemail": "Cancelar confirmação do correio eletrónico",
        "notificationemail_subject_changed": "O endereço de correio eletrónico registado na wiki {{SITENAME}} foi alterado",
        "specialpages-group-developer": "Ferramentas de desenvolvimento",
        "blankpage": "Página em branco",
        "intentionallyblankpage": "Esta página foi intencionalmente deixada em branco",
-       "external_image_whitelist": " # Deixe esta linha exatamente como ela está<pre>\n# Coloque fragmentos de expressões regulares (apenas a parte entre //) abaixo\n# Estas serão comparadas com os URL das imagens externas (com ligação direta)\n# As que corresponderem serão apresentadas como imagens, caso contrário apenas será apresentado um link para a imagem\n# As linhas que começam com um símbolo de cardinal (#) são tratadas como comentários\n# Esta lista não distingue maiúsculas de minúsculas\n\n# Coloque todos os fragmentos de expressões regulares (regex) acima desta linha. Deixe esta linha exatamente como ela está</pre>",
+       "external_image_whitelist": " # Deixe esta linha exatamente como ela está<pre>\n# Coloque fragmentos de expressões regulares (apenas a parte entre //) abaixo\n# Estas serão comparadas com os URL das imagens externas (com ligação direta)\n# As que corresponderem serão apresentadas como imagens, caso contrário apenas será apresentada uma hiperligação para a imagem\n# As linhas que começam com um símbolo de cardinal (#) são tratadas como comentários\n# Esta lista não distingue maiúsculas de minúsculas\n\n# Coloque todos os fragmentos de expressões regulares (regex) acima desta linha. Deixe esta linha exatamente como ela está</pre>",
        "tags": "Etiquetas de modificação válidas",
        "tag-filter": "Filtro de [[Special:Tags|etiquetas]]:",
        "tag-filter-submit": "Filtrar",
        "tag-mw-changed-redirect-target": "Destino de redirecionamento alterado",
        "tag-mw-changed-redirect-target-description": "Edições que modificam o destino de um redirecionamento",
        "tag-mw-blank": "Esvaziamento",
-       "tag-mw-blank-description": "Edita que esvaziam uma página",
+       "tag-mw-blank-description": "Edições que esvaziam uma página",
        "tag-mw-replace": "Substituição",
        "tag-mw-replace-description": "Edições que removem mais de 90% do conteúdo de uma página",
        "tag-mw-rollback": "Reversão",
        "tag-mw-rollback-description": "Edições que revertem edições anteriores usando a hiperligação desfazer",
+       "tag-mw-undo": "Desfazer",
+       "tag-mw-undo-description": "Edições que desfazem edições anteriores usando a hiperligação «desfazer»",
        "tags-title": "Etiquetas de modificação válidas",
        "tags-intro": "Esta página lista as etiquetas com que o software poderá marcar uma edição, e o seu significado.",
        "tags-tag": "Nome da etiqueta",
        "diff-form-oldid": "Identificador de revisão antigo (opcional)",
        "diff-form-revid": "Identificador de revisão da diferença",
        "diff-form-submit": "Mostrar diferenças",
-       "permanentlink": "Link permanente",
+       "permanentlink": "Hiperligação permanente",
        "permanentlink-revid": "Identificador de revisão",
        "permanentlink-submit": "Ir para a revisão",
        "dberr-problems": "Desculpe! Este site está com dificuldades técnicas.",
        "json-error-recursion": "Uma ou mais referências recursivas no valor a ser codificado",
        "json-error-inf-or-nan": "Um ou mais valores NaN ou INF no valor a ser codificado",
        "json-error-unsupported-type": "Foi dado um valor de um tipo que não pode ser codificado",
-       "headline-anchor-title": "Ligação para esta secção",
+       "headline-anchor-title": "Hiperligação para esta secção",
        "special-characters-group-latin": "Latim",
        "special-characters-group-latinextended": "Latim expandido",
        "special-characters-group-ipa": "AFI (IPA)",
index 49ff907..5bf406b 100644 (file)
        "right-siteadmin": "блокировка и разблокировка базы данных",
        "right-override-export-depth": "экспортирование страниц, включая связанные страницы с глубиной до 5",
        "right-sendemail": "отправка электронной почты другим участникам",
+       "right-sendemail-new-users": "отправка электронной почты участникам без записей журналов",
        "right-managechangetags": "создание и (де)активация [[Special:Tags|меток]]",
        "right-applychangetags": "применение [[Special:Tags|меток]] вместе со своими правками",
        "right-changetags": "добавление и удаление произвольных [[Special:Tags|меток]] на отдельных правках и записях в журнале",
        "recentchanges-noresult": "Изменений в указанный период, соответствующих указанным условиям, нет.",
        "recentchanges-timeout": "Время ожидания этого поиска истекло. Вы можете попробовать задать другие параметры поиска.",
        "recentchanges-network": "Из-за технической ошибки результаты не могут быть загружены. Попробуйте обновить страницу.",
+       "recentchanges-notargetpage": "Введите название страницы выше, чтобы увидеть правки, связанные с этой страницей.",
        "recentchanges-feed-description": "Отслеживание последних изменений в вики.",
        "recentchanges-label-newpage": "Этой правкой была создана новая страница",
        "recentchanges-label-minor": "Это незначительное изменение",
        "rcfilters-watchlist-showupdated": "Изменения страниц, которые вы не посещали с того момента, как они изменились, выделены <strong>жирным</strong> и отмечены полным маркером.",
        "rcfilters-preference-label": "Скрыть улучшенную версию Последних изменений",
        "rcfilters-preference-help": "Откатывает редизайн интерфейса 2017 года и все инструменты, добавленные с тех пор.",
+       "rcfilters-filter-showlinkedfrom-label": "Показать правки на ссылаемых страницах",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Страницы, на которые ссылается</strong> выбранная",
+       "rcfilters-filter-showlinkedto-label": "Показать правки на ссылающихся страницах",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Страницы, ссылающиеся</strong> на выбранную",
        "rcfilters-target-page-placeholder": "Введите имя страницы",
        "rcnotefrom": "Ниже {{PLURAL:$5|указано изменение|перечислены изменения}} с <strong>$3, $4</strong> (показано не более <strong>$1</strong>).",
        "rclistfromreset": "Сбросить выбор даты",
        "uploadstash-bad-path-unrecognized-thumb-name": "Нераспознанное имя миниатюры.",
        "uploadstash-bad-path-no-handler": "Не найден обработчик для mime-типа $1 файла $2.",
        "uploadstash-bad-path-bad-format": "Ключ «$1» — в неподходящем формате.",
+       "uploadstash-file-not-found": "Ключ «$1» не найден во временном хранилище.",
        "uploadstash-file-not-found-no-thumb": "Не удалось получить миниатюру.",
+       "uploadstash-file-not-found-no-local-path": "Не найдено локального пути к отмасштабированному изображению.",
        "uploadstash-file-not-found-no-object": "Не удалось создать объект локального файла для миниатюры.",
        "uploadstash-file-not-found-no-remote-thumb": "Извлечение эскиза не удалось: $1\nURL = $2",
        "uploadstash-file-not-found-missing-content-type": "Отсутствует заголовок content-type.",
+       "uploadstash-file-not-found-not-exists": "Путь не найден или файл непонятен.",
        "uploadstash-file-too-large": "Невозможно обработать файл размером более $1 байт.",
+       "uploadstash-not-logged-in": "Нет авторизованных участников, файлы должны принадлежать участникам.",
        "uploadstash-wrong-owner": "Этот файл ($1) не принадлежит текущему участнику.",
+       "uploadstash-no-such-key": "Нет ключа ($1), удаление невозможно.",
        "uploadstash-no-extension": "Пустое расширение.",
        "uploadstash-zero-length": "Файл нулевой длины.",
        "invalid-chunk-offset": "Недопустимое смещение фрагмента",
        "upload-disallowed-here": "Вы не можете перезаписать этот файл.",
        "filerevert": "Возврат к старой версии $1",
        "filerevert-legend": "Возвратить версию файла",
-       "filerevert-intro": "<span class=\"plainlinks\">Вы возвращаете '''[[Media:$1|$1]]''' к [$4 версии от $3, $2].</span>",
+       "filerevert-intro": "Вы возвращаете <strong>[[Media:$1|$1]]</strong> к [$4 версии от $3, $2].",
        "filerevert-comment": "Причина:",
        "filerevert-defaultcomment": "Возврат к версии от $2, $1 ($3)",
        "filerevert-submit": "Возвратить",
        "filedelete": "$1 — удаление",
        "filedelete-legend": "Удалить файл",
        "filedelete-intro": "Вы собираетесь удалить файл '''[[Media:$1|$1]]''' со всей его историей.",
-       "filedelete-intro-old": "<span class=\"plainlinks\">Вы удаляете версию '''[[Media:$1|$1]]''' от [$4 $3, $2].</span>",
+       "filedelete-intro-old": "Вы удаляете версию <strong>[[Media:$1|$1]]</strong> от [$4 $3, $2].",
        "filedelete-comment": "Причина:",
        "filedelete-submit": "Удалить",
        "filedelete-success": "'''$1''' был удалён.",
        "import-mapping-subpage": "Импортировать как подстраницы следующей страницы:",
        "import-upload-filename": "Имя файла:",
        "import-upload-username-prefix": "Префиксы интервики:",
+       "import-assign-known-users": "Связать правки с локальными участниками, когда участники с такими именами существуют.",
        "import-comment": "Примечание:",
        "importtext": "Пожалуйста, экспортируйте страницу из исходной вики, используя [[Special:Export|соответствующий инструмент]]. Сохраните файл на диск, а затем загрузите его сюда.",
        "importstart": "Импортирование страниц…",
        "imported-log-entries": "{{PLURAL:$1|Импортирована $1 запись|Импортированы $1 записи|Импортировано $1 записей}} журнала.",
        "importfailed": "Не удалось импортировать: $1",
        "importunknownsource": "Неизвестный тип импортируемой страницы",
+       "importnoprefix": "Не указан префикс интервики",
        "importcantopen": "Невозможно открыть импортируемый файл",
        "importbadinterwiki": "Неправильная интервики-ссылка",
        "importsuccess": "Импортирование выполнено!",
        "tag-mw-replace-description": "Правки, которые удаляют более 90 % содержимого страницы",
        "tag-mw-rollback": "откат",
        "tag-mw-rollback-description": "Правки, которые откатывают предыдущие правки по нажатию ссылки отката",
+       "tag-mw-undo": "отмена",
+       "tag-mw-undo-description": "Правки, отменяющие предыдущие с помощью ссылки «отменить»",
        "tags-title": "Метки",
        "tags-intro": "На этой странице приведён список меток, которыми программное обеспечение отмечает правки, а также значения этих меток.",
        "tags-tag": "Имя метки",
index b889bd4..0cd11fe 100644 (file)
        "cannotdelete": "$1 نالي صفحو يا فائيل ڊهي نہ سگھيو. ٿي سگھي ٿو تہ ڪنهن ان کي اڳ ۾ ئي ڊاهي ڇڏيو هجي.",
        "cannotdelete-title": "$1 نالي صفحي کي ڊاهي نہ ٿا سگھون.",
        "badtitle": "خراب عنوان",
-       "badtitletext": "صفحي جو گھربل عنوان ڪار ڪونهي، يا خالي آهي، يا وري غيردرست طريقي سان ڳنڍيل بين‌الزباني يا بين‌الوڪي عنوان آهي. \nان ۾ هڪ يا هڪ کان وڌيڪ اهڙا اکر موجود آهن، جيڪي عنوان ۾ استعمال ڪري نہ ٿا سگھجن.",
-       "title-invalid-utf8": "صفحي جي ڄاڻايل عنوان ۾ ناقابل ڪار يُو ٽِي ايف اکر شامل آهن.",
-       "title-invalid-interwiki": "ڄاڻايل عنوان ۾ اهڙو بين‌الوڪِي ڳنڍڻو شامل آهي، جيڪو عنوانن ۾ استعمال ڪري نہ ٿو سگھجي.",
-       "title-invalid-characters": "صفحي جي ڄاڻايل عنوان ۾ ناقابل ڪار اکر شامل آهن: $1",
-       "title-invalid-leading-colon": "صفحي جي ڄاڻايل عنوان جي ابتدا ۾ ناقابل ڪار ڪالن شامل آهي.",
+       "badtitletext": "صفحي جو گھربل عنوان ڪار ڪونهي، يا خالي آهي، يا وري غيردرست طريقي سان ڳنڍيل بين‌الزباني يا بين‌الوڪي عنوان آهي. \nان ۾ هڪ يا هڪ کان وڌيڪ اهڙا اکر موجود آهن، جيڪي عنوان ۾ استعمال ڪري نٿا سگھجن.",
+       "title-invalid-utf8": "صفحي جي ڄاڻايل عنوان ۾ ناقابلِڪار يُو ٽِيئيف-8 ترتيب شامل آھي.",
+       "title-invalid-interwiki": "ڄاڻايل عنوان ۾ اهڙو بين‌الوڪِي ڳنڍڻو شامل آهي، جيڪو عنوانن ۾ استعمال ڪري نٿو سگھجي.",
+       "title-invalid-characters": "صفحي جي ڄاڻايل عنوان ۾ ناقابلِڪار اکر شامل آهن: \"$1\".",
+       "title-invalid-leading-colon": "صفحي جي ڄاڻايل عنوان جي ابتدا ۾ ناقابلِڪار ڪالن شامل آهي.",
        "viewsource": "ڪوڊ ڏسو",
        "viewsource-title": "$1 جو ڪوڊ ڏسو",
-       "protectedpagetext": "هيءُ صفحو ترميمن کان تحفظيل آهي.",
-       "viewsourcetext": "توهان هن صفحي جو ڪوڊ ڏسي ۽ نقل ڪري سگھو ٿا:",
-       "namespaceprotected": "توهان کي نانءُ پولار '''$1''' جا صفحا سنوارڻ جا اختيار ناهن.",
+       "protectedpagetext": "هيءُ صفحو ترميمن ۽ ٻين عملن کان بچائڻ لاءِ تحفظيل آهي.",
+       "viewsourcetext": "توهان هن صفحي جو ڪوڊ ڏسي ۽ نقل ڪري سگھو ٿا.",
+       "namespaceprotected": "توهان کي نانءُپولار <strong>$1</strong> جا صفحا سنوارڻ جا اختيار ناهن.",
        "mycustomcssprotected": "توهان کي هيءُ CSS صفحو سنوارڻ جي اجازت نہ آهي.",
        "mycustomjsprotected": "توهان کي هيءُ جاوا اسڪرپٽ صفحو سنوارڻ جي اجازت حاصل ڪانهي.",
        "myprivateinfoprotected": "توهان کي پنهنجي ذاتي معلومات سنوارڻ جي اجازت حاصل نہ آهي.",
        "virus-unknownscanner": "اڻڄاتل نِس وائرس:",
        "cannotlogoutnow-title": "ھاڻي خارج نٿو ٿي سگھجي",
        "cannotlogoutnow-text": "$1 استعمال ڪرڻ دوران خارج ٿيڻ ممڪن نہ آھي.",
-       "welcomeuser": "ڀلي ڪري آيا، $1!",
+       "welcomeuser": "ڀليڪار، $1!",
        "yourname": "واپرائيندڙ-نانءُ:",
        "userlogin-yourname": "واپرائيندڙ-نانءُ",
        "userlogin-yourname-ph": "پنھنجو يوزرنانءُ ڄاڻايو",
        "nosuchusershort": "\"$1\" نالي ڪو بہ واپرائيندڙ ناهي.\nپنھنجي هِجي جي پڪ ڪندا.",
        "nouserspecified": "توهان کي ڪو واپرائيندڙ-نان‎ءُ ڄاڻائڻو پوندو.",
        "login-userblocked": "هيءُ واپرائيندڙ بندشيل آهي. داخل ٿيڻ جي اجازت نٿي ڏجي.",
-       "wrongpassword": "ڏنل ڳجھولفظ غير درست آهي. مھرباني ڪري ٻيھر ڪوشش ڪندا.",
+       "wrongpassword": "ڏنل واپرائيندڙ-نانءُ يا ڳجھولفظ غير درست آهي.\nمھرباني ڪري ٻيھر ڪوشش ڪندا.",
        "wrongpasswordempty": "ڏنل ڳجھولفظ خالي هو.\nمهرباني ڪري وري ڪوشش ڪندا.",
        "passwordtooshort": "ڳجھولفظ گھٽ ۾ گھٽ  {{PLURAL:$1|1 اکر|$1 اکرَن}} تي ٻڌل هوڻ گھرجي.",
        "passwordtoolong": "ڳجھولفظ {{PLURAL:$1|1 اکر|$1 اکرن}} کان وڏو نٿو ٿي سگھي.",
        "login-abort-generic": "توهان جو داخل ٿيڻ ناڪام ويو - بند ڪيل",
        "login-migrated-generic": "توهان جو کاتو لڏي چڪو آهي، ۽ هن وڪيءَ تي توهان جو واپرائيندڙ-نان‎ءُ هاڻي وجود نٿو رکي.",
        "loginlanguagelabel": "ٻولي: $1",
-       "createacct-another-realname-tip": "اصل نالو ڄاڻائڻ اختياري آهي. جيڪڏهن توهان اصل نالو ڄاڻايو ٿا، تہ اهو توهان کي توهان جي ڪم جي مڃتا ڏيڻ لاءِ ڪم آندو ويندو.",
+       "createacct-another-realname-tip": "اصل نالو ڄاڻائڻ اختياري آھي.\nجيڪڏھن توھان اھو ڄاڻائڻ چونڊيو ٿا، تہ اھو واپرائيندڙ کي انھن جي ڪم جي مڃتا ڏيڻ لاءِ ڪم آندو ويندو.",
        "pt-login": "داخل ٿيو",
        "pt-login-button": "داخل ٿيو",
        "pt-login-continue-button": "داخل ٿيڻ جاري رکو",
        "pt-createaccount": "کاتو کوليو",
        "pt-userlogout": "خارج ٿيو",
-       "php-mail-error-unknown": "پي ايڇ پي جي  ڪاڄ اندر اڻڄاتل چُڪَ.",
+       "php-mail-error-unknown": "پي ايڇ پي جي  ڪاڄ() اندر اڻڄاتل چُڪَ.",
        "user-mail-no-addy": "برقٽپال پتو ڄاڻائڻ کان سواءِ برقٽپال اماڻڻ جي ڪوشش ڪئي وئي.",
        "changepassword": "ڳجھولفظ تبديل ڪريو",
        "resetpass_announce": "داخل ٿيڻ جو عمل پورو ڪرڻ لاءِ، توهان کي نئون ڳجھولفظ اختيار مقرر ڪرڻو پوندو.",
        "botpasswords-label-create": "سرجيو",
        "botpasswords-label-update": "تجديد",
        "botpasswords-label-cancel": "رد",
-       "botpasswords-label-delete": "ڊاهيو",
+       "botpasswords-label-delete": "ڊاھيو",
        "botpasswords-label-resetpassword": "ڳجھولفظ ٻيھر مقرر ڪريو",
        "botpasswords-label-grants-column": "منظور",
        "botpasswords-bad-appid": "بوٽ نانءُ \"$1\" قابلِڪار ناھي.",
        "passwordreset": "ڳجھولفظ مَٽايو",
        "passwordreset-text-one": "برقٽپال ذريعي عارضي ڳجھولفظ حاصل ڪرڻ لاءِ هيءُ فارم پُر ڪريو.",
        "passwordreset-disabled": "هن وڪيءَ تي ڳجھولفظ ٻيھر مقرر ڪرڻ وارو چارو غير فعال بڻايو ويو آهي.",
-       "passwordreset-emaildisabled": "هن وڪيءَ تي برق‌ٽپال واريون خصوصيتون غير فعال بڻايون ويون آهن.",
+       "passwordreset-emaildisabled": "ھن وڪيءَ تي برق‌ٽپال واريون خصوصيتون غير فعال بڻايون ويون آهن.",
        "passwordreset-username": "واپرائيندڙ-نانءُ:",
        "passwordreset-domain": "ميدان:",
        "passwordreset-email": "برقٽپال پتو:",
        "bold_sample": "گھري لکت",
        "bold_tip": "گھري لکت",
        "italic_sample": "ترڇي لکت",
-       "italic_tip": "ترڇي لکت",
+       "italic_tip": "ٽيڏي لکت",
        "link_sample": "ڳنڍڻي جو عنوان",
        "link_tip": "داخلي ڳنڍڻو",
        "extlink_sample": "http://www.example.com ڳنڍڻي جو عنوان",
        "showdiff": "تبديليون ڏيکاريو",
        "anoneditwarning": "<strong>چتاءُ:</strong> توھان داخل ٿيل نہ آھيو. توھان جو آءِپي پتو عوامي طور ظاھر ٿيندو جي توھان ڪي ترميمون ڪريو ٿا. جيڪڏھن توھان <strong>[$1 داخل ٿيو]</strong> ٿا يا <strong>[$2 کاتو کوليو]</strong> ٿا، تہ ٻين فائدن سان گڏ توھان جون ترميمون توھان جي يوزرنانءَ سان منسوب ڪيون وينديون.",
        "anonpreviewwarning": "توهان داخل ٿيل نہ آهيو. جيڪڏهن توهان صفحي ۾ تبديليون سانڍيون تہ اهڙين تبديلين ساڻ توهان جو آءِپي پتو درج ڪيو ويندو.",
-       "missingcommenttext": "براءِ مھرباني هيٺ پنهنجو تاثر درج ڪندا.",
+       "missingcommenttext": "براءِ مھرباني ڪو تاثر درج ڪندا.",
        "summary-preview": "تت جي پيش نگاھ:",
        "subject-preview": "موضوع جي پيش نگاھ:",
        "blockedtitle": "واپرائيندڙ بندشيل آهي",
        "editingsection": "ترميم ھيٺ $1 (سيڪشن)",
        "editingcomment": "ترميم هيٺ $1 (نئون سيڪشن)",
        "editconflict": "ترميمي تڪرار: $1",
-       "yourtext": "تÙ\88Ù\87اÙ\86 Ø¬Ù\88 Ù½Ù\8aڪسٽ",
+       "yourtext": "تÙ\88Ù\87اÙ\86 Ø¬Ù\88 Ù\85تÙ\86",
        "storedversion": "سانڍيل مسودو",
        "yourdiff": "تفاوت",
        "copyrightwarning": "ياد رکندا ته {{SITENAME}} لاءِ سموريون ڀاڱيداريون $2 تحت پڌريون ڪجن ٿيون (تفصيلن لاءِ $1 ڏسندا). اوهان جي تحرير کي {{SITENAME}} جي قائدن تحت ترميمي سگهجي ٿو. جيڪڏهن اوهان نه ٿا چاهيو ته اوهان جي لکڻين کي بي رحميءَ سان ترميميو وڃي يا ورهائي عام ڪيو وڃي ته پوءِ پنهنجي لکڻي هتي جمع نه ڪرايو. پنهنجو مواد هتي جمع ڪرڻ جو مطلب هوندو ته توهان کي جمع ڪرايل مواد جي مفت فراهمي ۽ کُليل تبديليءَ تي ڪو به اعتراز ناهي.<br />\nتوهان اهڙي پڪ ڏيڻ جا پابند پڻ آهيو ته توهان جو جمع ڪرايل مواد توهان جو پنهنجو لکيل آهي يا وري توهان ڪنهن مفت وسيلي تان ڪاپي ڪيو آهي.\n'''تحفظيل حق ۽ واسطا رکندڙ مواد واسطيدار مالڪ کان اڳواٽ اجازت وٺڻ کان سواءِ هتي جمع نه ڪريو.'''",
        "timezoneregion-europe": "يُورپ",
        "timezoneregion-indian": "سنڌي ساگر",
        "timezoneregion-pacific": "ماٺو ساگر",
-       "allowemail": "Ù»Ù\8aÙ\86 Ù\8aÙ\8fÙ\88زرس Ú©Ø§Ù\86 Ø§Ù\8aÙ\86دÚ\99 Ù½Ù¾Ø§Ù\84 Ø¨Ø­Ø§Ù\84 ÚªØ±يو",
+       "allowemail": "Ù»Ù\8aÙ\86 Ù\88اپرائÙ\8aÙ\86دÚ\99Ù\86 Ú©Ù\8a Ù\85Ù\88Ù\86 Ú\8fاÙ\86Ú¾Ù\86 Ø¨Ø±Ù\82ٽپاÙ\84 ÚªØ±Ú» Ø¬Ù\8a Ø§Ø¬Ø§Ø²Øª Ú\8fيو",
        "prefs-searchoptions": "ڳولا",
        "prefs-namespaces": "نانءُپولار",
        "default": "ڏنل",
        "rcfilters-quickfilters": "سانڍيل ڇاڻيون",
        "rcfilters-savedqueries-defaultlabel": "سانڍيل ڇاڻيون",
        "rcfilters-restore-default-filters": "ڏنل ڇاڻيون ريسٽور ڪريو",
-       "rcfilters-search-placeholder": "تازÙ\8aÙ\88Ù\86 ØªØ¨Ø¯Ù\8aÙ\84Ù\8aÙ\88Ù\86 Ú\87اڻÙ\8aÙ\88 (Ú\87اÙ\86Ú¯Ù\8aÙ\88 Ù\8aا Ù\84Ú©Ú» Ø´Ø±Ù\88ع ڪريو)",
+       "rcfilters-search-placeholder": "تبدÙ\8aÙ\84Ù\8aÙ\88Ù\86 Ú\87اڻÙ\8aÙ\88 (Ù\85Ù\8aÙ\86Ù\8aÙ\88 Ø§Ø³ØªØ¹Ù\85اÙ\84 ÚªØ±Ù\8aÙ\88 Ù\8aا Ú\87اڻÙ\8aØ¡Ù\8e Ø¬Ù\8a Ú³Ù\88Ù\84ا ڪريو)",
        "rcfilters-empty-filter": "ڪي بہ سرگرم ڇاڻيون ناھن. سڀ ڀاڱيداريون ڏيکاريل آھن.",
        "rcfilters-filterlist-title": "ڇاڻيون",
        "rcfilters-filterlist-whatsthis": "هي ڪيئن ڪم ڪن ٿا؟",
index be42b72..22399b3 100644 (file)
        "specialpages": "خاص ورقے",
        "tag-filter": "[[Special:Tags|Tag]] نتارا:",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|ٹیگ|ٹیگز}}]]: $2)",
+       "tag-mw-undo": "واپس",
        "tags-active-yes": "ڄیا",
        "tags-active-no": "کو",
        "tags-hitcount": "$1 {{PLURAL:$1|تبدیلی|تبدیلیاں}}",
index 227f007..aa5b420 100644 (file)
        "tag-mw-replace-description": "Urejanja, ki odstranijo več kot 90 % vsebine strani",
        "tag-mw-rollback": "Vrnitev",
        "tag-mw-rollback-description": "Urejanja, ki vrnejo prejšnja urejanja s povezavo za vrnitev",
+       "tag-mw-undo": "Razveljavljeno",
+       "tag-mw-undo-description": "Urejanja, ki razveljavijo prejšnja urejanja z uporabo povezave za razveljavitev",
        "tags-title": "Etikete",
        "tags-intro": "Ta stran navaja etikete, s katerimi lahko programje označi urejanja, in njihov pomen.",
        "tags-tag": "Ime oznake",
index 54c1b2b..b9be5d7 100644 (file)
        "autosumm-blank": "Уклоњен целокупан садржај странице",
        "autosumm-replace": "Замењен садржај странице са „$1“",
        "autoredircomment": "Преусмерење на [[$1]]",
+       "autosumm-removed-redirect": "Уклоњено преусмјерење ка [[$1]]",
        "autosumm-new": "Нова страница: $1",
        "autosumm-newblank": "Направљена празна страница",
        "size-bytes": "$1 {{PLURAL:$1|бајт|бајта|бајтова}}",
        "tag-list-wrapper": "([[Special:Tags|$1 {{PLURAL:$1|ознака|ознаке|ознака}}]]: $2)",
        "tag-mw-contentmodelchange": "промена модела садржаја",
        "tag-mw-contentmodelchange-description": "Измене које мењају модел садржаја странице",
+       "tag-mw-new-redirect": "Ново преусмјерење",
+       "tag-mw-removed-redirect": "Уклоњено преусмјерење",
        "tag-mw-rollback": "Враћање",
        "tags-title": "Ознаке",
        "tags-intro": "На овој страници је наведен списак ознака с којима програм може да означи измене и његово значење.",
index 46ba7d1..a08cea1 100644 (file)
        "rcfilters-preference-label": "Dölj den förbättrade versionen av Senaste ändringar",
        "rcfilters-preference-help": "Stänger det nydesignade gränssnittet från 2017 och alla verktyg som lades till från och med då.",
        "rcfilters-filter-showlinkedfrom-label": "Visa ändringar på sidor som länkas från",
-       "rcfilters-filter-showlinkedfrom-option-label": "Visa ändringar på sidor som länkas <strong>FRÅN</strong> en sida",
-       "rcfilters-filter-showlinkedto-label": "Visa ändringar på sidor som länkas till",
-       "rcfilters-filter-showlinkedto-option-label": "Visa ändringar på sidor som länkas <strong>TILL</strong> en sida",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Sidor som länkas från</strong> den valda sidan",
+       "rcfilters-filter-showlinkedto-label": "Visa ändringar på sidor som länkar till",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Sidor som länkar till</strong> den valda sidan",
        "rcfilters-target-page-placeholder": "Ange namnet på en sida",
        "rcnotefrom": "Nedan visas {{PLURAL:$5|ändringen|ändringar}} sedan <strong>$3, $4</strong> (upp till <strong>$1</strong> ändringar visas).",
        "rclistfromreset": "Återställ datumval",
        "tag-mw-replace-description": "Redigeringar som tar bort mer än 90 % av innehållet",
        "tag-mw-rollback": "Tillbakarullning",
        "tag-mw-rollback-description": "Redigeringar som rullar tillbaka en tidigare redigering med tillbakarullningslänken",
+       "tag-mw-undo": "Ångra",
+       "tag-mw-undo-description": "Redigeringar som ångrar föregående redigeringar med ångralänken",
        "tags-title": "Märken",
        "tags-intro": "Denna sida listar de taggar som mjukvaran kan markera en redigering med, och deras betydelse.",
        "tags-tag": "Märkesnamn",
index cfb1ef8..bfe9af0 100644 (file)
        "import-logentry-upload-detail": "นำเข้า $1 {{PLURAL:$1|รุ่นการแก้ไข|รุ่นการแก้ไข}}",
        "import-logentry-interwiki-detail": "นำเข้า $1 {{PLURAL:$1|รุ่นการแก้ไข|รุ่นการแก้ไข}}จาก $2",
        "javascripttest": "การทดสอบจาวาสคริปต์",
+       "javascripttest-pagetext-unknownaction": "ปฏิบัติการที่ไม่รู้จัก: \"$1\"",
        "javascripttest-qunit-intro": "ดู[$1 เอกสารกำกับการทดสอบ]บน mediawiki.org",
        "tooltip-pt-userpage": "{{GENDER:|หน้าผู้ใช้}}ของคุณ",
        "tooltip-pt-anonuserpage": "หน้าผู้ใช้ของเลขที่อยู่ไอพีที่คุณกำลังใช้แก้ไข",
        "pageinfo-templates": "แม่แบบที่ใช้ ($1)",
        "pageinfo-toolboxlink": "สารสนเทศหน้า",
        "pageinfo-redirectsto": "เปลี่ยนทางไป",
+       "pageinfo-redirectsto-info": "สนเทศ",
        "pageinfo-contentpage": "นับเป็นหน้าเนื้อหา",
        "pageinfo-contentpage-yes": "ใช่",
        "pageinfo-protect-cascading": "การล็อกที่ต่อเรียงจากหน้านี้",
        "tag-mw-replace-description": "การแก้ไขซึ่งลบเนื้อหากว่า 90% ของหน้า",
        "tag-mw-rollback": "ย้อนกลับ",
        "tag-mw-rollback-description": "การแก้ไขซึ่งย้อนการแก้ไขก่อนหน้าโดยใช้ลิงก์ย้อนกลับฉุกเฉิน",
+       "tag-mw-undo": "ทำกลับ",
+       "tag-mw-undo-description": "การแก้ไขที่ทำกลับการแก้ไขก่อนหน้าโดยใช้ลิงก์ทำกลับ",
        "tags-title": "ป้ายระบุ",
        "tags-intro": "หน้านี้แสดงรายการและความหมายของป้ายระบุที่ซอฟต์แวร์อาจใช้ทำเครื่องหมายกำกับการแก้ไข",
        "tags-tag": "ชื่อป้ายกำกับ",
        "special-characters-group-canadianaboriginal": "แคนาดาพื้นเมืองดั้งเดิม",
        "special-characters-title-minus": "เครื่องหมายลบ",
        "mw-widgets-dateinput-no-date": "ไม่เลือกวันที่",
+       "date-range-from": "ตั้งแต่วันที่:",
+       "date-range-to": "ถึงวันที่:",
        "randomrootpage": "สุ่มหน้าราก",
        "log-action-filter-block": "ประเภทของการบล็อก:",
        "log-action-filter-contentmodel": "ประเภทของการเปลี่ยนตัวแบบเนื้อหา:",
index 94708e5..032787a 100644 (file)
@@ -97,7 +97,8 @@
                        "Alerque",
                        "Bulgu",
                        "Botansahin",
-                       "Catrope"
+                       "Catrope",
+                       "Hedda"
                ]
        },
        "tog-underline": "Bağlantıların altını çizme:",
        "rcfilters-empty-filter": "Etkin süzgeç bulunmuyor. Tüm katkıları gösteriliyor.",
        "rcfilters-filterlist-title": "Süzgeçler",
        "rcfilters-filterlist-whatsthis": "Bunlar nasıl çalışır?",
-       "rcfilters-filterlist-feedbacklink": "Bu (yeni) süzgeç araçları konusunda ne düşündüğünüzü bize aktarın",
+       "rcfilters-filterlist-feedbacklink": "Bu (yeni) süzgeç araçları konusunda ne düşündüğünüzü bize bildirin",
        "rcfilters-highlightbutton-title": "Sonuçları vurgula",
        "rcfilters-highlightmenu-title": "Bir renk seçin",
        "rcfilters-highlightmenu-help": "Bu özelliği vurgulamak için bir renk seçin",
        "rcfilters-filterlist-noresults": "Süzgeç bulunamadı",
-       "rcfilters-noresults-conflict": "Hiçbir sonuç bulunamadı çünkü arama kriterleri çelişkili",
+       "rcfilters-noresults-conflict": "Arama kriterleri çelişkili olduğu için hiçbir sonuç bulunamadı",
        "rcfilters-filtergroup-authorship": "Düzenleme sahipliği",
        "rcfilters-filter-editsbyself-label": "Senin değişiklikleriniz",
        "rcfilters-filter-editsbyself-description": "Kendi katkılarınız.",
index 0d2a97f..88b33ac 100644 (file)
@@ -72,7 +72,8 @@
                        "Bunyk",
                        "Choomaq",
                        "SimondR",
-                       "Renamerr"
+                       "Renamerr",
+                       "Avatar6"
                ]
        },
        "tog-underline": "Підкреслювання посилань:",
        "tagline": "Матеріал з {{grammar:genitive|{{SITENAME}}}}",
        "help": "Довідка",
        "search": "Пошук",
-       "search-ignored-headings": " #<!-- залиште цей рядок точно таким, яким він є --> <pre>\n# Заголовки, які будуть ігноруватися при пошуці.\n# Зміни, які набирають сили при індексуванні сторінки з заголовком.\n# Ви можете примусити переіндексувати сторінку з нульовим редагуванням.\n# Синтаксис наступний:\n#   * Усе, що починається з символу \"#\" до кінця рядка, є коментарем\n#   * Кожний непорожній рядок є точним заголовком для ігнорування\nПосилання\nЗовнішні посилання\nДив. також\n #</pre> <!-- залиште цей рядок точно таким, яким він є -->",
+       "search-ignored-headings": " #<!-- залиште цей рядок точно таким, яким він є --> <pre>\n# Заголовки, які будуть ігноруватися при пошуці.\n# Зміни, які набирають сили при індексуванні сторінки з заголовком.\n# Ви можете примусити переіндексувати сторінку з нульовим редагуванням.\n# Синтаксис наступний:\n#   * Усе, що починається з символу \"#\" до кінця рядка, є коментарем\n#   * Кожний непорожній рядок є точним заголовком для ігнорування\nПримітки\nПосилання\nДив. також\n #</pre> <!-- залиште цей рядок точно таким, яким він є -->",
        "searchbutton": "Пошук",
        "go": "Перейти",
        "searcharticle": "Перейти",
        "red-link-title": "$1 (такої сторінки не існує)",
        "sort-descending": "Сортувати за спаданням",
        "sort-ascending": "Сортувати за зростанням",
-       "nstab-main": "СÑ\82аÑ\82Ñ\82Ñ\8f",
+       "nstab-main": "СÑ\82оÑ\80Ñ\96нка",
        "nstab-user": "Сторінка користувача",
        "nstab-media": "Медіа-сторінка",
        "nstab-special": "Спеціальна сторінка",
        "ns-specialprotected": "Спеціальні сторінки не можна редагувати.",
        "titleprotected": "Створення сторінки з такою назвою було заборонене користувачем [[User:$1|$1]].\nЗазначена така причина: <em>$2</em>.",
        "filereadonlyerror": "Неможливо змінити файл «$1» тому, що файловий архів «$2» перебуває в режимі «лише для читання».\n\nАдміністратор, що заблокував його, залишив таке пояснення: «''$3''».",
-       "invalidtitle-knownnamespace": "Неприйнятна назва у просторі імен «$2» і текстом «$3»",
-       "invalidtitle-unknownnamespace": "Ð\9dепÑ\80авилÑ\8cний Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº Ð· Ð½ÐµÐ²Ñ\96домим Ð½Ð¾Ð¼ÐµÑ\80ом Ð¿Ñ\80оÑ\81Ñ\82оÑ\80Ñ\83 Ñ\96мен ($1) і текстом: «$2»",
+       "invalidtitle-knownnamespace": "Неприйнятна назва у просторі назв «$2» і текстом «$3»",
+       "invalidtitle-unknownnamespace": "Ð\9dевалÑ\96дний Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²Ð¾Ðº Ð· Ð½ÐµÐ²Ñ\96домим Ð½Ð¾Ð¼ÐµÑ\80ом Ð¿Ñ\80оÑ\81Ñ\82оÑ\80Ñ\83 Ð½Ð°Ð·Ð² ($1) і текстом: «$2»",
        "exception-nologin": "Не виконано вхід",
        "exception-nologin-text": "Необхідно увійти, щоб мати доступ до цієї сторінки або дії.",
        "exception-nologin-text-manual": "Потрібно $1, щоб мати доступ до цієї сторінки або дії.",
        "cannotlogoutnow-title": "Неможливо вийти прямо зараз",
        "cannotlogoutnow-text": "Неможливо вийти із системи під час використання $1.",
        "welcomeuser": "Вітаємо, $1!",
-       "welcomecreation-msg": "Ваш обліковий запис створено.\nТепер маєте змогу за бажанням змінювати ваші [[Special:Preferences|налаштування у {{GRAMMAR:genitive|{{SITENAME}}}}]].",
+       "welcomecreation-msg": "Ваш обліковий запис створено.\nТепер є можливість за Вашим бажанням змінювати [[Special:Preferences|персональні налаштування у {{GRAMMAR:genitive|{{SITENAME}}}}]].",
        "yourname": "Ім'я користувача:",
        "userlogin-yourname": "Ім'я користувача",
        "userlogin-yourname-ph": "Введіть ім'я користувача",
        "nosuchusershort": "Користувача з іменем «$1» не існує.\nПеревірте правильність написання імені.",
        "nouserspecified": "Ви повинні зазначити ім'я користувача.",
        "login-userblocked": "Цей користувач заблокований. Вхід в систему не дозволений.",
-       "wrongpassword": "Ð\92и Ð²Ð²ÐµÐ»Ð¸ Ñ\85ибний Ð¿Ð°Ñ\80олÑ\8c. Ð¡Ð¿Ñ\80обÑ\83йÑ\82е Ñ\89е Ñ\80аз.",
+       "wrongpassword": "Ð\92и Ð²Ð²ÐµÐ»Ð¸ Ñ\85ибне Ñ\96м'Ñ\8f ÐºÐ¾Ñ\80иÑ\81Ñ\82Ñ\83ваÑ\87а Ð°Ð±Ð¾ Ð¿Ð°Ñ\80олÑ\8c. Ð\91Ñ\83дÑ\8c Ð»Ð°Ñ\81ка, Ñ\81пÑ\80обÑ\83йÑ\82е Ð·Ð½Ð¾Ð²Ñ\83.",
        "wrongpasswordempty": "Ви не ввели пароль. Будь ласка, спробуйте ще раз.",
        "passwordtooshort": "Ваш пароль закороткий, він має містити принаймні $1 {{PLURAL:$1|символ|символи|символів}}.",
        "passwordtoolong": "Пароль не може бути довшим ніж {{PLURAL:$1|1 символ|$1 символи|$1 символів}}.",
        "botpasswords-insert-failed": "Не вдалось додати бота з іменем «$1». Можливо, він вже був доданий?",
        "botpasswords-update-failed": "Не вдалось оновити бота з іменем «$1». Можливо, він був видалений?",
        "botpasswords-created-title": "Пароль бота створено",
-       "botpasswords-created-body": "Пароль бота з ім'ям «$1» користувача «$2» було створено.",
+       "botpasswords-created-body": "Пароль бота з ім'ям «$1» {{GENDER:$2|користувача|користувачки}} «$2» було створено.",
        "botpasswords-updated-title": "Пароль бота оновлено",
-       "botpasswords-updated-body": "Пароль бота з ім'ям «$1» користувача «$2» було оновлено.",
+       "botpasswords-updated-body": "Пароль бота з ім'ям «$1» {{GENDER:$2|користувача|користувачки}} «$2» було оновлено.",
        "botpasswords-deleted-title": "Пароль бота видалено",
-       "botpasswords-deleted-body": "Пароль бота з ім'ям «$1» користувача «$2» було видалено",
+       "botpasswords-deleted-body": "Пароль бота з ім'ям «$1» {{GENDER:$2|користувача|користувачки}} «$2» було вилучено",
        "botpasswords-newpassword": "Новий пароль для входу під <strong>$1</strong> — <strong>$2</strong>. <em>Запишіть його для подальшого використання.</em> <br> (Для старих ботів, які вимагають, щоб логін був такий же, як і ім'я користувача, Ви також можете використовувати <strong>$3</strong> як ім'я користувача і <strong>$4</strong> як пароль.)",
        "botpasswords-no-provider": "BotPasswordsSessionProvider не доступний.",
        "botpasswords-restriction-failed": "Вхід не було здійснено через обмеження для паролю бота.",
        "extlink_tip": "Зовнішнє посилання (не забудьте про префікс http://)",
        "headline_sample": "Текст заголовка",
        "headline_tip": "Заголовок 2-го рівня",
-       "nowiki_sample": "Ð\92Ñ\81Ñ\82авиÑ\82и сюди неформатований текст.",
+       "nowiki_sample": "Ð\94одайÑ\82е сюди неформатований текст.",
        "nowiki_tip": "Ігнорувати вікі-форматування",
        "image_sample": "Example.jpg",
        "image_tip": "Файл",
        "cascadeprotectedwarning": "<strong>Попередження:</strong> Цю сторінку можуть редагувати лише користувачі зі [[Special:ListGroupRights|специфічними правами]], оскільки вона включена на {{PLURAL:$1|1=сторінці|сторінках}}, де встановлено каскадний захист:",
        "titleprotectedwarning": "'''Попередження. Ця сторінка була захищена так, що для її створення потрібні [[Special:ListGroupRights|особливі права]].'''\nОстанній запис журналу наведений нижче для довідки:",
        "templatesused": "{{PLURAL:$1|1=Шаблон, використаний|Шаблони, використані}} на цій сторінці:",
-       "templatesusedpreview": "{{PLURAL:$1|1=Шаблон, використаний|Шаблони, використані}} у цьому попередньому перегляді:",
+       "templatesusedpreview": "{{PLURAL:$1|1=Шаблон, використаний|Шаблони, використані}} в цьому попередньому перегляді:",
        "templatesusedsection": "{{PLURAL:$1|1=Шаблон, використаний|Шаблони, використані}} в цьому розділі:",
        "template-protected": "(захищено)",
        "template-semiprotected": "(частково захищено)",
        "diff-multi-sameuser": "(Не {{PLURAL:$1|показано одну проміжну версію|показані $1 проміжні версії|показано $1 проміжних версій}} цього користувача)",
        "diff-multi-otherusers": "(Не {{PLURAL:$1|показана $1 проміжна версія|показано $1 проміжні версії|показані $1 проміжних версій}} {{PLURAL:$2|ще одного користувача|$2 користувачів}})",
        "diff-multi-manyusers": "({{PLURAL:$1|не показана $1 проміжна версія|не показані $1 проміжні версії|не показано $1 проміжних версій}}, зроблених більш, ніж {{PLURAL:$2|1=$1 користувачем|$2 користувачами}})",
+       "diff-paragraph-moved-tonew": "Абзац було переміщено. Натисніть щоб перестрибнути до нового розташування.",
+       "diff-paragraph-moved-toold": "Абзац було переміщено. Натисніть щоб перестрибнути до старого розташування.",
        "difference-missing-revision": "{{PLURAL:$2|$2 версія|$2 версії|$2 версій}} для цього порівняння ($1) не {{PLURAL:$2|1=знайдена|знайдені}}.\n\nІмовірно, ви перейшли за застарілим посиланням на порівняння версій вилученої сторінки.\nПодробиці можна дізнатися з [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} журналу вилучень].",
        "searchresults": "Результати пошуку",
        "searchresults-title": "Результати пошуку для «$1»",
        "prefs-watchlist-days-max": "Максимум $1 {{PLURAL:$1|день|дні|днів}}",
        "prefs-watchlist-edits": "Максимальна кількість змін, яку можна виводити у списку спостереження:",
        "prefs-watchlist-edits-max": "Максимально: 1000",
-       "prefs-watchlist-token": "Ð\9cÑ\96Ñ\82ка списку спостереження:",
+       "prefs-watchlist-token": "Токен списку спостереження:",
        "prefs-misc": "Інші налаштування",
        "prefs-resetpass": "Змінити пароль",
        "prefs-changeemail": "Змінити або вилучити адресу електронної пошти",
        "timezoneregion-indian": "Індійський океан",
        "timezoneregion-pacific": "Тихий океан",
        "allowemail": "Дозволити електронну пошту від інших користувачів",
+       "email-allow-new-users-label": "Дозволити електронні листи від новозареєстрованих користувачів.",
        "email-blacklist-label": "Заборонити цим користувачам надсилати мені електронну пошту:",
        "prefs-searchoptions": "Пошук",
        "prefs-namespaces": "Простори назв",
        "right-siteadmin": "Блокування і розблокування бази даних",
        "right-override-export-depth": "експорт сторінок, включаючи пов'язані сторінки з глибиною до 5",
        "right-sendemail": "надсилання електронної пошти іншим користувачам",
+       "right-sendemail-new-users": "надсилати електронні листи до користувачів без логованих дій",
        "right-managechangetags": "створення та (де)активування [[Special:Tags|міток]]",
        "right-applychangetags": "додавання [[Special:Tags|міток]] разом зі змінами",
        "right-changetags": "додавання або вилучення будь-яких [[Special:Tags|міток]] для певних версій сторінок або записів журналів",
        "recentchanges-summary": "Відстеження останніх змін на сторінках {{grammar:genitive|{{SITENAME}}}}.",
        "recentchanges-noresult": "Немає змін за даний період, що відповідають цим критеріям.",
        "recentchanges-timeout": "Час, відведений на цей пошук, вичерпано. Можливо, Ви захочете спробувати інші пошукові параметри.",
+       "recentchanges-network": "Через технічну помилку не вдалось завантажити результати. Будь ласка, спробуйте перезавантажити сторінку.",
+       "recentchanges-notargetpage": "Щоб побачити зміни пов'язані зі сторінкою, уведіть її назву вище.",
        "recentchanges-feed-description": "Відстежувати останні зміни у вікі в цьому потоці.",
        "recentchanges-label-newpage": "Цим редагуванням створена нова сторінка",
        "recentchanges-label-minor": "Це незначна зміна",
        "rcfilters-savedqueries-apply-and-setdefault-label": "Створити стандартний фільтр",
        "rcfilters-savedqueries-cancel-label": "Скасувати",
        "rcfilters-savedqueries-add-new-title": "Зберегти поточні налаштування фільтрів",
+       "rcfilters-savedqueries-already-saved": "Ці фільтри вже збережено. Змініть свої налаштування щоб створити новий Збережений фільтр.",
        "rcfilters-restore-default-filters": "Відновити стандартні фільтри",
        "rcfilters-clear-all-filters": "Очистити фільтри",
        "rcfilters-show-new-changes": "Переглянути найновіші зміни",
-       "rcfilters-search-placeholder": "Фільтруйте нові редагування (перегляньте або почніть вводити)",
+       "rcfilters-search-placeholder": "Фільтруйте редагування (використовуйте меню, або скористайтесь пошуком фільтру за назвою)",
        "rcfilters-invalid-filter": "Недійсний фільтр",
        "rcfilters-empty-filter": "Без фільтрів. Показано всі зміни.",
        "rcfilters-filterlist-title": "Фільтри",
        "rcfilters-watchlist-showupdated": "Зміни до сторінок, які Ви не відвідували з моменту здійснення змін, виділені <strong>жирним</strong>, із цілісними маркерами.",
        "rcfilters-preference-label": "Приховати покращену версію Нових редагувань",
        "rcfilters-preference-help": "Скасовує зміну дизайну 2017 року та всі інструменти, додані тоді й пізніше.",
+       "rcfilters-filter-showlinkedfrom-label": "Показати зміни на сторінках, на які звідси посилання",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>Сторінки, на які є посилання з</strong> обраної сторінки",
+       "rcfilters-filter-showlinkedto-label": "Показати зміни на сторінках, що посилаються сюди",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>Сторінки, що посилаються на</strong> обрану сторінку",
+       "rcfilters-target-page-placeholder": "Уведіть назву сторінки",
        "rcnotefrom": "Нижче знаходяться {{PLURAL:$5|редагування}} з <strong>$3, $4</strong> (відображено до <strong>$1</strong>).",
        "rclistfromreset": "Скинути вибір дати",
        "rclistfrom": "Показати редагування починаючи з $3 $2.",
        "recentchangeslinked-feed": "Пов'язані редгування",
        "recentchangeslinked-toolbox": "Пов'язані редагування",
        "recentchangeslinked-title": "Пов'язані редагування для «$1»",
-       "recentchangeslinked-summary": "Це Ñ\81пиÑ\81ок Ð½ÐµÑ\89одавнÑ\96Ñ\85 Ð·Ð¼Ñ\96н Ð½Ð° Ñ\81Ñ\82оÑ\80Ñ\96нкаÑ\85, Ð½Ð° Ñ\8fкÑ\96 Ð¿Ð¾Ñ\81илаÑ\94Ñ\82Ñ\8cÑ\81Ñ\8f Ð·Ð°Ð·Ð½Ð°Ñ\87ена Ñ\81Ñ\82оÑ\80Ñ\96нка (або Ð½Ð° Ñ\81Ñ\82оÑ\80Ñ\96нкаÑ\85, Ñ\89о Ð¼Ñ\96Ñ\81Ñ\82Ñ\8fÑ\82Ñ\8cÑ\81Ñ\8f Ð² Ñ\86Ñ\96й ÐºÐ°Ñ\82егоÑ\80Ñ\96Ñ\97).\nСÑ\82оÑ\80Ñ\96нки Ð· [[Special:Watchlist|Ð\92аÑ\88ого Ñ\81пиÑ\81кÑ\83 Ñ\81поÑ\81Ñ\82еÑ\80еженнÑ\8f]] Ð²Ð¸Ð´Ñ\96лено '''жиÑ\80ним Ñ\88Ñ\80иÑ\84Ñ\82ом'''.",
+       "recentchangeslinked-summary": "УведÑ\96Ñ\82Ñ\8c Ð½Ð°Ð·Ð²Ñ\83 Ñ\81Ñ\82оÑ\80Ñ\96нки Ñ\89об Ð¿Ð¾Ð±Ð°Ñ\87иÑ\82и Ð·Ð¼Ñ\96ни Ð½Ð° Ñ\81Ñ\82оÑ\80Ñ\96нкаÑ\85 Ñ\8fкÑ\96 Ð¿Ð¾Ñ\81илаÑ\8eÑ\82Ñ\8cÑ\81Ñ\8f Ð½Ð° Ð½ÐµÑ\97, Ð°Ð±Ð¾ Ð½Ð° Ñ\8fкÑ\96 Ð²Ð¾Ð½Ð° Ñ\81ама Ð¿Ð¾Ñ\81илаÑ\94Ñ\82Ñ\8cÑ\81Ñ\8f. (Ð\94лÑ\8f Ð¿ÐµÑ\80еглÑ\8fдÑ\83 Ñ\87ленÑ\96в ÐºÐ°Ñ\82егоÑ\80Ñ\96Ñ\97 Ð²Ð²Ð¾Ð´Ñ\8cÑ\82е {{ns:14}}:Ð\9dазва ÐºÐ°Ñ\82егоÑ\80Ñ\96Ñ\97). Ð\97мÑ\96ни Ð½Ð° Ñ\81Ñ\82оÑ\80Ñ\96нкаÑ\85 Ð· [[Special:Watchlist|Ð\92аÑ\88ого Ð¡Ð¿Ð¸Ñ\81кÑ\83 Ñ\81поÑ\81Ñ\82еÑ\80еженнÑ\8f]] Ð²Ð¸Ð´Ñ\96ленÑ\96 <strong>жиÑ\80ним</strong>.",
        "recentchangeslinked-page": "Назва сторінки:",
        "recentchangeslinked-to": "Показати зміни на сторінках, пов'язаних з даною",
        "recentchanges-page-added-to-category": "[[:$1]] Додано до категорії",
        "uploadstash-refresh": "Оновити список файлів",
        "uploadstash-thumbnail": "перегляд мініатюри",
        "uploadstash-exception": "Не вдалося зберегти завантаження у сховку ($1): «$2».",
+       "uploadstash-bad-path": "Шлях не існує.",
+       "uploadstash-bad-path-invalid": "Неправильний шлях.",
+       "uploadstash-bad-path-unknown-type": "Невідомий тип «$1»",
+       "uploadstash-bad-path-unrecognized-thumb-name": "Нерозпізнана назва мініатюри.",
+       "uploadstash-bad-path-no-handler": "Не знайдено обробник для mime-типу «$1» файлу «$2».",
+       "uploadstash-bad-path-bad-format": "Ключ «$1» в неправильному форматі.",
+       "uploadstash-file-not-found": "Ключ «$1» не знайдено у тимчасовому сховищі.",
+       "uploadstash-file-not-found-no-thumb": "Не вдалось отримати мініатюру.",
+       "uploadstash-file-not-found-no-local-path": "Немає локального шляху для масштабованого елементу.",
+       "uploadstash-file-not-found-no-object": "Не вдалось створити локальний об'єкт файлу для мініатюри.",
+       "uploadstash-file-not-found-no-remote-thumb": "Отримання мініатюри не вдалось: $1\nURL = $2",
+       "uploadstash-file-not-found-missing-content-type": "Відсутній заголовок content-type.",
+       "uploadstash-file-not-found-not-exists": "Не вдалось отримати шлях, або не простий файл.",
+       "uploadstash-file-too-large": "Не вдалось подати файл більший за $1 {{PLURAL:$1|байт|байти|байтів}}.",
+       "uploadstash-not-logged-in": "Немає користувачів, що увійшли до системи, файли повинні належати користувачам.",
+       "uploadstash-wrong-owner": "Цей файл ($1) не належить поточному користувачу.",
+       "uploadstash-no-such-key": "Немає такого файлу ($1), неможливо вилучити.",
+       "uploadstash-no-extension": "Розширення є порожнім.",
+       "uploadstash-zero-length": "Файл нульової довжини.",
        "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 Відкриття доступу до зображень]",
        "import-mapping-namespace": "Імпортувати до простору назв:",
        "import-mapping-subpage": "Імпортувати як підсторінки такої сторінки:",
        "import-upload-filename": "Назва файлу:",
+       "import-upload-username-prefix": "Інтервікі-префікс:",
+       "import-assign-known-users": "Призначити редагування до локальних користувачів де користувачі з такими іменами існують локально.",
        "import-comment": "Примітка:",
        "importtext": "Будь ласка, експортуйте сторінку з іншої вікі, використовуючи [[Special:Export|засіб експорту]], збережіть файл, а потім завантажте його сюди.",
        "importstart": "Імпорт сторінок…",
        "imported-log-entries": "{{PLURAL:$1|Заімпортований $1 запис журналу|Заімпортовані $1 записи журналу|Заімпортовані $1 записів журналу}}.",
        "importfailed": "Не вдалося імпортувати: $1",
        "importunknownsource": "Невідомий тип імпортованої сторінки",
+       "importnoprefix": "Не вказано інтервікі-префікс",
        "importcantopen": "Неможливо відкрити файл імпорту",
        "importbadinterwiki": "Невірне інтервікі-посилання",
        "importsuccess": "Імпорт виконано!",
        "autosumm-blank": "Сторінка очищена",
        "autosumm-replace": "Замінено вміст на «$1»",
        "autoredircomment": "Перенаправлено на [[$1]]",
+       "autosumm-removed-redirect": "Вилучено перенаправлення на [[$1]]",
+       "autosumm-changed-redirect-target": "Змінено ціль перенаправлення з [[$1]] на [[$2]]",
        "autosumm-new": "Створена сторінка: $1",
        "autosumm-newblank": "Створити порожню сторінку",
        "size-bytes": "$1 {{PLURAL:$1|байт|байти|байтів}}",
        "tag-filter": "Фільтр&nbsp;[[Special:Tags|міток]]:",
        "tag-filter-submit": "Відфільтрувати",
        "tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Мітка|Мітки}}]]: $2)",
-       "tag-mw-contentmodelchange": "зміна контентної моделі",
-       "tag-mw-contentmodelchange-description": "Редагування, якими була здійснена [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel зміна контентної моделі] сторінки",
+       "tag-mw-contentmodelchange": "зміна моделі вмісту",
+       "tag-mw-contentmodelchange-description": "Редагування, які змінюють [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel модель вмісту] сторінки",
+       "tag-mw-new-redirect": "Нове перенаправлення",
+       "tag-mw-new-redirect-description": "Редагування, що створюють нове перенаправлення, або заміняють сторінку перенаправленням",
+       "tag-mw-removed-redirect": "Вилучено перенаправлення",
+       "tag-mw-removed-redirect-description": "Редагування, що змінюють дійсне перенаправлення на не-перенаправлення",
+       "tag-mw-changed-redirect-target": "Змінено ціль перенаправлення",
+       "tag-mw-changed-redirect-target-description": "Редагування, що змінюють ціль перенаправлення",
+       "tag-mw-blank": "Очищення",
+       "tag-mw-blank-description": "Редагування, що очищують сторінку",
+       "tag-mw-replace": "Замінено",
+       "tag-mw-replace-description": "Редагування, що вилучають понад 90% вмісту сторінки",
+       "tag-mw-rollback": "Відкіт",
+       "tag-mw-rollback-description": "Редагування, що відкидають попередні правки використовуючи посилання відкоту",
+       "tag-mw-undo": "Скасування",
+       "tag-mw-undo-description": "Редагування, що скасовують попередні правки використовуючи посилання скасування",
        "tags-title": "Мітки",
        "tags-intro": "На цій сторінці наведений список міток, якими програмне забезпечення помічає редагування, а також значення цих міток.",
        "tags-tag": "Назва мітки",
index 934d8e9..aa8d509 100644 (file)
        "rev-deleted-diff-view": "اس فرق کی کسی ایک ترمیم کو <strong>حذف کر دیا گیا ہے</strong>۔\nآپ اس فرق کو دیکھ سکتے ہیں؛ مزید تفصیلات [{{fullurl:{{#Special:Log}}/delete|page={{FULLPAGENAMEE}}}} نوشتہ حذف شدگی] میں دیکھی جا سکتی ہیں۔",
        "rev-suppressed-diff-view": "اس فرق کی کسی ایک ترمیم کو <strong>پوشیدہ کر دیا گیا ہے</strong>۔\nآپ اس فرق کو دیکھ سکتے ہیں؛ مزید تفصیلات [{{fullurl:{{#Special:Log}}/suppress|page={{FULLPAGENAMEE}}}} نوشتہ پوشیدگی] میں دیکھی جا سکتی ہیں۔",
        "rev-delundel": "مرئیت تبدیل کریں",
-       "rev-showdeleted": "دکھاؤ",
+       "rev-showdeleted": "دکھائÛ\8cÚº",
        "revisiondelete": "نظرثانی حذف کریں/واپس لائیں",
        "revdelete-nooldid-title": "ناقص مقصود نظرثانی",
        "revdelete-nooldid-text": "اس فنکشن کو جس نسخے پر انجام دینا ہے اسے آپ نے منتخب نہیں کیا، یا منتخب کردہ نسخہ موجود نہیں، یا آپ موجودہ نسخہ کو پوشیدہ کرنے کی کوشش کر رہے ہیں۔",
        "difference-multipage": "(فرق مابین صفحات)",
        "lineno": "سطر $1:",
        "compareselectedversions": "منتخب متـن کا موازنہ",
-       "showhideselectedversions": "منتخب نسخوں کی مرئیت تبدیل کریں",
+       "showhideselectedversions": "منتخب نسخوں کی رویت تبدیل کریں",
        "editundo": "رد ترمیم",
        "diff-empty": "(کوئی فرق نہیں)",
        "diff-multi-sameuser": "(ایک ہی صارف کا {{PLURAL: $1 |ایک درمیانی نسخہ نہیں دکھایا گیا| $1 درمیانی نسخے نہیں دکھائے گئے}})",
        "userrights-reason": "وجہ:",
        "userrights-no-interwiki": "دوسرے ویکیوں پر حقوقِ صارف میں ترمیم کی آپ کو اجازت نہیں ہے.",
        "userrights-nodatabase": "ڈیٹابیس $1 موجود نہیں یا مقامی نہیں۔",
-       "userrights-changeable-col": "مجموعات جو آپ تبدیل کرسکتے ہیں",
-       "userrights-unchangeable-col": "مجموعات جو آپ تبدیل نہیں کرسکتے",
+       "userrights-changeable-col": "جن حلقوں کو آپ تبدیل کر سکتے ہیں",
+       "userrights-unchangeable-col": "جن حلقوں کو آپ تبدیل نہیں کر سکتے",
        "userrights-expiry-current": "وقت اختتام $1",
        "userrights-expiry-none": "لامحدود",
        "userrights-expiry": "اختتام:",
        "undeleterevision-duplicate-revid": "{{PLURAL:$1|ایک نسخہ بحال نہیں کیا جا سکا|$1 نسخے بحال نہیں کیے جا سکے}}، کیونکہ {{PLURAL:$1|اس کا|ان کے}} <code>rev_id</code> زیر استعمال ہے۔",
        "undelete-nodiff": "کوئی پرانا نسخہ نہیں ملا۔",
        "undeletebtn": "بحال",
-       "undeletelink": "دیکھو/بحال کرو",
+       "undeletelink": "دیکھیں/بحال کریں",
        "undeleteviewlink": "دکھاؤ",
        "undeleteinvert": "انتخاب بالعکس",
        "undeletecomment": "وجہ:",
        "newtitle": "نـیــا عـنــوان:",
        "move-watch": "اصل اور ہدف صفحہ کو زیر نظر کریں",
        "movepagebtn": "مـنـتـقـل",
-       "pagemovedsub": "انتقال کامیاب",
+       "pagemovedsub": "منتقلی کامیاب",
        "movepage-moved": "<strong>\"$1\" کو \"$2\" کی جانب منتقل کر دیا گیا</strong>",
        "movepage-moved-redirect": "رجوع مکرر تخلیق کر دیا گیا۔",
        "movepage-moved-noredirect": "رجوع مکرر کو بننے سے روک دیا گیا ہے۔",
        "tag-mw-new-redirect": "نیا رجوع مکرر",
        "tag-mw-removed-redirect": "رجوع مکرر ہٹایا",
        "tag-mw-changed-redirect-target": "ہدف رجوع مکرر کی تبدیلی",
-       "tag-mw-blank": "خاÙ\84Û\8cÙ\94 ØµÙ\81Ø­Û\81",
+       "tag-mw-blank": "صÙ\81Ø­Û\81 Ø³Û\92 ØªÙ\85اÙ\85 Ù\85Ù\88اد Ø­Ø°Ù\81",
        "tag-mw-replace": "مواد کی تبدیلی",
        "tag-mw-rollback": "استرجع",
        "tags-title": "ٹیگ",
        "htmlform-title-not-exists": "$1 موجود نہیں ہے۔",
        "htmlform-user-not-exists": "<strong>$1</strong> موجود نہیں ہے۔",
        "htmlform-user-not-valid": "<strong>$1</strong> درست صارف نام نہیں ہے۔",
-       "logentry-delete-delete": "$1 {{GENDER:$2|حذف کیا گیا}} صفحہ $3",
+       "logentry-delete-delete": "$1 نے صفحہ $3 {{GENDER:$2|حذف کیا}}",
        "logentry-delete-delete_redir": "$1 نے بر تحریر کرتے ہوئے $3 رجوع مکرر کو {{GENDER:$2|حذف کیا}}",
        "logentry-delete-restore": "$1 نے صفحہ $3 کو {{GENDER:$2|بحال کیا}}",
        "logentry-delete-restore-nocount": "$1 نے صفحہ $3 کو {{GENDER:$2|بحال کیا}}",
index 14ac649..5262c8c 100644 (file)
        "rcfilters-preference-label": "隐藏改进的最近更改版本",
        "rcfilters-preference-help": "返回到2017年界面重新设计版,并重新添加这以后新增的工具。",
        "rcfilters-filter-showlinkedfrom-label": "显示链接自该页面的页面上的更改",
-       "rcfilters-filter-showlinkedfrom-option-label": "显示链接<strong>自</strong>某一页面的页面上的更改",
+       "rcfilters-filter-showlinkedfrom-option-label": "<strong>链接自</strong>选定页面的页面",
        "rcfilters-filter-showlinkedto-label": "显示链接到该页面的页面上的更改",
-       "rcfilters-filter-showlinkedto-option-label": "显示链接<strong>到</strong>某一页面的页面上的更改",
+       "rcfilters-filter-showlinkedto-option-label": "<strong>链接到</strong>选定页面的页面",
        "rcfilters-target-page-placeholder": "输入页面名称",
        "rcnotefrom": "下面{{PLURAL:$5|是}}<strong>$3 $4</strong>之后的更改(最多显示<strong>$1</strong>个)。",
        "rclistfromreset": "重置时间选择",
index a6fd58a..ee2bbb3 100644 (file)
@@ -236,6 +236,7 @@ $separatorTransformTable = [
        ',' => "\xc2\xa0", # nbsp
        '.' => ','
 ];
+$minimumGroupingDigits = 2;
 
 $linkTrail = '/^([абвгґджзеёжзійклмнопрстуўфхцчшыьэюяćčłńśšŭźža-z]+)(.*)$/sDu';
 
index 3a21e75..383a3cd 100644 (file)
@@ -218,3 +218,4 @@ $bookstoreList = [
 $linkTrail = '/^([a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]+)(.*)$/sDu';
 
 $separatorTransformTable = [ ',' => "\xc2\xa0", '.' => ',' ];
+$minimumGroupingDigits = 2;
index d7a780e..16698d1 100644 (file)
@@ -299,4 +299,6 @@ $dateFormats = [
 ];
 
 $separatorTransformTable = [ ',' => "\xc2\xa0", '.' => ',' ];
+$minimumGroupingDigits = 2;
+
 $linkTrail = '/^([a-záéíóúñ]+)(.*)$/sDu';
index fcc12c9..d2f8f32 100644 (file)
@@ -259,6 +259,8 @@ $magicWords = [
 ];
 
 $separatorTransformTable = [ ',' => "\xc2\xa0", '.' => ',' ];
+$minimumGroupingDigits = 2;
+
 $linkTrail = '/^([äöõšüža-z]+)(.*)$/sDu';
 
 $datePreferences = [
index 9a5a809..34306d3 100644 (file)
@@ -12,6 +12,7 @@ $separatorTransformTable = [
        ',' => "\xc2\xa0", # nbsp
        '.' => ','
 ];
+$minimumGroupingDigits = 2;
 
 $fallback8bitEncoding = 'UTF-8';
 
index 52e8e77..2c7cb9e 100644 (file)
@@ -14,6 +14,7 @@ $separatorTransformTable = [
        ',' => "\xc2\xa0",
        '.' => ',',
 ];
+$minimumGroupingDigits = 2;
 
 $fallback8bitEncoding = 'windows-1254';
 
index 2857721..c559d02 100644 (file)
@@ -22,6 +22,7 @@ $separatorTransformTable = [
        ',' => "\xc2\xa0",
        '.' => ',',
 ];
+$minimumGroupingDigits = 2;
 
 $fallback8bitEncoding = 'windows-1251';
 
index 1fef838..291ed14 100644 (file)
@@ -95,6 +95,8 @@ $namespaceAliases = [
 ];
 
 $separatorTransformTable = [ ',' => "\xc2\xa0", '.' => ',' ];
+$minimumGroupingDigits = 2;
+
 $linkTrail = '/^([äöüėëijßəğåůæœça-z]+)(.*)$/sDu';
 
 // Remove German aliases
index 32844a2..c1bf76d 100644 (file)
@@ -51,6 +51,7 @@ $namespaceAliases = [
 ];
 
 $separatorTransformTable = [ ',' => '.', '.' => ',' ];
+$minimumGroupingDigits = 2;
 
 $specialPageAliases = [
        'Allmessages'               => [ 'Hemû_Peyam' ],
index 01a9d1a..1af008f 100644 (file)
@@ -119,10 +119,12 @@ $dateFormats = [
 ];
 
 $fallback8bitEncoding = 'iso-8859-2';
+
 $separatorTransformTable = [
        ',' => "\xc2\xa0", // T4749
        '.' => ','
 ];
+$minimumGroupingDigits = 2;
 
 $linkTrail = '/^([a-zęóąśłżźćńĘÓĄŚŁŻŹĆŃ]+)(.*)$/sDu';
 
index b5f310d..1abecad 100644 (file)
@@ -420,6 +420,7 @@ $separatorTransformTable = [
        ',' => "\xc2\xa0", # nbsp
        '.' => ','
 ];
+$minimumGroupingDigits = 2;
 
 $fallback8bitEncoding = 'windows-1251';
 $linkPrefixExtension = false;
index d851e1c..55bc1fc 100644 (file)
@@ -58,6 +58,7 @@ $separatorTransformTable = [
        ',' => "\xc2\xa0", # nbsp
        '.' => ','
 ];
+$minimumGroupingDigits = 2;
 
 $fallback8bitEncoding = 'windows-1251';
 $linkPrefixExtension = true;
index a3e0ffd..07f547f 100644 (file)
@@ -381,6 +381,11 @@ abstract class Maintenance {
         * @param mixed $channel Unique identifier for the channel. See function outputChanneled.
         */
        protected function output( $out, $channel = null ) {
+               // Try to periodically flush buffered metrics to avoid OOMs
+               $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
+               if ( $stats->getDataCount() > 1000 ) {
+                       MediaWiki::emitBufferedStatsdData( $stats, $this->getConfig() );
+               }
                if ( $this->mQuiet ) {
                        return;
                }
@@ -591,36 +596,41 @@ abstract class Maintenance {
                $lbFactory->setAgentName(
                        mb_strlen( $agent ) > 15 ? mb_substr( $agent, 0, 15 ) . '...' : $agent
                );
-               self::setLBFactoryTriggers( $lbFactory );
+               self::setLBFactoryTriggers( $lbFactory, $this->getConfig() );
        }
 
        /**
         * @param LBFactory $LBFactory
+        * @param Config $config
         * @since 1.28
         */
-       public static function setLBFactoryTriggers( LBFactory $LBFactory ) {
+       public static function setLBFactoryTriggers( LBFactory $LBFactory, Config $config ) {
+               $services = MediaWikiServices::getInstance();
+               $stats = $services->getStatsdDataFactory();
                // Hook into period lag checks which often happen in long-running scripts
-               $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
+               $lbFactory = $services->getDBLoadBalancerFactory();
                $lbFactory->setWaitForReplicationListener(
                        __METHOD__,
-                       function () {
-                               global $wgCommandLineMode;
+                       function () use ( $stats, $config ) {
                                // Check config in case of JobRunner and unit tests
-                               if ( $wgCommandLineMode ) {
+                               if ( $config->get( 'CommandLineMode' ) ) {
                                        DeferredUpdates::tryOpportunisticExecute( 'run' );
                                }
+                               // Try to periodically flush buffered metrics to avoid OOMs
+                               MediaWiki::emitBufferedStatsdData( $stats, $config );
                        }
                );
                // Check for other windows to run them. A script may read or do a few writes
                // to the master but mostly be writing to something else, like a file store.
                $lbFactory->getMainLB()->setTransactionListener(
                        __METHOD__,
-                       function ( $trigger ) {
-                               global $wgCommandLineMode;
+                       function ( $trigger ) use ( $stats, $config ) {
                                // Check config in case of JobRunner and unit tests
-                               if ( $wgCommandLineMode && $trigger === IDatabase::TRIGGER_COMMIT ) {
+                               if ( $config->get( 'CommandLineMode' ) && $trigger === IDatabase::TRIGGER_COMMIT ) {
                                        DeferredUpdates::tryOpportunisticExecute( 'run' );
                                }
+                               // Try to periodically flush buffered metrics to avoid OOMs
+                               MediaWiki::emitBufferedStatsdData( $stats, $config );
                        }
                );
        }
index 832da4d..ffb8cb3 100644 (file)
@@ -26,7 +26,9 @@
  * @ingroup Benchmark
  */
 
+// @codeCoverageIgnoreStart
 require_once __DIR__ . '/../Maintenance.php';
+// @codeCoverageIgnoreEnd
 
 /**
  * Base class for benchmark scripts.
index 3091de6..52b00f1 100644 (file)
@@ -37,7 +37,7 @@ class BenchUtf8TitleCheck extends Benchmarker {
        public function __construct() {
                parent::__construct();
 
-               // @codingStandardsIgnoreStart Ignore long line warnings.
+               // phpcs:disable Generic.Files.LineLength
                $this->data = [
                        "",
                        "United States of America", // 7bit ASCII
@@ -59,7 +59,7 @@ class BenchUtf8TitleCheck extends Benchmarker {
                        . "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"
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
 
                $this->addDescription( "Benchmark for using a regexp vs. mb_check_encoding " .
                        "to check for UTF-8 encoding." );
index bff2c13..0870d6d 100644 (file)
@@ -21,8 +21,9 @@
  * @todo document
  * @ingroup Maintenance
  */
-use \Cdb\Exception as CdbException;
-use \Cdb\Reader as CdbReader;
+
+use Cdb\Exception as CdbException;
+use Cdb\Reader as CdbReader;
 
 require_once __DIR__ . '/commandLine.inc';
 
index 206e046..3329958 100644 (file)
 
 require_once __DIR__ . '/Maintenance.php';
 
-// @codingStandardsIgnoreStart MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
-global $optionsWithArgs;
-global $optionsWithoutArgs;
-// @codingStandardsIgnoreEnd
+// phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
+global $optionsWithArgs, $optionsWithoutArgs;
+
 if ( !isset( $optionsWithArgs ) ) {
        $optionsWithArgs = [];
 }
@@ -36,9 +35,9 @@ if ( !isset( $optionsWithoutArgs ) ) {
 
 class CommandLineInc extends Maintenance {
        public function __construct() {
-               // @codingStandardsIgnoreStart MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
+               // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
                global $optionsWithArgs, $optionsWithoutArgs;
-               // @codingStandardsIgnoreEnd
+
                parent::__construct();
                foreach ( $optionsWithArgs as $name ) {
                        $this->addOption( $name, '', false, true );
@@ -60,9 +59,9 @@ class CommandLineInc extends Maintenance {
        }
 
        public function execute() {
-               // @codingStandardsIgnoreStart MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
+               // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
                global $args, $options;
-               // @codingStandardsIgnoreEnd
+
                $args = $this->mArgs;
                $options = $this->mOptions;
        }
index eceadc1..c3cbdeb 100644 (file)
@@ -83,9 +83,8 @@ class DeleteBatch extends Maintenance {
                $dbw = $this->getDB( DB_MASTER );
 
                # Handle each entry
-               // @codingStandardsIgnoreStart Ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall.NotAllowed
+               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $linenum = 1; !feof( $file ); $linenum++ ) {
-                       // @codingStandardsIgnoreEnd
                        $line = trim( fgets( $file ) );
                        if ( $line == '' ) {
                                continue;
index 2ac756c..ad75c6b 100644 (file)
@@ -62,7 +62,7 @@ if ( !defined( 'MW_CONFIG_CALLBACK' ) && !defined( 'MW_CONFIG_FILE' ) ) {
 // Custom setup for Maintenance entry point
 if ( !defined( 'MW_SETUP_CALLBACK' ) ) {
        function wfMaintenanceSetup() {
-               // @codingStandardsIgnoreLine MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
+               // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
                global $maintenance, $wgLocalisationCacheConf, $wgCacheDirectory;
                if ( $maintenance->getDbType() === Maintenance::DB_NONE ) {
                        if ( $wgLocalisationCacheConf['storeClass'] === false
index 254f368..707f4b3 100644 (file)
@@ -77,6 +77,9 @@ abstract class DumpIterator extends Maintenance {
 
                $importer->setRevisionCallback(
                        [ $this, 'handleRevision' ] );
+               $importer->setNoticeCallback( function ( $msg, $params ) {
+                       echo wfMessage( $msg, $params )->text() . "\n";
+               } );
 
                $this->from = $this->getOption( 'from', null );
                $this->count = 0;
index 2b79b54..0604f48 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 require_once __DIR__ . '/backup.inc';
+require_once __DIR__ . '/7zip.inc';
 require_once __DIR__ . '/../includes/export/WikiExporter.php';
 
 use Wikimedia\Rdbms\IMaintainableDatabase;
index bed84a8..1be2a27 100644 (file)
@@ -484,8 +484,7 @@ class GenerateSitemap extends Maintenance {
         * @return string
         */
        function indexEntry( $filename ) {
-               return
-                       "\t<sitemap>\n" .
+               return "\t<sitemap>\n" .
                        "\t\t<loc>{$this->urlpath}$filename</loc>\n" .
                        "\t\t<lastmod>{$this->timestamp}</lastmod>\n" .
                        "\t</sitemap>\n";
@@ -518,8 +517,7 @@ class GenerateSitemap extends Maintenance {
         * @return string
         */
        function fileEntry( $url, $date, $priority ) {
-               return
-                       "\t<url>\n" .
+               return "\t<url>\n" .
                        // T36666: $url may contain bad characters such as ampersands.
                        "\t\t<loc>" . htmlspecialchars( $url ) . "</loc>\n" .
                        "\t\t<lastmod>$date</lastmod>\n" .
index 2923b38..918c1ab 100644 (file)
@@ -322,6 +322,9 @@ TEXT
                        $this->pageCount = $nthPage - 1;
                }
                $importer->setPageCallback( [ $this, 'reportPage' ] );
+               $importer->setNoticeCallback( function ( $msg, $params ) {
+                       echo wfMessage( $msg, $params )->text() . "\n";
+               } );
                $this->importCallback = $importer->setRevisionCallback(
                        [ $this, 'handleRevision' ] );
                $this->uploadCallback = $importer->setUploadCallback(
index 9e9fd3e..007ced1 100644 (file)
@@ -332,9 +332,8 @@ ENDS;
                        return $blacklist;
                }
 
-               // @codingStandardsIgnoreStart Ignore that globals should have a "wg" prefix.
+               // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
                global $checkBlacklist;
-               // @codingStandardsIgnoreEnd
 
                $blacklist = $checkBlacklist;
 
@@ -517,7 +516,7 @@ ENDS;
                $tableRows = implode( "\n|-\n", $rows );
 
                $version = SpecialVersion::getVersion( 'nodb' );
-               // @codingStandardsIgnoreStart Long line.
+               // phpcs:disable Generic.Files.LineLength
                echo <<<EOL
 '''Check results are for:''' <code>$version</code>
 
@@ -529,7 +528,7 @@ $tableRows
 $detailText
 
 EOL;
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
index 9fee611..e762494 100644 (file)
@@ -112,6 +112,7 @@ U+0636E据|U+064DA據|U+0636E据|
 U+06597斗|U+06597斗|U+09B25鬥|
 U+065CB旋|U+065CB旋|U+0955F镟|
 U+065D7旗|U+065D7旗|U+065C2旂|
+U+06606昆|U+06606昆|U+05D11崑|U+05D10崐|
 U+066F2曲|U+066F2曲|U+09EAF麯|U+09EB4麯|
 U+0672F术|U+08853術|U+0672E朮|
 U+06731朱|U+06731朱|U+07843硃|
index 4715cec..b0aa131 100644 (file)
 收錄著      收录着
 促著 促着
 咬著 咬着
+埋著 埋着
 三十六著   三十六着
 走為上著   走为上着
 記憶體      内存
 巨集 宏
 掃瞄器      扫描仪
 資料庫      数据库
-母音 元音
 印表機      打印机
 位元組      字节
 列印 打印
 托巴哥      多巴哥
 多明尼加   多米尼加
 斯堪地那維亞     斯堪的纳维亚
+加泰隆尼亞        加泰罗尼亚
 頻寬 带宽
 數位相機   数码相机
 數位照相機        数码照相机
index efcfcb6..59f8c9e 100644 (file)
 彩球 綵球
 彩绸 綵綢
 彩綢 綵綢
-彩线 綵綫
-彩線 綵線
 彩船 綵船
-彩衣 綵衣
 结彩 結綵
 結彩 結綵
 戏彩娱亲   戲綵娛親
 紀錄著      紀錄着
 收錄著      收錄着
 咬著 咬着
+埋著 埋着
 三十六著   三十六着
 走為上著   走為上着
 鬧著 鬧着
 得克萨斯   德克薩斯
 蒙特婁      蒙特利爾
 紐賓士域   紐賓士域
-默多克      梅鐸
+加泰隆尼亞        加泰羅尼亞
 梅鐸 梅鐸
 麦克尔      米高
 迈克尔      米高
@@ -2971,9 +2969,6 @@ IP地址  IP位址
 埃博拉      伊波拉
 哥特式      哥德式
 正體中文   繁體中文
-板球 木球
-籃板球      籃板球
-篮板球      籃板球
 智慧財產權        知識產權
 智財權      知識產權
 首席执行官        行政總裁
index 56400c3..2124eba 100644 (file)
 碁圣 碁圣
 慇懃 殷勤
 慇勤 殷勤
-崑崙 昆仑
-崑山 昆山
-崑劇 昆剧
-崑曲 昆曲
-崑腔 昆腔
-崑蘇 昆苏
-崑調 昆调
-崑島 昆岛
 諠譁 喧哗
 慫慂 怂恿
 陈元扞      陈元扞
 爾冬陞      尔冬升
 內聯陞      内联升
 同陞和      同升和
-拿破崙      拿破仑
 酒麴 酒曲
 麴黴 曲霉
 造麴 造曲
index 6b5a857..c907640 100644 (file)
 斯堪的纳维亚     斯堪地那維亞
 斯堪的納維亞     斯堪地那維亞
 圣佩德罗苏拉     汕埠
+加泰罗尼亚        加泰隆尼亞
+加泰羅尼亞        加泰隆尼亞
 麦克尔      麥可
 迈克尔      麥可
 魯賓斯·巴里切羅        魯本·巴瑞切羅
index 1d53615..d4e621d 100644 (file)
 佣鈿 佣鈿
 阁府 閤府
 太阁 太閤
-昆仑 崑崙
-昆山 崑山
-昆剧 崑劇
-昆曲 崑曲
-昆腔 崑腔
-昆苏 崑蘇
-昆调 崑調
-昆冈 崑岡
-西昆 西崑
-苏昆 蘇崑
 苏醒 甦醒
 复苏 復甦
 苹果 蘋果
index 1912bcf..89719ff 100644 (file)
@@ -182,6 +182,8 @@ U+05C5B屛|U+05C4F屏|
 U+05C6D屭|U+05C43屃|
 U+05C85岅|U+05742坂|
 U+05CDD峝|U+05CD2峒|
+U+05D11崑|U+06606昆|
+U+05D19崙|U+04ED1仑|
 U+05D57嵗|U+05C81岁|
 U+05D83嶃|U+05D2D崭|
 U+05DBD嶽|U+05CB3岳|
index ba2f5e8..3e0ef0e 100644 (file)
 咬薑呷醋
 薑蓉
 薑黃
+嫩薑
+酸薑
+薑啤
 狐藉虎威
 滑藉
 藉寇兵
 徵吏
 徵令
 本徵
+吉徵
+凶徵
+免徵
+體徵
+表徵
+綜合徵
 黃鈺筑
 當準
 憑準
 尸佼
 尸子
 尸羅
+帛尸梨
 尸羅精舍
 毗婆尸佛
 尸棄佛
 鬱南
 鬱林
 饑荒
-免徵
 艷后
 廢后
 妖后
 製衣
 巨製
 窗簾
-吉徵
-凶徵
 臟腑
 臟胸
 弄髒胸
 角牴
 扼肮
 搤肮
-嫩薑
-酸薑
-薑啤
+薑酮
 騰湧
 草蓆
 竹蓆
 強制
 改制成
 考試制度
-體徵
-綜合徵
 价川
 商標准許
 批准確定
 關系統
 關系所
 關系科
+崑崙
+崑山
+崑劇
+崑曲
+崑腔
+崑蘇
+崑調
+崑岡
+西崑
+蘇崑
index b749da4..7d85259 100644 (file)
@@ -52,9 +52,8 @@ class MergeMessageFileList extends Maintenance {
        }
 
        public function execute() {
-               // @codingStandardsIgnoreStart Ignore error: Global variable "$mmfl" is lacking 'wg' prefix
+               // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
                global $mmfl;
-               // @codingStandardsIgnoreEnd
                global $wgExtensionEntryPointListFiles;
 
                if ( !count( $wgExtensionEntryPointListFiles )
index fa25a06..9c53daa 100644 (file)
@@ -86,9 +86,8 @@ class MoveBatch extends Maintenance {
 
                # Setup complete, now start
                $dbw = $this->getDB( DB_MASTER );
-               // @codingStandardsIgnoreStart Ignore avoid function calls in a FOR loop test part warning
+               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $linenum = 1; !feof( $file ); $linenum++ ) {
-                       // @codingStandardsIgnoreEnd
                        $line = fgets( $file );
                        if ( $line === false ) {
                                break;
index 68a371c..458556f 100644 (file)
@@ -66,6 +66,9 @@ class DumpRenderer extends Maintenance {
 
                $importer->setRevisionCallback(
                        [ $this, 'handleRevision' ] );
+               $importer->setNoticeCallback( function ( $msg, $params ) {
+                       echo wfMessage( $msg, $params )->text() . "\n";
+               } );
 
                $importer->doImport();
 
index 6348e96..8f55b88 100644 (file)
@@ -493,6 +493,9 @@ class CheckStorage {
                        MediaWikiServices::getInstance()->getMainConfig()
                );
                $importer->setRevisionCallback( [ $this, 'importRevision' ] );
+               $importer->setNoticeCallback( function ( $msg, $params ) {
+                       echo wfMessage( $msg, $params )->text() . "\n";
+               } );
                $importer->doImport();
        }
 
index 0ae46ae..4d56ef0 100644 (file)
@@ -361,10 +361,9 @@ class CompressOld extends Maintenance {
                                $usedChunk = false;
                                $primaryOldid = $revs[$i]->rev_text_id;
 
-                               // @codingStandardsIgnoreStart Ignore avoid function calls in a FOR loop test part warning
                                # Get the text of each revision and add it to the object
+                               // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                                for ( $j = 0; $j < $thisChunkSize && $chunk->isHappy(); $j++ ) {
-                                       // @codingStandardsIgnoreEnd
                                        $oldid = $revs[$i + $j]->rev_text_id;
 
                                        # Get text
index 529c069..e60efdb 100755 (executable)
@@ -170,11 +170,9 @@ class UpdateMediaWiki extends Maintenance {
 
                $badPhpUnit = dirname( __DIR__ ) . '/vendor/phpunit/phpunit/src/Util/PHP/eval-stdin.php';
                if ( file_exists( $badPhpUnit ) ) {
-                       // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
                        // Bad versions of the file are:
                        // https://raw.githubusercontent.com/sebastianbergmann/phpunit/c820f915bfae34e5a836f94967a2a5ea5ef34f21/src/Util/PHP/eval-stdin.php
                        // https://raw.githubusercontent.com/sebastianbergmann/phpunit/3aaddb1c5bd9b9b8d070b4cf120e71c36fd08412/src/Util/PHP/eval-stdin.php
-                       // @codingStandardsIgnoreEnd
                        $md5 = md5_file( $badPhpUnit );
                        if ( $md5 === '120ac49800671dc383b6f3709c25c099'
                                || $md5 === '28af792cb38fc9a1b236b91c1aad2876'
index 5692f11..eb8da57 100644 (file)
@@ -107,18 +107,16 @@ The new option is NOT validated.' );
 
                                $userValue = $user->getOption( $option );
                                if ( $userValue <> $defaultOptions[$option] ) {
-                                       // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
+                                       // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
                                        @$ret[$option][$userValue]++;
-                                       // @codingStandardsIgnoreEnd
                                }
                        } else {
 
                                foreach ( $defaultOptions as $name => $defaultValue ) {
                                        $userValue = $user->getOption( $name );
                                        if ( $userValue != $defaultValue ) {
-                                               // @codingStandardsIgnoreStart Ignore silencing errors is discouraged warning
+                                               // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
                                                @$ret[$name][$userValue]++;
-                                               // @codingStandardsIgnoreEnd
                                        }
                                }
                        }
index 10b8d97..72cf654 100644 (file)
@@ -1,5 +1,5 @@
 <?php
-// @codingStandardsIgnoreFile Generic.Arrays.DisallowLongArraySyntax
+// phpcs:ignoreFile Generic.Arrays.DisallowLongArraySyntax
 /**
  * New version of MediaWiki web-based config/installation
  *
@@ -23,9 +23,8 @@
 
 // Bail on old versions of PHP, or if composer has not been run yet to install
 // dependencies. Using dirname( __FILE__ ) here because __DIR__ is PHP5.3+.
-// @codingStandardsIgnoreStart MediaWiki.Usage.DirUsage.FunctionFound
+// phpcs:ignore MediaWiki.Usage.DirUsage.FunctionFound
 require_once dirname( __FILE__ ) . '/../includes/PHPVersionCheck.php';
-// @codingStandardsIgnoreEnd
 wfEntryPointCheck( 'mw-config/index.php' );
 
 define( 'MW_CONFIG_CALLBACK', 'Installer::overrideConfig' );
index 83ae193..ca8c1bb 100644 (file)
@@ -168,9 +168,8 @@ if ( isset( $_REQUEST['expand'] ) ) {
        }
 }
 
-// @codingStandardsIgnoreStart
+// phpcs:ignore Squiz.Classes.ValidClassName.NotCamelCaps
 class profile_point {
-       // @codingStandardsIgnoreEnd
 
        public $name;
        public $count;
@@ -222,7 +221,7 @@ class profile_point {
                                <?php echo htmlspecialchars( str_replace( ',', ', ', $this->name() ) ) . $extet ?>
                        </div>
                </th>
-               <?php //@codingStandardsIgnoreStart ?>
+               <?php // phpcs:disable Generic.Files.LineLength,Generic.PHP.NoSilencedErrors ?>
                <td class="mw-profileinfo-timep"><?php echo @wfPercent( $this->time() / self::$totaltime * 100 ); ?></td>
                <td class="mw-profileinfo-memoryp"><?php echo @wfPercent( $this->memory() / self::$totalmemory * 100 ); ?></td>
                <td class="mw-profileinfo-count"><?php echo $this->count(); ?></td>
@@ -231,7 +230,7 @@ class profile_point {
                <td class="mw-profileinfo-mpc"><?php echo round( sprintf( '%.2f', $this->memoryPerCall() / 1024 ), 2 ); ?></td>
                <td class="mw-profileinfo-tpr"><?php echo @round( sprintf( '%.2f', $this->time() / self::$totalcount ), 2 ); ?></td>
                <td class="mw-profileinfo-mpr"><?php echo @round( sprintf( '%.2f', $this->memory() / self::$totalcount / 1024 ), 2 ); ?></td>
-               <?php //@codingStandardsIgnoreEnd ?>
+               <?php // phpcs:enable ?>
        </tr>
                <?php
                if ( $ex ) {
@@ -258,33 +257,28 @@ class profile_point {
        }
 
        public function timePerCall() {
-               // @codingStandardsIgnoreStart
+               // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
                return @( $this->time / $this->count );
-               // @codingStandardsIgnoreEnd
        }
 
        public function memoryPerCall() {
-               // @codingStandardsIgnoreStart
+               // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
                return @( $this->memory / $this->count );
-               // @codingStandardsIgnoreEnd
        }
 
        public function callsPerRequest() {
-               // @codingStandardsIgnoreStart
+               // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
                return @( $this->count / self::$totalcount );
-               // @codingStandardsIgnoreEnd
        }
 
        public function timePerRequest() {
-               // @codingStandardsIgnoreStart
+               // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
                return @( $this->time / self::$totalcount );
-               // @codingStandardsIgnoreEnd
        }
 
        public function memoryPerRequest() {
-               // @codingStandardsIgnoreStart
+               // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
                return @( $this->memory / self::$totalcount );
-               // @codingStandardsIgnoreEnd
        }
 
        public function fmttime() {
@@ -293,9 +287,9 @@ class profile_point {
 };
 
 function compare_point( profile_point $a, profile_point $b ) {
-       // @codingStandardsIgnoreStart
+       // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
        global $sort;
-       // @codingStandardsIgnoreEnd
+
        switch ( $sort ) {
                case 'name':
                        return strcmp( $a->name(), $b->name() );
@@ -390,9 +384,8 @@ if ( isset( $_REQUEST['filter'] ) ) {
        profile_point::$totalmemory = 0.0;
 
        function getEscapedProfileUrl( $_filter = false, $_sort = false, $_expand = false ) {
-               // @codingStandardsIgnoreStart
+               // phpcs:ignore MediaWiki.NamingConventions.ValidGlobalName.wgPrefix
                global $filter, $sort, $expand;
-               // @codingStandardsIgnoreEnd
 
                if ( $_expand === false ) {
                        $_expand = $expand;
@@ -441,9 +434,8 @@ if ( isset( $_REQUEST['filter'] ) ) {
        }
        $points[] = $s;
 
-       // @codingStandardsIgnoreStart
+       // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
        @usort( $points, 'compare_point' );
-       // @codingStandardsIgnoreEnd
 
        foreach ( $points as $point ) {
                if ( strlen( $filter ) && !strstr( $point->name(), $filter ) ) {
index b494429..7d37b50 100644 (file)
@@ -1842,9 +1842,13 @@ return [
                        'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.LiveUpdateButtonWidget.less',
                        'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RcTopSectionWidget.less',
                        'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclToOrFromWidget.less',
+                       'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTargetPageWidget.less',
                        'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.WatchlistTopSectionWidget.less',
                ],
                'skinStyles' => [
+                       'vector' => [
+                               'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.Overlay.vector.less',
+                       ],
                        'monobook' => [
                                'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.Overlay.monobook.less',
                                'resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.CapsuleItemWidget.monobook.less',
index 0675dc5..5e1332c 100644 (file)
@@ -1,10 +1,9 @@
-# Chosen, a Select Box Enhancer for jQuery and Protoype
-## by Patrick Filler for [Harvest](http://getharvest.com)
+#### Chosen
+- by Patrick Filler for [Harvest](http://getharvest.com)
+- Copyright (c) 2011-2016 by Harvest
 
 Available for use under the [MIT License](http://en.wikipedia.org/wiki/MIT_License)
 
-Copyright (c) 2011-2013 by Harvest
-
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
diff --git a/resources/lib/jquery.chosen/README.md b/resources/lib/jquery.chosen/README.md
new file mode 100644 (file)
index 0000000..5b21256
--- /dev/null
@@ -0,0 +1,48 @@
+# Chosen
+
+Chosen is a library for making long, unwieldy select boxes more user friendly.
+
+- jQuery support: 1.7+
+- Prototype support: 1.7+
+
+For **documentation**, usage, and examples, see:
+http://harvesthq.github.io/chosen/
+
+For **downloads**, see:
+https://github.com/harvesthq/chosen/releases/
+
+### Package managers
+
+Chosen is available through [Bower](https://bower.io/) and [npm](https://www.npmjs.com),
+_however, the package names are not the same_.
+
+To install with Bower:
+
+```
+bower install chosen
+```
+
+To install with npm:
+
+```
+npm install chosen-js
+```
+
+The compiled files for these packages are automatically generated and stored in a [2nd Chosen repository](https://github.com/harvesthq/chosen-package). No pull requests will be accepted to that repository.
+
+### Contributing to this project
+
+We welcome all to participate in making Chosen the best software it can be. The repository is maintained by only a few people, but has accepted contributions from over 50 authors after reviewing hundreds of pull requests related to thousands of issues. You can help reduce the maintainers' workload (and increase your chance of having an accepted contribution to Chosen) by following the
+[guidelines for contributing](contributing.md).
+
+* [Bug reports](contributing.md#bugs)
+* [Feature requests](contributing.md#features)
+* [Pull requests](contributing.md#pull-requests)
+
+### Chosen Credits
+
+- Concept and development by [Patrick Filler](http://patrickfiller.com) for [Harvest](http://getharvest.com/).
+- Design and CSS by [Matthew Lettini](http://matthewlettini.com/)
+- Repository maintained by [@pfiller](http://github.com/pfiller), [@kenearley](http://github.com/kenearley), [@stof](http://github.com/stof), [@koenpunt](http://github.com/koenpunt), and [@tjschuck](http://github.com/tjschuck).
+- Chosen includes [contributions by many fine folks](https://github.com/harvesthq/chosen/contributors).
+
index 3611ae4..c57da70 100644 (file)
Binary files a/resources/lib/jquery.chosen/chosen-sprite.png and b/resources/lib/jquery.chosen/chosen-sprite.png differ
index bd61d96..6b50545 100644 (file)
Binary files a/resources/lib/jquery.chosen/chosen-sprite@2x.png and b/resources/lib/jquery.chosen/chosen-sprite@2x.png differ
index 17793ed..d4219b4 100644 (file)
+/*!
+Chosen, a Select Box Enhancer for jQuery and Prototype
+by Patrick Filler for Harvest, http://getharvest.com
+
+Version 1.8.2
+Full source at https://github.com/harvesthq/chosen
+Copyright (c) 2011-2017 Harvest http://getharvest.com
+
+MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
+This file is generated by `grunt build`, do not edit it by hand.
+*/
+
 /* @group Base */
-.chzn-container {
-  font-size: 13px;
+.chosen-container {
   position: relative;
   display: inline-block;
   vertical-align: middle;
-  zoom: 1;
-  *display: inline;
+  font-size: 13px;
+  -webkit-user-select: none;
+     -moz-user-select: none;
+      -ms-user-select: none;
+          user-select: none;
 }
-.chzn-container .chzn-drop {
-  background: #fff;
-  border: 1px solid #aaa;
-  border-top: 0;
+
+.chosen-container * {
+  -webkit-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+.chosen-container .chosen-drop {
   position: absolute;
   top: 100%;
-  left: -9999px;
-  -webkit-box-shadow: 0 4px 5px rgba(0,0,0,.15);
-  -moz-box-shadow   : 0 4px 5px rgba(0,0,0,.15);
-  box-shadow        : 0 4px 5px rgba(0,0,0,.15);
   z-index: 1010;
   width: 100%;
-  -moz-box-sizing   : border-box;
-  -ms-box-sizing    : border-box;
-  -webkit-box-sizing: border-box;
-  -khtml-box-sizing : border-box;
-  box-sizing        : border-box;
+  border: 1px solid #aaa;
+  border-top: 0;
+  background: #fff;
+  -webkit-box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15);
+          box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15);
+  clip: rect(0, 0, 0, 0);
 }
 
-.chzn-container.chzn-with-drop .chzn-drop {
-  left: 0;
+.chosen-container.chosen-with-drop .chosen-drop {
+  clip: auto;
 }
 
-/* @end */
+.chosen-container a {
+  cursor: pointer;
+}
 
-/* @group Single Chosen */
-.chzn-container-single .chzn-single {
-  background-color: #ffffff;
-  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0 );   
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4));
-  background-image: -webkit-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
-  background-image: -moz-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
-  background-image: -o-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
-  background-image: linear-gradient(#ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); 
-  -webkit-border-radius: 5px;
-  -moz-border-radius   : 5px;
-  border-radius        : 5px;
-  -moz-background-clip   : padding;
-  -webkit-background-clip: padding-box;
-  background-clip        : padding-box;
-  border: 1px solid #aaaaaa;
-  -webkit-box-shadow: 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1);
-  -moz-box-shadow   : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1);
-  box-shadow        : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1);
-  display: block;
+.chosen-container .search-choice .group-name, .chosen-container .chosen-single .group-name {
+  margin-right: 4px;
   overflow: hidden;
   white-space: nowrap;
+  text-overflow: ellipsis;
+  font-weight: normal;
+  color: #999999;
+}
+
+.chosen-container .search-choice .group-name:after, .chosen-container .chosen-single .group-name:after {
+  content: ":";
+  padding-left: 2px;
+  vertical-align: top;
+}
+
+/* @end */
+/* @group Single Chosen */
+.chosen-container-single .chosen-single {
   position: relative;
-  height: 23px;
-  line-height: 24px;
+  display: block;
+  overflow: hidden;
   padding: 0 0 0 8px;
-  color: #444444;
+  height: 25px;
+  border: 1px solid #aaa;
+  border-radius: 5px;
+  background-color: #fff;
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(20%, #fff), color-stop(50%, #f6f6f6), color-stop(52%, #eee), to(#f4f4f4));
+  background: linear-gradient(#fff 20%, #f6f6f6 50%, #eee 52%, #f4f4f4 100%);
+  background-clip: padding-box;
+  -webkit-box-shadow: 0 0 3px #fff inset, 0 1px 1px rgba(0, 0, 0, 0.1);
+          box-shadow: 0 0 3px #fff inset, 0 1px 1px rgba(0, 0, 0, 0.1);
+  color: #444;
   text-decoration: none;
+  white-space: nowrap;
+  line-height: 24px;
 }
-.chzn-container-single .chzn-default {
+
+.chosen-container-single .chosen-default {
   color: #999;
 }
-.chzn-container-single .chzn-single span {
-  margin-right: 26px;
+
+.chosen-container-single .chosen-single span {
   display: block;
   overflow: hidden;
-  white-space: nowrap;
-  -o-text-overflow: ellipsis;
-  -ms-text-overflow: ellipsis;
+  margin-right: 26px;
   text-overflow: ellipsis;
+  white-space: nowrap;
 }
-.chzn-container-single .chzn-single abbr {
-  display: block;
+
+.chosen-container-single .chosen-single-with-deselect span {
+  margin-right: 38px;
+}
+
+.chosen-container-single .chosen-single abbr {
   position: absolute;
-  right: 26px;
   top: 6px;
+  right: 26px;
+  display: block;
   width: 12px;
   height: 12px;
+  background: url("chosen-sprite.png") -42px 1px no-repeat;
   font-size: 1px;
-  background: url('chosen-sprite.png') -42px 1px no-repeat;
 }
-.chzn-container-single .chzn-single abbr:hover {
+
+.chosen-container-single .chosen-single abbr:hover {
   background-position: -42px -10px;
 }
-.chzn-container-single.chzn-disabled .chzn-single abbr:hover {
+
+.chosen-container-single.chosen-disabled .chosen-single abbr:hover {
   background-position: -42px -10px;
 }
-.chzn-container-single .chzn-single div {
+
+.chosen-container-single .chosen-single div {
   position: absolute;
-  right: 0;
   top: 0;
+  right: 0;
   display: block;
-  height: 100%;
   width: 18px;
+  height: 100%;
 }
-.chzn-container-single .chzn-single div b {
-  background: url('chosen-sprite.png') no-repeat 0px 2px;
+
+.chosen-container-single .chosen-single div b {
   display: block;
   width: 100%;
   height: 100%;
+  background: url("chosen-sprite.png") no-repeat 0px 2px;
 }
-.chzn-container-single .chzn-search {
-  padding: 3px 4px;
+
+.chosen-container-single .chosen-search {
   position: relative;
+  z-index: 1010;
   margin: 0;
+  padding: 3px 4px;
   white-space: nowrap;
-  z-index: 1010;
 }
-.chzn-container-single .chzn-search input {
-  background: #fff url('chosen-sprite.png') no-repeat 100% -20px;
-  background: url('chosen-sprite.png') no-repeat 100% -20px, -webkit-gradient(linear, 0 0, 0 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
-  background: url('chosen-sprite.png') no-repeat 100% -20px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
-  background: url('chosen-sprite.png') no-repeat 100% -20px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
-  background: url('chosen-sprite.png') no-repeat 100% -20px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
-  background: url('chosen-sprite.png') no-repeat 100% -20px, linear-gradient(#eeeeee 1%, #ffffff 15%);
+
+.chosen-container-single .chosen-search input[type="text"] {
   margin: 1px 0;
   padding: 4px 20px 4px 5px;
+  width: 100%;
+  height: auto;
   outline: 0;
   border: 1px solid #aaa;
-  font-family: sans-serif;
+  background: url("chosen-sprite.png") no-repeat 100% -20px;
   font-size: 1em;
-  width: 100%;
-  -moz-box-sizing   : border-box;
-  -ms-box-sizing    : border-box;
-  -webkit-box-sizing: border-box;
-  -khtml-box-sizing : border-box;
-  box-sizing        : border-box;
+  font-family: sans-serif;
+  line-height: normal;
+  border-radius: 0;
 }
-.chzn-container-single .chzn-drop {
+
+.chosen-container-single .chosen-drop {
   margin-top: -1px;
-  -webkit-border-radius: 0 0 4px 4px;
-  -moz-border-radius   : 0 0 4px 4px;
-  border-radius        : 0 0 4px 4px;
-  -moz-background-clip   : padding;
-  -webkit-background-clip: padding-box;
-  background-clip        : padding-box;
-}
-.chzn-container-single-nosearch .chzn-search {
+  border-radius: 0 0 4px 4px;
+  background-clip: padding-box;
+}
+
+.chosen-container-single.chosen-container-single-nosearch .chosen-search {
   position: absolute;
-  left: -9999px;
+  clip: rect(0, 0, 0, 0);
 }
+
 /* @end */
+/* @group Results */
+.chosen-container .chosen-results {
+  color: #444;
+  position: relative;
+  overflow-x: hidden;
+  overflow-y: auto;
+  margin: 0 4px 4px 0;
+  padding: 0 0 0 4px;
+  max-height: 240px;
+  -webkit-overflow-scrolling: touch;
+}
 
-/* @group Multi Chosen */
-.chzn-container-multi .chzn-choices {
-  background-color: #fff;
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
-  background-image: -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
-  background-image: -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
-  background-image: -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
-  background-image: linear-gradient(#eeeeee 1%, #ffffff 15%);
-  border: 1px solid #aaa;
+.chosen-container .chosen-results li {
+  display: none;
   margin: 0;
-  padding: 0;
-  cursor: text;
-  overflow: hidden;
-  height: auto !important;
-  height: 1%;
+  padding: 5px 6px;
+  list-style: none;
+  line-height: 15px;
+  word-wrap: break-word;
+  -webkit-touch-callout: none;
+}
+
+.chosen-container .chosen-results li.active-result {
+  display: list-item;
+  cursor: pointer;
+}
+
+.chosen-container .chosen-results li.disabled-result {
+  display: list-item;
+  color: #ccc;
+  cursor: default;
+}
+
+.chosen-container .chosen-results li.highlighted {
+  background-color: #3875d7;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(20%, #3875d7), color-stop(90%, #2a62bc));
+  background-image: linear-gradient(#3875d7 20%, #2a62bc 90%);
+  color: #fff;
+}
+
+.chosen-container .chosen-results li.no-results {
+  color: #777;
+  display: list-item;
+  background: #f4f4f4;
+}
+
+.chosen-container .chosen-results li.group-result {
+  display: list-item;
+  font-weight: bold;
+  cursor: default;
+}
+
+.chosen-container .chosen-results li.group-option {
+  padding-left: 15px;
+}
+
+.chosen-container .chosen-results li em {
+  font-style: normal;
+  text-decoration: underline;
+}
+
+/* @end */
+/* @group Multi Chosen */
+.chosen-container-multi .chosen-choices {
   position: relative;
+  overflow: hidden;
+  margin: 0;
+  padding: 0 5px;
   width: 100%;
-  -moz-box-sizing   : border-box;
-  -ms-box-sizing    : border-box;
-  -webkit-box-sizing: border-box;
-  -khtml-box-sizing : border-box;
-  box-sizing        : border-box;
+  height: auto;
+  border: 1px solid #aaa;
+  background-color: #fff;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(1%, #eee), color-stop(15%, #fff));
+  background-image: linear-gradient(#eee 1%, #fff 15%);
+  cursor: text;
 }
-.chzn-container-multi .chzn-choices li {
+
+.chosen-container-multi .chosen-choices li {
   float: left;
   list-style: none;
 }
-.chzn-container-multi .chzn-choices .search-field {
-  white-space: nowrap;
+
+.chosen-container-multi .chosen-choices li.search-field {
   margin: 0;
   padding: 0;
+  white-space: nowrap;
 }
-.chzn-container-multi .chzn-choices .search-field input {
-  color: #666;
-  background: transparent !important;
-  border: 0 !important;
-  font-family: sans-serif;
-  font-size: 100%;
-  height: 15px;
-  padding: 5px;
+
+.chosen-container-multi .chosen-choices li.search-field input[type="text"] {
   margin: 1px 0;
+  padding: 0;
+  height: 25px;
   outline: 0;
+  border: 0 !important;
+  background: transparent !important;
   -webkit-box-shadow: none;
-  -moz-box-shadow   : none;
-  box-shadow        : none;
-}
-.chzn-container-multi .chzn-choices .search-field .default {
+          box-shadow: none;
   color: #999;
+  font-size: 100%;
+  font-family: sans-serif;
+  line-height: normal;
+  border-radius: 0;
+  width: 25px;
 }
-.chzn-container-multi .chzn-choices .search-choice {
-  -webkit-border-radius: 3px;
-  -moz-border-radius   : 3px;
-  border-radius        : 3px;
-  -moz-background-clip   : padding;
-  -webkit-background-clip: padding-box;
-  background-clip        : padding-box;
-  background-color: #e4e4e4;
-  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0 ); 
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
-  background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
-  background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
-  background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
-  background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); 
-  -webkit-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05);
-  -moz-box-shadow   : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05);
-  box-shadow        : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05);
+
+.chosen-container-multi .chosen-choices li.search-choice {
+  position: relative;
+  margin: 3px 5px 3px 0;
+  padding: 3px 20px 3px 5px;
+  border: 1px solid #aaa;
+  max-width: 100%;
+  border-radius: 3px;
+  background-color: #eeeeee;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), to(#eee));
+  background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
+  background-size: 100% 19px;
+  background-repeat: repeat-x;
+  background-clip: padding-box;
+  -webkit-box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
+          box-shadow: 0 0 2px #fff inset, 0 1px 0 rgba(0, 0, 0, 0.05);
   color: #333;
-  border: 1px solid #aaaaaa;
   line-height: 13px;
-  padding: 3px 20px 3px 5px;
-  margin: 3px 0 3px 5px;
-  position: relative;
   cursor: default;
 }
-.chzn-container-multi .chzn-choices .search-choice.search-choice-disabled {
-  background-color: #e4e4e4;
-  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0 );
-  background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
-  background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
-  background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
-  background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
-  background-image: -ms-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
-  background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
-  color: #666;
-  border: 1px solid #cccccc;
-  padding-right: 5px;
-}
-.chzn-container-multi .chzn-choices .search-choice-focus {
-  background: #d4d4d4;
+
+.chosen-container-multi .chosen-choices li.search-choice span {
+  word-wrap: break-word;
 }
-.chzn-container-multi .chzn-choices .search-choice .search-choice-close {
-  display: block;
+
+.chosen-container-multi .chosen-choices li.search-choice .search-choice-close {
   position: absolute;
-  right: 3px;
   top: 4px;
+  right: 3px;
+  display: block;
   width: 12px;
   height: 12px;
+  background: url("chosen-sprite.png") -42px 1px no-repeat;
   font-size: 1px;
-  background: url('chosen-sprite.png') -42px 1px no-repeat;
 }
-.chzn-container-multi .chzn-choices .search-choice .search-choice-close:hover {
+
+.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover {
   background-position: -42px -10px;
 }
-.chzn-container-multi .chzn-choices .search-choice-focus .search-choice-close {
-  background-position: -42px -10px;
+
+.chosen-container-multi .chosen-choices li.search-choice-disabled {
+  padding-right: 5px;
+  border: 1px solid #ccc;
+  background-color: #e4e4e4;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), to(#eee));
+  background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%);
+  color: #666;
 }
-/* @end */
 
-/* @group Results */
-.chzn-container .chzn-results {
-  margin: 0 4px 4px 0;
-  max-height: 240px;
-  padding: 0 0 0 4px;
-  position: relative;
-  overflow-x: hidden;
-  overflow-y: auto;
-  -webkit-overflow-scrolling: touch;
+.chosen-container-multi .chosen-choices li.search-choice-focus {
+  background: #d4d4d4;
 }
-.chzn-container-multi .chzn-results {
-  margin: 0;
-  padding: 0;
+
+.chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close {
+  background-position: -42px -10px;
 }
-.chzn-container .chzn-results li {
-  display: none;
-  line-height: 15px;
-  padding: 5px 6px;
+
+.chosen-container-multi .chosen-results {
   margin: 0;
-  list-style: none;
-}
-.chzn-container .chzn-results .active-result {
-  cursor: pointer;
-  display: list-item;
-}
-.chzn-container .chzn-results .highlighted {
-  background-color: #3875d7;
-  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3875d7', endColorstr='#2a62bc', GradientType=0 );  
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc));
-  background-image: -webkit-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
-  background-image: -moz-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
-  background-image: -o-linear-gradient(top, #3875d7 20%, #2a62bc 90%);
-  background-image: linear-gradient(#3875d7 20%, #2a62bc 90%);
-  color: #fff;
-}
-.chzn-container .chzn-results li em {
-  background: #feffde;
-  font-style: normal;
-}
-.chzn-container .chzn-results .highlighted em {
-  background: transparent;
+  padding: 0;
 }
-.chzn-container .chzn-results .no-results {
-  background: #f4f4f4;
+
+.chosen-container-multi .chosen-drop .result-selected {
   display: list-item;
-}
-.chzn-container .chzn-results .group-result {
+  color: #ccc;
   cursor: default;
-  color: #999;
-  font-weight: bold;
-}
-.chzn-container .chzn-results .group-option {
-  padding-left: 15px;
-}
-.chzn-container-multi .chzn-drop .result-selected {
-  display: none;
-}
-.chzn-container .chzn-results-scroll {
-  background: white;
-  margin: 0 4px;
-  position: absolute;
-  text-align: center;
-  width: 321px; /* This should by dynamic with js */
-  z-index: 1;
-}
-.chzn-container .chzn-results-scroll span {
-  display: inline-block;
-  height: 17px;
-  text-indent: -5000px;
-  width: 9px;
-}
-.chzn-container .chzn-results-scroll-down {
-  bottom: 0;
-}
-.chzn-container .chzn-results-scroll-down span {
-  background: url('chosen-sprite.png') no-repeat -4px -3px;
-}
-.chzn-container .chzn-results-scroll-up span {
-  background: url('chosen-sprite.png') no-repeat -22px -3px;
 }
-/* @end */
 
+/* @end */
 /* @group Active  */
-.chzn-container-active .chzn-single {
-  -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3);
-  -moz-box-shadow   : 0 0 5px rgba(0,0,0,.3);
-  box-shadow        : 0 0 5px rgba(0,0,0,.3);
+.chosen-container-active .chosen-single {
   border: 1px solid #5897fb;
+  -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+          box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
 }
-.chzn-container-active.chzn-with-drop .chzn-single {
+
+.chosen-container-active.chosen-with-drop .chosen-single {
   border: 1px solid #aaa;
-  -webkit-box-shadow: 0 1px 0 #fff inset;
-  -moz-box-shadow   : 0 1px 0 #fff inset;
-  box-shadow        : 0 1px 0 #fff inset;
-  background-color: #eee;
-  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0 );
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff));
-  background-image: -webkit-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
-  background-image: -moz-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
-  background-image: -o-linear-gradient(top, #eeeeee 20%, #ffffff 80%);
-  background-image: linear-gradient(#eeeeee 20%, #ffffff 80%);
-  -webkit-border-bottom-left-radius : 0;
-  -webkit-border-bottom-right-radius: 0;
-  -moz-border-radius-bottomleft : 0;
-  -moz-border-radius-bottomright: 0;
-  border-bottom-left-radius : 0;
   border-bottom-right-radius: 0;
+  border-bottom-left-radius: 0;
+  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(20%, #eee), color-stop(80%, #fff));
+  background-image: linear-gradient(#eee 20%, #fff 80%);
+  -webkit-box-shadow: 0 1px 0 #fff inset;
+          box-shadow: 0 1px 0 #fff inset;
 }
-.chzn-container-active.chzn-with-drop .chzn-single div {
-  background: transparent;
+
+.chosen-container-active.chosen-with-drop .chosen-single div {
   border-left: none;
+  background: transparent;
 }
-.chzn-container-active.chzn-with-drop .chzn-single div b {
+
+.chosen-container-active.chosen-with-drop .chosen-single div b {
   background-position: -18px 2px;
 }
-.chzn-container-active .chzn-choices {
-  -webkit-box-shadow: 0 0 5px rgba(0,0,0,.3);
-  -moz-box-shadow   : 0 0 5px rgba(0,0,0,.3);
-  box-shadow        : 0 0 5px rgba(0,0,0,.3);
+
+.chosen-container-active .chosen-choices {
   border: 1px solid #5897fb;
+  -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+          box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
 }
-.chzn-container-active .chzn-choices .search-field input {
-  color: #111 !important;
+
+.chosen-container-active .chosen-choices li.search-field input[type="text"] {
+  color: #222 !important;
 }
-/* @end */
 
+/* @end */
 /* @group Disabled Support */
-.chzn-disabled {
+.chosen-disabled {
+  opacity: 0.5 !important;
   cursor: default;
-  opacity:0.5 !important;
 }
-.chzn-disabled .chzn-single {
+
+.chosen-disabled .chosen-single {
   cursor: default;
 }
-.chzn-disabled .chzn-choices .search-choice .search-choice-close {
+
+.chosen-disabled .chosen-choices .search-choice .search-choice-close {
   cursor: default;
 }
 
+/* @end */
 /* @group Right to Left */
-.chzn-rtl { text-align: right; }
-.chzn-rtl .chzn-single { padding: 0 8px 0 0; overflow: visible; }
-.chzn-rtl .chzn-single span { margin-left: 26px; margin-right: 0; direction: rtl; }
+.chosen-rtl {
+  text-align: right;
+}
+
+.chosen-rtl .chosen-single {
+  overflow: visible;
+  padding: 0 8px 0 0;
+}
 
-.chzn-rtl .chzn-single div { left: 3px; right: auto; }
-.chzn-rtl .chzn-single abbr {
+.chosen-rtl .chosen-single span {
+  margin-right: 0;
+  margin-left: 26px;
+  direction: rtl;
+}
+
+.chosen-rtl .chosen-single-with-deselect span {
+  margin-left: 38px;
+}
+
+.chosen-rtl .chosen-single div {
+  right: auto;
+  left: 3px;
+}
+
+.chosen-rtl .chosen-single abbr {
+  right: auto;
   left: 26px;
+}
+
+.chosen-rtl .chosen-choices li {
+  float: right;
+}
+
+.chosen-rtl .chosen-choices li.search-field input[type="text"] {
+  direction: rtl;
+}
+
+.chosen-rtl .chosen-choices li.search-choice {
+  margin: 3px 5px 3px 0;
+  padding: 3px 5px 3px 19px;
+}
+
+.chosen-rtl .chosen-choices li.search-choice .search-choice-close {
   right: auto;
+  left: 4px;
+}
+
+.chosen-rtl.chosen-container-single .chosen-results {
+  margin: 0 0 4px 4px;
+  padding: 0 4px 0 0;
+}
+
+.chosen-rtl .chosen-results li.group-option {
+  padding-right: 15px;
+  padding-left: 0;
 }
-.chzn-rtl .chzn-choices .search-field input { direction: rtl; }
-.chzn-rtl .chzn-choices li { float: right; }
-.chzn-rtl .chzn-choices .search-choice { padding: 3px 5px 3px 19px; margin: 3px 5px 3px 0; }
-.chzn-rtl .chzn-choices .search-choice .search-choice-close { left: 4px; right: auto; }
-.chzn-rtl .chzn-search { left: 9999px; }
-.chzn-rtl.chzn-with-drop .chzn-search { left: 0px; }
-.chzn-rtl .chzn-drop { left: 9999px; }
-.chzn-rtl.chzn-container-single .chzn-results { margin: 0 0 4px 4px; padding: 0 4px 0 0; }
-.chzn-rtl .chzn-results .group-option { padding-left: 0; padding-right: 15px; }
-.chzn-rtl.chzn-container-active.chzn-with-drop .chzn-single div { border-right: none; }
-.chzn-rtl .chzn-search input {
-  background: #fff url('chosen-sprite.png') no-repeat -30px -20px;
-  background: url('chosen-sprite.png') no-repeat -30px -20px, -webkit-gradient(linear, 0 0, 0 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
-  background: url('chosen-sprite.png') no-repeat -30px -20px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%);  
-  background: url('chosen-sprite.png') no-repeat -30px -20px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
-  background: url('chosen-sprite.png') no-repeat -30px -20px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%);
-  background: url('chosen-sprite.png') no-repeat -30px -20px, linear-gradient(#eeeeee 1%, #ffffff 15%);
+
+.chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div {
+  border-right: none;
+}
+
+.chosen-rtl .chosen-search input[type="text"] {
   padding: 4px 5px 4px 20px;
+  background: url("chosen-sprite.png") no-repeat -30px -20px;
   direction: rtl;
 }
-.chzn-container-single.chzn-rtl .chzn-single div b {
+
+.chosen-rtl.chosen-container-single .chosen-single div b {
   background-position: 6px 2px;
 }
-.chzn-container-single.chzn-rtl.chzn-with-drop .chzn-single div b {
+
+.chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b {
   background-position: -12px 2px;
 }
-/* @end */
 
+/* @end */
 /* @group Retina compatibility */
-@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-resolution: 144dpi)  {
-  .chzn-rtl .chzn-search input, .chzn-container-single .chzn-single abbr, .chzn-container-single .chzn-single div b, .chzn-container-single .chzn-search input, .chzn-container-multi .chzn-choices .search-choice .search-choice-close, .chzn-container .chzn-results-scroll-down span, .chzn-container .chzn-results-scroll-up span {
-      background-image: url('chosen-sprite@2x.png') !important;
-      background-repeat: no-repeat !important;
-      background-size: 52px 37px !important;
+@media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-resolution: 144dpi), only screen and (min-resolution: 1.5dppx) {
+  .chosen-rtl .chosen-search input[type="text"],
+  .chosen-container-single .chosen-single abbr,
+  .chosen-container-single .chosen-single div b,
+  .chosen-container-single .chosen-search input[type="text"],
+  .chosen-container-multi .chosen-choices .search-choice .search-choice-close,
+  .chosen-container .chosen-results-scroll-down span,
+  .chosen-container .chosen-results-scroll-up span {
+    background-image: url("chosen-sprite@2x.png") !important;
+    background-size: 52px 37px !important;
+    background-repeat: no-repeat !important;
   }
 }
+
 /* @end */
index 745174f..b8e20eb 100644 (file)
@@ -1,17 +1,22 @@
-// Chosen, a Select Box Enhancer for jQuery and Protoype
-// by Patrick Filler for Harvest, http://getharvest.com
-//
-// Version 0.9.14
-// Full source at https://github.com/harvesthq/chosen
-// Copyright (c) 2011 Harvest http://getharvest.com
-
-// MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
-// This file is generated by `cake build`, do not edit it by hand.
+/*!
+Chosen, a Select Box Enhancer for jQuery and Prototype
+by Patrick Filler for Harvest, http://getharvest.com
+
+Version 1.8.2
+Full source at https://github.com/harvesthq/chosen
+Copyright (c) 2011-2017 Harvest http://getharvest.com
+
+MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
+This file is generated by `grunt build`, do not edit it by hand.
+*/
+
 (function() {
-  var SelectParser;
+  var $, AbstractChosen, Chosen, SelectParser,
+    bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
+    extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
+    hasProp = {}.hasOwnProperty;
 
   SelectParser = (function() {
-
     function SelectParser() {
       this.options_index = 0;
       this.parsed = [];
     };
 
     SelectParser.prototype.add_group = function(group) {
-      var group_position, option, _i, _len, _ref, _results;
+      var group_position, i, len, option, ref, results1;
       group_position = this.parsed.length;
       this.parsed.push({
         array_index: group_position,
         group: true,
         label: group.label,
+        title: group.title ? group.title : void 0,
         children: 0,
-        disabled: group.disabled
+        disabled: group.disabled,
+        classes: group.className
       });
-      _ref = group.childNodes;
-      _results = [];
-      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
-        option = _ref[_i];
-        _results.push(this.add_option(option, group_position, group.disabled));
+      ref = group.childNodes;
+      results1 = [];
+      for (i = 0, len = ref.length; i < len; i++) {
+        option = ref[i];
+        results1.push(this.add_option(option, group_position, group.disabled));
       }
-      return _results;
+      return results1;
     };
 
     SelectParser.prototype.add_option = function(option, group_position, group_disabled) {
             value: option.value,
             text: option.text,
             html: option.innerHTML,
+            title: option.title ? option.title : void 0,
             selected: option.selected,
             disabled: group_disabled === true ? group_disabled : option.disabled,
             group_array_index: group_position,
+            group_label: group_position != null ? this.parsed[group_position].label : null,
             classes: option.className,
             style: option.style.cssText
           });
   })();
 
   SelectParser.select_to_array = function(select) {
-    var child, parser, _i, _len, _ref;
+    var child, i, len, parser, ref;
     parser = new SelectParser();
-    _ref = select.childNodes;
-    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
-      child = _ref[_i];
+    ref = select.childNodes;
+    for (i = 0, len = ref.length; i < len; i++) {
+      child = ref[i];
       parser.add_node(child);
     }
     return parser.parsed;
   };
 
-  this.SelectParser = SelectParser;
-
-}).call(this);
-
-/*
-Chosen source: generate output using 'cake build'
-Copyright (c) 2011 by Harvest
-*/
-
-
-(function() {
-  var AbstractChosen, root;
-
-  root = this;
-
   AbstractChosen = (function() {
-
-    function AbstractChosen(form_field, options) {
+    function AbstractChosen(form_field, options1) {
       this.form_field = form_field;
-      this.options = options != null ? options : {};
+      this.options = options1 != null ? options1 : {};
+      this.label_click_handler = bind(this.label_click_handler, this);
       if (!AbstractChosen.browser_is_supported()) {
         return;
       }
@@ -117,31 +111,40 @@ Copyright (c) 2011 by Harvest
       this.setup();
       this.set_up_html();
       this.register_observers();
-      this.finish_setup();
+      this.on_ready();
     }
 
     AbstractChosen.prototype.set_default_values = function() {
-      var _this = this;
-      this.click_test_action = function(evt) {
-        return _this.test_active_click(evt);
-      };
-      this.activate_action = function(evt) {
-        return _this.activate_field(evt);
-      };
+      this.click_test_action = (function(_this) {
+        return function(evt) {
+          return _this.test_active_click(evt);
+        };
+      })(this);
+      this.activate_action = (function(_this) {
+        return function(evt) {
+          return _this.activate_field(evt);
+        };
+      })(this);
       this.active_field = false;
       this.mouse_on_container = false;
       this.results_showing = false;
       this.result_highlighted = null;
-      this.result_single_selected = null;
+      this.is_rtl = this.options.rtl || /\bchosen-rtl\b/.test(this.form_field.className);
       this.allow_single_deselect = (this.options.allow_single_deselect != null) && (this.form_field.options[0] != null) && this.form_field.options[0].text === "" ? this.options.allow_single_deselect : false;
       this.disable_search_threshold = this.options.disable_search_threshold || 0;
       this.disable_search = this.options.disable_search || false;
       this.enable_split_word_search = this.options.enable_split_word_search != null ? this.options.enable_split_word_search : true;
+      this.group_search = this.options.group_search != null ? this.options.group_search : true;
       this.search_contains = this.options.search_contains || false;
-      this.choices = 0;
-      this.single_backstroke_delete = this.options.single_backstroke_delete || false;
+      this.single_backstroke_delete = this.options.single_backstroke_delete != null ? this.options.single_backstroke_delete : true;
       this.max_selected_options = this.options.max_selected_options || Infinity;
-      return this.inherit_select_classes = this.options.inherit_select_classes || false;
+      this.inherit_select_classes = this.options.inherit_select_classes || false;
+      this.display_selected_options = this.options.display_selected_options != null ? this.options.display_selected_options : true;
+      this.display_disabled_options = this.options.display_disabled_options != null ? this.options.display_disabled_options : true;
+      this.include_group_label_in_selected = this.options.include_group_label_in_selected || false;
+      this.max_shown_results = this.options.max_shown_results || Number.POSITIVE_INFINITY;
+      this.case_sensitive_search = this.options.case_sensitive_search || false;
+      return this.hide_results_on_select = this.options.hide_results_on_select != null ? this.options.hide_results_on_select : true;
     };
 
     AbstractChosen.prototype.set_default_text = function() {
@@ -152,9 +155,18 @@ Copyright (c) 2011 by Harvest
       } else {
         this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || AbstractChosen.default_single_text;
       }
+      this.default_text = this.escape_html(this.default_text);
       return this.results_none_found = this.form_field.getAttribute("data-no_results_text") || this.options.no_results_text || AbstractChosen.default_no_result_text;
     };
 
+    AbstractChosen.prototype.choice_label = function(item) {
+      if (this.include_group_label_in_selected && (item.group_label != null)) {
+        return "<b class='group-name'>" + item.group_label + "</b>" + item.html;
+      } else {
+        return item.html;
+      }
+    };
+
     AbstractChosen.prototype.mouse_enter = function() {
       return this.mouse_on_container = true;
     };
@@ -164,12 +176,13 @@ Copyright (c) 2011 by Harvest
     };
 
     AbstractChosen.prototype.input_focus = function(evt) {
-      var _this = this;
       if (this.is_multiple) {
         if (!this.active_field) {
-          return setTimeout((function() {
-            return _this.container_mousedown();
-          }), 50);
+          return setTimeout(((function(_this) {
+            return function() {
+              return _this.container_mousedown();
+            };
+          })(this)), 50);
         }
       } else {
         if (!this.active_field) {
@@ -179,34 +192,110 @@ Copyright (c) 2011 by Harvest
     };
 
     AbstractChosen.prototype.input_blur = function(evt) {
-      var _this = this;
       if (!this.mouse_on_container) {
         this.active_field = false;
-        return setTimeout((function() {
-          return _this.blur_test();
-        }), 100);
+        return setTimeout(((function(_this) {
+          return function() {
+            return _this.blur_test();
+          };
+        })(this)), 100);
       }
     };
 
-    AbstractChosen.prototype.result_add_option = function(option) {
-      var classes, style;
-      if (!option.disabled) {
-        option.dom_id = this.container_id + "_o_" + option.array_index;
-        classes = option.selected && this.is_multiple ? [] : ["active-result"];
-        if (option.selected) {
-          classes.push("result-selected");
+    AbstractChosen.prototype.label_click_handler = function(evt) {
+      if (this.is_multiple) {
+        return this.container_mousedown(evt);
+      } else {
+        return this.activate_field();
+      }
+    };
+
+    AbstractChosen.prototype.results_option_build = function(options) {
+      var content, data, data_content, i, len, ref, shown_results;
+      content = '';
+      shown_results = 0;
+      ref = this.results_data;
+      for (i = 0, len = ref.length; i < len; i++) {
+        data = ref[i];
+        data_content = '';
+        if (data.group) {
+          data_content = this.result_add_group(data);
+        } else {
+          data_content = this.result_add_option(data);
+        }
+        if (data_content !== '') {
+          shown_results++;
+          content += data_content;
         }
-        if (option.group_array_index != null) {
-          classes.push("group-option");
+        if (options != null ? options.first : void 0) {
+          if (data.selected && this.is_multiple) {
+            this.choice_build(data);
+          } else if (data.selected && !this.is_multiple) {
+            this.single_set_selected_text(this.choice_label(data));
+          }
         }
-        if (option.classes !== "") {
-          classes.push(option.classes);
+        if (shown_results >= this.max_shown_results) {
+          break;
         }
-        style = option.style.cssText !== "" ? " style=\"" + option.style + "\"" : "";
-        return '<li id="' + option.dom_id + '" class="' + classes.join(' ') + '"' + style + '>' + option.html + '</li>';
-      } else {
-        return "";
       }
+      return content;
+    };
+
+    AbstractChosen.prototype.result_add_option = function(option) {
+      var classes, option_el;
+      if (!option.search_match) {
+        return '';
+      }
+      if (!this.include_option_in_results(option)) {
+        return '';
+      }
+      classes = [];
+      if (!option.disabled && !(option.selected && this.is_multiple)) {
+        classes.push("active-result");
+      }
+      if (option.disabled && !(option.selected && this.is_multiple)) {
+        classes.push("disabled-result");
+      }
+      if (option.selected) {
+        classes.push("result-selected");
+      }
+      if (option.group_array_index != null) {
+        classes.push("group-option");
+      }
+      if (option.classes !== "") {
+        classes.push(option.classes);
+      }
+      option_el = document.createElement("li");
+      option_el.className = classes.join(" ");
+      option_el.style.cssText = option.style;
+      option_el.setAttribute("data-option-array-index", option.array_index);
+      option_el.innerHTML = option.highlighted_html || option.html;
+      if (option.title) {
+        option_el.title = option.title;
+      }
+      return this.outerHTML(option_el);
+    };
+
+    AbstractChosen.prototype.result_add_group = function(group) {
+      var classes, group_el;
+      if (!(group.search_match || group.group_match)) {
+        return '';
+      }
+      if (!(group.active_options > 0)) {
+        return '';
+      }
+      classes = [];
+      classes.push("group-result");
+      if (group.classes) {
+        classes.push(group.classes);
+      }
+      group_el = document.createElement("li");
+      group_el.className = classes.join(" ");
+      group_el.innerHTML = group.highlighted_html || this.escape_html(group.label);
+      if (group.title) {
+        group_el.title = group.title;
+      }
+      return this.outerHTML(group_el);
     };
 
     AbstractChosen.prototype.results_update_field = function() {
@@ -215,8 +304,25 @@ Copyright (c) 2011 by Harvest
         this.results_reset_cleanup();
       }
       this.result_clear_highlight();
-      this.result_single_selected = null;
-      return this.results_build();
+      this.results_build();
+      if (this.results_showing) {
+        return this.winnow_results();
+      }
+    };
+
+    AbstractChosen.prototype.reset_single_select_options = function() {
+      var i, len, ref, result, results1;
+      ref = this.results_data;
+      results1 = [];
+      for (i = 0, len = ref.length; i < len; i++) {
+        result = ref[i];
+        if (result.selected) {
+          results1.push(result.selected = false);
+        } else {
+          results1.push(void 0);
+        }
+      }
+      return results1;
     };
 
     AbstractChosen.prototype.results_toggle = function() {
@@ -235,106 +341,279 @@ Copyright (c) 2011 by Harvest
       }
     };
 
+    AbstractChosen.prototype.winnow_results = function() {
+      var escapedQuery, fix, i, len, option, prefix, query, ref, regex, results, results_group, search_match, startpos, suffix, text;
+      this.no_results_clear();
+      results = 0;
+      query = this.get_search_text();
+      escapedQuery = query.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+      regex = this.get_search_regex(escapedQuery);
+      ref = this.results_data;
+      for (i = 0, len = ref.length; i < len; i++) {
+        option = ref[i];
+        option.search_match = false;
+        results_group = null;
+        search_match = null;
+        option.highlighted_html = '';
+        if (this.include_option_in_results(option)) {
+          if (option.group) {
+            option.group_match = false;
+            option.active_options = 0;
+          }
+          if ((option.group_array_index != null) && this.results_data[option.group_array_index]) {
+            results_group = this.results_data[option.group_array_index];
+            if (results_group.active_options === 0 && results_group.search_match) {
+              results += 1;
+            }
+            results_group.active_options += 1;
+          }
+          text = option.group ? option.label : option.text;
+          if (!(option.group && !this.group_search)) {
+            search_match = this.search_string_match(text, regex);
+            option.search_match = search_match != null;
+            if (option.search_match && !option.group) {
+              results += 1;
+            }
+            if (option.search_match) {
+              if (query.length) {
+                startpos = search_match.index;
+                prefix = text.slice(0, startpos);
+                fix = text.slice(startpos, startpos + query.length);
+                suffix = text.slice(startpos + query.length);
+                option.highlighted_html = (this.escape_html(prefix)) + "<em>" + (this.escape_html(fix)) + "</em>" + (this.escape_html(suffix));
+              }
+              if (results_group != null) {
+                results_group.group_match = true;
+              }
+            } else if ((option.group_array_index != null) && this.results_data[option.group_array_index].search_match) {
+              option.search_match = true;
+            }
+          }
+        }
+      }
+      this.result_clear_highlight();
+      if (results < 1 && query.length) {
+        this.update_results_content("");
+        return this.no_results(query);
+      } else {
+        this.update_results_content(this.results_option_build());
+        return this.winnow_results_set_highlight();
+      }
+    };
+
+    AbstractChosen.prototype.get_search_regex = function(escaped_search_string) {
+      var regex_flag, regex_string;
+      regex_string = this.search_contains ? escaped_search_string : "(^|\\s|\\b)" + escaped_search_string + "[^\\s]*";
+      if (!(this.enable_split_word_search || this.search_contains)) {
+        regex_string = "^" + regex_string;
+      }
+      regex_flag = this.case_sensitive_search ? "" : "i";
+      return new RegExp(regex_string, regex_flag);
+    };
+
+    AbstractChosen.prototype.search_string_match = function(search_string, regex) {
+      var match;
+      match = regex.exec(search_string);
+      if (!this.search_contains && (match != null ? match[1] : void 0)) {
+        match.index += 1;
+      }
+      return match;
+    };
+
+    AbstractChosen.prototype.choices_count = function() {
+      var i, len, option, ref;
+      if (this.selected_option_count != null) {
+        return this.selected_option_count;
+      }
+      this.selected_option_count = 0;
+      ref = this.form_field.options;
+      for (i = 0, len = ref.length; i < len; i++) {
+        option = ref[i];
+        if (option.selected) {
+          this.selected_option_count += 1;
+        }
+      }
+      return this.selected_option_count;
+    };
+
     AbstractChosen.prototype.choices_click = function(evt) {
       evt.preventDefault();
-      if (!this.results_showing) {
+      this.activate_field();
+      if (!(this.results_showing || this.is_disabled)) {
         return this.results_show();
       }
     };
 
+    AbstractChosen.prototype.keydown_checker = function(evt) {
+      var ref, stroke;
+      stroke = (ref = evt.which) != null ? ref : evt.keyCode;
+      this.search_field_scale();
+      if (stroke !== 8 && this.pending_backstroke) {
+        this.clear_backstroke();
+      }
+      switch (stroke) {
+        case 8:
+          this.backstroke_length = this.get_search_field_value().length;
+          break;
+        case 9:
+          if (this.results_showing && !this.is_multiple) {
+            this.result_select(evt);
+          }
+          this.mouse_on_container = false;
+          break;
+        case 13:
+          if (this.results_showing) {
+            evt.preventDefault();
+          }
+          break;
+        case 27:
+          if (this.results_showing) {
+            evt.preventDefault();
+          }
+          break;
+        case 32:
+          if (this.disable_search) {
+            evt.preventDefault();
+          }
+          break;
+        case 38:
+          evt.preventDefault();
+          this.keyup_arrow();
+          break;
+        case 40:
+          evt.preventDefault();
+          this.keydown_arrow();
+          break;
+      }
+    };
+
     AbstractChosen.prototype.keyup_checker = function(evt) {
-      var stroke, _ref;
-      stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
+      var ref, stroke;
+      stroke = (ref = evt.which) != null ? ref : evt.keyCode;
       this.search_field_scale();
       switch (stroke) {
         case 8:
-          if (this.is_multiple && this.backstroke_length < 1 && this.choices > 0) {
-            return this.keydown_backstroke();
+          if (this.is_multiple && this.backstroke_length < 1 && this.choices_count() > 0) {
+            this.keydown_backstroke();
           } else if (!this.pending_backstroke) {
             this.result_clear_highlight();
-            return this.results_search();
+            this.results_search();
           }
           break;
         case 13:
           evt.preventDefault();
           if (this.results_showing) {
-            return this.result_select(evt);
+            this.result_select(evt);
           }
           break;
         case 27:
           if (this.results_showing) {
             this.results_hide();
           }
-          return true;
+          break;
         case 9:
+        case 16:
+        case 17:
+        case 18:
         case 38:
         case 40:
-        case 16:
         case 91:
-        case 17:
           break;
         default:
-          return this.results_search();
+          this.results_search();
+          break;
       }
     };
 
-    AbstractChosen.prototype.generate_field_id = function() {
-      var new_id;
-      new_id = this.generate_random_id();
-      this.form_field.id = new_id;
-      return new_id;
-    };
-
-    AbstractChosen.prototype.generate_random_char = function() {
-      var chars, newchar, rand;
-      chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-      rand = Math.floor(Math.random() * chars.length);
-      return newchar = chars.substring(rand, rand + 1);
+    AbstractChosen.prototype.clipboard_event_checker = function(evt) {
+      if (this.is_disabled) {
+        return;
+      }
+      return setTimeout(((function(_this) {
+        return function() {
+          return _this.results_search();
+        };
+      })(this)), 50);
     };
 
     AbstractChosen.prototype.container_width = function() {
-      var width;
       if (this.options.width != null) {
         return this.options.width;
+      } else {
+        return this.form_field.offsetWidth + "px";
       }
-      width = window.getComputedStyle != null ? parseFloat(window.getComputedStyle(this.form_field).getPropertyValue('width')) : (typeof jQuery !== "undefined" && jQuery !== null) && (this.form_field_jq != null) ? this.form_field_jq.outerWidth() : this.form_field.getWidth();
-      return width + "px";
     };
 
-    AbstractChosen.browser_is_supported = function() {
-      var _ref;
-      if (window.navigator.appName === "Microsoft Internet Explorer") {
-        return (null !== (_ref = document.documentMode) && _ref >= 8);
+    AbstractChosen.prototype.include_option_in_results = function(option) {
+      if (this.is_multiple && (!this.display_selected_options && option.selected)) {
+        return false;
+      }
+      if (!this.display_disabled_options && option.disabled) {
+        return false;
+      }
+      if (option.empty) {
+        return false;
       }
       return true;
     };
 
-    AbstractChosen.default_multiple_text = "Select Some Options";
+    AbstractChosen.prototype.search_results_touchstart = function(evt) {
+      this.touch_started = true;
+      return this.search_results_mouseover(evt);
+    };
 
-    AbstractChosen.default_single_text = "Select an Option";
+    AbstractChosen.prototype.search_results_touchmove = function(evt) {
+      this.touch_started = false;
+      return this.search_results_mouseout(evt);
+    };
 
-    AbstractChosen.default_no_result_text = "No results match";
+    AbstractChosen.prototype.search_results_touchend = function(evt) {
+      if (this.touch_started) {
+        return this.search_results_mouseup(evt);
+      }
+    };
 
-    return AbstractChosen;
+    AbstractChosen.prototype.outerHTML = function(element) {
+      var tmp;
+      if (element.outerHTML) {
+        return element.outerHTML;
+      }
+      tmp = document.createElement("div");
+      tmp.appendChild(element);
+      return tmp.innerHTML;
+    };
 
-  })();
+    AbstractChosen.prototype.get_single_html = function() {
+      return "<a class=\"chosen-single chosen-default\">\n  <span>" + this.default_text + "</span>\n  <div><b></b></div>\n</a>\n<div class=\"chosen-drop\">\n  <div class=\"chosen-search\">\n    <input class=\"chosen-search-input\" type=\"text\" autocomplete=\"off\" />\n  </div>\n  <ul class=\"chosen-results\"></ul>\n</div>";
+    };
 
-  root.AbstractChosen = AbstractChosen;
+    AbstractChosen.prototype.get_multi_html = function() {
+      return "<ul class=\"chosen-choices\">\n  <li class=\"search-field\">\n    <input class=\"chosen-search-input\" type=\"text\" autocomplete=\"off\" value=\"" + this.default_text + "\" />\n  </li>\n</ul>\n<div class=\"chosen-drop\">\n  <ul class=\"chosen-results\"></ul>\n</div>";
+    };
 
-}).call(this);
+    AbstractChosen.prototype.get_no_results_html = function(terms) {
+      return "<li class=\"no-results\">\n  " + this.results_none_found + " <span>" + (this.escape_html(terms)) + "</span>\n</li>";
+    };
 
-/*
-Chosen source: generate output using 'cake build'
-Copyright (c) 2011 by Harvest
-*/
+    AbstractChosen.browser_is_supported = function() {
+      if ("Microsoft Internet Explorer" === window.navigator.appName) {
+        return document.documentMode >= 8;
+      }
+      if (/iP(od|hone)/i.test(window.navigator.userAgent) || /IEMobile/i.test(window.navigator.userAgent) || /Windows Phone/i.test(window.navigator.userAgent) || /BlackBerry/i.test(window.navigator.userAgent) || /BB10/i.test(window.navigator.userAgent) || /Android.*Mobile/i.test(window.navigator.userAgent)) {
+        return false;
+      }
+      return true;
+    };
 
+    AbstractChosen.default_multiple_text = "Select Some Options";
 
-(function() {
-  var $, Chosen, root,
-    __hasProp = {}.hasOwnProperty,
-    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
+    AbstractChosen.default_single_text = "Select an Option";
 
-  root = this;
+    AbstractChosen.default_no_result_text = "No results match";
+
+    return AbstractChosen;
+
+  })();
 
   $ = jQuery;
 
@@ -344,18 +623,24 @@ Copyright (c) 2011 by Harvest
         return this;
       }
       return this.each(function(input_field) {
-        var $this;
+        var $this, chosen;
         $this = $(this);
-        if (!$this.hasClass("chzn-done")) {
-          return $this.data('chosen', new Chosen(this, options));
+        chosen = $this.data('chosen');
+        if (options === 'destroy') {
+          if (chosen instanceof Chosen) {
+            chosen.destroy();
+          }
+          return;
+        }
+        if (!(chosen instanceof Chosen)) {
+          $this.data('chosen', new Chosen(this, options));
         }
       });
     }
   });
 
-  Chosen = (function(_super) {
-
-    __extends(Chosen, _super);
+  Chosen = (function(superClass) {
+    extend(Chosen, superClass);
 
     function Chosen() {
       return Chosen.__super__.constructor.apply(this, arguments);
@@ -363,153 +648,233 @@ Copyright (c) 2011 by Harvest
 
     Chosen.prototype.setup = function() {
       this.form_field_jq = $(this.form_field);
-      this.current_selectedIndex = this.form_field.selectedIndex;
-      return this.is_rtl = this.form_field_jq.hasClass("chzn-rtl");
-    };
-
-    Chosen.prototype.finish_setup = function() {
-      return this.form_field_jq.addClass("chzn-done");
+      return this.current_selectedIndex = this.form_field.selectedIndex;
     };
 
     Chosen.prototype.set_up_html = function() {
       var container_classes, container_props;
-      this.container_id = this.form_field.id.length ? this.form_field.id.replace(/[^\w]/g, '_') : this.generate_field_id();
-      this.container_id += "_chzn";
-      container_classes = ["chzn-container"];
-      container_classes.push("chzn-container-" + (this.is_multiple ? "multi" : "single"));
+      container_classes = ["chosen-container"];
+      container_classes.push("chosen-container-" + (this.is_multiple ? "multi" : "single"));
       if (this.inherit_select_classes && this.form_field.className) {
         container_classes.push(this.form_field.className);
       }
       if (this.is_rtl) {
-        container_classes.push("chzn-rtl");
+        container_classes.push("chosen-rtl");
       }
       container_props = {
-        'id': this.container_id,
         'class': container_classes.join(' '),
-        'style': "width: " + (this.container_width()) + ";",
         'title': this.form_field.title
       };
+      if (this.form_field.id.length) {
+        container_props.id = this.form_field.id.replace(/[^\w]/g, '_') + "_chosen";
+      }
       this.container = $("<div />", container_props);
+      this.container.width(this.container_width());
       if (this.is_multiple) {
-        this.container.html('<ul class="chzn-choices"><li class="search-field"><input type="text" value="' + this.default_text + '" class="default" autocomplete="off" style="width:auto;" /></li></ul><div class="chzn-drop"><ul class="chzn-results"></ul></div>');
+        this.container.html(this.get_multi_html());
       } else {
-        this.container.html('<a href="javascript:void(0)" class="chzn-single chzn-default" tabindex="-1"><span>' + this.default_text + '</span><div><b></b></div></a><div class="chzn-drop"><div class="chzn-search"><input type="text" autocomplete="off" /></div><ul class="chzn-results"></ul></div>');
+        this.container.html(this.get_single_html());
       }
       this.form_field_jq.hide().after(this.container);
-      this.dropdown = this.container.find('div.chzn-drop').first();
+      this.dropdown = this.container.find('div.chosen-drop').first();
       this.search_field = this.container.find('input').first();
-      this.search_results = this.container.find('ul.chzn-results').first();
+      this.search_results = this.container.find('ul.chosen-results').first();
       this.search_field_scale();
       this.search_no_results = this.container.find('li.no-results').first();
       if (this.is_multiple) {
-        this.search_choices = this.container.find('ul.chzn-choices').first();
+        this.search_choices = this.container.find('ul.chosen-choices').first();
         this.search_container = this.container.find('li.search-field').first();
       } else {
-        this.search_container = this.container.find('div.chzn-search').first();
-        this.selected_item = this.container.find('.chzn-single').first();
+        this.search_container = this.container.find('div.chosen-search').first();
+        this.selected_item = this.container.find('.chosen-single').first();
       }
       this.results_build();
       this.set_tab_index();
-      this.set_label_behavior();
-      return this.form_field_jq.trigger("liszt:ready", {
+      return this.set_label_behavior();
+    };
+
+    Chosen.prototype.on_ready = function() {
+      return this.form_field_jq.trigger("chosen:ready", {
         chosen: this
       });
     };
 
     Chosen.prototype.register_observers = function() {
-      var _this = this;
-      this.container.mousedown(function(evt) {
-        _this.container_mousedown(evt);
-      });
-      this.container.mouseup(function(evt) {
-        _this.container_mouseup(evt);
-      });
-      this.container.mouseenter(function(evt) {
-        _this.mouse_enter(evt);
-      });
-      this.container.mouseleave(function(evt) {
-        _this.mouse_leave(evt);
-      });
-      this.search_results.mouseup(function(evt) {
-        _this.search_results_mouseup(evt);
-      });
-      this.search_results.mouseover(function(evt) {
-        _this.search_results_mouseover(evt);
-      });
-      this.search_results.mouseout(function(evt) {
-        _this.search_results_mouseout(evt);
-      });
-      this.search_results.bind('mousewheel DOMMouseScroll', function(evt) {
-        _this.search_results_mousewheel(evt);
-      });
-      this.form_field_jq.bind("liszt:updated", function(evt) {
-        _this.results_update_field(evt);
-      });
-      this.form_field_jq.bind("liszt:activate", function(evt) {
-        _this.activate_field(evt);
-      });
-      this.form_field_jq.bind("liszt:open", function(evt) {
-        _this.container_mousedown(evt);
-      });
-      this.search_field.blur(function(evt) {
-        _this.input_blur(evt);
-      });
-      this.search_field.keyup(function(evt) {
-        _this.keyup_checker(evt);
-      });
-      this.search_field.keydown(function(evt) {
-        _this.keydown_checker(evt);
-      });
-      this.search_field.focus(function(evt) {
-        _this.input_focus(evt);
-      });
+      this.container.on('touchstart.chosen', (function(_this) {
+        return function(evt) {
+          _this.container_mousedown(evt);
+        };
+      })(this));
+      this.container.on('touchend.chosen', (function(_this) {
+        return function(evt) {
+          _this.container_mouseup(evt);
+        };
+      })(this));
+      this.container.on('mousedown.chosen', (function(_this) {
+        return function(evt) {
+          _this.container_mousedown(evt);
+        };
+      })(this));
+      this.container.on('mouseup.chosen', (function(_this) {
+        return function(evt) {
+          _this.container_mouseup(evt);
+        };
+      })(this));
+      this.container.on('mouseenter.chosen', (function(_this) {
+        return function(evt) {
+          _this.mouse_enter(evt);
+        };
+      })(this));
+      this.container.on('mouseleave.chosen', (function(_this) {
+        return function(evt) {
+          _this.mouse_leave(evt);
+        };
+      })(this));
+      this.search_results.on('mouseup.chosen', (function(_this) {
+        return function(evt) {
+          _this.search_results_mouseup(evt);
+        };
+      })(this));
+      this.search_results.on('mouseover.chosen', (function(_this) {
+        return function(evt) {
+          _this.search_results_mouseover(evt);
+        };
+      })(this));
+      this.search_results.on('mouseout.chosen', (function(_this) {
+        return function(evt) {
+          _this.search_results_mouseout(evt);
+        };
+      })(this));
+      this.search_results.on('mousewheel.chosen DOMMouseScroll.chosen', (function(_this) {
+        return function(evt) {
+          _this.search_results_mousewheel(evt);
+        };
+      })(this));
+      this.search_results.on('touchstart.chosen', (function(_this) {
+        return function(evt) {
+          _this.search_results_touchstart(evt);
+        };
+      })(this));
+      this.search_results.on('touchmove.chosen', (function(_this) {
+        return function(evt) {
+          _this.search_results_touchmove(evt);
+        };
+      })(this));
+      this.search_results.on('touchend.chosen', (function(_this) {
+        return function(evt) {
+          _this.search_results_touchend(evt);
+        };
+      })(this));
+      this.form_field_jq.on("chosen:updated.chosen", (function(_this) {
+        return function(evt) {
+          _this.results_update_field(evt);
+        };
+      })(this));
+      this.form_field_jq.on("chosen:activate.chosen", (function(_this) {
+        return function(evt) {
+          _this.activate_field(evt);
+        };
+      })(this));
+      this.form_field_jq.on("chosen:open.chosen", (function(_this) {
+        return function(evt) {
+          _this.container_mousedown(evt);
+        };
+      })(this));
+      this.form_field_jq.on("chosen:close.chosen", (function(_this) {
+        return function(evt) {
+          _this.close_field(evt);
+        };
+      })(this));
+      this.search_field.on('blur.chosen', (function(_this) {
+        return function(evt) {
+          _this.input_blur(evt);
+        };
+      })(this));
+      this.search_field.on('keyup.chosen', (function(_this) {
+        return function(evt) {
+          _this.keyup_checker(evt);
+        };
+      })(this));
+      this.search_field.on('keydown.chosen', (function(_this) {
+        return function(evt) {
+          _this.keydown_checker(evt);
+        };
+      })(this));
+      this.search_field.on('focus.chosen', (function(_this) {
+        return function(evt) {
+          _this.input_focus(evt);
+        };
+      })(this));
+      this.search_field.on('cut.chosen', (function(_this) {
+        return function(evt) {
+          _this.clipboard_event_checker(evt);
+        };
+      })(this));
+      this.search_field.on('paste.chosen', (function(_this) {
+        return function(evt) {
+          _this.clipboard_event_checker(evt);
+        };
+      })(this));
       if (this.is_multiple) {
-        return this.search_choices.click(function(evt) {
-          _this.choices_click(evt);
-        });
+        return this.search_choices.on('click.chosen', (function(_this) {
+          return function(evt) {
+            _this.choices_click(evt);
+          };
+        })(this));
       } else {
-        return this.container.click(function(evt) {
+        return this.container.on('click.chosen', function(evt) {
           evt.preventDefault();
         });
       }
     };
 
+    Chosen.prototype.destroy = function() {
+      $(this.container[0].ownerDocument).off('click.chosen', this.click_test_action);
+      if (this.form_field_label.length > 0) {
+        this.form_field_label.off('click.chosen');
+      }
+      if (this.search_field[0].tabIndex) {
+        this.form_field_jq[0].tabIndex = this.search_field[0].tabIndex;
+      }
+      this.container.remove();
+      this.form_field_jq.removeData('chosen');
+      return this.form_field_jq.show();
+    };
+
     Chosen.prototype.search_field_disabled = function() {
-      this.is_disabled = this.form_field_jq[0].disabled;
+      this.is_disabled = this.form_field.disabled || this.form_field_jq.parents('fieldset').is(':disabled');
+      this.container.toggleClass('chosen-disabled', this.is_disabled);
+      this.search_field[0].disabled = this.is_disabled;
+      if (!this.is_multiple) {
+        this.selected_item.off('focus.chosen', this.activate_field);
+      }
       if (this.is_disabled) {
-        this.container.addClass('chzn-disabled');
-        this.search_field[0].disabled = true;
-        if (!this.is_multiple) {
-          this.selected_item.unbind("focus", this.activate_action);
-        }
         return this.close_field();
-      } else {
-        this.container.removeClass('chzn-disabled');
-        this.search_field[0].disabled = false;
-        if (!this.is_multiple) {
-          return this.selected_item.bind("focus", this.activate_action);
-        }
+      } else if (!this.is_multiple) {
+        return this.selected_item.on('focus.chosen', this.activate_field);
       }
     };
 
     Chosen.prototype.container_mousedown = function(evt) {
-      if (!this.is_disabled) {
-        if (evt && evt.type === "mousedown" && !this.results_showing) {
-          evt.preventDefault();
-        }
-        if (!((evt != null) && ($(evt.target)).hasClass("search-choice-close"))) {
-          if (!this.active_field) {
-            if (this.is_multiple) {
-              this.search_field.val("");
-            }
-            $(document).click(this.click_test_action);
-            this.results_show();
-          } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chzn-single").length)) {
-            evt.preventDefault();
-            this.results_toggle();
+      var ref;
+      if (this.is_disabled) {
+        return;
+      }
+      if (evt && ((ref = evt.type) === 'mousedown' || ref === 'touchstart') && !this.results_showing) {
+        evt.preventDefault();
+      }
+      if (!((evt != null) && ($(evt.target)).hasClass("search-choice-close"))) {
+        if (!this.active_field) {
+          if (this.is_multiple) {
+            this.search_field.val("");
           }
-          return this.activate_field();
+          $(this.container[0].ownerDocument).on('click.chosen', this.click_test_action);
+          this.results_show();
+        } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chosen-single").length)) {
+          evt.preventDefault();
+          this.results_toggle();
         }
+        return this.activate_field();
       }
     };
 
@@ -520,8 +885,10 @@ Copyright (c) 2011 by Harvest
     };
 
     Chosen.prototype.search_results_mousewheel = function(evt) {
-      var delta, _ref, _ref1;
-      delta = -((_ref = evt.originalEvent) != null ? _ref.wheelDelta : void 0) || ((_ref1 = evt.originialEvent) != null ? _ref1.detail : void 0);
+      var delta;
+      if (evt.originalEvent) {
+        delta = evt.originalEvent.deltaY || -evt.originalEvent.wheelDelta || evt.originalEvent.detail;
+      }
       if (delta != null) {
         evt.preventDefault();
         if (evt.type === 'DOMMouseScroll') {
@@ -532,31 +899,36 @@ Copyright (c) 2011 by Harvest
     };
 
     Chosen.prototype.blur_test = function(evt) {
-      if (!this.active_field && this.container.hasClass("chzn-container-active")) {
+      if (!this.active_field && this.container.hasClass("chosen-container-active")) {
         return this.close_field();
       }
     };
 
     Chosen.prototype.close_field = function() {
-      $(document).unbind("click", this.click_test_action);
+      $(this.container[0].ownerDocument).off("click.chosen", this.click_test_action);
       this.active_field = false;
       this.results_hide();
-      this.container.removeClass("chzn-container-active");
-      this.winnow_results_clear();
+      this.container.removeClass("chosen-container-active");
       this.clear_backstroke();
       this.show_search_field_default();
-      return this.search_field_scale();
+      this.search_field_scale();
+      return this.search_field.blur();
     };
 
     Chosen.prototype.activate_field = function() {
-      this.container.addClass("chzn-container-active");
+      if (this.is_disabled) {
+        return;
+      }
+      this.container.addClass("chosen-container-active");
       this.active_field = true;
       this.search_field.val(this.search_field.val());
       return this.search_field.focus();
     };
 
     Chosen.prototype.test_active_click = function(evt) {
-      if ($(evt.target).parents('#' + this.container_id).length) {
+      var active_container;
+      active_container = $(evt.target).closest('.chosen-container');
+      if (active_container.length && this.container[0] === active_container[0]) {
         return this.active_field = true;
       } else {
         return this.close_field();
@@ -564,54 +936,30 @@ Copyright (c) 2011 by Harvest
     };
 
     Chosen.prototype.results_build = function() {
-      var content, data, _i, _len, _ref;
       this.parsing = true;
-      this.results_data = root.SelectParser.select_to_array(this.form_field);
-      if (this.is_multiple && this.choices > 0) {
+      this.selected_option_count = null;
+      this.results_data = SelectParser.select_to_array(this.form_field);
+      if (this.is_multiple) {
         this.search_choices.find("li.search-choice").remove();
-        this.choices = 0;
       } else if (!this.is_multiple) {
-        this.selected_item.addClass("chzn-default").find("span").text(this.default_text);
+        this.single_set_selected_text();
         if (this.disable_search || this.form_field.options.length <= this.disable_search_threshold) {
-          this.container.addClass("chzn-container-single-nosearch");
+          this.search_field[0].readOnly = true;
+          this.container.addClass("chosen-container-single-nosearch");
         } else {
-          this.container.removeClass("chzn-container-single-nosearch");
-        }
-      }
-      content = '';
-      _ref = this.results_data;
-      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
-        data = _ref[_i];
-        if (data.group) {
-          content += this.result_add_group(data);
-        } else if (!data.empty) {
-          content += this.result_add_option(data);
-          if (data.selected && this.is_multiple) {
-            this.choice_build(data);
-          } else if (data.selected && !this.is_multiple) {
-            this.selected_item.removeClass("chzn-default").find("span").text(data.text);
-            if (this.allow_single_deselect) {
-              this.single_deselect_control_build();
-            }
-          }
+          this.search_field[0].readOnly = false;
+          this.container.removeClass("chosen-container-single-nosearch");
         }
       }
+      this.update_results_content(this.results_option_build({
+        first: true
+      }));
       this.search_field_disabled();
       this.show_search_field_default();
       this.search_field_scale();
-      this.search_results.html(content);
       return this.parsing = false;
     };
 
-    Chosen.prototype.result_add_group = function(group) {
-      if (!group.disabled) {
-        group.dom_id = this.container_id + "_g_" + group.array_index;
-        return '<li id="' + group.dom_id + '" class="group-result">' + $("<div />").text(group.label).html() + '</li>';
-      } else {
-        return "";
-      }
-    };
-
     Chosen.prototype.result_do_highlight = function(el) {
       var high_bottom, high_top, maxHeight, visible_bottom, visible_top;
       if (el.length) {
@@ -639,61 +987,58 @@ Copyright (c) 2011 by Harvest
     };
 
     Chosen.prototype.results_show = function() {
-      if (this.result_single_selected != null) {
-        this.result_do_highlight(this.result_single_selected);
-      } else if (this.is_multiple && this.max_selected_options <= this.choices) {
-        this.form_field_jq.trigger("liszt:maxselected", {
+      if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
+        this.form_field_jq.trigger("chosen:maxselected", {
           chosen: this
         });
         return false;
       }
-      this.container.addClass("chzn-with-drop");
-      this.form_field_jq.trigger("liszt:showing_dropdown", {
-        chosen: this
-      });
+      this.container.addClass("chosen-with-drop");
       this.results_showing = true;
       this.search_field.focus();
-      this.search_field.val(this.search_field.val());
-      return this.winnow_results();
+      this.search_field.val(this.get_search_field_value());
+      this.winnow_results();
+      return this.form_field_jq.trigger("chosen:showing_dropdown", {
+        chosen: this
+      });
+    };
+
+    Chosen.prototype.update_results_content = function(content) {
+      return this.search_results.html(content);
     };
 
     Chosen.prototype.results_hide = function() {
-      this.result_clear_highlight();
-      this.container.removeClass("chzn-with-drop");
-      this.form_field_jq.trigger("liszt:hiding_dropdown", {
-        chosen: this
-      });
+      if (this.results_showing) {
+        this.result_clear_highlight();
+        this.container.removeClass("chosen-with-drop");
+        this.form_field_jq.trigger("chosen:hiding_dropdown", {
+          chosen: this
+        });
+      }
       return this.results_showing = false;
     };
 
     Chosen.prototype.set_tab_index = function(el) {
       var ti;
-      if (this.form_field_jq.attr("tabindex")) {
-        ti = this.form_field_jq.attr("tabindex");
-        this.form_field_jq.attr("tabindex", -1);
-        return this.search_field.attr("tabindex", ti);
+      if (this.form_field.tabIndex) {
+        ti = this.form_field.tabIndex;
+        this.form_field.tabIndex = -1;
+        return this.search_field[0].tabIndex = ti;
       }
     };
 
     Chosen.prototype.set_label_behavior = function() {
-      var _this = this;
       this.form_field_label = this.form_field_jq.parents("label");
       if (!this.form_field_label.length && this.form_field.id.length) {
-        this.form_field_label = $("label[for=" + this.form_field.id + "]");
+        this.form_field_label = $("label[for='" + this.form_field.id + "']");
       }
       if (this.form_field_label.length > 0) {
-        return this.form_field_label.click(function(evt) {
-          if (_this.is_multiple) {
-            return _this.container_mousedown(evt);
-          } else {
-            return _this.activate_field();
-          }
-        });
+        return this.form_field_label.on('click.chosen', this.label_click_handler);
       }
     };
 
     Chosen.prototype.show_search_field_default = function() {
-      if (this.is_multiple && this.choices < 1 && !this.active_field) {
+      if (this.is_multiple && this.choices_count() < 1 && !this.active_field) {
         this.search_field.val(this.default_text);
         return this.search_field.addClass("default");
       } else {
@@ -721,32 +1066,31 @@ Copyright (c) 2011 by Harvest
     };
 
     Chosen.prototype.search_results_mouseout = function(evt) {
-      if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) {
+      if ($(evt.target).hasClass("active-result") || $(evt.target).parents('.active-result').first()) {
         return this.result_clear_highlight();
       }
     };
 
     Chosen.prototype.choice_build = function(item) {
-      var choice_id, html, link,
-        _this = this;
-      if (this.is_multiple && this.max_selected_options <= this.choices) {
-        this.form_field_jq.trigger("liszt:maxselected", {
-          chosen: this
-        });
-        return false;
-      }
-      choice_id = this.container_id + "_c_" + item.array_index;
-      this.choices += 1;
+      var choice, close_link;
+      choice = $('<li />', {
+        "class": "search-choice"
+      }).html("<span>" + (this.choice_label(item)) + "</span>");
       if (item.disabled) {
-        html = '<li class="search-choice search-choice-disabled" id="' + choice_id + '"><span>' + item.html + '</span></li>';
+        choice.addClass('search-choice-disabled');
       } else {
-        html = '<li class="search-choice" id="' + choice_id + '"><span>' + item.html + '</span><a href="javascript:void(0)" class="search-choice-close" rel="' + item.array_index + '"></a></li>';
+        close_link = $('<a />', {
+          "class": 'search-choice-close',
+          'data-option-array-index': item.array_index
+        });
+        close_link.on('click.chosen', (function(_this) {
+          return function(evt) {
+            return _this.choice_destroy_link_click(evt);
+          };
+        })(this));
+        choice.append(close_link);
       }
-      this.search_container.before(html);
-      link = $('#' + choice_id).find("a").first();
-      return link.click(function(evt) {
-        return _this.choice_destroy_link_click(evt);
-      });
+      return this.search_container.before(choice);
     };
 
     Chosen.prototype.choice_destroy_link_click = function(evt) {
@@ -758,10 +1102,13 @@ Copyright (c) 2011 by Harvest
     };
 
     Chosen.prototype.choice_destroy = function(link) {
-      if (this.result_deselect(link.attr("rel"))) {
-        this.choices -= 1;
-        this.show_search_field_default();
-        if (this.is_multiple && this.choices > 0 && this.search_field.val().length < 1) {
+      if (this.result_deselect(link[0].getAttribute("data-option-array-index"))) {
+        if (this.active_field) {
+          this.search_field.focus();
+        } else {
+          this.show_search_field_default();
+        }
+        if (this.is_multiple && this.choices_count() > 0 && this.get_search_field_value().length < 1) {
           this.results_hide();
         }
         link.parents('li').first().remove();
@@ -770,14 +1117,12 @@ Copyright (c) 2011 by Harvest
     };
 
     Chosen.prototype.results_reset = function() {
+      this.reset_single_select_options();
       this.form_field.options[0].selected = true;
-      this.selected_item.find("span").text(this.default_text);
-      if (!this.is_multiple) {
-        this.selected_item.addClass("chzn-default");
-      }
+      this.single_set_selected_text();
       this.show_search_field_default();
       this.results_reset_cleanup();
-      this.form_field_jq.trigger("change");
+      this.trigger_form_field_change();
       if (this.active_field) {
         return this.results_hide();
       }
@@ -789,64 +1134,74 @@ Copyright (c) 2011 by Harvest
     };
 
     Chosen.prototype.result_select = function(evt) {
-      var high, high_id, item, position;
+      var high, item;
       if (this.result_highlight) {
         high = this.result_highlight;
-        high_id = high.attr("id");
         this.result_clear_highlight();
+        if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
+          this.form_field_jq.trigger("chosen:maxselected", {
+            chosen: this
+          });
+          return false;
+        }
         if (this.is_multiple) {
-          this.result_deactivate(high);
+          high.removeClass("active-result");
         } else {
-          this.search_results.find(".result-selected").removeClass("result-selected");
-          this.result_single_selected = high;
-          this.selected_item.removeClass("chzn-default");
+          this.reset_single_select_options();
         }
         high.addClass("result-selected");
-        position = high_id.substr(high_id.lastIndexOf("_") + 1);
-        item = this.results_data[position];
+        item = this.results_data[high[0].getAttribute("data-option-array-index")];
         item.selected = true;
         this.form_field.options[item.options_index].selected = true;
+        this.selected_option_count = null;
+        this.search_field.val("");
         if (this.is_multiple) {
           this.choice_build(item);
         } else {
-          this.selected_item.find("span").first().text(item.text);
-          if (this.allow_single_deselect) {
-            this.single_deselect_control_build();
-          }
+          this.single_set_selected_text(this.choice_label(item));
         }
-        if (!((evt.metaKey || evt.ctrlKey) && this.is_multiple)) {
+        if (this.is_multiple && (!this.hide_results_on_select || (evt.metaKey || evt.ctrlKey))) {
+          this.winnow_results();
+        } else {
           this.results_hide();
+          this.show_search_field_default();
         }
-        this.search_field.val("");
         if (this.is_multiple || this.form_field.selectedIndex !== this.current_selectedIndex) {
-          this.form_field_jq.trigger("change", {
-            'selected': this.form_field.options[item.options_index].value
+          this.trigger_form_field_change({
+            selected: this.form_field.options[item.options_index].value
           });
         }
         this.current_selectedIndex = this.form_field.selectedIndex;
+        evt.preventDefault();
         return this.search_field_scale();
       }
     };
 
-    Chosen.prototype.result_activate = function(el) {
-      return el.addClass("active-result");
-    };
-
-    Chosen.prototype.result_deactivate = function(el) {
-      return el.removeClass("active-result");
+    Chosen.prototype.single_set_selected_text = function(text) {
+      if (text == null) {
+        text = this.default_text;
+      }
+      if (text === this.default_text) {
+        this.selected_item.addClass("chosen-default");
+      } else {
+        this.single_deselect_control_build();
+        this.selected_item.removeClass("chosen-default");
+      }
+      return this.selected_item.find("span").html(text);
     };
 
     Chosen.prototype.result_deselect = function(pos) {
-      var result, result_data;
+      var result_data;
       result_data = this.results_data[pos];
       if (!this.form_field.options[result_data.options_index].disabled) {
         result_data.selected = false;
         this.form_field.options[result_data.options_index].selected = false;
-        result = $("#" + this.container_id + "_o_" + pos);
-        result.removeClass("result-selected").addClass("active-result").show();
+        this.selected_option_count = null;
         this.result_clear_highlight();
-        this.winnow_results();
-        this.form_field_jq.trigger("change", {
+        if (this.results_showing) {
+          this.winnow_results();
+        }
+        this.trigger_form_field_change({
           deselected: this.form_field.options[result_data.options_index].value
         });
         this.search_field_scale();
@@ -857,108 +1212,43 @@ Copyright (c) 2011 by Harvest
     };
 
     Chosen.prototype.single_deselect_control_build = function() {
-      if (this.allow_single_deselect && this.selected_item.find("abbr").length < 1) {
-        return this.selected_item.find("span").first().after("<abbr class=\"search-choice-close\"></abbr>");
+      if (!this.allow_single_deselect) {
+        return;
+      }
+      if (!this.selected_item.find("abbr").length) {
+        this.selected_item.find("span").first().after("<abbr class=\"search-choice-close\"></abbr>");
       }
+      return this.selected_item.addClass("chosen-single-with-deselect");
     };
 
-    Chosen.prototype.winnow_results = function() {
-      var found, option, part, parts, regex, regexAnchor, result, result_id, results, searchText, startpos, text, zregex, _i, _j, _len, _len1, _ref;
-      this.no_results_clear();
-      results = 0;
-      searchText = this.search_field.val() === this.default_text ? "" : $('<div/>').text($.trim(this.search_field.val())).html();
-      regexAnchor = this.search_contains ? "" : "^";
-      regex = new RegExp(regexAnchor + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i');
-      zregex = new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i');
-      _ref = this.results_data;
-      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
-        option = _ref[_i];
-        if (!option.disabled && !option.empty) {
-          if (option.group) {
-            $('#' + option.dom_id).css('display', 'none');
-          } else if (!(this.is_multiple && option.selected)) {
-            found = false;
-            result_id = option.dom_id;
-            result = $("#" + result_id);
-            if (regex.test(option.html)) {
-              found = true;
-              results += 1;
-            } else if (this.enable_split_word_search && (option.html.indexOf(" ") >= 0 || option.html.indexOf("[") === 0)) {
-              parts = option.html.replace(/\[|\]/g, "").split(" ");
-              if (parts.length) {
-                for (_j = 0, _len1 = parts.length; _j < _len1; _j++) {
-                  part = parts[_j];
-                  if (regex.test(part)) {
-                    found = true;
-                    results += 1;
-                  }
-                }
-              }
-            }
-            if (found) {
-              if (searchText.length) {
-                startpos = option.html.search(zregex);
-                text = option.html.substr(0, startpos + searchText.length) + '</em>' + option.html.substr(startpos + searchText.length);
-                text = text.substr(0, startpos) + '<em>' + text.substr(startpos);
-              } else {
-                text = option.html;
-              }
-              result.html(text);
-              this.result_activate(result);
-              if (option.group_array_index != null) {
-                $("#" + this.results_data[option.group_array_index].dom_id).css('display', 'list-item');
-              }
-            } else {
-              if (this.result_highlight && result_id === this.result_highlight.attr('id')) {
-                this.result_clear_highlight();
-              }
-              this.result_deactivate(result);
-            }
-          }
-        }
-      }
-      if (results < 1 && searchText.length) {
-        return this.no_results(searchText);
-      } else {
-        return this.winnow_results_set_highlight();
-      }
+    Chosen.prototype.get_search_field_value = function() {
+      return this.search_field.val();
     };
 
-    Chosen.prototype.winnow_results_clear = function() {
-      var li, lis, _i, _len, _results;
-      this.search_field.val("");
-      lis = this.search_results.find("li");
-      _results = [];
-      for (_i = 0, _len = lis.length; _i < _len; _i++) {
-        li = lis[_i];
-        li = $(li);
-        if (li.hasClass("group-result")) {
-          _results.push(li.css('display', 'auto'));
-        } else if (!this.is_multiple || !li.hasClass("result-selected")) {
-          _results.push(this.result_activate(li));
-        } else {
-          _results.push(void 0);
-        }
-      }
-      return _results;
+    Chosen.prototype.get_search_text = function() {
+      return $.trim(this.get_search_field_value());
+    };
+
+    Chosen.prototype.escape_html = function(text) {
+      return $('<div/>').text(text).html();
     };
 
     Chosen.prototype.winnow_results_set_highlight = function() {
       var do_high, selected_results;
-      if (!this.result_highlight) {
-        selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : [];
-        do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first();
-        if (do_high != null) {
-          return this.result_do_highlight(do_high);
-        }
+      selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : [];
+      do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first();
+      if (do_high != null) {
+        return this.result_do_highlight(do_high);
       }
     };
 
     Chosen.prototype.no_results = function(terms) {
       var no_results_html;
-      no_results_html = $('<li class="no-results">' + this.results_none_found + ' "<span></span>"</li>');
-      no_results_html.find("span").first().html(terms);
-      return this.search_results.append(no_results_html);
+      no_results_html = this.get_no_results_html(terms);
+      this.search_results.append(no_results_html);
+      return this.form_field_jq.trigger("chosen:no_results", {
+        chosen: this
+      });
     };
 
     Chosen.prototype.no_results_clear = function() {
@@ -966,19 +1256,13 @@ Copyright (c) 2011 by Harvest
     };
 
     Chosen.prototype.keydown_arrow = function() {
-      var first_active, next_sib;
-      if (!this.result_highlight) {
-        first_active = this.search_results.find("li.active-result").first();
-        if (first_active) {
-          this.result_do_highlight($(first_active));
-        }
-      } else if (this.results_showing) {
+      var next_sib;
+      if (this.results_showing && this.result_highlight) {
         next_sib = this.result_highlight.nextAll("li.active-result").first();
         if (next_sib) {
-          this.result_do_highlight(next_sib);
+          return this.result_do_highlight(next_sib);
         }
-      }
-      if (!this.results_showing) {
+      } else {
         return this.results_show();
       }
     };
@@ -992,7 +1276,7 @@ Copyright (c) 2011 by Harvest
         if (prev_sibs.length) {
           return this.result_do_highlight(prev_sibs.first());
         } else {
-          if (this.choices > 0) {
+          if (this.choices_count() > 0) {
             this.results_hide();
           }
           return this.result_clear_highlight();
@@ -1025,79 +1309,41 @@ Copyright (c) 2011 by Harvest
       return this.pending_backstroke = null;
     };
 
-    Chosen.prototype.keydown_checker = function(evt) {
-      var stroke, _ref;
-      stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
-      this.search_field_scale();
-      if (stroke !== 8 && this.pending_backstroke) {
-        this.clear_backstroke();
+    Chosen.prototype.search_field_scale = function() {
+      var div, i, len, style, style_block, styles, width;
+      if (!this.is_multiple) {
+        return;
       }
-      switch (stroke) {
-        case 8:
-          this.backstroke_length = this.search_field.val().length;
-          break;
-        case 9:
-          if (this.results_showing && !this.is_multiple) {
-            this.result_select(evt);
-          }
-          this.mouse_on_container = false;
-          break;
-        case 13:
-          evt.preventDefault();
-          break;
-        case 38:
-          evt.preventDefault();
-          this.keyup_arrow();
-          break;
-        case 40:
-          this.keydown_arrow();
-          break;
+      style_block = {
+        position: 'absolute',
+        left: '-1000px',
+        top: '-1000px',
+        display: 'none',
+        whiteSpace: 'pre'
+      };
+      styles = ['fontSize', 'fontStyle', 'fontWeight', 'fontFamily', 'lineHeight', 'textTransform', 'letterSpacing'];
+      for (i = 0, len = styles.length; i < len; i++) {
+        style = styles[i];
+        style_block[style] = this.search_field.css(style);
       }
-    };
-
-    Chosen.prototype.search_field_scale = function() {
-      var div, h, style, style_block, styles, w, _i, _len;
-      if (this.is_multiple) {
-        h = 0;
-        w = 0;
-        style_block = "position:absolute; left: -1000px; top: -1000px; display:none;";
-        styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing'];
-        for (_i = 0, _len = styles.length; _i < _len; _i++) {
-          style = styles[_i];
-          style_block += style + ":" + this.search_field.css(style) + ";";
-        }
-        div = $('<div />', {
-          'style': style_block
-        });
-        div.text(this.search_field.val());
-        $('body').append(div);
-        w = div.width() + 25;
-        div.remove();
-        if (!this.f_width) {
-          this.f_width = this.container.outerWidth();
-        }
-        if (w > this.f_width - 10) {
-          w = this.f_width - 10;
-        }
-        return this.search_field.css({
-          'width': w + 'px'
-        });
+      div = $('<div />').css(style_block);
+      div.text(this.get_search_field_value());
+      $('body').append(div);
+      width = div.width() + 25;
+      div.remove();
+      if (this.container.is(':visible')) {
+        width = Math.min(this.container.outerWidth() - 10, width);
       }
+      return this.search_field.width(width);
     };
 
-    Chosen.prototype.generate_random_id = function() {
-      var string;
-      string = "sel" + this.generate_random_char() + this.generate_random_char() + this.generate_random_char();
-      while ($("#" + string).length > 0) {
-        string += this.generate_random_char();
-      }
-      return string;
+    Chosen.prototype.trigger_form_field_change = function(extra) {
+      this.form_field_jq.trigger("input", extra);
+      return this.form_field_jq.trigger("change", extra);
     };
 
     return Chosen;
 
   })(AbstractChosen);
 
-  root.Chosen = Chosen;
-
 }).call(this);
index 11f472e..ce24b0d 100644 (file)
@@ -2,18 +2,20 @@
 
 /* Table Sorting */
 
-table.jquery-tablesorter th.headerSort {
-       .background-image-svg( 'images/sort_both.svg', 'images/sort_both.png' );
-       cursor: pointer;
-       background-repeat: no-repeat;
-       background-position: center right;
-       padding-right: 21px;
-}
+table.jquery-tablesorter {
+       th.headerSort {
+               .background-image-svg( 'images/sort_both.svg', 'images/sort_both.png' );
+               cursor: pointer;
+               background-repeat: no-repeat;
+               background-position: center right;
+               padding-right: 21px;
+       }
 
-table.jquery-tablesorter th.headerSortUp {
-       .background-image-svg( 'images/sort_up.svg', 'images/sort_up.png' );
-}
+       th.headerSortUp {
+               .background-image-svg( 'images/sort_up.svg', 'images/sort_up.png' );
+       }
 
-table.jquery-tablesorter th.headerSortDown {
-       .background-image-svg( 'images/sort_down.svg', 'images/sort_down.png' );
+       th.headerSortDown {
+               .background-image-svg( 'images/sort_down.svg', 'images/sort_down.png' );
+       }
 }
index 1d578e4..e4443f6 100644 (file)
        .editOptions {
                border-radius: 0 0 2px 2px;
        }
+
+       .editButtons .oo-ui-buttonInputWidget,
+       .cancelLink,
+       .editHelp {
+               margin-top: 0.5em;
+       }
+
+       .cancelLink,
+       .editHelp {
+               display: inline-block;
+               vertical-align: middle;
+       }
+
+       // FIXME: Remove CSS magic together with DOM element in T183672
+       .mw-editButtons-pipe-separator {
+               display: inline-block;
+               padding-top: 0.625em;
+               padding-bottom: 0.546875em;
+               line-height: 1.172em;
+               vertical-align: middle;
+       }
 }
index f4cdae3..bb29b36 100644 (file)
@@ -34,6 +34,7 @@
         * @cfg {string} [whatsThis.body] The body of the whatsThis popup message
         * @cfg {string} [whatsThis.url] The url for the link in the whatsThis popup message
         * @cfg {string} [whatsThis.linkMessage] The text for the link in the whatsThis popup message
+        * @cfg {boolean} [visible=true] The visibility of the group
         */
        mw.rcfilters.dm.FilterGroup = function MwRcfiltersDmFilterGroup( name, config ) {
                config = config || {};
@@ -52,6 +53,7 @@
                this.numericRange = config.range;
                this.separator = config.separator || '|';
                this.labelPrefixKey = config.labelPrefixKey;
+               this.visible = config.visible === undefined ? true : !!config.visible;
 
                this.currSelected = null;
                this.active = !!config.active;
 
                return value;
        };
+
+       /**
+        * Toggle the visibility of this group
+        *
+        * @param {boolean} [isVisible] Item is visible
+        */
+       mw.rcfilters.dm.FilterGroup.prototype.toggleVisible = function ( isVisible ) {
+               isVisible = isVisible === undefined ? !this.visible : isVisible;
+
+               if ( this.visible !== isVisible ) {
+                       this.visible = isVisible;
+                       this.emit( 'update' );
+               }
+       };
+
+       /**
+        * Check whether the group is visible
+        *
+        * @return {boolean} Group is visible
+        */
+       mw.rcfilters.dm.FilterGroup.prototype.isVisible = function () {
+               return this.visible;
+       };
+
+       /**
+        * Set the visibility of the items under this group by the given items array
+        *
+        * @param {mw.rcfilters.dm.ItemModel[]} visibleItems An array of visible items
+        */
+       mw.rcfilters.dm.FilterGroup.prototype.setVisibleItems = function ( visibleItems ) {
+               this.getItems().forEach( function ( itemModel ) {
+                       itemModel.toggleVisible( visibleItems.indexOf( itemModel ) !== -1 );
+               } );
+       };
 }( mediaWiki ) );
index 4e2079d..682a937 100644 (file)
@@ -12,6 +12,7 @@
         *  selected, makes inactive.
         * @cfg {string[]} [subset] Defining the names of filters that are a subset of this filter
         * @cfg {Object} [conflicts] Defines the conflicts for this filter
+        * @cfg {boolean} [visible=true] The visibility of the group
         */
        mw.rcfilters.dm.FilterItem = function MwRcfiltersDmFilterItem( param, groupModel, config ) {
                config = config || {};
@@ -29,6 +30,7 @@
                this.subset = config.subset || [];
                this.conflicts = config.conflicts || {};
                this.superset = [];
+               this.visible = config.visible === undefined ? true : !!config.visible;
 
                // Interaction states
                this.included = false;
                        this.emit( 'update' );
                }
        };
+
+       /**
+        * Toggle the visibility of this item
+        *
+        * @param {boolean} [isVisible] Item is visible
+        */
+       mw.rcfilters.dm.FilterItem.prototype.toggleVisible = function ( isVisible ) {
+               isVisible = isVisible === undefined ? !this.visible : !!isVisible;
+
+               if ( this.visible !== isVisible ) {
+                       this.visible = isVisible;
+                       this.emit( 'update' );
+               }
+       };
+
+       /**
+        * Check whether the item is visible
+        *
+        * @return {boolean} Item is visible
+        */
+       mw.rcfilters.dm.FilterItem.prototype.isVisible = function () {
+               return this.visible;
+       };
+
 }( mediaWiki ) );
index 8d22c23..c9f5924 100644 (file)
@@ -20,6 +20,7 @@
 
                this.views = {};
                this.currentView = 'default';
+               this.searchQuery = null;
 
                // Events
                this.aggregate( { update: 'filterItemUpdate' } );
                        }
                } );
 
-               this.currentView = 'default';
+               this.setSearch( '' );
 
                this.updateHighlightedState();
 
 
                $.each( this.groups, function ( name, model ) {
                        if ( model.isSticky() ) {
-                               $.extend( true, result, model.getDefaultParams() );
+                               $.extend( true, result, model.getParamRepresentation() );
                        }
                } );
 
        mw.rcfilters.dm.FiltersViewModel.prototype.areNamespacesEffectivelyInverted = function () {
                return this.getInvertModel().isSelected() &&
                        this.getSelectedItems().some( function ( itemModel ) {
-                               return itemModel.getGroupModel().getView() === 'namespace';
+                               return itemModel.getGroupModel().getName() === 'namespace';
                        } );
        };
 
                return allSelected;
        };
 
-       /**
-        * Switch the current view
-        *
-        * @param {string} view View name
-        * @fires update
-        */
-       mw.rcfilters.dm.FiltersViewModel.prototype.switchView = function ( view ) {
-               if ( this.views[ view ] && this.currentView !== view ) {
-                       this.currentView = view;
-                       this.emit( 'update' );
-               }
-       };
-
        /**
         * Get the current view
         *
                return result;
        };
 
+       /**
+        * Return a version of the given string that is without any
+        * view triggers.
+        *
+        * @param {string} str Given string
+        * @return {string} Result
+        */
+       mw.rcfilters.dm.FiltersViewModel.prototype.removeViewTriggers = function ( str ) {
+               if ( this.getViewFromString( str ) !== 'default' ) {
+                       str = str.substr( 1 );
+               }
+
+               return str;
+       };
+
+       /**
+        * Get the view from the given string by a trigger, if it exists
+        *
+        * @param {string} str Given string
+        * @return {string} View name
+        */
+       mw.rcfilters.dm.FiltersViewModel.prototype.getViewFromString = function ( str ) {
+               return this.getViewByTrigger( str.substr( 0, 1 ) );
+       };
+
+       /**
+        * Set the current search for the system.
+        * This also dictates what items and groups are visible according
+        * to the search in #findMatches
+        *
+        * @param {string} searchQuery Search query, including triggers
+        * @fires searchChange
+        */
+       mw.rcfilters.dm.FiltersViewModel.prototype.setSearch = function ( searchQuery ) {
+               var visibleGroups, visibleGroupNames;
+
+               if ( this.searchQuery !== searchQuery ) {
+                       // Check if the view changed
+                       this.switchView( this.getViewFromString( searchQuery ) );
+
+                       visibleGroups = this.findMatches( searchQuery );
+                       visibleGroupNames = Object.keys( visibleGroups );
+
+                       // Update visibility of items and groups
+                       $.each( this.getFilterGroups(), function ( groupName, groupModel ) {
+                               // Check if the group is visible at all
+                               groupModel.toggleVisible( visibleGroupNames.indexOf( groupName ) !== -1 );
+                               groupModel.setVisibleItems( visibleGroups[ groupName ] || [] );
+                       } );
+
+                       this.searchQuery = searchQuery;
+                       this.emit( 'searchChange', this.searchQuery );
+               }
+       };
+
+       /**
+        * Get the current search
+        *
+        * @return {string} Current search query
+        */
+       mw.rcfilters.dm.FiltersViewModel.prototype.getSearch = function () {
+               return this.searchQuery;
+       };
+
+       /**
+        * Switch the current view
+        *
+        * @private
+        * @param {string} view View name
+        */
+       mw.rcfilters.dm.FiltersViewModel.prototype.switchView = function ( view ) {
+               if ( this.views[ view ] && this.currentView !== view ) {
+                       this.currentView = view;
+               }
+       };
+
        /**
         * Toggle the highlight feature on and off.
         * Propagate the change to filter items.
                this.getItemByName( filterName ).clearHighlightColor();
        };
 
-       /**
-        * Return a version of the given string that is without any
-        * view triggers.
-        *
-        * @param {string} str Given string
-        * @return {string} Result
-        */
-       mw.rcfilters.dm.FiltersViewModel.prototype.removeViewTriggers = function ( str ) {
-               if ( this.getViewByTrigger( str.substr( 0, 1 ) ) !== 'default' ) {
-                       str = str.substr( 1 );
-               }
-
-               return str;
-       };
 }( mediaWiki, jQuery ) );
index 79546b4..cec570c 100644 (file)
                } );
        };
 
-       /**
-        * Switch the view of the filters model
-        *
-        * @param {string} view Requested view
-        */
-       mw.rcfilters.Controller.prototype.switchView = function ( view ) {
-               this.filtersModel.switchView( view );
-       };
-
        /**
         * Reset to default filters
         */
                        this.updateChangesList( null, 'markSeen' );
                }.bind( this ) );
        };
+
+       /**
+        * Set the current search for the system.
+        *
+        * @param {string} searchQuery Search query, including triggers
+        */
+       mw.rcfilters.Controller.prototype.setSearch = function ( searchQuery ) {
+               this.filtersModel.setSearch( searchQuery );
+       };
+
+       /**
+        * Switch the view by changing the search query trigger
+        * without changing the search term
+        *
+        * @param  {string} view View to change to
+        */
+       mw.rcfilters.Controller.prototype.switchView = function ( view ) {
+               this.setSearch(
+                       this.filtersModel.getViewTrigger( view ) +
+                       this.filtersModel.removeViewTriggers( this.filtersModel.getSearch() )
+               );
+       };
+
+       /**
+        * Reset the search for a specific view. This means we null the search query
+        * and replace it with the relevant trigger for the requested view
+        *
+        * @param  {string} [view='default'] View to change to
+        */
+       mw.rcfilters.Controller.prototype.resetSearchForView = function ( view ) {
+               view = view || 'default';
+
+               this.setSearch(
+                       this.filtersModel.getViewTrigger( view )
+               );
+       };
 }( mediaWiki, jQuery ) );
index 7dd78e7..0906d68 100644 (file)
        }
 
        &-noresults {
-               display: none;
                padding: 0.5em;
                color: @colorGray5;
-
-               .oo-ui-menuSelectWidget-invisible & {
-                       display: inline-block;
-               }
        }
 
        &-body {
diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.Overlay.vector.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.Overlay.vector.less
new file mode 100644 (file)
index 0000000..528707b
--- /dev/null
@@ -0,0 +1,4 @@
+// Fix z-index for the overlay in Vector, see T183442
+.mw-rcfilters-ui-overlay {
+       z-index: 101;
+}
diff --git a/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTargetPageWidget.less b/resources/src/mediawiki.rcfilters/styles/mw.rcfilters.ui.RclTargetPageWidget.less
new file mode 100644 (file)
index 0000000..2d92e27
--- /dev/null
@@ -0,0 +1,3 @@
+.mw-rcfilters-ui-rclTargetPageWidget {
+       min-width: 400px;
+}
index af01f68..d63f35b 100644 (file)
@@ -1,6 +1,4 @@
 .mw-rcfilters-ui-rclToOrFromWidget {
-       min-width: 340px;
-
        // need to be very specific to override bg-color
        &.oo-ui-dropdownWidget.oo-ui-widget-enabled {
                .oo-ui-dropdownWidget-handle {
index dceb132..c047e83 100644 (file)
                        .connect( this, { click: 'onInvertNamespacesButtonClick' } );
                this.model.connect( this, {
                        highlightChange: 'onModelHighlightChange',
-                       update: 'onModelUpdate',
+                       searchChange: 'onModelSearchChange',
                        initialize: 'onModelInitialize'
                } );
+               this.view = this.model.getCurrentView();
 
                // Initialize
                this.$element
        /**
         * Respond to model update event
         */
-       mw.rcfilters.ui.FilterMenuHeaderWidget.prototype.onModelUpdate = function () {
+       mw.rcfilters.ui.FilterMenuHeaderWidget.prototype.onModelSearchChange = function () {
                var currentView = this.model.getCurrentView();
 
-               this.setLabel( this.model.getViewTitle( currentView ) );
+               if ( this.view !== currentView ) {
+                       this.setLabel( this.model.getViewTitle( currentView ) );
 
-               this.invertNamespacesButton.toggle( currentView === 'namespaces' );
-               this.backButton.toggle( currentView !== 'default' );
-               this.helpIcon.toggle( currentView === 'tags' );
+                       this.invertNamespacesButton.toggle( currentView === 'namespaces' );
+                       this.backButton.toggle( currentView !== 'default' );
+                       this.helpIcon.toggle( currentView === 'tags' );
+                       this.view = currentView;
+               }
        };
 
        /**
index e053914..20bf73f 100644 (file)
                }
 
                // Events
-               this.model.connect( this, { update: 'onModelUpdate' } );
+               this.model.connect( this, { update: 'updateUiBasedOnState' } );
 
                // Initialize
                this.$element
                        .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget' )
                        .addClass( 'mw-rcfilters-ui-filterMenuSectionOptionWidget-name-' + this.model.getName() )
                        .append( $header );
+               this.updateUiBasedOnState();
        };
 
        /* Initialize */
        /**
         * Respond to model update event
         */
-       mw.rcfilters.ui.FilterMenuSectionOptionWidget.prototype.onModelUpdate = function () {
+       mw.rcfilters.ui.FilterMenuSectionOptionWidget.prototype.updateUiBasedOnState = function () {
                this.$element.toggleClass(
                        'mw-rcfilters-ui-filterMenuSectionOptionWidget-active',
                        this.model.isActive()
                );
+               this.toggle( this.model.isVisible() );
        };
 
        /**
index 91a2d5f..3f47df2 100644 (file)
@@ -41,6 +41,8 @@
                        allowReordering: false,
                        $overlay: this.$overlay,
                        menu: {
+                               // Our filtering is done through the model
+                               filterFromInput: false,
                                hideWhenOutOfView: false,
                                hideOnChoose: false,
                                width: 650,
                this.model.connect( this, {
                        initialize: 'onModelInitialize',
                        update: 'onModelUpdate',
+                       searchChange: 'onModelSearchChange',
                        itemUpdate: 'onModelItemUpdate',
                        highlightChange: 'onModelHighlightChange'
                } );
                this.focus();
        };
 
+       /**
+        * Respond to model search change event
+        *
+        * @param {string} value Search value
+        */
+       mw.rcfilters.ui.FilterTagMultiselectWidget.prototype.onModelSearchChange = function ( value ) {
+               this.input.setValue( value );
+       };
+
        /**
         * Respond to input change event
         *
         * @param {string} value Value of the input
         */
        mw.rcfilters.ui.FilterTagMultiselectWidget.prototype.onInputChange = function ( value ) {
-               var view;
-
-               value = value.trim();
-
-               view = this.model.getViewByTrigger( value.substr( 0, 1 ) );
-
-               this.controller.switchView( view );
+               this.controller.setSearch( value );
        };
+
        /**
         * Respond to query button click
         */
                        // Clear selection
                        this.selectTag( null );
 
-                       // Clear input if the only thing in the input is the prefix
-                       if (
-                               this.input.getValue().trim() === this.model.getViewTrigger( this.model.getCurrentView() )
-                       ) {
-                               // Clear the input
-                               this.input.setValue( '' );
-                       }
+                       // Clear the search
+                       this.controller.setSearch( '' );
 
                        // Log filter grouping
                        this.controller.trackFilterGroupings( 'filtermenu' );
         * @inheritdoc
         */
        mw.rcfilters.ui.FilterTagMultiselectWidget.prototype.onTagSelect = function ( tagItem ) {
-               var widget = this,
-                       menuOption = this.menu.getItemFromModel( tagItem.getModel() ),
-                       oldInputValue = this.input.getValue().trim();
+               var menuOption = this.menu.getItemFromModel( tagItem.getModel() );
 
                this.menu.setUserSelecting( true );
-
-               // Reset input
-               this.input.setValue( '' );
-
-               // Switch view
-               this.controller.switchView( tagItem.getView() );
-
                // Parent method
                mw.rcfilters.ui.FilterTagMultiselectWidget.parent.prototype.onTagSelect.call( this, tagItem );
 
-               this.menu.selectItem( menuOption );
-               this.selectTag( tagItem );
+               // Switch view
+               this.controller.resetSearchForView( tagItem.getView() );
 
-               // Scroll to the item
-               if ( this.model.removeViewTriggers( oldInputValue ) ) {
-                       // We're binding a 'once' to the itemVisibilityChange event
-                       // so this happens when the menu is ready after the items
-                       // are visible again, in case this is done right after the
-                       // user filtered the results
-                       this.getMenu().once(
-                               'itemVisibilityChange',
-                               function () {
-                                       widget.scrollToTop( menuOption.$element );
-                                       widget.menu.setUserSelecting( false );
-                               }
-                       );
-               } else {
-                       this.scrollToTop( menuOption.$element );
-                       this.menu.setUserSelecting( false );
-               }
+               this.selectTag( tagItem );
+               this.scrollToTop( menuOption.$element );
 
+               this.menu.setUserSelecting( false );
        };
 
        /**
                return new mw.rcfilters.ui.MenuSelectWidget(
                        this.controller,
                        this.model,
-                       $.extend( {
-                               filterFromInput: true
-                       }, menuConfig )
+                       menuConfig
                );
        };
 
index 51fc9bc..1508510 100644 (file)
 
                        this.$element.addClass( classes.join( ' ' ) );
                }
+
+               this.updateUiBasedOnState();
        };
 
        /* Initialization */
                        this.itemModel.isSelected() &&
                        this.invertModel.isSelected()
                );
+               this.toggle( this.itemModel.isVisible() );
        };
 
        /**
index 98acab0..07d8c88 100644 (file)
@@ -33,7 +33,6 @@
                this.userSelecting = false;
 
                this.menuInitialized = false;
-               this.inputValue = '';
                this.$overlay = config.$overlay || this.$element;
                this.$body = $( '<div>' ).addClass( 'mw-rcfilters-ui-menuSelectWidget-body' );
                this.footers = [];
@@ -41,7 +40,9 @@
                // Parent
                mw.rcfilters.ui.MenuSelectWidget.parent.call( this, $.extend( {
                        $autoCloseIgnore: this.$overlay,
-                       width: 650
+                       width: 650,
+                       // Our filtering is done through the model
+                       filterFromInput: false
                }, config ) );
                this.setGroupElement(
                        $( '<div>' )
@@ -65,8 +66,8 @@
 
                // Events
                this.model.connect( this, {
-                       update: 'onModelUpdate',
-                       initialize: 'onModelInitialize'
+                       initialize: 'onModelInitialize',
+                       searchChange: 'onModelSearchChange'
                } );
 
                // Initialization
                }.bind( this ) );
 
                // Switch to the correct view
-               this.switchView( this.model.getCurrentView() );
+               this.updateView();
        };
 
        /* Initialize */
 
        /* Events */
 
-       /**
-        * @event itemVisibilityChange
-        *
-        * Item visibility has changed
-        */
-
        /* Methods */
-
-       /**
-        * Respond to model update event
-        */
-       mw.rcfilters.ui.MenuSelectWidget.prototype.onModelUpdate = function () {
-               // Change view
-               this.switchView( this.model.getCurrentView() );
+       mw.rcfilters.ui.MenuSelectWidget.prototype.onModelSearchChange = function () {
+               this.updateView();
        };
 
        /**
         */
        mw.rcfilters.ui.MenuSelectWidget.prototype.lazyMenuCreation = function () {
                var widget = this,
+                       items = [],
                        viewGroupCount = {},
                        groups = this.model.getFilterGroups();
 
                }
 
                this.menuInitialized = true;
-               // Reset
-               this.clearItems();
 
                // Count groups per view
                $.each( groups, function ( groupName, groupModel ) {
                                // without rebuilding the widgets each time
                                widget.views[ view ] = widget.views[ view ] || [];
                                widget.views[ view ] = widget.views[ view ].concat( currentItems );
+                               items = items.concat( currentItems );
                        }
                } );
 
-               this.switchView( this.model.getCurrentView() );
+               this.addItems( items );
+               this.updateView();
        };
 
        /**
        };
 
        /**
-        * Switch view
-        *
-        * @param {string} [viewName] View name. If not given, default is used.
+        * Update view
         */
-       mw.rcfilters.ui.MenuSelectWidget.prototype.switchView = function ( viewName ) {
-               viewName = viewName || 'default';
+       mw.rcfilters.ui.MenuSelectWidget.prototype.updateView = function () {
+               var viewName = this.model.getCurrentView();
 
                if ( this.views[ viewName ] && this.currentView !== viewName ) {
-                       this.clearItems();
-                       this.addItems( this.views[ viewName ] );
                        this.updateFooterVisibility( viewName );
 
                        this.$element
 
                        this.currentView = viewName;
                        this.scrollToTop();
-                       this.clip();
                }
+
+               this.postProcessItems();
+               this.clip();
        };
 
        /**
        };
 
        /**
-        * @fires itemVisibilityChange
-        * @inheritdoc
+        * Post-process items after the visibility changed. Make sure
+        * that we always have an item selected, and that the no-results
+        * widget appears if the menu is empty.
         */
-       mw.rcfilters.ui.MenuSelectWidget.prototype.updateItemVisibility = function () {
+       mw.rcfilters.ui.MenuSelectWidget.prototype.postProcessItems = function () {
                var i,
                        itemWasSelected = false,
-                       inputVal = this.$input.val(),
                        items = this.getItems();
 
-               // Since the method hides/shows items, we don't want to
-               // call it unless the input actually changed
-               if (
-                       !this.userSelecting &&
-                       this.inputValue !== inputVal
-               ) {
-                       // Parent method
-                       mw.rcfilters.ui.MenuSelectWidget.parent.prototype.updateItemVisibility.call( this );
-
+               // If we are not already selecting an item, always make sure
+               // that the top item is selected
+               if ( !this.userSelecting ) {
                        // Select the first item in the list
                        for ( i = 0; i < items.length; i++ ) {
                                if (
                        if ( !itemWasSelected ) {
                                this.selectItem( null );
                        }
-
-                       // Cache value
-                       this.inputValue = inputVal;
-
-                       this.emit( 'itemVisibilityChange' );
                }
 
                this.noResults.toggle( !this.getItems().some( function ( item ) {
                } )[ 0 ];
        };
 
-       /**
-        * Override the item matcher to use the model's match process
-        *
-        * @inheritdoc
-        */
-       mw.rcfilters.ui.MenuSelectWidget.prototype.getItemMatcher = function ( s ) {
-               var results = this.model.findMatches( s, true );
-
-               return function ( item ) {
-                       return results.indexOf( item.getModel() ) > -1;
-               };
-       };
-
        /**
         * @inheritdoc
         */
index d5c5e26..527d790 100644 (file)
@@ -71,7 +71,9 @@
         * Respond to the model being updated
         */
        mw.rcfilters.ui.RclTargetPageWidget.prototype.updateUiBasedOnModel = function () {
-               var title = mw.Title.newFromText( this.model.getValue() );
-               this.titleSearch.setValue( title ? title.toText() : this.model.getValue() );
+               var title = mw.Title.newFromText( this.model.getValue() ),
+                       text = title ? title.toText() : this.model.getValue();
+               this.titleSearch.setValue( text );
+               this.titleSearch.setTitle( text );
        };
 }( mediaWiki ) );
index bb837e0..f546d97 100644 (file)
@@ -26,7 +26,6 @@
                mw.rcfilters.ui.SaveFiltersPopupButtonWidget.parent.call( this, $.extend( {
                        framed: false,
                        icon: 'unClip',
-                       $overlay: this.$overlay,
                        title: mw.msg( 'rcfilters-savedqueries-add-new-title' ),
                        popup: {
                                classes: [ 'mw-rcfilters-ui-saveFiltersPopupButtonWidget-popup' ],
index 8cd25d8..e2aeffd 100644 (file)
@@ -16,8 +16,9 @@
 }
 
 textarea {
-       /* Support Firefox: Border rule required to override system appearance on Linux */
-       border: 1px solid #a2a9b1;
+       /* Support: Firefox */
+       /* Border rule required to override system appearance on Linux (T136415) */
+       border: 1px solid #c8ccd1;
 }
 
 .editOptions {
index 44868b3..a51008e 100644 (file)
@@ -24,7 +24,7 @@
 global $wgAutoloadClasses;
 $testDir = __DIR__ . "/..";
 
-// @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
+// phpcs:disable Generic.Files.LineLength
 $wgAutoloadClasses += [
 
        # tests/common
@@ -62,6 +62,7 @@ $wgAutoloadClasses += [
        'TestUser' => "$testDir/phpunit/includes/TestUser.php",
        'TestUserRegistry' => "$testDir/phpunit/includes/TestUserRegistry.php",
        'LessFileCompilationTest' => "$testDir/phpunit/LessFileCompilationTest.php",
+       'MediaWikiCoversValidator' => "$testDir/phpunit/MediaWikiCoversValidator.php",
 
        # tests/phpunit/includes
        'RevisionDbTestBase' => "$testDir/phpunit/includes/RevisionDbTestBase.php",
@@ -174,4 +175,4 @@ $wgAutoloadClasses += [
        'ParserTestFileSuite' => "$testDir/phpunit/suites/ParserTestFileSuite.php",
        'ParserTestTopLevelSuite' => "$testDir/phpunit/suites/ParserTestTopLevelSuite.php",
 ];
-// @codingStandardsIgnoreEnd
+// phpcs:enable
index 5bf50ea..5995012 100644 (file)
@@ -57,8 +57,7 @@ class ParserTestParserHook {
                        $parser->static_tag_buf = null;
                        return $tmp;
                } else { // wtf?
-                       return
-                               "\nCall this extension as <statictag>string</statictag> or as" .
+                       return "\nCall this extension as <statictag>string</statictag> or as" .
                                " <statictag action=flush/>, not in any other way.\n" .
                                "text: " . var_export( $in, true ) . "\n" .
                                "argv: " . var_export( $argv, true ) . "\n";
index a9704e6..cb430f2 100644 (file)
@@ -419,8 +419,7 @@ class ParserEditTests extends Maintenance {
                        print "Wrote updated file\n";
                } else {
                        print "Cannot write updated file, here is a patch you can paste:\n\n";
-                       print
-                               "--- {$fileName}\n" .
+                       print "--- {$fileName}\n" .
                                "+++ {$fileName}~\n" .
                                $this->unifiedDiff( $text, $result ) .
                                "\n";
index 72ee550..aa03c0e 100644 (file)
@@ -12633,6 +12633,19 @@ parsoid=wt2html
 <p><span typeof="mw:LanguageVariant" data-mw-variant='{"disabled":{"t":"&lt;span about=\"#mwt1\" typeof=\"mw:Transclusion\" data-parsoid=&#39;{\"pi\":[[{\"k\":\"1\"}]],\"dsr\":[2,14,null,null]}&#39; data-mw=&#39;{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"foo\"}},\"i\":0}}]}&#39;>foo&lt;/span>bar"}}'></span></p>
 !! end
 
+!! test
+Preprocessor precedence 17: template w/o target shouldn't prevent closing
+!! options
+parsoid=wt2html
+!! wikitext
+{{echo|hi {{}}}}
+!! html/php
+<p>hi {{}}
+</p>
+!! html/parsoid
+<p about="#mwt1" typeof="mw:Transclusion" data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"hi {{}}"}},"i":0}}]}'>hi {{}}</p>
+!! end
+
 ###
 ### Token Stream Patcher tests
 ###
@@ -16578,7 +16591,7 @@ Section headings with TOC
 Some text
 ===Another headline===
 !! html
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Headline_1"><span class="tocnumber">1</span> <span class="toctext">Headline 1</span></a>
 <ul>
@@ -16621,7 +16634,7 @@ __FORCETOC__
 == Headline 2 ==
 == Headline ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Headline_2"><span class="tocnumber">1</span> <span class="toctext">Headline 2</span></a></li>
 <li class="toclevel-1 tocsection-2"><a href="#Headline"><span class="tocnumber">2</span> <span class="toctext">Headline</span></a></li>
@@ -16655,7 +16668,7 @@ parsoid=wt2html
 ========= Level 9 Heading=========
 ========== Level 10 Heading==========
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Level_1_Heading"><span class="tocnumber">1</span> <span class="toctext">Level 1 Heading</span></a>
 <ul>
@@ -16719,7 +16732,7 @@ TOC regression (T11764)
 == title 2 ==
 === title 2.1 ===
 !! html
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#title_1"><span class="tocnumber">1</span> <span class="toctext">title 1</span></a>
 <ul>
@@ -16754,7 +16767,7 @@ TOC for heading containing <span id="..."></span> (T96153)
 __FORCETOC__
 ==<span id="old-anchor"></span>New title==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#New_title"><span class="tocnumber">1</span> <span class="toctext">New title</span></a></li>
 </ul>
@@ -16776,7 +16789,7 @@ wgMaxTocLevel=3
 == title 2 ==
 === title 2.1 ===
 !! html
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#title_1"><span class="tocnumber">1</span> <span class="toctext">title 1</span></a>
 <ul>
@@ -16812,7 +16825,7 @@ wgMaxTocLevel=3
 ====Section 1.1.1.1====
 ==Section 2==
 !! html
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Section_1"><span class="tocnumber">1</span> <span class="toctext">Section 1</span></a>
 <ul>
@@ -16905,7 +16918,7 @@ __TOC__
 === title 1.1 ===
 == title 2 ==
 !! html
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#title_1"><span class="tocnumber">1</span> <span class="toctext">title 1</span></a>
 <ul>
@@ -16981,7 +16994,7 @@ section 5
 !! html/php
 <p>The tooltips shall not show entities to the user (ie. be double escaped)
 </p>
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#text_.3E_text"><span class="tocnumber">1</span> <span class="toctext">text &gt; text</span></a></li>
 <li class="toclevel-1 tocsection-2"><a href="#text_.3C_text"><span class="tocnumber">2</span> <span class="toctext">text &lt; text</span></a></li>
@@ -17057,7 +17070,7 @@ section 6
 !! html/php
 <p>Id should not contain + for spaces
 </p>
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Space_between_Text"><span class="tocnumber">1</span> <span class="toctext">Space between Text</span></a></li>
 <li class="toclevel-1 tocsection-2"><a href="#Space-Entity_between_Text"><span class="tocnumber">2</span> <span class="toctext">Space-Entity&#32;between&#32;Text</span></a></li>
@@ -17133,7 +17146,7 @@ parsoid=wt2html,wt2wt,html2html
 =''italic'' heading==
 ==''italic'' heading=
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#foo.3D"><span class="tocnumber">1</span> <span class="toctext">foo=</span></a></li>
 <li class="toclevel-1 tocsection-2"><a href="#.3Dfoo"><span class="tocnumber">2</span> <span class="toctext">=foo</span></a></li>
@@ -17168,7 +17181,7 @@ HTML headers vs TOC (T25393)
 == Header 2.2 ==
 __NOEDITSECTION__
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1"><a href="#Header_1"><span class="tocnumber">1</span> <span class="toctext">Header 1</span></a>
 <ul>
@@ -19081,7 +19094,7 @@ Fuzz testing: Parser14
 http://__TOC__
 !! html/php
 <h2><span class="mw-headline" id="onmouseover.3D">onmouseover=</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: onmouseover=">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
-http://<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+http://<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#onmouseover.3D"><span class="tocnumber">1</span> <span class="toctext">onmouseover=</span></a></li>
 </ul>
@@ -19092,7 +19105,7 @@ http://<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
 <h2><span class="mw-headline" id="onmouseover.3D">onmouseover=</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: onmouseover=">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
 <p>http://</p>
 <div id="toc" class="toc">
-<div class="toctitle">
+<div class="toctitle" lang="en" dir="ltr" xml:lang="en">
 <h2>Contents</h2>
 </div>
 <ul>
@@ -21608,7 +21621,7 @@ Out-of-order TOC heading levels
 =====5=====
 ==2==
 !! html
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#2"><span class="tocnumber">1</span> <span class="toctext">2</span></a>
 <ul>
@@ -24242,7 +24255,7 @@ title=[[Main Page]]
 __TOC__
 == ''Lost'' episodes ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Lost_episodes"><span class="tocnumber">1</span> <span class="toctext"><i>Lost</i> episodes</span></a></li>
 </ul>
@@ -24263,7 +24276,7 @@ title=[[Main Page]]
 __TOC__
 == '''should be bold''' then normal text ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#should_be_bold_then_normal_text"><span class="tocnumber">1</span> <span class="toctext"><b>should be bold</b> then normal text</span></a></li>
 </ul>
@@ -24284,7 +24297,7 @@ title=[[Main Page]]
 __TOC__
 == Image [[Image:foobar.jpg]] ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Image"><span class="tocnumber">1</span> <span class="toctext">Image</span></a></li>
 </ul>
@@ -24305,7 +24318,7 @@ title=[[Main Page]]
 __TOC__
 == <blockquote>Quote</blockquote> ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Quote"><span class="tocnumber">1</span> <span class="toctext">Quote</span></a></li>
 </ul>
@@ -24316,7 +24329,7 @@ __TOC__
 !! html/php+tidy
 <p></p>
 <div id="toc" class="toc">
-<div class="toctitle">
+<div class="toctitle" lang="en" dir="ltr" xml:lang="en">
 <h2>Contents</h2>
 </div>
 <ul>
@@ -24346,7 +24359,7 @@ __TOC__
 <small>Hanc marginis exiguitas non caperet.</small>
 QED
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Proof:_2_&lt;_3"><span class="tocnumber">1</span> <span class="toctext">Proof: 2 &lt; 3</span></a></li>
 </ul>
@@ -24371,7 +24384,7 @@ __TOC__
 
 == <i>Foo</i> <blockquote>Bar</blockquote> ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Foo_Bar"><span class="tocnumber">1</span> <span class="toctext"><i>Foo</i> <b>Bar</b></span></a></li>
 <li class="toclevel-1 tocsection-2"><a href="#Foo_Bar_2"><span class="tocnumber">2</span> <span class="toctext"><i>Foo</i> Bar</span></a></li>
@@ -24384,7 +24397,7 @@ __TOC__
 !! html/php+tidy
 <p></p>
 <div id="toc" class="toc">
-<div class="toctitle">
+<div class="toctitle" lang="en" dir="ltr" xml:lang="en">
 <h2>Contents</h2>
 </div>
 <ul>
@@ -24418,7 +24431,7 @@ __TOC__
 
 == <sup class="a > b">Evilbye</sup> ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Hello"><span class="tocnumber">1</span> <span class="toctext"><sup>Hello</sup></span></a></li>
 <li class="toclevel-1 tocsection-2"><a href="#b.22.3EEvilbye"><span class="tocnumber">2</span> <span class="toctext"><sup> b"&gt;Evilbye</sup></span></a></li>
@@ -24449,7 +24462,7 @@ __TOC__
 
 == <span dir="ltr" style="font-style: italic">Attributes after dir on these span tags must be deleted from the TOC</span> ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#C.2B.2B"><span class="tocnumber">1</span> <span class="toctext"><span dir="ltr">C++</span></span></a></li>
 <li class="toclevel-1 tocsection-2"><a href="#.D7.96.D7.91.D7.A0.D7.92.21"><span class="tocnumber">2</span> <span class="toctext"><span dir="rtl">זבנג!</span></span></a></li>
@@ -24480,7 +24493,7 @@ T74884: bdi element in ToC
 __TOC__
 == <bdi>test</bdi> ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#test"><span class="tocnumber">1</span> <span class="toctext"><bdi>test</bdi></span></a></li>
 </ul>
@@ -24499,7 +24512,7 @@ T35715: s/strike element in ToC
 __TOC__
 == <s>test</s> test <strike>test</strike> ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#test_test_test"><span class="tocnumber">1</span> <span class="toctext"><s>test</s> test <strike>test</strike></span></a></li>
 </ul>
@@ -24521,7 +24534,7 @@ Empty <p> tag in TOC, removed by Sanitizer (T92892)
 __TOC__
 == x ==
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#x"><span class="tocnumber">1</span> <span class="toctext">x</span></a></li>
 </ul>
@@ -24532,7 +24545,7 @@ __TOC__
 !! html/php+tidy
 <p></p>
 <div id="toc" class="toc">
-<div class="toctitle">
+<div class="toctitle" lang="en" dir="ltr" xml:lang="en">
 <h2>Contents</h2>
 </div>
 <ul>
@@ -29955,7 +29968,7 @@ wgFragmentMode=[ 'html5', 'legacy' ]
 [[#啤酒]] [[#%E5%95%A4%E9%85%92]]
 
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Foo_bar"><span class="tocnumber">1</span> <span class="toctext">Foo bar</span></a></li>
 <li class="toclevel-1 tocsection-2"><a href="#foo_Bar_2"><span class="tocnumber">2</span> <span class="toctext">foo Bar</span></a></li>
@@ -30021,7 +30034,7 @@ wgFragmentMode=[ 'legacy', 'html5' ]
 [[#啤酒]] [[#%E5%95%A4%E9%85%92]]
 
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Foo_bar"><span class="tocnumber">1</span> <span class="toctext">Foo bar</span></a></li>
 <li class="toclevel-1 tocsection-2"><a href="#foo_Bar_2"><span class="tocnumber">2</span> <span class="toctext">foo Bar</span></a></li>
@@ -30069,7 +30082,7 @@ wgFragmentMode=[ 'html5' ]
 [[#啤酒]] [[#%E5%95%A4%E9%85%92]]
 
 !! html/php
-<div id="toc" class="toc"><div class="toctitle"><h2>Contents</h2></div>
+<div id="toc" class="toc"><div class="toctitle" lang="en" dir="ltr"><h2>Contents</h2></div>
 <ul>
 <li class="toclevel-1 tocsection-1"><a href="#Foo_bar"><span class="tocnumber">1</span> <span class="toctext">Foo bar</span></a></li>
 <li class="toclevel-1 tocsection-2"><a href="#foo_Bar_2"><span class="tocnumber">2</span> <span class="toctext">foo Bar</span></a></li>
 </section><section data-mw-section-id="2"><h1 id="2"> 2 </h1>
 <p>b</p></section>
 !! end
+
+!! test
+Pseudo-sections emitted by templates should have id -2 
+!! options
+parsoid={
+  "wrapSections": true
+}
+!! wikitext
+foo
+{{echo|<div>
+== a ==
+== b ==
+</div>
+}}
+!! html/parsoid
+<section data-mw-section-id="-1"><p>foo</p>
+</section><section data-mw-section-id="-2"><div about="#mwt1" typeof="mw:Transclusion" data-parsoid='{"stx":"html","pi":[[{"k":"1"}]]}' data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"&lt;div>\n== a ==\n== b ==\n&lt;/div>\n"}},"i":0}}]}'>
+<section data-mw-section-id="-1"><h2 id="a"> a </h2>
+</section><section data-mw-section-id="-1"><h2 id="b"> b </h2>
+</section></div><span about="#mwt1">
+</span></section>
+!! end
index 79feaa0..364ebda 100644 (file)
@@ -16,7 +16,7 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
-// @codingStandardsIgnoreFile
+// phpcs:ignoreFile
 
 /**
  * @param callable $callback
index 7cd9016..ba1efb9 100644 (file)
@@ -3,7 +3,7 @@
 /**
  * Minimal set of classes necessary for UserMailer to be happy. Types
  * taken from documentation at pear.php.net.
- * @codingStandardsIgnoreFile
+ * phpcs:ignoreFile
  */
 
 class PEAR {
index ee47937..0f8859d 100644 (file)
@@ -5,7 +5,7 @@
  * that they are optional. Phan can not detect this and thus throws an error for a usage with
  * no params. So we have this small stub just for the constructor to allow no params.
  * @see https://secure.php.net/manual/en/memcached.construct.php
- * @codingStandardsIgnoreFile
+ * phpcs:ignoreFile
  */
 
 class Memcached {
index 1372219..34ac735 100644 (file)
@@ -2,7 +2,7 @@
 
 /**
  * Minimal set of classes necessary for Xhprof using tideways
- * @codingStandardsIgnoreFile
+ * phpcs:ignoreFile
  */
 
 function tideways_enable(){
index 1015b0b..bd4ed63 100644 (file)
@@ -16,7 +16,7 @@
  * http://www.gnu.org/copyleft/gpl.html
  */
 
-// @codingStandardsIgnoreFile
+// phpcs:ignoreFile
 
 /**
  * @param string $text1
diff --git a/tests/phpunit/MediaWikiCoversValidator.php b/tests/phpunit/MediaWikiCoversValidator.php
new file mode 100644 (file)
index 0000000..a79a139
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Copyright (C) 2017 Kunal Mehta <legoktm@member.fsf.org>
+ *
+ * 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.
+ *
+ */
+
+/**
+ * Trait that checks that covers tags are valid, since PHPUnit
+ * won't do it unless you run it with coverage, which is super
+ * slow.
+ *
+ * @since 1.31
+ */
+trait MediaWikiCoversValidator {
+
+       /**
+        * Test that all methods in this class that begin
+        * with "test" have valid covers tags.
+        */
+       public function testValidCovers() {
+               $methods = get_class_methods( $this );
+               $class = get_class( $this );
+               $bad = '';
+               foreach ( $methods as $method ) {
+                       if ( strpos( $method, 'test' ) === 0 ) {
+                               try {
+                                       PHPUnit_Util_Test::getLinesToBeCovered( $class, $method );
+                               } catch ( PHPUnit_Framework_CodeCoverageException $e ) {
+                                       $bad .= "$class::$method: {$e->getMessage()}\n";
+                               }
+                       }
+               }
+
+               $this->assertEquals( '', $bad );
+       }
+}
index 4d3c37b..d542826 100644 (file)
@@ -14,6 +14,8 @@ use Wikimedia\TestingAccessWrapper;
  */
 abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * The service locator created by prepareServices(). This service locator will
         * be restored after each test. Tests that pollute the global service locator
@@ -515,8 +517,9 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
 
                // XXX: reset maintenance triggers
                // Hook into period lag checks which often happen in long-running scripts
-               $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
-               Maintenance::setLBFactoryTriggers( $lbFactory );
+               $services = MediaWikiServices::getInstance();
+               $lbFactory = $services->getDBLoadBalancerFactory();
+               Maintenance::setLBFactoryTriggers( $lbFactory, $services->getMainConfig() );
 
                ob_start( 'MediaWikiTestCase::wfResetOutputBuffersBarrier' );
        }
@@ -1008,10 +1011,6 @@ abstract class MediaWikiTestCase extends PHPUnit_Framework_TestCase {
                $user = static::getTestSysop()->getUser();
                $comment = __METHOD__ . ': Sample page for unit test.';
 
-               // Avoid memory leak...?
-               // LinkCache::singleton()->clear();
-               // Maybe.  But doing this absolutely breaks $title->isRedirect() when called during unit tests....
-
                $page = WikiPage::factory( $title );
                $page->doEditContent( ContentHandler::makeContent( $text, $title ), $comment, 0, false, $user );
 
index 785aa4e..24f6596 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers Autopromote
+ */
 class AutopromoteTest extends MediaWikiTestCase {
        /**
         * T157718: Verify Autopromote does not perform edit count lookup if requirement is 0 or invalid
index 70715e2..b765494 100644 (file)
@@ -81,6 +81,7 @@ class BlockTest extends MediaWikiLangTestCase {
 
        /**
         * per T28425
+        * @covers Block::__construct
         */
        public function testBug26425BlockTimestampDefaultsToTime() {
                $user = $this->getUserForBlocking();
@@ -366,6 +367,9 @@ class BlockTest extends MediaWikiLangTestCase {
                $this->assertEquals( $exResult, $block->mReason, 'Correct block type for XFF header ' . $xff );
        }
 
+       /**
+        * @covers Block::__construct
+        */
        public function testDeprecatedConstructor() {
                $this->hideDeprecated( 'Block::__construct with multiple arguments' );
                $username = 'UnthinkablySecretRandomUsername';
@@ -418,6 +422,11 @@ class BlockTest extends MediaWikiLangTestCase {
                );
        }
 
+       /**
+        * @covers Block::getSystemBlockType
+        * @covers Block::insert
+        * @covers Block::doAutoblock
+        */
        public function testSystemBlocks() {
                $user = $this->getUserForBlocking();
                $this->addBlockForUser( $user );
index 9fe694d..f6ccbc7 100644 (file)
@@ -3,6 +3,9 @@
 use MediaWiki\Session\SessionManager;
 
 class FauxRequestTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
         * @covers FauxRequest::__construct
         */
@@ -39,13 +42,19 @@ class FauxRequestTest extends PHPUnit_Framework_TestCase {
                $this->assertEquals( '', $req->getText( 'z' ) );
        }
 
-       // Integration test for parent method.
+       /**
+        * Integration test for parent method
+        * @covers FauxRequest::getVal
+        */
        public function testGetVal() {
                $req = new FauxRequest( [ 'crlf' => "A\r\nb" ] );
                $this->assertSame( "A\r\nb", $req->getVal( 'crlf' ), 'CRLF' );
        }
 
-       // Integration test for parent method.
+       /**
+        * Integration test for parent method
+        * @covers FauxRequest::getRawVal
+        */
        public function testGetRawVal() {
                $req = new FauxRequest( [
                        'x' => 'Value',
index d961e41..9d56150 100644 (file)
@@ -752,6 +752,9 @@ class GlobalTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers ::wfMemcKey
+        */
        public function testWfMemcKey() {
                $cache = ObjectCache::getLocalClusterInstance();
                $this->assertEquals(
@@ -760,6 +763,9 @@ class GlobalTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers ::wfForeignMemcKey
+        */
        public function testWfForeignMemcKey() {
                $cache = ObjectCache::getLocalClusterInstance();
                $keyspace = $this->readAttribute( $cache, 'keyspace' );
@@ -769,6 +775,9 @@ class GlobalTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers ::wfGlobalCacheKey
+        */
        public function testWfGlobalCacheKey() {
                $cache = ObjectCache::getLocalClusterInstance();
                $this->assertEquals(
index 6660516..efe92ec 100644 (file)
@@ -69,6 +69,7 @@ class HooksTest extends MediaWikiTestCase {
         * @dataProvider provideHooks
         * @covers Hooks::register
         * @covers Hooks::run
+        * @covers Hooks::callHook
         */
        public function testNewStyleHooks( $msg, $hook, $expectedFoo, $expectedBar ) {
                $foo = $bar = 'original';
@@ -85,6 +86,7 @@ class HooksTest extends MediaWikiTestCase {
         * @covers Hooks::register
         * @covers Hooks::getHandlers
         * @covers Hooks::run
+        * @covers Hooks::callHook
         */
        public function testNewStyleHookInteraction() {
                global $wgHooks;
@@ -124,6 +126,7 @@ class HooksTest extends MediaWikiTestCase {
        /**
         * @expectedException MWException
         * @covers Hooks::run
+        * @covers Hooks::callHook
         */
        public function testUncallableFunction() {
                Hooks::register( 'MediaWikiHooksTest001', 'ThisFunctionDoesntExist' );
@@ -132,6 +135,7 @@ class HooksTest extends MediaWikiTestCase {
 
        /**
         * @covers Hooks::run
+        * @covers Hooks::callHook
         */
        public function testFalseReturn() {
                Hooks::register( 'MediaWikiHooksTest001', function ( &$foo ) {
@@ -149,6 +153,7 @@ class HooksTest extends MediaWikiTestCase {
 
        /**
         * @covers Hooks::runWithoutAbort
+        * @covers Hooks::callHook
         */
        public function testRunWithoutAbort() {
                $list = [];
@@ -171,6 +176,7 @@ class HooksTest extends MediaWikiTestCase {
 
        /**
         * @covers Hooks::runWithoutAbort
+        * @covers Hooks::callHook
         */
        public function testRunWithoutAbortWarning() {
                Hooks::register( 'MediaWikiHooksTest001', function ( &$foo ) {
index e867f5e..7e32770 100644 (file)
@@ -386,6 +386,9 @@ class HtmlTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers Html::namespaceSelector
+        */
        public function testCanFilterOutNamespaces() {
                $this->assertEquals(
                        '<select id="namespace" name="namespace">' . "\n" .
@@ -408,6 +411,9 @@ class HtmlTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers Html::namespaceSelector
+        */
        public function testCanDisableANamespaces() {
                $this->assertEquals(
                        '<select id="namespace" name="namespace">' . "\n" .
@@ -678,6 +684,9 @@ class HtmlTest extends MediaWikiTestCase {
                return $ret;
        }
 
+       /**
+        * @covers Html::input
+        */
        public function testWrapperInput() {
                $this->assertEquals(
                        '<input type="radio" value="testval" name="testname"/>',
@@ -691,6 +700,9 @@ class HtmlTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers Html::check
+        */
        public function testWrapperCheck() {
                $this->assertEquals(
                        '<input type="checkbox" value="1" name="testname"/>',
@@ -709,6 +721,9 @@ class HtmlTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers Html::radio
+        */
        public function testWrapperRadio() {
                $this->assertEquals(
                        '<input type="radio" value="1" name="testname"/>',
@@ -727,6 +742,9 @@ class HtmlTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @covers Html::label
+        */
        public function testWrapperLabel() {
                $this->assertEquals(
                        '<label for="testid">testlabel</label>',
index ed4958f..51b54d2 100644 (file)
@@ -3,6 +3,7 @@
 use Wikimedia\Rdbms\LikeMatch;
 
 /**
+ * @covers LinkFilter
  * @group Database
  */
 class LinkFilterTest extends MediaWikiLangTestCase {
index f4844f8..7f42254 100644 (file)
@@ -133,7 +133,7 @@ class LinkerTest extends MediaWikiLangTestCase {
        public function provideCasesForFormatComment() {
                $wikiId = 'enwiki'; // $wgConf has a fake entry for this
 
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        // Linker::formatComment
                        [
@@ -257,7 +257,7 @@ class LinkerTest extends MediaWikiLangTestCase {
                                false, false, $wikiId
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
@@ -289,7 +289,7 @@ class LinkerTest extends MediaWikiLangTestCase {
        }
 
        public static function provideCasesForFormatLinksInComment() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [
                                'foo bar <a href="/wiki/Special:BlankPage" title="Special:BlankPage">Special:BlankPage</a>',
@@ -312,43 +312,43 @@ class LinkerTest extends MediaWikiLangTestCase {
                                'enwiki',
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        public static function provideLinkBeginHook() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        // Modify $html
                        [
-                               function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+                               function ( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
                                        $html = 'foobar';
                                },
                                '<a href="/wiki/Special:BlankPage" title="Special:BlankPage">foobar</a>'
                        ],
                        // Modify $attribs
                        [
-                               function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+                               function ( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
                                        $attribs['bar'] = 'baz';
                                },
                                '<a href="/wiki/Special:BlankPage" title="Special:BlankPage" bar="baz">Special:BlankPage</a>'
                        ],
                        // Modify $query
                        [
-                               function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+                               function ( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
                                        $query['bar'] = 'baz';
                                },
                                '<a href="/w/index.php?title=Special:BlankPage&amp;bar=baz" title="Special:BlankPage">Special:BlankPage</a>'
                        ],
                        // Force HTTP $options
                        [
-                               function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+                               function ( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
                                        $options = [ 'http' ];
                                },
                                '<a href="http://example.org/wiki/Special:BlankPage" title="Special:BlankPage">Special:BlankPage</a>'
                        ],
                        // Force 'forcearticlepath' in $options
                        [
-                               function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+                               function ( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
                                        $options = [ 'forcearticlepath' ];
                                        $query['foo'] = 'bar';
                                },
@@ -356,14 +356,14 @@ class LinkerTest extends MediaWikiLangTestCase {
                        ],
                        // Abort early
                        [
-                               function( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
+                               function ( $dummy, $title, &$html, &$attribs, &$query, &$options, &$ret ) {
                                        $ret = 'foobar';
                                        return false;
                                },
                                'foobar'
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
index 498532f..91101bd 100644 (file)
@@ -7,7 +7,6 @@
 
 /**
  * Test class for MWNamespace.
- * @todo covers tags
  * @todo FIXME: this test file is a mess
  */
 class MWNamespaceTest extends MediaWikiTestCase {
index a5c4688..dbb7799 100644 (file)
@@ -7,6 +7,10 @@ use MediaWiki\Services\DestructibleService;
 use MediaWiki\Services\SalvageableService;
 use MediaWiki\Services\ServiceDisabledException;
 use MediaWiki\Shell\CommandFactory;
+use MediaWiki\Storage\BlobStore;
+use MediaWiki\Storage\BlobStoreFactory;
+use MediaWiki\Storage\RevisionStore;
+use MediaWiki\Storage\SqlBlobStore;
 
 /**
  * @covers MediaWiki\MediaWikiServices
@@ -331,6 +335,10 @@ class MediaWikiServicesTest extends MediaWikiTestCase {
                        'LocalServerObjectCache' => [ 'LocalServerObjectCache', BagOStuff::class ],
                        'VirtualRESTServiceClient' => [ 'VirtualRESTServiceClient', VirtualRESTServiceClient::class ],
                        'ShellCommandFactory' => [ 'ShellCommandFactory', CommandFactory::class ],
+                       'BlobStoreFactory' => [ 'BlobStoreFactory', BlobStoreFactory::class ],
+                       'BlobStore' => [ 'BlobStore', BlobStore::class ],
+                       '_SqlBlobStore' => [ '_SqlBlobStore', SqlBlobStore::class ],
+                       'RevisionStore' => [ 'RevisionStore', RevisionStore::class ],
                ];
        }
 
index fa59ef2..6aa9849 100644 (file)
@@ -12,6 +12,8 @@
  */
 class MediaWikiVersionFetcherTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public function testReturnsResult() {
                $versionFetcher = new MediaWikiVersionFetcher();
                $this->assertInternalType( 'string', $versionFetcher->fetchVersion() );
index d5948ed..44b9707 100644 (file)
@@ -274,7 +274,7 @@ class OutputPageTest extends MediaWikiTestCase {
        }
 
        public static function provideMakeResourceLoaderLink() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        // Single only=scripts load
                        [
@@ -297,7 +297,7 @@ class OutputPageTest extends MediaWikiTestCase {
                                        . "});</script>"
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
@@ -345,6 +345,7 @@ class OutputPageTest extends MediaWikiTestCase {
        }
 
        public static function provideBuildExemptModules() {
+               // phpcs:disable Generic.Files.LineLength
                return [
                        'empty' => [
                                'exemptStyleModules' => [],
@@ -354,7 +355,6 @@ class OutputPageTest extends MediaWikiTestCase {
                                'exemptStyleModules' => [ 'site' => [], 'noscript' => [], 'private' => [], 'user' => [] ],
                                '<meta name="ResourceLoaderDynamicStyles" content=""/>',
                        ],
-                       // @codingStandardsIgnoreStart Generic.Files.LineLength
                        'default logged-out' => [
                                'exemptStyleModules' => [ 'site' => [ 'site.styles' ] ],
                                '<meta name="ResourceLoaderDynamicStyles" content=""/>' . "\n" .
@@ -377,8 +377,8 @@ class OutputPageTest extends MediaWikiTestCase {
                                '<link rel="stylesheet" href="/w/load.php?debug=false&amp;lang=en&amp;modules=example.user&amp;only=styles&amp;skin=fallback&amp;version=0a56zyi"/>' . "\n" .
                                '<link rel="stylesheet" href="/w/load.php?debug=false&amp;lang=en&amp;modules=user.styles&amp;only=styles&amp;skin=fallback&amp;version=1e9z0ox"/>',
                        ],
-                       // @codingStandardsIgnoreEnd Generic.Files.LineLength
                ];
+               // phpcs:enable
        }
 
        /**
@@ -525,7 +525,7 @@ class OutputPageTest extends MediaWikiTestCase {
                $this->assertTrue( $outputPage->haveCacheVaryCookies() );
        }
 
-       /*
+       /**
         * @covers OutputPage::addCategoryLinks
         * @covers OutputPage::getCategories
         */
index 6420c39..15b26c2 100644 (file)
@@ -11,8 +11,9 @@
  * ^--- important, causes tests not to fail with timeout
  */
 class PageArchiveTest extends MediaWikiTestCase {
+
        /**
-        * @var WikiPage $archivedPage
+        * @var PageArchive $archivedPage
         */
        private $archivedPage;
 
@@ -78,6 +79,7 @@ class PageArchiveTest extends MediaWikiTestCase {
 
        /**
         * @covers PageArchive::undelete
+        * @covers PageArchive::undeleteRevisions
         */
        public function testUndeleteRevisions() {
                // First make sure old revisions are archived
@@ -107,4 +109,134 @@ class PageArchiveTest extends MediaWikiTestCase {
                $row = $res->fetchObject();
                $this->assertEquals( IP::toHex( $this->ipEditor ), $row->ipc_hex );
        }
+
+       /**
+        * @covers PageArchive::listRevisions
+        */
+       public function testListRevisions() {
+               $revisions = $this->archivedPage->listRevisions();
+               $this->assertEquals( 2, $revisions->numRows() );
+
+               // Get the rows as arrays
+               $row1 = (array)$revisions->current();
+               $row2 = (array)$revisions->next();
+               // Unset the timestamps (we assume they will be right...
+               $this->assertInternalType( 'string', $row1['ar_timestamp'] );
+               $this->assertInternalType( 'string', $row2['ar_timestamp'] );
+               unset( $row1['ar_timestamp'] );
+               unset( $row2['ar_timestamp'] );
+
+               $this->assertEquals(
+                       [
+                               'ar_minor_edit' => '0',
+                               'ar_user' => '0',
+                               'ar_user_text' => '2600:387:ed7:947e:8c16:a1ad:dd34:1dd7',
+                               'ar_len' => '11',
+                               'ar_deleted' => '0',
+                               'ar_rev_id' => '3',
+                               'ar_sha1' => '0qdrpxl537ivfnx4gcpnzz0285yxryy',
+                               'ar_page_id' => '2',
+                               'ar_comment_text' => 'just a test',
+                               'ar_comment_data' => null,
+                               'ar_comment_cid' => null,
+                               'ar_content_format' => null,
+                               'ar_content_model' => null,
+                               'ts_tags' => null,
+                               'ar_id' => '2',
+                               'ar_namespace' => '0',
+                               'ar_title' => 'PageArchiveTest_thePage',
+                               'ar_text' => '',
+                               'ar_text_id' => '3',
+                               'ar_parent_id' => '2',
+                       ],
+                       $row1
+               );
+               $this->assertEquals(
+                       [
+                               'ar_minor_edit' => '0',
+                               'ar_user' => '0',
+                               'ar_user_text' => '127.0.0.1',
+                               'ar_len' => '7',
+                               'ar_deleted' => '0',
+                               'ar_rev_id' => '2',
+                               'ar_sha1' => 'pr0s8e18148pxhgjfa0gjrvpy8fiyxc',
+                               'ar_page_id' => '2',
+                               'ar_comment_text' => 'testing',
+                               'ar_comment_data' => null,
+                               'ar_comment_cid' => null,
+                               'ar_content_format' => null,
+                               'ar_content_model' => null,
+                               'ts_tags' => null,
+                               'ar_id' => '1',
+                               'ar_namespace' => '0',
+                               'ar_title' => 'PageArchiveTest_thePage',
+                               'ar_text' => '',
+                               'ar_text_id' => '2',
+                               'ar_parent_id' => '0',
+                       ],
+                       $row2
+               );
+       }
+
+       /**
+        * @covers PageArchive::listPagesBySearch
+        */
+       public function testListPagesBySearch() {
+               $pages = PageArchive::listPagesBySearch( 'PageArchiveTest_thePage' );
+               $this->assertSame( 1, $pages->numRows() );
+
+               $page = (array)$pages->current();
+
+               $this->assertSame(
+                       [
+                               'ar_namespace' => '0',
+                               'ar_title' => 'PageArchiveTest_thePage',
+                               'count' => '2',
+                       ],
+                       $page
+               );
+       }
+
+       /**
+        * @covers PageArchive::listPagesBySearch
+        */
+       public function testListPagesByPrefix() {
+               $pages = PageArchive::listPagesByPrefix( 'PageArchiveTest' );
+               $this->assertSame( 1, $pages->numRows() );
+
+               $page = (array)$pages->current();
+
+               $this->assertSame(
+                       [
+                               'ar_namespace' => '0',
+                               'ar_title' => 'PageArchiveTest_thePage',
+                               'count' => '2',
+                       ],
+                       $page
+               );
+       }
+
+       /**
+        * @covers PageArchive::getTextFromRow
+        */
+       public function testGetTextFromRow() {
+               $row = (object)[ 'ar_text_id' => 2 ];
+               $text = $this->archivedPage->getTextFromRow( $row );
+               $this->assertSame( 'testing', $text );
+       }
+
+       /**
+        * @covers PageArchive::getLastRevisionText
+        */
+       public function testGetLastRevisionText() {
+               $text = $this->archivedPage->getLastRevisionText();
+               $this->assertSame( 'Lorem Ipsum', $text );
+       }
+
+       /**
+        * @covers PageArchive::isDeleted
+        */
+       public function testIsDeleted() {
+               $this->assertTrue( $this->archivedPage->isDeleted() );
+       }
 }
index c96d987..f602cda 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 
 /**
+ * @covers PageProps
+ *
  * @group Database
  *     ^--- tell jenkins this test needs the database
  *
index 67364cb..fc6a70b 100644 (file)
@@ -236,7 +236,7 @@ class PathRouterTest extends MediaWikiTestCase {
         * Ensure the router doesn't choke on long paths.
         */
        public function testLength() {
-               // @codingStandardsIgnoreStart Ignore long line warnings
+               // phpcs:disable Generic.Files.LineLength
                $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."
                );
@@ -244,7 +244,7 @@ class PathRouterTest extends MediaWikiTestCase {
                        $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
+               // phpcs:enable
        }
 
        /**
index 91dbf2c..6139524 100644 (file)
@@ -1,4 +1,8 @@
 <?php
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\RevisionStore;
+use MediaWiki\Storage\IncompleteRevisionException;
+use MediaWiki\Storage\RevisionRecord;
 
 /**
  * RevisionDbTestBase contains test cases for the Revision class that have Database interactions.
@@ -72,6 +76,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                MWNamespace::clearCaches();
                // Reset namespace cache
                $wgContLang->resetNamespaces();
+
                if ( !$this->testPage ) {
                        /**
                         * We have to create a new page for each subclass as the page creation may result
@@ -102,6 +107,14 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        $props['text'] = 'Lorem Ipsum';
                }
 
+               if ( !isset( $props['user_text'] ) ) {
+                       $props['user_text'] = 'Tester';
+               }
+
+               if ( !isset( $props['user'] ) ) {
+                       $props['user'] = 0;
+               }
+
                if ( !isset( $props['comment'] ) ) {
                        $props['comment'] = 'just a test';
                }
@@ -110,6 +123,10 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        $props['page'] = $this->testPage->getId();
                }
 
+               if ( !isset( $props['content_model'] ) ) {
+                       $props['content_model'] = CONTENT_MODEL_WIKITEXT;
+               }
+
                $rev = new Revision( $props );
 
                $dbw = wfGetDB( DB_MASTER );
@@ -202,14 +219,23 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $revId = $rev->insertOn( wfGetDB( DB_MASTER ) );
 
                $this->assertInternalType( 'integer', $revId );
-               $this->assertInternalType( 'integer', $rev->getTextId() );
                $this->assertSame( $revId, $rev->getId() );
 
+               // getTextId() must be an int!
+               $this->assertInternalType( 'integer', $rev->getTextId() );
+
+               $mainSlot = $rev->getRevisionRecord()->getSlot( 'main', RevisionRecord::RAW );
+
+               // we currently only support storage in the text table
+               $textId = MediaWikiServices::getInstance()
+                       ->getBlobStore()
+                       ->getTextIdFromAddress( $mainSlot->getAddress() );
+
                $this->assertSelect(
                        'text',
                        [ 'old_id', 'old_text' ],
-                       "old_id = {$rev->getTextId()}",
-                       [ [ strval( $rev->getTextId() ), 'Revision Text' ] ]
+                       "old_id = $textId",
+                       [ [ strval( $textId ), 'Revision Text' ] ]
                );
                $this->assertSelect(
                        'revision',
@@ -228,7 +254,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        [ [
                                strval( $rev->getId() ),
                                strval( $this->testPage->getId() ),
-                               strval( $rev->getTextId() ),
+                               strval( $textId ),
                                '0',
                                '0',
                                '0',
@@ -246,11 +272,12 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                // If an ExternalStore is set don't use it.
                $this->setMwGlobals( 'wgDefaultExternalStore', false );
                $this->setExpectedException(
-                       MWException::class,
-                       "Cannot insert revision: page ID must be nonzero"
+                       IncompleteRevisionException::class,
+                       "rev_page field must not be 0!"
                );
 
-               $rev = new Revision( [] );
+               $title = Title::newFromText( 'Nonexistant-' . __METHOD__ );
+               $rev = new Revision( [], 0, $title );
 
                $rev->insertOn( wfGetDB( DB_MASTER ) );
        }
@@ -321,12 +348,42 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                                return $f + [ 'ar_namespace', 'ar_title' ];
                        },
                ];
+               yield [
+                       function ( $f ) {
+                               unset( $f['ar_text'] );
+                               return $f;
+                       },
+               ];
                yield [
                        function ( $f ) {
                                unset( $f['ar_text_id'] );
                                return $f;
                        },
                ];
+               yield [
+                       function ( $f ) {
+                               unset( $f['ar_page_id'] );
+                               return $f;
+                       },
+               ];
+               yield [
+                       function ( $f ) {
+                               unset( $f['ar_parent_id'] );
+                               return $f;
+                       },
+               ];
+               yield [
+                       function ( $f ) {
+                               unset( $f['ar_rev_id'] );
+                               return $f;
+                       },
+               ];
+               yield [
+                       function ( $f ) {
+                               unset( $f['ar_sha1'] );
+                               return $f;
+                       },
+               ];
        }
 
        /**
@@ -334,6 +391,17 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
         * @covers Revision::newFromArchiveRow
         */
        public function testNewFromArchiveRow( $selectModifier ) {
+               $services = MediaWikiServices::getInstance();
+
+               $store = new RevisionStore(
+                       $services->getDBLoadBalancer(),
+                       $services->getService( '_SqlBlobStore' ),
+                       $services->getMainWANObjectCache()
+               );
+
+               $store->setContentHandlerUseDB( $this->getContentHandlerUseDB() );
+               $this->setService( 'RevisionStore', $store );
+
                $page = $this->createPage(
                        'RevisionStorageTest_testNewFromArchiveRow',
                        'Lorem Ipsum',
@@ -354,6 +422,8 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $row = $res->fetchObject();
                $res->free();
 
+               // MCR migration note: $row is now required to contain ar_title and ar_namespace.
+               // Alternatively, a Title object can be passed to RevisionStore::newRevisionFromArchiveRow
                $rev = Revision::newFromArchiveRow( $row );
 
                $this->assertRevEquals( $orig, $rev );
@@ -382,7 +452,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $row = $res->fetchObject();
                $res->free();
 
-               $rev = Revision::newFromArchiveRow( $row, [ 'comment' => 'SOMEOVERRIDE' ] );
+               $rev = Revision::newFromArchiveRow( $row, [ 'comment_text' => 'SOMEOVERRIDE' ] );
 
                $this->assertNotEquals( $orig->getComment(), $rev->getComment() );
                $this->assertEquals( 'SOMEOVERRIDE', $rev->getComment() );
@@ -426,7 +496,8 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
         * @covers Revision::newFromPageId
         */
        public function testNewFromPageIdWithNotLatestId() {
-               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $content = new WikitextContent( __METHOD__ );
+               $this->testPage->doEditContent( $content, __METHOD__ );
                $rev = Revision::newFromPageId(
                        $this->testPage->getId(),
                        $this->testPage->getRevision()->getPrevious()->getId()
@@ -447,6 +518,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
                $id = $this->testPage->getRevision()->getId();
 
+               $this->hideDeprecated( 'Revision::fetchRevision' );
                $res = Revision::fetchRevision( $this->testPage->getTitle() );
 
                # note: order is unspecified
@@ -455,8 +527,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        $rows[$row->rev_id] = $row;
                }
 
-               $this->assertEquals( 1, count( $rows ), 'expected exactly one revision' );
-               $this->assertArrayHasKey( $id, $rows, 'missing revision with id ' . $id );
+               $this->assertEmpty( $rows, 'expected empty set' );
        }
 
        /**
@@ -541,6 +612,10 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        'new null revision should have a different id from the original revision' );
                $this->assertEquals( $orig->getTextId(), $rev->getTextId(),
                        'new null revision should have the same text id as the original revision' );
+               $this->assertEquals( $orig->getSha1(), $rev->getSha1(),
+                       'new null revision should have the same SHA1 as the original revision' );
+               $this->assertTrue( $orig->getRevisionRecord()->hasSameContent( $rev->getRevisionRecord() ),
+                       'new null revision should have the same content as the original revision' );
                $this->assertEquals( __METHOD__, $rev->getContent()->getNativeData() );
        }
 
@@ -574,6 +649,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
        }
 
        /**
+        * @covers Revision::userWasLastToEdit
         * @dataProvider provideUserWasLastToEdit
         */
        public function testUserWasLastToEdit( $sinceIdx, $expectedLast ) {
@@ -606,7 +682,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        'user' => $userA->getId(),
                        'text' => 'zero',
                        'content_model' => CONTENT_MODEL_WIKITEXT,
-                       'summary' => 'edit zero'
+                       'comment' => 'edit zero'
                ] );
                $revisions[0]->insertOn( $dbw );
 
@@ -618,7 +694,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        'user' => $userA->getId(),
                        'text' => 'one',
                        'content_model' => CONTENT_MODEL_WIKITEXT,
-                       'summary' => 'edit one'
+                       'comment' => 'edit one'
                ] );
                $revisions[1]->insertOn( $dbw );
 
@@ -629,7 +705,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        'user' => $userB->getId(),
                        'text' => 'two',
                        'content_model' => CONTENT_MODEL_WIKITEXT,
-                       'summary' => 'edit two'
+                       'comment' => 'edit two'
                ] );
                $revisions[2]->insertOn( $dbw );
 
@@ -640,7 +716,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        'user' => $userA->getId(),
                        'text' => 'three',
                        'content_model' => CONTENT_MODEL_WIKITEXT,
-                       'summary' => 'edit three'
+                       'comment' => 'edit three'
                ] );
                $revisions[3]->insertOn( $dbw );
 
@@ -651,13 +727,24 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        'user' => $userA->getId(),
                        'text' => 'zero',
                        'content_model' => CONTENT_MODEL_WIKITEXT,
-                       'summary' => 'edit four'
+                       'comment' => 'edit four'
                ] );
                $revisions[4]->insertOn( $dbw );
 
                // test it ---------------------------------
                $since = $revisions[$sinceIdx]->getTimestamp();
 
+               $allRows = iterator_to_array( $dbw->select(
+                       'revision',
+                       [ 'rev_id', 'rev_timestamp', 'rev_user' ],
+                       [
+                               'rev_page' => $page->getId(),
+                               //'rev_timestamp > ' . $dbw->addQuotes( $dbw->timestamp( $since ) )
+                       ],
+                       __METHOD__,
+                       [ 'ORDER BY' => 'rev_timestamp ASC', 'LIMIT' => 50 ]
+               ) );
+
                $wasLast = Revision::userWasLastToEdit( $dbw, $page->getId(), $userA->getId(), $since );
 
                $this->assertEquals( $expectedLast, $wasLast );
@@ -805,12 +892,16 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        'text_id' => 123456789, // not in the test DB
                ] );
 
+               MediaWiki\suppressWarnings(); // bad text_id will trigger a warning.
+
                $this->assertNull( $rev->getContent(),
                        "getContent() should return null if the revision's text blob could not be loaded." );
 
                // NOTE: check this twice, once for lazy initialization, and once with the cached value.
                $this->assertNull( $rev->getContent(),
                        "getContent() should return null if the revision's text blob could not be loaded." );
+
+               MediaWiki\suppressWarnings( 'end' );
        }
 
        public function provideGetSize() {
@@ -904,6 +995,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
         */
        public function testLoadFromId() {
                $rev = $this->testPage->getRevision();
+               $this->hideDeprecated( 'Revision::loadFromId' );
                $this->assertRevEquals(
                        $rev,
                        Revision::loadFromId( wfGetDB( DB_MASTER ), $rev->getId() )
@@ -1026,7 +1118,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $rev[1] = $this->testPage->getLatest();
 
                $this->assertSame(
-                       [ $rev[1] => strval( $textLength ) ],
+                       [ $rev[1] => $textLength ],
                        Revision::getParentLengths(
                                wfGetDB( DB_MASTER ),
                                [ $rev[1] ]
@@ -1049,7 +1141,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $rev[2] = $this->testPage->getLatest();
 
                $this->assertSame(
-                       [ $rev[1] => strval( $textOneLength ), $rev[2] => strval( $textTwoLength ) ],
+                       [ $rev[1] => $textOneLength, $rev[2] => $textTwoLength ],
                        Revision::getParentLengths(
                                wfGetDB( DB_MASTER ),
                                [ $rev[1], $rev[2] ]
@@ -1080,14 +1172,6 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                );
        }
 
-       /**
-        * @covers Revision::getTitle
-        */
-       public function testGetTitle_forBadRevision() {
-               $rev = new Revision( [] );
-               $this->assertNull( $rev->getTitle() );
-       }
-
        /**
         * @covers Revision::isMinor
         */
@@ -1263,14 +1347,39 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                $rev = $this->testPage->getRevision();
 
                // Clear any previous cache for the revision during creation
-               $key = $cache->makeGlobalKey( 'revision', $db->getDomainID(), $rev->getPage(), $rev->getId() );
+               $key = $cache->makeGlobalKey( 'revision-row-1.29',
+                       $db->getDomainID(),
+                       $rev->getPage(),
+                       $rev->getId()
+               );
                $cache->delete( $key, WANObjectCache::HOLDOFF_NONE );
                $this->assertFalse( $cache->get( $key ) );
 
                // Get the new revision and make sure it is in the cache and correct
                $newRev = Revision::newKnownCurrent( $db, $rev->getPage(), $rev->getId() );
                $this->assertRevEquals( $rev, $newRev );
-               $this->assertRevEquals( $rev, $cache->get( $key ) );
+
+               $cachedRow = $cache->get( $key );
+               $this->assertNotFalse( $cachedRow );
+               $this->assertEquals( $rev->getId(), $cachedRow->rev_id );
+       }
+
+       public function testNewKnownCurrent_withPageId() {
+               $db = wfGetDB( DB_MASTER );
+
+               $this->testPage->doEditContent( new WikitextContent( __METHOD__ ), __METHOD__ );
+               $rev = $this->testPage->getRevision();
+
+               $pageId = $this->testPage->getId();
+
+               $newRev = Revision::newKnownCurrent( $db, $pageId, $rev->getId() );
+               $this->assertRevEquals( $rev, $newRev );
+       }
+
+       public function testNewKnownCurrent_returnsFalseWhenTitleDoesntExist() {
+               $db = wfGetDB( DB_MASTER );
+
+               $this->assertFalse( Revision::newKnownCurrent( $db, 0 ) );
        }
 
        public function provideUserCanBitfield() {
@@ -1377,7 +1486,7 @@ abstract class RevisionDbTestBase extends MediaWikiTestCase {
                        ]
                );
                $user = $this->getTestUser( $userGroups )->getUser();
-               $revision = new Revision( [ 'deleted' => $bitField ] );
+               $revision = new Revision( [ 'deleted' => $bitField ], 0, $this->testPage->getTitle() );
 
                $this->assertSame(
                        $expected,
index e4ea40f..0db76ff 100644 (file)
@@ -1,6 +1,10 @@
 <?php
 
-use Wikimedia\TestingAccessWrapper;
+use MediaWiki\Storage\BlobStoreFactory;
+use MediaWiki\Storage\RevisionStore;
+use MediaWiki\Storage\SqlBlobStore;
+use Wikimedia\Rdbms\IDatabase;
+use Wikimedia\Rdbms\LoadBalancer;
 
 /**
  * Test cases in RevisionTest should not interact with the Database.
@@ -39,7 +43,7 @@ class RevisionTest extends MediaWikiTestCase {
                        ->method( 'getPrefixedText' )
                        ->will( $this->returnValue( 'RevisionTest' ) );
                $mock->expects( $this->any() )
-                       ->method( 'getDBKey' )
+                       ->method( 'getDBkey' )
                        ->will( $this->returnValue( 'RevisionTest' ) );
                $mock->expects( $this->any() )
                        ->method( 'getArticleID' )
@@ -54,10 +58,10 @@ class RevisionTest extends MediaWikiTestCase {
        /**
         * @dataProvider provideConstructFromArray
         * @covers Revision::__construct
-        * @covers Revision::constructFromRowArray
+        * @covers \MediaWiki\Storage\RevisionStore::newMutableRevisionFromArray
         */
-       public function testConstructFromArray( array $rowArray ) {
-               $rev = new Revision( $rowArray );
+       public function testConstructFromArray( $rowArray ) {
+               $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
                $this->assertNotNull( $rev->getContent(), 'no content object available' );
                $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContent()->getModel() );
                $this->assertEquals( CONTENT_MODEL_JAVASCRIPT, $rev->getContentModel() );
@@ -65,7 +69,7 @@ class RevisionTest extends MediaWikiTestCase {
 
        /**
         * @covers Revision::__construct
-        * @covers Revision::constructFromRowArray
+        * @covers \MediaWiki\Storage\RevisionStore::newMutableRevisionFromArray
         */
        public function testConstructFromEmptyArray() {
                $rev = new Revision( [], 0, $this->getMockTitle() );
@@ -90,30 +94,20 @@ class RevisionTest extends MediaWikiTestCase {
                        99,
                        'SomeTextUserName',
                ];
-               // Note: the below XXX test cases are odd and probably result in unexpected behaviour if used
-               // in production code.
-               yield 'XXX: user text only' => [
+               yield 'user text only' => [
                        [
                                'content' => new JavaScriptContent( 'hello world.' ),
                                'user_text' => '111.111.111.111',
                        ],
-                       null,
+                       0,
                        '111.111.111.111',
                ];
-               yield 'XXX: user id only' => [
-                       [
-                               'content' => new JavaScriptContent( 'hello world.' ),
-                               'user' => 9989,
-                       ],
-                       9989,
-                       null,
-               ];
        }
 
        /**
         * @dataProvider provideConstructFromArray_userSetAsExpected
         * @covers Revision::__construct
-        * @covers Revision::constructFromRowArray
+        * @covers \MediaWiki\Storage\RevisionStore::newMutableRevisionFromArray
         *
         * @param array $rowArray
         * @param mixed $expectedUserId null to expect the current wgUser ID
@@ -133,7 +127,7 @@ class RevisionTest extends MediaWikiTestCase {
                        $expectedUserName = $testUser->getName();
                }
 
-               $rev = new Revision( $rowArray );
+               $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
                $this->assertEquals( $expectedUserId, $rev->getUser() );
                $this->assertEquals( $expectedUserName, $rev->getUserText() );
        }
@@ -143,28 +137,37 @@ class RevisionTest extends MediaWikiTestCase {
                        [
                                'content' => new WikitextContent( 'GOAT' ),
                                'text_id' => 'someid',
-                               ],
+                       ],
                        new MWException( "Text already stored in external store (id someid), " .
                                "can't serialize content object" )
                ];
+               yield 'unknown user id and no user name' => [
+                       [
+                               'content' => new JavaScriptContent( 'hello world.' ),
+                               'user' => 9989,
+                       ],
+                       new MWException( 'user_text not given, and unknown user ID 9989' )
+               ];
                yield 'with bad content object (class)' => [
                        [ 'content' => new stdClass() ],
-                       new MWException( '`content` field must contain a Content object.' )
+                       new MWException( 'content field must contain a Content object.' )
                ];
                yield 'with bad content object (string)' => [
                        [ 'content' => 'ImAGoat' ],
-                       new MWException( '`content` field must contain a Content object.' )
+                       new MWException( 'content field must contain a Content object.' )
                ];
                yield 'bad row format' => [
                        'imastring, not a row',
-                       new MWException( 'Revision constructor passed invalid row format.' )
+                       new InvalidArgumentException(
+                               '$row must be a row object, an associative array, or a RevisionRecord'
+                       )
                ];
        }
 
        /**
         * @dataProvider provideConstructFromArrayThrowsExceptions
         * @covers Revision::__construct
-        * @covers Revision::constructFromRowArray
+        * @covers \MediaWiki\Storage\RevisionStore::newMutableRevisionFromArray
         */
        public function testConstructFromArrayThrowsExceptions( $rowArray, Exception $expectedException ) {
                $this->setExpectedException(
@@ -172,23 +175,25 @@ class RevisionTest extends MediaWikiTestCase {
                        $expectedException->getMessage(),
                        $expectedException->getCode()
                );
-               new Revision( $rowArray );
+               new Revision( $rowArray, 0, $this->getMockTitle() );
        }
 
        /**
         * @covers Revision::__construct
-        * @covers Revision::constructFromRowArray
+        * @covers \MediaWiki\Storage\RevisionStore::newMutableRevisionFromArray
         */
        public function testConstructFromNothing() {
-               $rev = new Revision( [] );
-               $this->assertNull( $rev->getId(), 'getId()' );
+               $this->setExpectedException(
+                       InvalidArgumentException::class
+               );
+               new Revision( [] );
        }
 
        public function provideConstructFromRow() {
                yield 'Full construction' => [
                        [
-                               'rev_id' => '2',
-                               'rev_page' => '1',
+                               'rev_id' => '42',
+                               'rev_page' => '23',
                                'rev_text_id' => '2',
                                'rev_timestamp' => '20171017114835',
                                'rev_user_text' => '127.0.0.1',
@@ -205,8 +210,8 @@ class RevisionTest extends MediaWikiTestCase {
                                'rev_content_model' => 'GOATMODEL',
                        ],
                        function ( RevisionTest $testCase, Revision $rev ) {
-                               $testCase->assertSame( 2, $rev->getId() );
-                               $testCase->assertSame( 1, $rev->getPage() );
+                               $testCase->assertSame( 42, $rev->getId() );
+                               $testCase->assertSame( 23, $rev->getPage() );
                                $testCase->assertSame( 2, $rev->getTextId() );
                                $testCase->assertSame( '20171017114835', $rev->getTimestamp() );
                                $testCase->assertSame( '127.0.0.1', $rev->getUserText() );
@@ -221,10 +226,10 @@ class RevisionTest extends MediaWikiTestCase {
                                $testCase->assertSame( 'GOATMODEL', $rev->getContentModel() );
                        }
                ];
-               yield 'null fields' => [
+               yield 'default field values' => [
                        [
-                               'rev_id' => '2',
-                               'rev_page' => '1',
+                               'rev_id' => '42',
+                               'rev_page' => '23',
                                'rev_text_id' => '2',
                                'rev_timestamp' => '20171017114835',
                                'rev_user_text' => '127.0.0.1',
@@ -236,11 +241,24 @@ class RevisionTest extends MediaWikiTestCase {
                                'rev_comment_cid' => null,
                        ],
                        function ( RevisionTest $testCase, Revision $rev ) {
-                               $testCase->assertNull( $rev->getSize() );
-                               $testCase->assertNull( $rev->getParentId() );
-                               $testCase->assertNull( $rev->getSha1() );
-                               $testCase->assertSame( 'text/x-wiki', $rev->getContentFormat() );
-                               $testCase->assertSame( 'wikitext', $rev->getContentModel() );
+                               // parent ID may be null
+                               $testCase->assertSame( null, $rev->getParentId(), 'revision id' );
+
+                               // given fields
+                               $testCase->assertSame( $rev->getTimestamp(), '20171017114835', 'timestamp' );
+                               $testCase->assertSame( $rev->getUserText(), '127.0.0.1', 'user name' );
+                               $testCase->assertSame( $rev->getUser(), 0, 'user id' );
+                               $testCase->assertSame( $rev->getComment(), 'Goat Comment!' );
+                               $testCase->assertSame( false, $rev->isMinor(), 'minor edit' );
+                               $testCase->assertSame( 0, $rev->getVisibility(), 'visibility flags' );
+
+                               // computed fields
+                               $testCase->assertNotNull( $rev->getSize(), 'size' );
+                               $testCase->assertNotNull( $rev->getSha1(), 'hash' );
+
+                               // NOTE: model and format will be detected based on the namespace of the (mock) title
+                               $testCase->assertSame( 'text/x-wiki', $rev->getContentFormat(), 'format' );
+                               $testCase->assertSame( 'wikitext', $rev->getContentModel(), 'model' );
                        }
                ];
        }
@@ -248,11 +266,34 @@ class RevisionTest extends MediaWikiTestCase {
        /**
         * @dataProvider provideConstructFromRow
         * @covers Revision::__construct
-        * @covers Revision::constructFromRowArray
+        * @covers \MediaWiki\Storage\RevisionStore::newMutableRevisionFromArray
         */
        public function testConstructFromRow( array $arrayData, $assertions ) {
+               $data = 'Hello goat.'; // needs to match model and format
+
+               $blobStore = $this->getMockBuilder( SqlBlobStore::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $blobStore->method( 'getBlob' )
+                       ->will( $this->returnValue( $data ) );
+
+               $blobStore->method( 'getTextIdFromAddress' )
+                       ->will( $this->returnCallback(
+                               function ( $address ) {
+                                       // Turn "tt:1234" into 12345.
+                                       // Note that this must be functional so we can test getTextId().
+                                       // Ideally, we'd un-mock getTextIdFromAddress and use its actual implementation.
+                                       $parts = explode( ':', $address );
+                                       return (int)array_pop( $parts );
+                               }
+                       ) );
+
+               // Note override internal service, so RevisionStore uses it as well.
+               $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
+
                $row = (object)$arrayData;
-               $rev = new Revision( $row );
+               $rev = new Revision( $row, 0, $this->getMockTitle() );
                $assertions( $this, $rev );
        }
 
@@ -282,7 +323,7 @@ class RevisionTest extends MediaWikiTestCase {
         * @covers Revision::getId
         */
        public function testGetId( $rowArray, $expectedId ) {
-               $rev = new Revision( $rowArray );
+               $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
                $this->assertEquals( $expectedId, $rev->getId() );
        }
 
@@ -296,7 +337,7 @@ class RevisionTest extends MediaWikiTestCase {
         * @covers Revision::setId
         */
        public function testSetId( $input, $expected ) {
-               $rev = new Revision( [] );
+               $rev = new Revision( [], 0, $this->getMockTitle() );
                $rev->setId( $input );
                $this->assertSame( $expected, $rev->getId() );
        }
@@ -311,7 +352,7 @@ class RevisionTest extends MediaWikiTestCase {
         * @covers Revision::setUserIdAndName
         */
        public function testSetUserIdAndName( $inputId, $expectedId, $name ) {
-               $rev = new Revision( [] );
+               $rev = new Revision( [], 0, $this->getMockTitle() );
                $rev->setUserIdAndName( $inputId, $name );
                $this->assertSame( $expectedId, $rev->getUser( Revision::RAW ) );
                $this->assertEquals( $name, $rev->getUserText( Revision::RAW ) );
@@ -328,7 +369,7 @@ class RevisionTest extends MediaWikiTestCase {
         * @covers Revision::getTextId()
         */
        public function testGetTextId( $rowArray, $expected ) {
-               $rev = new Revision( $rowArray );
+               $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
                $this->assertSame( $expected, $rev->getTextId() );
        }
 
@@ -343,7 +384,7 @@ class RevisionTest extends MediaWikiTestCase {
         * @covers Revision::getParentId()
         */
        public function testGetParentId( $rowArray, $expected ) {
-               $rev = new Revision( $rowArray );
+               $rev = new Revision( $rowArray, 0, $this->getMockTitle() );
                $this->assertSame( $expected, $rev->getParentId() );
        }
 
@@ -376,9 +417,58 @@ class RevisionTest extends MediaWikiTestCase {
                $this->testGetRevisionText( $expected, $rowData );
        }
 
+       private function getWANObjectCache() {
+               return new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
+       }
+
+       /**
+        * @return SqlBlobStore
+        */
+       private function getBlobStore() {
+               /** @var LoadBalancer $lb */
+               $lb = $this->getMockBuilder( LoadBalancer::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $cache = $this->getWANObjectCache();
+
+               $blobStore = new SqlBlobStore( $lb, $cache );
+               return $blobStore;
+       }
+
+       private function mockBlobStoreFactory( $blobStore ) {
+               /** @var LoadBalancer $lb */
+               $factory = $this->getMockBuilder( BlobStoreFactory::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $factory->expects( $this->any() )
+                       ->method( 'newBlobStore' )
+                       ->willReturn( $blobStore );
+               $factory->expects( $this->any() )
+                       ->method( 'newSqlBlobStore' )
+                       ->willReturn( $blobStore );
+               return $factory;
+       }
+
+       /**
+        * @return RevisionStore
+        */
+       private function getRevisionStore() {
+               /** @var LoadBalancer $lb */
+               $lb = $this->getMockBuilder( LoadBalancer::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $cache = $this->getWANObjectCache();
+
+               $blobStore = new RevisionStore( $lb, $this->getBlobStore(), $cache );
+               return $blobStore;
+       }
+
        public function provideGetRevisionTextWithLegacyEncoding() {
                yield 'Utf8Native' => [
                        "Wiki est l'\xc3\xa9cole superieur !",
+                       'fr',
                        'iso-8859-1',
                        [
                                'old_flags' => 'utf-8',
@@ -387,6 +477,7 @@ class RevisionTest extends MediaWikiTestCase {
                ];
                yield 'Utf8Legacy' => [
                        "Wiki est l'\xc3\xa9cole superieur !",
+                       'fr',
                        'iso-8859-1',
                        [
                                'old_flags' => '',
@@ -399,8 +490,11 @@ class RevisionTest extends MediaWikiTestCase {
         * @covers Revision::getRevisionText
         * @dataProvider provideGetRevisionTextWithLegacyEncoding
         */
-       public function testGetRevisionWithLegacyEncoding( $expected, $encoding, $rowData ) {
-               $this->setMwGlobals( 'wgLegacyEncoding', $encoding );
+       public function testGetRevisionWithLegacyEncoding( $expected, $lang, $encoding, $rowData ) {
+               $blobStore = $this->getBlobStore();
+               $blobStore->setLegacyEncoding( $encoding, Language::factory( $lang ) );
+               $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
+
                $this->testGetRevisionText( $expected, $rowData );
        }
 
@@ -412,6 +506,7 @@ class RevisionTest extends MediaWikiTestCase {
                 */
                yield 'Utf8NativeGzip' => [
                        "Wiki est l'\xc3\xa9cole superieur !",
+                       'fr',
                        'iso-8859-1',
                        [
                                'old_flags' => 'gzip,utf-8',
@@ -420,6 +515,7 @@ class RevisionTest extends MediaWikiTestCase {
                ];
                yield 'Utf8LegacyGzip' => [
                        "Wiki est l'\xc3\xa9cole superieur !",
+                       'fr',
                        'iso-8859-1',
                        [
                                'old_flags' => 'gzip',
@@ -432,9 +528,13 @@ class RevisionTest extends MediaWikiTestCase {
         * @covers Revision::getRevisionText
         * @dataProvider provideGetRevisionTextWithGzipAndLegacyEncoding
         */
-       public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $encoding, $rowData ) {
+       public function testGetRevisionWithGzipAndLegacyEncoding( $expected, $lang, $encoding, $rowData ) {
                $this->checkPHPExtension( 'zlib' );
-               $this->setMwGlobals( 'wgLegacyEncoding', $encoding );
+
+               $blobStore = $this->getBlobStore();
+               $blobStore->setLegacyEncoding( $encoding, Language::factory( $lang ) );
+               $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
+
                $this->testGetRevisionText( $expected, $rowData );
        }
 
@@ -460,7 +560,10 @@ class RevisionTest extends MediaWikiTestCase {
         */
        public function testCompressRevisionTextUtf8Gzip() {
                $this->checkPHPExtension( 'zlib' );
-               $this->setMwGlobals( 'wgCompressRevisions', true );
+
+               $blobStore = $this->getBlobStore();
+               $blobStore->setCompressBlobs( true );
+               $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
 
                $row = new stdClass;
                $row->old_text = "Wiki est l'\xc3\xa9cole superieur !";
@@ -475,20 +578,41 @@ class RevisionTest extends MediaWikiTestCase {
                        Revision::getRevisionText( $row ), "getRevisionText" );
        }
 
-       public function provideFetchFromConds() {
-               yield [ 0, [] ];
-               yield [ Revision::READ_LOCKING, [ 'FOR UPDATE' ] ];
-       }
-
        /**
-        * @dataProvider provideFetchFromConds
-        * @covers Revision::fetchFromConds
+        * @covers Revision::loadFromTitle
         */
-       public function testFetchFromConds( $flags, array $options ) {
-               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
-               $conditions = [ 'conditionsArray' ];
+       public function testLoadFromTitle() {
+               $title = $this->getMockTitle();
+
+               $conditions = [
+                       'rev_id=page_latest',
+                       'page_namespace' => $title->getNamespace(),
+                       'page_title' => $title->getDBkey()
+               ];
+
+               $row = (object)[
+                       'rev_id' => '42',
+                       'rev_page' => $title->getArticleID(),
+                       'rev_text_id' => '2',
+                       'rev_timestamp' => '20171017114835',
+                       'rev_user_text' => '127.0.0.1',
+                       'rev_user' => '0',
+                       'rev_minor_edit' => '0',
+                       'rev_deleted' => '0',
+                       'rev_len' => '46',
+                       'rev_parent_id' => '1',
+                       'rev_sha1' => 'rdqbbzs3pkhihgbs8qf2q9jsvheag5z',
+                       'rev_comment_text' => 'Goat Comment!',
+                       'rev_comment_data' => null,
+                       'rev_comment_cid' => null,
+                       'rev_content_format' => 'GOATFORMAT',
+                       'rev_content_model' => 'GOATMODEL',
+               ];
 
                $db = $this->getMock( IDatabase::class );
+               $db->expects( $this->any() )
+                       ->method( 'getDomainId' )
+                       ->will( $this->returnValue( wfWikiID() ) );
                $db->expects( $this->once() )
                        ->method( 'selectRow' )
                        ->with(
@@ -497,17 +621,24 @@ class RevisionTest extends MediaWikiTestCase {
                                $this->isType( 'array' ),
                                $this->equalTo( $conditions ),
                                // Method name
-                               $this->equalTo( 'Revision::fetchFromConds' ),
-                               $this->equalTo( $options ),
+                               $this->stringContains( 'fetchRevisionRowFromConds' ),
+                               // We don't really care about the options here
+                               $this->isType( 'array' ),
                                // We don't really care about the join conds are they come from the joinCond methods
                                $this->isType( 'array' )
                        )
-                       ->willReturn( 'RETURNVALUE' );
-
-               $wrapper = TestingAccessWrapper::newFromClass( Revision::class );
-               $result = $wrapper->fetchFromConds( $db, $conditions, $flags );
-
-               $this->assertEquals( 'RETURNVALUE', $result );
+                       ->willReturn( $row );
+
+               $revision = Revision::loadFromTitle( $db, $title );
+
+               $this->assertEquals( $title->getArticleID(), $revision->getTitle()->getArticleID() );
+               $this->assertEquals( $row->rev_id, $revision->getId() );
+               $this->assertEquals( $row->rev_len, $revision->getSize() );
+               $this->assertEquals( $row->rev_sha1, $revision->getSha1() );
+               $this->assertEquals( $row->rev_parent_id, $revision->getParentId() );
+               $this->assertEquals( $row->rev_timestamp, $revision->getTimestamp() );
+               $this->assertEquals( $row->rev_comment_text, $revision->getComment() );
+               $this->assertEquals( $row->rev_user_text, $revision->getUserText() );
        }
 
        public function provideDecompressRevisionText() {
@@ -572,8 +703,12 @@ class RevisionTest extends MediaWikiTestCase {
         * @param mixed $expected
         */
        public function testDecompressRevisionText( $legacyEncoding, $text, $flags, $expected ) {
-               $this->setMwGlobals( 'wgLegacyEncoding', $legacyEncoding );
-               $this->setMwGlobals( 'wgLanguageCode', 'en' );
+               $blobStore = $this->getBlobStore();
+               if ( $legacyEncoding ) {
+                       $blobStore->setLegacyEncoding( $legacyEncoding, Language::factory( 'en' ) );
+               }
+
+               $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
                $this->assertSame(
                        $expected,
                        Revision::decompressRevisionText( $text, $flags )
@@ -669,14 +804,20 @@ class RevisionTest extends MediaWikiTestCase {
         * @covers Revision::getRevisionText
         */
        public function testGetRevisionText_external_oldId() {
-               $cache = new WANObjectCache( [ 'cache' => new HashBagOStuff() ] );
+               $cache = $this->getWANObjectCache();
                $this->setService( 'MainWANObjectCache', $cache );
+
                $this->setService(
                        'ExternalStoreFactory',
                        new ExternalStoreFactory( [ 'ForTesting' ] )
                );
 
-               $cacheKey = $cache->makeKey( 'revisiontext', 'textid', '7777' );
+               $lb = $this->getMockBuilder( LoadBalancer::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $blobStore = new SqlBlobStore( $lb, $cache );
+               $this->setService( 'BlobStoreFactory', $this->mockBlobStoreFactory( $blobStore ) );
 
                $this->assertSame(
                        'AAAABBAAA',
@@ -688,6 +829,8 @@ class RevisionTest extends MediaWikiTestCase {
                                ]
                        )
                );
+
+               $cacheKey = $cache->makeKey( 'revisiontext', 'textid', 'tt:7777' );
                $this->assertSame( 'AAAABBAAA', $cache->get( $cacheKey ) );
        }
 
@@ -883,6 +1026,8 @@ class RevisionTest extends MediaWikiTestCase {
                                'fields' => [
                                        'ar_id',
                                        'ar_page_id',
+                                       'ar_namespace',
+                                       'ar_title',
                                        'ar_rev_id',
                                        'ar_text',
                                        'ar_text_id',
@@ -911,6 +1056,8 @@ class RevisionTest extends MediaWikiTestCase {
                                'fields' => [
                                        'ar_id',
                                        'ar_page_id',
+                                       'ar_namespace',
+                                       'ar_title',
                                        'ar_rev_id',
                                        'ar_text',
                                        'ar_text_id',
@@ -944,6 +1091,8 @@ class RevisionTest extends MediaWikiTestCase {
                                'fields' => [
                                        'ar_id',
                                        'ar_page_id',
+                                       'ar_namespace',
+                                       'ar_title',
                                        'ar_rev_id',
                                        'ar_text',
                                        'ar_text_id',
@@ -980,6 +1129,8 @@ class RevisionTest extends MediaWikiTestCase {
                                'fields' => [
                                        'ar_id',
                                        'ar_page_id',
+                                       'ar_namespace',
+                                       'ar_title',
                                        'ar_rev_id',
                                        'ar_text',
                                        'ar_text_id',
@@ -1016,6 +1167,8 @@ class RevisionTest extends MediaWikiTestCase {
                                'fields' => [
                                        'ar_id',
                                        'ar_page_id',
+                                       'ar_namespace',
+                                       'ar_title',
                                        'ar_rev_id',
                                        'ar_text',
                                        'ar_text_id',
@@ -1047,6 +1200,11 @@ class RevisionTest extends MediaWikiTestCase {
         */
        public function testGetArchiveQueryInfo( $globals, $expected ) {
                $this->setMwGlobals( $globals );
+
+               $revisionStore = $this->getRevisionStore();
+               $revisionStore->setContentHandlerUseDB( $globals['wgContentHandlerUseDB'] );
+               $this->setService( 'RevisionStore', $revisionStore );
+
                $this->assertEquals(
                        $expected,
                        Revision::getArchiveQueryInfo()
@@ -1398,6 +1556,11 @@ class RevisionTest extends MediaWikiTestCase {
         */
        public function testGetQueryInfo( $globals, $options, $expected ) {
                $this->setMwGlobals( $globals );
+
+               $revisionStore = $this->getRevisionStore();
+               $revisionStore->setContentHandlerUseDB( $globals['wgContentHandlerUseDB'] );
+               $this->setService( 'RevisionStore', $revisionStore );
+
                $this->assertEquals(
                        $expected,
                        Revision::getQueryInfo( $options )
index 31eebe3..c0930e3 100644 (file)
@@ -57,12 +57,12 @@ class SampleTest extends MediaWikiLangTestCase {
                ];
        }
 
-       // @codingStandardsIgnoreStart Generic.Files.LineLength
        /**
+        * phpcs:disable Generic.Files.LineLength
         * @dataProvider provideTitles
         * See https://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.dataProvider
+        * phpcs:enable
         */
-       // @codingStandardsIgnoreEnd
        public function testCreateBasicListOfTitles( $titleName, $ns, $text ) {
                $title = Title::newFromText( $titleName, $ns );
                $this->assertEquals( $text, "$title", "see if '$titleName' matches '$text'" );
@@ -95,12 +95,10 @@ class SampleTest extends MediaWikiLangTestCase {
                $this->assertTrue( $title->isLocal() );
        }
 
-       // @codingStandardsIgnoreStart Generic.Files.LineLength
        /**
         * @expectedException InvalidArgumentException
         * See https://phpunit.de/manual/3.7/en/appendixes.annotations.html#appendixes.annotations.expectedException
         */
-       // @codingStandardsIgnoreEnd
        public function testTitleObjectFromObject() {
                $title = Title::newFromText( Title::newFromText( "test" ) );
                $this->assertEquals( "Test", $title->isLocal() );
index 2448513..c7e15ea 100644 (file)
@@ -7,6 +7,8 @@
  */
 class SanitizerValidateEmailTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        private function checkEmail( $addr, $expected = true, $msg = '' ) {
                if ( $msg == '' ) {
                        $msg = "Testing $addr";
diff --git a/tests/phpunit/includes/Services/ServiceContainerTest.php b/tests/phpunit/includes/Services/ServiceContainerTest.php
deleted file mode 100644 (file)
index b68ee48..0000000
+++ /dev/null
@@ -1,411 +0,0 @@
-<?php
-use MediaWiki\Services\ServiceContainer;
-
-/**
- * @covers MediaWiki\Services\ServiceContainer
- *
- * @group MediaWiki
- */
-class ServiceContainerTest extends PHPUnit_Framework_TestCase {
-
-       private function newServiceContainer( $extraArgs = [] ) {
-               return new ServiceContainer( $extraArgs );
-       }
-
-       public function testGetServiceNames() {
-               $services = $this->newServiceContainer();
-               $names = $services->getServiceNames();
-
-               $this->assertInternalType( 'array', $names );
-               $this->assertEmpty( $names );
-
-               $name = 'TestService92834576';
-               $services->defineService( $name, function () {
-                       return null;
-               } );
-
-               $names = $services->getServiceNames();
-               $this->assertContains( $name, $names );
-       }
-
-       public function testHasService() {
-               $services = $this->newServiceContainer();
-
-               $name = 'TestService92834576';
-               $this->assertFalse( $services->hasService( $name ) );
-
-               $services->defineService( $name, function () {
-                       return null;
-               } );
-
-               $this->assertTrue( $services->hasService( $name ) );
-       }
-
-       public function testGetService() {
-               $services = $this->newServiceContainer( [ 'Foo' ] );
-
-               $theService = new stdClass();
-               $name = 'TestService92834576';
-               $count = 0;
-
-               $services->defineService(
-                       $name,
-                       function ( $actualLocator, $extra ) use ( $services, $theService, &$count ) {
-                               $count++;
-                               PHPUnit_Framework_Assert::assertSame( $services, $actualLocator );
-                               PHPUnit_Framework_Assert::assertSame( $extra, 'Foo' );
-                               return $theService;
-                       }
-               );
-
-               $this->assertSame( $theService, $services->getService( $name ) );
-
-               $services->getService( $name );
-               $this->assertSame( 1, $count, 'instantiator should be called exactly once!' );
-       }
-
-       public function testGetService_fail_unknown() {
-               $services = $this->newServiceContainer();
-
-               $name = 'TestService92834576';
-
-               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
-
-               $services->getService( $name );
-       }
-
-       public function testPeekService() {
-               $services = $this->newServiceContainer();
-
-               $services->defineService(
-                       'Foo',
-                       function () {
-                               return new stdClass();
-                       }
-               );
-
-               $services->defineService(
-                       'Bar',
-                       function () {
-                               return new stdClass();
-                       }
-               );
-
-               // trigger instantiation of Foo
-               $services->getService( 'Foo' );
-
-               $this->assertInternalType(
-                       'object',
-                       $services->peekService( 'Foo' ),
-                       'Peek should return the service object if it had been accessed before.'
-               );
-
-               $this->assertNull(
-                       $services->peekService( 'Bar' ),
-                       'Peek should return null if the service was never accessed.'
-               );
-       }
-
-       public function testPeekService_fail_unknown() {
-               $services = $this->newServiceContainer();
-
-               $name = 'TestService92834576';
-
-               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
-
-               $services->peekService( $name );
-       }
-
-       public function testDefineService() {
-               $services = $this->newServiceContainer();
-
-               $theService = new stdClass();
-               $name = 'TestService92834576';
-
-               $services->defineService( $name, function ( $actualLocator ) use ( $services, $theService ) {
-                       PHPUnit_Framework_Assert::assertSame( $services, $actualLocator );
-                       return $theService;
-               } );
-
-               $this->assertTrue( $services->hasService( $name ) );
-               $this->assertSame( $theService, $services->getService( $name ) );
-       }
-
-       public function testDefineService_fail_duplicate() {
-               $services = $this->newServiceContainer();
-
-               $theService = new stdClass();
-               $name = 'TestService92834576';
-
-               $services->defineService( $name, function () use ( $theService ) {
-                       return $theService;
-               } );
-
-               $this->setExpectedException( 'MediaWiki\Services\ServiceAlreadyDefinedException' );
-
-               $services->defineService( $name, function () use ( $theService ) {
-                       return $theService;
-               } );
-       }
-
-       public function testApplyWiring() {
-               $services = $this->newServiceContainer();
-
-               $wiring = [
-                       'Foo' => function () {
-                               return 'Foo!';
-                       },
-                       'Bar' => function () {
-                               return 'Bar!';
-                       },
-               ];
-
-               $services->applyWiring( $wiring );
-
-               $this->assertSame( 'Foo!', $services->getService( 'Foo' ) );
-               $this->assertSame( 'Bar!', $services->getService( 'Bar' ) );
-       }
-
-       public function testImportWiring() {
-               $services = $this->newServiceContainer();
-
-               $wiring = [
-                       'Foo' => function () {
-                               return 'Foo!';
-                       },
-                       'Bar' => function () {
-                               return 'Bar!';
-                       },
-                       'Car' => function () {
-                               return 'FUBAR!';
-                       },
-               ];
-
-               $services->applyWiring( $wiring );
-
-               $newServices = $this->newServiceContainer();
-
-               // define a service before importing, so we can later check that
-               // existing service instances survive importWiring()
-               $newServices->defineService( 'Car', function () {
-                       return 'Car!';
-               } );
-
-               // force instantiation
-               $newServices->getService( 'Car' );
-
-               // Define another service, so we can later check that extra wiring
-               // is not lost.
-               $newServices->defineService( 'Xar', function () {
-                       return 'Xar!';
-               } );
-
-               // import wiring, but skip `Bar`
-               $newServices->importWiring( $services, [ 'Bar' ] );
-
-               $this->assertNotContains( 'Bar', $newServices->getServiceNames(), 'Skip `Bar` service' );
-               $this->assertSame( 'Foo!', $newServices->getService( 'Foo' ) );
-
-               // import all wiring, but preserve existing service instance
-               $newServices->importWiring( $services );
-
-               $this->assertContains( 'Bar', $newServices->getServiceNames(), 'Import all services' );
-               $this->assertSame( 'Bar!', $newServices->getService( 'Bar' ) );
-               $this->assertSame( 'Car!', $newServices->getService( 'Car' ), 'Use existing service instance' );
-               $this->assertSame( 'Xar!', $newServices->getService( 'Xar' ), 'Predefined services are kept' );
-       }
-
-       public function testLoadWiringFiles() {
-               $services = $this->newServiceContainer();
-
-               $wiringFiles = [
-                       __DIR__ . '/TestWiring1.php',
-                       __DIR__ . '/TestWiring2.php',
-               ];
-
-               $services->loadWiringFiles( $wiringFiles );
-
-               $this->assertSame( 'Foo!', $services->getService( 'Foo' ) );
-               $this->assertSame( 'Bar!', $services->getService( 'Bar' ) );
-       }
-
-       public function testLoadWiringFiles_fail_duplicate() {
-               $services = $this->newServiceContainer();
-
-               $wiringFiles = [
-                       __DIR__ . '/TestWiring1.php',
-                       __DIR__ . '/./TestWiring1.php',
-               ];
-
-               // loading the same file twice should fail, because
-               $this->setExpectedException( 'MediaWiki\Services\ServiceAlreadyDefinedException' );
-
-               $services->loadWiringFiles( $wiringFiles );
-       }
-
-       public function testRedefineService() {
-               $services = $this->newServiceContainer( [ 'Foo' ] );
-
-               $theService1 = new stdClass();
-               $name = 'TestService92834576';
-
-               $services->defineService( $name, function () {
-                       PHPUnit_Framework_Assert::fail(
-                               'The original instantiator function should not get called'
-                       );
-               } );
-
-               // redefine before instantiation
-               $services->redefineService(
-                       $name,
-                       function ( $actualLocator, $extra ) use ( $services, $theService1 ) {
-                               PHPUnit_Framework_Assert::assertSame( $services, $actualLocator );
-                               PHPUnit_Framework_Assert::assertSame( 'Foo', $extra );
-                               return $theService1;
-                       }
-               );
-
-               // force instantiation, check result
-               $this->assertSame( $theService1, $services->getService( $name ) );
-       }
-
-       public function testRedefineService_disabled() {
-               $services = $this->newServiceContainer( [ 'Foo' ] );
-
-               $theService1 = new stdClass();
-               $name = 'TestService92834576';
-
-               $services->defineService( $name, function () {
-                       return 'Foo';
-               } );
-
-               // disable the service. we should be able to redefine it anyway.
-               $services->disableService( $name );
-
-               $services->redefineService( $name, function () use ( $theService1 ) {
-                       return $theService1;
-               } );
-
-               // force instantiation, check result
-               $this->assertSame( $theService1, $services->getService( $name ) );
-       }
-
-       public function testRedefineService_fail_undefined() {
-               $services = $this->newServiceContainer();
-
-               $theService = new stdClass();
-               $name = 'TestService92834576';
-
-               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
-
-               $services->redefineService( $name, function () use ( $theService ) {
-                       return $theService;
-               } );
-       }
-
-       public function testRedefineService_fail_in_use() {
-               $services = $this->newServiceContainer( [ 'Foo' ] );
-
-               $theService = new stdClass();
-               $name = 'TestService92834576';
-
-               $services->defineService( $name, function () {
-                       return 'Foo';
-               } );
-
-               // create the service, so it can no longer be redefined
-               $services->getService( $name );
-
-               $this->setExpectedException( 'MediaWiki\Services\CannotReplaceActiveServiceException' );
-
-               $services->redefineService( $name, function () use ( $theService ) {
-                       return $theService;
-               } );
-       }
-
-       public function testDisableService() {
-               $services = $this->newServiceContainer( [ 'Foo' ] );
-
-               $destructible = $this->getMockBuilder( 'MediaWiki\Services\DestructibleService' )
-                       ->getMock();
-               $destructible->expects( $this->once() )
-                       ->method( 'destroy' );
-
-               $services->defineService( 'Foo', function () use ( $destructible ) {
-                       return $destructible;
-               } );
-               $services->defineService( 'Bar', function () {
-                       return new stdClass();
-               } );
-               $services->defineService( 'Qux', function () {
-                       return new stdClass();
-               } );
-
-               // instantiate Foo and Bar services
-               $services->getService( 'Foo' );
-               $services->getService( 'Bar' );
-
-               // disable service, should call destroy() once.
-               $services->disableService( 'Foo' );
-
-               // disabled service should still be listed
-               $this->assertContains( 'Foo', $services->getServiceNames() );
-
-               // getting other services should still work
-               $services->getService( 'Bar' );
-
-               // disable non-destructible service, and not-yet-instantiated service
-               $services->disableService( 'Bar' );
-               $services->disableService( 'Qux' );
-
-               $this->assertNull( $services->peekService( 'Bar' ) );
-               $this->assertNull( $services->peekService( 'Qux' ) );
-
-               // disabled service should still be listed
-               $this->assertContains( 'Bar', $services->getServiceNames() );
-               $this->assertContains( 'Qux', $services->getServiceNames() );
-
-               $this->setExpectedException( 'MediaWiki\Services\ServiceDisabledException' );
-               $services->getService( 'Qux' );
-       }
-
-       public function testDisableService_fail_undefined() {
-               $services = $this->newServiceContainer();
-
-               $theService = new stdClass();
-               $name = 'TestService92834576';
-
-               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
-
-               $services->redefineService( $name, function () use ( $theService ) {
-                       return $theService;
-               } );
-       }
-
-       public function testDestroy() {
-               $services = $this->newServiceContainer();
-
-               $destructible = $this->getMockBuilder( 'MediaWiki\Services\DestructibleService' )
-                       ->getMock();
-               $destructible->expects( $this->once() )
-                       ->method( 'destroy' );
-
-               $services->defineService( 'Foo', function () use ( $destructible ) {
-                       return $destructible;
-               } );
-
-               $services->defineService( 'Bar', function () {
-                       return new stdClass();
-               } );
-
-               // create the service
-               $services->getService( 'Foo' );
-
-               // destroy the container
-               $services->destroy();
-
-               $this->setExpectedException( 'MediaWiki\Services\ContainerDisabledException' );
-               $services->getService( 'Bar' );
-       }
-
-}
diff --git a/tests/phpunit/includes/Services/TestWiring1.php b/tests/phpunit/includes/Services/TestWiring1.php
deleted file mode 100644 (file)
index b6ff4eb..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-/**
- * Test file for testing ServiceContainer::loadWiringFiles
- */
-
-return [
-       'Foo' => function () {
-               return 'Foo!';
-       },
-];
diff --git a/tests/phpunit/includes/Services/TestWiring2.php b/tests/phpunit/includes/Services/TestWiring2.php
deleted file mode 100644 (file)
index dfff64f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?php
-/**
- * Test file for testing ServiceContainer::loadWiringFiles
- */
-
-return [
-       'Bar' => function () {
-               return 'Bar!';
-       },
-];
index 7e56ebf..ae23a43 100644 (file)
@@ -5,11 +5,6 @@
  */
 class StatusTest extends MediaWikiLangTestCase {
 
-       public function testCanConstruct() {
-               new Status();
-               $this->assertTrue( true );
-       }
-
        /**
         * @dataProvider provideValues
         * @covers Status::newGood
diff --git a/tests/phpunit/includes/Storage/BlobStoreFactoryTest.php b/tests/phpunit/includes/Storage/BlobStoreFactoryTest.php
new file mode 100644 (file)
index 0000000..5db1634
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+
+namespace MediaWiki\Tests\Storage;
+
+use MediaWiki\MediaWikiServices;
+use MediaWiki\Storage\BlobStore;
+use MediaWiki\Storage\SqlBlobStore;
+use MediaWikiTestCase;
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * @covers \MediaWiki\Storage\BlobStore
+ */
+class BlobStoreFactoryTest extends MediaWikiTestCase {
+
+       public function provideWikiIds() {
+               yield [ false ];
+               yield [ 'someWiki' ];
+       }
+
+       /**
+        * @dataProvider provideWikiIds
+        */
+       public function testNewBlobStore( $wikiId ) {
+               $factory = MediaWikiServices::getInstance()->getBlobStoreFactory();
+               $store = $factory->newBlobStore( $wikiId );
+               $this->assertInstanceOf( BlobStore::class, $store );
+
+               // This only works as we currently know this is a SqlBlobStore object
+               $wrapper = TestingAccessWrapper::newFromObject( $store );
+               $this->assertEquals( $wikiId, $wrapper->wikiId );
+       }
+
+       /**
+        * @dataProvider provideWikiIds
+        */
+       public function testNewSqlBlobStore( $wikiId ) {
+               $factory = MediaWikiServices::getInstance()->getBlobStoreFactory();
+               $store = $factory->newSqlBlobStore( $wikiId );
+               $this->assertInstanceOf( SqlBlobStore::class, $store );
+
+               $wrapper = TestingAccessWrapper::newFromObject( $store );
+               $this->assertEquals( $wikiId, $wrapper->wikiId );
+       }
+
+}
index 695a6b3..ee8fdc7 100644 (file)
@@ -340,6 +340,9 @@ class RevisionStoreDbTest extends MediaWikiTestCase {
                $this->assertSame( 0, $result );
        }
 
+       /**
+        * @covers \MediaWiki\Storage\RevisionStore::getRecentChange
+        */
        public function testGetRecentChange() {
                $page = WikiPage::factory( Title::newFromText( 'UTPage' ) );
                $content = new WikitextContent( __METHOD__ );
index efad1b1..18dbc25 100644 (file)
@@ -213,6 +213,7 @@ class RevisionStoreTest extends MediaWikiTestCase {
        public function testGetQueryInfo( $contentHandlerUseDb, $options, $expected ) {
                $store = $this->getRevisionStore();
                $store->setContentHandlerUseDB( $contentHandlerUseDb );
+               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
                $this->assertEquals( $expected, $store->getQueryInfo( $options ) );
        }
 
@@ -242,6 +243,7 @@ class RevisionStoreTest extends MediaWikiTestCase {
        public function testGetArchiveQueryInfo_contentHandlerDb() {
                $store = $this->getRevisionStore();
                $store->setContentHandlerUseDB( true );
+               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
                $this->assertEquals(
                        [
                                'tables' => [
@@ -269,6 +271,7 @@ class RevisionStoreTest extends MediaWikiTestCase {
        public function testGetArchiveQueryInfo_noContentHandlerDb() {
                $store = $this->getRevisionStore();
                $store->setContentHandlerUseDB( false );
+               $this->setMwGlobals( 'wgCommentTableSchemaMigrationStage', MIGRATION_OLD );
                $this->assertEquals(
                        [
                                'tables' => [
index c161f85..4a803e6 100644 (file)
@@ -2,6 +2,7 @@
 
 /**
  * @group Templates
+ * @covers TemplateParser
  */
 class TemplateParserTest extends MediaWikiTestCase {
 
@@ -19,9 +20,6 @@ class TemplateParserTest extends MediaWikiTestCase {
 
        /**
         * @dataProvider provideProcessTemplate
-        * @covers TemplateParser::processTemplate
-        * @covers TemplateParser::getTemplate
-        * @covers TemplateParser::getTemplateFilename
         */
        public function testProcessTemplate( $name, $args, $result, $exception = false ) {
                if ( $exception ) {
index 7c2973f..8882214 100644 (file)
@@ -6,6 +6,8 @@
  */
 class TitleArrayFromResultTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        private function getMockResultWrapper( $row = null, $numRows = 1 ) {
                $resultWrapper = $this->getMockBuilder( 'ResultWrapper' )
                        ->disableOriginalConstructor();
index b760c22..54cdbe2 100644 (file)
@@ -325,6 +325,9 @@ class TitleMethodsTest extends MediaWikiLangTestCase {
                $this->assertEquals( $expected, $title->getOtherPage()->getPrefixedText() );
        }
 
+       /**
+        * @covers Title::clearCaches
+        */
        public function testClearCaches() {
                $linkCache = LinkCache::singleton();
 
index 75e0c3e..d12e4b8 100644 (file)
@@ -552,6 +552,7 @@ class TitleTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers Title::newFromTitleValue
         * @dataProvider provideNewFromTitleValue
         */
        public function testNewFromTitleValue( TitleValue $value ) {
@@ -572,6 +573,7 @@ class TitleTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers Title::getTitleValue
         * @dataProvider provideGetTitleValue
         */
        public function testGetTitleValue( $text ) {
@@ -603,6 +605,7 @@ class TitleTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers Title::getFragment
         * @dataProvider provideGetFragment
         *
         * @param string $full
@@ -913,6 +916,7 @@ class TitleTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers Title::getFragmentForURL
         * @dataProvider provideGetFragmentForURL
         *
         * @param string $titleStr
index 724dd60..227dd87 100644 (file)
@@ -6,6 +6,8 @@
 
 class WikiReferenceTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public function provideGetDisplayName() {
                return [
                        'http' => [ 'foo.bar', 'http://foo.bar' ],
index c2bc73e..dec7bf3 100644 (file)
@@ -5,6 +5,8 @@
  */
 class XmlJsTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @covers XmlJsCode::__construct
         * @dataProvider provideConstruction
index 4d4fa7b..4a280da 100644 (file)
@@ -141,6 +141,57 @@ class XmlTest extends MediaWikiTestCase {
                $this->assertEquals( '</element>', Xml::closeElement( 'element' ), 'closeElement() shortcut' );
        }
 
+       public function provideMonthSelector() {
+               global $wgLang;
+
+               $header = '<select name="month" id="month" class="mw-month-selector">';
+               $header2 = '<select name="month" id="monthSelector" class="mw-month-selector">';
+               $monthsString = '';
+               for ( $i = 1; $i < 13; $i++ ) {
+                       $monthName = $wgLang->getMonthName( $i );
+                       $monthsString .= "<option value=\"{$i}\">{$monthName}</option>";
+                       if ( $i !== 12 ) {
+                               $monthsString .= "\n";
+                       }
+               }
+               $monthsString2 = str_replace(
+                       '<option value="12">December</option>',
+                       '<option value="12" selected="">December</option>',
+                       $monthsString
+               );
+               $end = '</select>';
+
+               $allMonths = "<option value=\"AllMonths\">all</option>\n";
+               return [
+                       [ $header . $monthsString . $end, '', null, 'month' ],
+                       [ $header . $monthsString2 . $end, 12, null, 'month' ],
+                       [ $header2 . $monthsString . $end, '', null, 'monthSelector' ],
+                       [ $header . $allMonths . $monthsString . $end, '', 'AllMonths', 'month' ],
+
+               ];
+       }
+
+       /**
+        * @covers Xml::monthSelector
+        * @dataProvider provideMonthSelector
+        */
+       public function testMonthSelector( $expected, $selected, $allmonths, $id ) {
+               $this->assertEquals(
+                       $expected,
+                       Xml::monthSelector( $selected, $allmonths, $id )
+               );
+       }
+
+       /**
+        * @covers Xml::span
+        */
+       public function testSpan() {
+               $this->assertEquals(
+                       '<span class="foo" id="testSpan">element</span>',
+                       Xml::span( 'element', 'foo', [ 'id' => 'testSpan' ] )
+               );
+       }
+
        /**
         * @covers Xml::dateMenu
         */
@@ -533,4 +584,34 @@ class XmlTest extends MediaWikiTestCase {
                        'Entire element with legend and attributes'
                );
        }
+
+       /**
+        * @covers Xml::buildTable
+        */
+       public function testBuildTable() {
+               $firstRow = [ 'foo', 'bar' ];
+               $secondRow = [ 'Berlin', 'Tehran' ];
+               $headers = [ 'header1', 'header2' ];
+               $expected = '<table id="testTable"><thead id="testTable"><th>header1</th>' .
+                       '<th>header2</th></thead><tr><td>foo</td><td>bar</td></tr><tr><td>Berlin</td>' .
+                       '<td>Tehran</td></tr></table>';
+               $this->assertEquals(
+                       $expected,
+                       Xml::buildTable(
+                               [ $firstRow, $secondRow ],
+                               [ 'id' => 'testTable' ],
+                               $headers
+                       )
+               );
+       }
+
+       /**
+        * @covers Xml::buildTableRow
+        */
+       public function testBuildTableRow() {
+               $this->assertEquals(
+                       '<tr id="testRow"><td>foo</td><td>bar</td></tr>',
+                       Xml::buildTableRow( [ 'id' => 'testRow' ], [ 'foo', 'bar' ] )
+               );
+       }
 }
index ee0ad94..575f0c9 100644 (file)
@@ -51,6 +51,7 @@ class ApiBaseTest extends ApiTestCase {
         * @param array $paramSettings
         * @param mixed $expected
         * @param string[] $warnings
+        * @covers ApiBase::getParameterFromSettings
         */
        public function testGetParameterFromSettings( $input, $paramSettings, $expected, $warnings ) {
                $mock = new MockApi();
@@ -126,6 +127,9 @@ class ApiBaseTest extends ApiTestCase {
                ];
        }
 
+       /**
+        * @covers ApiBase::errorArrayToStatus
+        */
        public function testErrorArrayToStatus() {
                $mock = new MockApi();
 
diff --git a/tests/phpunit/includes/api/ApiCheckTokenTest.php b/tests/phpunit/includes/api/ApiCheckTokenTest.php
new file mode 100644 (file)
index 0000000..f1d95d0
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+
+use MediaWiki\Session\Token;
+
+/**
+ * @group API
+ * @group medium
+ * @covers ApiCheckToken
+ */
+class ApiCheckTokenTest extends ApiTestCase {
+
+       /**
+        * Test result of checking previously queried token (should be valid)
+        */
+       public function testCheckTokenValid() {
+               // Query token which will be checked later
+               $tokens = $this->doApiRequest( [
+                       'action' => 'query',
+                       'meta' => 'tokens',
+               ] );
+
+               $data = $this->doApiRequest( [
+                       'action' => 'checktoken',
+                       'type' => 'csrf',
+                       'token' => $tokens[0]['query']['tokens']['csrftoken'],
+               ], $tokens[1]->getSessionArray() );
+
+               $this->assertEquals( 'valid', $data[0]['checktoken']['result'] );
+               $this->assertArrayHasKey( 'generated', $data[0]['checktoken'] );
+       }
+
+       /**
+        * Test result of checking invalid token
+        */
+       public function testCheckTokenInvalid() {
+               $session = [];
+               $data = $this->doApiRequest( [
+                       'action' => 'checktoken',
+                       'type' => 'csrf',
+                       'token' => 'invalid_token',
+               ], $session );
+
+               $this->assertEquals( 'invalid', $data[0]['checktoken']['result'] );
+       }
+
+       /**
+        * Test result of checking token with negative max age (should be expired)
+        */
+       public function testCheckTokenExpired() {
+               // Query token which will be checked later
+               $tokens = $this->doApiRequest( [
+                       'action' => 'query',
+                       'meta' => 'tokens',
+               ] );
+
+               $data = $this->doApiRequest( [
+                       'action' => 'checktoken',
+                       'type' => 'csrf',
+                       'token' => $tokens[0]['query']['tokens']['csrftoken'],
+                       'maxtokenage' => -1,
+               ], $tokens[1]->getSessionArray() );
+
+               $this->assertEquals( 'expired', $data[0]['checktoken']['result'] );
+               $this->assertArrayHasKey( 'generated', $data[0]['checktoken'] );
+       }
+
+       /**
+        * Test if using token with incorrect suffix will produce a warning
+        */
+       public function testCheckTokenSuffixWarning() {
+               // Query token which will be checked later
+               $tokens = $this->doApiRequest( [
+                       'action' => 'query',
+                       'meta' => 'tokens',
+               ] );
+
+               // Get token and change the suffix
+               $token = $tokens[0]['query']['tokens']['csrftoken'];
+               $token = substr( $token, 0, -strlen( Token::SUFFIX ) ) . urldecode( Token::SUFFIX );
+
+               $data = $this->doApiRequest( [
+                       'action' => 'checktoken',
+                       'type' => 'csrf',
+                       'token' => $token,
+                       'errorformat' => 'raw',
+               ], $tokens[1]->getSessionArray() );
+
+               $this->assertEquals( 'invalid', $data[0]['checktoken']['result'] );
+               $this->assertArrayHasKey( 'warnings', $data[0] );
+               $this->assertCount( 1, $data[0]['warnings'] );
+               $this->assertEquals( 'checktoken', $data[0]['warnings'][0]['module'] );
+               $this->assertEquals( 'checktoken-percentencoding', $data[0]['warnings'][0]['code'] );
+       }
+
+}
diff --git a/tests/phpunit/includes/api/ApiClearHasMsgTest.php b/tests/phpunit/includes/api/ApiClearHasMsgTest.php
new file mode 100644 (file)
index 0000000..b7d3205
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @group API
+ * @group medium
+ * @covers ApiClearHasMsg
+ */
+class ApiClearHasMsgTest extends ApiTestCase {
+
+       /**
+        * Test clearing hasmsg flag for current user
+        */
+       public function testClearFlag() {
+               $user = self::$users['sysop']->getUser();
+               $user->setNewtalk( true );
+               $this->assertTrue( $user->getNewtalk() );
+
+               $data = $this->doApiRequest( [ 'action' => 'clearhasmsg' ], [] );
+
+               $this->assertEquals( 'success', $data[0]['clearhasmsg'] );
+               $this->assertFalse( $user->getNewtalk() );
+       }
+
+}
index 989d6bb..155a08e 100644 (file)
@@ -29,7 +29,7 @@ class ApiComparePagesTest extends ApiTestCase {
                $status = $page->doEditContent(
                        $content, 'Test for ApiComparePagesTest: ' . $text, 0, false, $user
                );
-               if ( !$status->isOk() ) {
+               if ( !$status->isOK() ) {
                        $this->fail( "Failed to create $title: " . $status->getWikiText( false, false, 'en' ) );
                }
                return $status->value['revision']->getId();
@@ -151,8 +151,8 @@ class ApiComparePagesTest extends ApiTestCase {
        }
 
        public static function provideDiff() {
+               // phpcs:disable Generic.Files.LineLength.TooLong
                return [
-                       // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
                        'Basic diff, titles' => [
                                [
                                        'fromtitle' => 'ApiComparePagesTest A',
@@ -604,8 +604,7 @@ class ApiComparePagesTest extends ApiTestCase {
                                [],
                                'missingcontent'
                        ],
-
-                       // @codingStandardsIgnoreEnd
                ];
+               // phpcs:enable
        }
 }
index 23fa7bc..cc993d5 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers ApiOpenSearch
+ */
 class ApiOpenSearchTest extends MediaWikiTestCase {
        public function testGetAllowedParams() {
                $config = $this->replaceSearchEngineConfig();
index 1aa0a13..10bdfa7 100644 (file)
@@ -4,6 +4,7 @@
  * @group API
  * @group medium
  * @group Database
+ * @covers ApiPageSet
  */
 class ApiPageSetTest extends ApiTestCase {
        public static function provideRedirectMergePolicy() {
index 07bf299..e236437 100644 (file)
@@ -21,7 +21,7 @@ class ApiParseTest extends ApiTestCase {
                        ContentHandler::makeContent( 'Test for revdel', $title, CONTENT_MODEL_WIKITEXT ),
                        __METHOD__ . ' Test for revdel', 0, false, $user
                );
-               if ( !$status->isOk() ) {
+               if ( !$status->isOK() ) {
                        $this->fail( "Failed to create $title: " . $status->getWikiText( false, false, 'en' ) );
                }
                self::$pageId = $status->value['revision']->getPage();
@@ -31,7 +31,7 @@ class ApiParseTest extends ApiTestCase {
                        ContentHandler::makeContent( 'Test for oldid', $title, CONTENT_MODEL_WIKITEXT ),
                        __METHOD__ . ' Test for oldid', 0, false, $user
                );
-               if ( !$status->isOk() ) {
+               if ( !$status->isOK() ) {
                        $this->fail( "Failed to edit $title: " . $status->getWikiText( false, false, 'en' ) );
                }
                self::$revIds['oldid'] = $status->value['revision']->getId();
@@ -40,7 +40,7 @@ class ApiParseTest extends ApiTestCase {
                        ContentHandler::makeContent( 'Test for latest', $title, CONTENT_MODEL_WIKITEXT ),
                        __METHOD__ . ' Test for latest', 0, false, $user
                );
-               if ( !$status->isOk() ) {
+               if ( !$status->isOK() ) {
                        $this->fail( "Failed to edit $title: " . $status->getWikiText( false, false, 'en' ) );
                }
                self::$revIds['latest'] = $status->value['revision']->getId();
index 9f28aaf..b482c31 100644 (file)
@@ -4,6 +4,8 @@
  * @group API
  * @group Database
  * @group medium
+ *
+ * @covers ApiQueryAllPages
  */
 class ApiQueryAllPagesTest extends ApiTestCase {
 
diff --git a/tests/phpunit/includes/api/ApiQueryRecentChangesIntegrationTest.php b/tests/phpunit/includes/api/ApiQueryRecentChangesIntegrationTest.php
new file mode 100644 (file)
index 0000000..19f66fa
--- /dev/null
@@ -0,0 +1,973 @@
+<?php
+
+use MediaWiki\Linker\LinkTarget;
+use MediaWiki\MediaWikiServices;
+
+/**
+ * @group API
+ * @group Database
+ * @group medium
+ *
+ * @covers ApiQueryRecentChanges
+ */
+class ApiQueryRecentChangesIntegrationTest extends ApiTestCase {
+
+       public function __construct( $name = null, array $data = [], $dataName = '' ) {
+               parent::__construct( $name, $data, $dataName );
+
+               $this->tablesUsed[] = 'recentchanges';
+               $this->tablesUsed[] = 'page';
+       }
+
+       protected function setUp() {
+               parent::setUp();
+
+               self::$users['ApiQueryRecentChangesIntegrationTestUser'] = $this->getMutableTestUser();
+               $this->doLogin( 'ApiQueryRecentChangesIntegrationTestUser' );
+               wfGetDB( DB_MASTER )->delete( 'recentchanges', '*', __METHOD__ );
+       }
+
+       private function getLoggedInTestUser() {
+               return self::$users['ApiQueryRecentChangesIntegrationTestUser']->getUser();
+       }
+
+       private function doPageEdit( User $user, LinkTarget $target, $summary ) {
+               static $i = 0;
+
+               $title = Title::newFromLinkTarget( $target );
+               $page = WikiPage::factory( $title );
+               $page->doEditContent(
+                       ContentHandler::makeContent( __CLASS__ . $i++, $title ),
+                       $summary,
+                       0,
+                       false,
+                       $user
+               );
+       }
+
+       private function doMinorPageEdit( User $user, LinkTarget $target, $summary ) {
+               $title = Title::newFromLinkTarget( $target );
+               $page = WikiPage::factory( $title );
+               $page->doEditContent(
+                       ContentHandler::makeContent( __CLASS__, $title ),
+                       $summary,
+                       EDIT_MINOR,
+                       false,
+                       $user
+               );
+       }
+
+       private function doBotPageEdit( User $user, LinkTarget $target, $summary ) {
+               $title = Title::newFromLinkTarget( $target );
+               $page = WikiPage::factory( $title );
+               $page->doEditContent(
+                       ContentHandler::makeContent( __CLASS__, $title ),
+                       $summary,
+                       EDIT_FORCE_BOT,
+                       false,
+                       $user
+               );
+       }
+
+       private function doAnonPageEdit( LinkTarget $target, $summary ) {
+               $title = Title::newFromLinkTarget( $target );
+               $page = WikiPage::factory( $title );
+               $page->doEditContent(
+                       ContentHandler::makeContent( __CLASS__, $title ),
+                       $summary,
+                       0,
+                       false,
+                       User::newFromId( 0 )
+               );
+       }
+
+       private function deletePage( LinkTarget $target, $reason ) {
+               $title = Title::newFromLinkTarget( $target );
+               $page = WikiPage::factory( $title );
+               $page->doDeleteArticleReal( $reason );
+       }
+
+       /**
+        * Performs a batch of page edits as a specified user
+        * @param User $user
+        * @param array $editData associative array, keys:
+        *                        - target    => LinkTarget page to edit
+        *                        - summary   => string edit summary
+        *                        - minorEdit => bool mark as minor edit if true (defaults to false)
+        *                        - botEdit   => bool mark as bot edit if true (defaults to false)
+        */
+       private function doPageEdits( User $user, array $editData ) {
+               foreach ( $editData as $singleEditData ) {
+                       if ( array_key_exists( 'minorEdit', $singleEditData ) && $singleEditData['minorEdit'] ) {
+                               $this->doMinorPageEdit(
+                                       $user,
+                                       $singleEditData['target'],
+                                       $singleEditData['summary']
+                               );
+                               continue;
+                       }
+                       if ( array_key_exists( 'botEdit', $singleEditData ) && $singleEditData['botEdit'] ) {
+                               $this->doBotPageEdit(
+                                       $user,
+                                       $singleEditData['target'],
+                                       $singleEditData['summary']
+                               );
+                               continue;
+                       }
+                       $this->doPageEdit(
+                               $user,
+                               $singleEditData['target'],
+                               $singleEditData['summary']
+                       );
+               }
+       }
+
+       private function doListRecentChangesRequest( array $params = [] ) {
+               return $this->doApiRequest(
+                       array_merge(
+                               [ 'action' => 'query', 'list' => 'recentchanges' ],
+                               $params
+                       ),
+                       null,
+                       false
+               );
+       }
+
+       private function doGeneratorRecentChangesRequest( array $params = [] ) {
+               return $this->doApiRequest(
+                       array_merge(
+                               [ 'action' => 'query', 'generator' => 'recentchanges' ],
+                               $params
+                       )
+               );
+       }
+
+       private function getItemsFromApiResponse( array $response ) {
+               return $response[0]['query']['recentchanges'];
+       }
+
+       private function getTitleFormatter() {
+               return new MediaWikiTitleCodec(
+                       Language::factory( 'en' ),
+                       MediaWikiServices::getInstance()->getGenderCache()
+               );
+       }
+
+       private function getPrefixedText( LinkTarget $target ) {
+               $formatter = $this->getTitleFormatter();
+               return $formatter->getPrefixedText( $target );
+       }
+
+       public function testListRecentChanges_returnsRCInfo() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
+
+               $result = $this->doListRecentChangesRequest();
+
+               $this->assertArrayHasKey( 'query', $result[0] );
+               $this->assertArrayHasKey( 'recentchanges', $result[0]['query'] );
+
+               $items = $this->getItemsFromApiResponse( $result );
+               $this->assertCount( 1, $items );
+               $item = $items[0];
+               $this->assertArraySubset(
+                       [
+                               'type' => 'new',
+                               'ns' => $target->getNamespace(),
+                               'title' => $this->getPrefixedText( $target ),
+                       ],
+                       $item
+               );
+               $this->assertArrayNotHasKey( 'bot', $item );
+               $this->assertArrayNotHasKey( 'new', $item );
+               $this->assertArrayNotHasKey( 'minor', $item );
+               $this->assertArrayHasKey( 'pageid', $item );
+               $this->assertArrayHasKey( 'revid', $item );
+               $this->assertArrayHasKey( 'old_revid', $item );
+       }
+
+       public function testIdsPropParameter() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'ids', ] );
+               $items = $this->getItemsFromApiResponse( $result );
+
+               $this->assertCount( 1, $items );
+               $this->assertArrayHasKey( 'pageid', $items[0] );
+               $this->assertArrayHasKey( 'revid', $items[0] );
+               $this->assertArrayHasKey( 'old_revid', $items[0] );
+               $this->assertEquals( 'new', $items[0]['type'] );
+       }
+
+       public function testTitlePropParameter() {
+               $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdits(
+                       $this->getLoggedInTestUser(),
+                       [
+                               [
+                                       'target' => $subjectTarget,
+                                       'summary' => 'Create the page',
+                               ],
+                               [
+                                       'target' => $talkTarget,
+                                       'summary' => 'Create Talk page',
+                               ],
+                       ]
+               );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'ns' => $talkTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $talkTarget ),
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'ns' => $subjectTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $subjectTarget ),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       public function testFlagsPropParameter() {
+               $normalEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $minorEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPageM' );
+               $botEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPageB' );
+               $this->doPageEdits(
+                       $this->getLoggedInTestUser(),
+                       [
+                               [
+                                       'target' => $normalEditTarget,
+                                       'summary' => 'Create the page',
+                               ],
+                               [
+                                       'target' => $minorEditTarget,
+                                       'summary' => 'Create the page',
+                               ],
+                               [
+                                       'target' => $minorEditTarget,
+                                       'summary' => 'Change content',
+                                       'minorEdit' => true,
+                               ],
+                               [
+                                       'target' => $botEditTarget,
+                                       'summary' => 'Create the page with a bot',
+                                       'botEdit' => true,
+                               ],
+                       ]
+               );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'flags', ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'new' => true,
+                                       'minor' => false,
+                                       'bot' => true,
+                               ],
+                               [
+                                       'type' => 'edit',
+                                       'new' => false,
+                                       'minor' => true,
+                                       'bot' => false,
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'new' => true,
+                                       'minor' => false,
+                                       'bot' => false,
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'new' => true,
+                                       'minor' => false,
+                                       'bot' => false,
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       public function testUserPropParameter() {
+               $userEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $anonEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPageA' );
+               $this->doPageEdit( $this->getLoggedInTestUser(), $userEditTarget, 'Create the page' );
+               $this->doAnonPageEdit( $anonEditTarget, 'Create the page' );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'user', ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'anon' => true,
+                                       'user' => User::newFromId( 0 )->getName(),
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'user' => $this->getLoggedInTestUser()->getName(),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       public function testUserIdPropParameter() {
+               $user = $this->getLoggedInTestUser();
+               $userEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $anonEditTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPageA' );
+               $this->doPageEdit( $user, $userEditTarget, 'Create the page' );
+               $this->doAnonPageEdit( $anonEditTarget, 'Create the page' );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'userid', ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'anon' => true,
+                                       'userid' => 0,
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'userid' => $user->getId(),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       public function testCommentPropParameter() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the <b>page</b>' );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'comment', ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'comment' => 'Create the <b>page</b>',
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       public function testParsedCommentPropParameter() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the <b>page</b>' );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'parsedcomment', ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'parsedcomment' => 'Create the &lt;b&gt;page&lt;/b&gt;',
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       public function testTimestampPropParameter() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'timestamp', ] );
+               $items = $this->getItemsFromApiResponse( $result );
+
+               $this->assertCount( 1, $items );
+               $this->assertArrayHasKey( 'timestamp', $items[0] );
+               $this->assertInternalType( 'string', $items[0]['timestamp'] );
+       }
+
+       public function testSizesPropParameter() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'sizes', ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'oldlen' => 0,
+                                       'newlen' => 38,
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       private function createPageAndDeleteIt( LinkTarget $target ) {
+               $this->doPageEdit( $this->getLoggedInTestUser(),
+                       $target,
+                       'Create the page that will be deleted'
+               );
+               $this->deletePage( $target, 'Important Reason' );
+       }
+
+       public function testLoginfoPropParameter() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->createPageAndDeleteIt( $target );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'loginfo', ] );
+
+               $items = $this->getItemsFromApiResponse( $result );
+               $this->assertCount( 1, $items );
+               $this->assertArraySubset(
+                       [
+                               'type' => 'log',
+                               'logtype' => 'delete',
+                               'logaction' => 'delete',
+                               'logparams' => [],
+                       ],
+                       $items[0]
+               );
+               $this->assertArrayHasKey( 'logid', $items[0] );
+       }
+
+       public function testEmptyPropParameter() {
+               $user = $this->getLoggedInTestUser();
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdit( $user, $target, 'Create the page' );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => '', ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                               ]
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       public function testNamespaceParam() {
+               $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdits(
+                       $this->getLoggedInTestUser(),
+                       [
+                               [
+                                       'target' => $subjectTarget,
+                                       'summary' => 'Create the page',
+                               ],
+                               [
+                                       'target' => $talkTarget,
+                                       'summary' => 'Create the talk page',
+                               ],
+                       ]
+               );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcnamespace' => '0', ] );
+
+               $items = $this->getItemsFromApiResponse( $result );
+               $this->assertCount( 1, $items );
+               $this->assertArraySubset(
+                       [
+                               'ns' => 0,
+                               'title' => $this->getPrefixedText( $subjectTarget ),
+                       ],
+                       $items[0]
+               );
+       }
+
+       public function testShowAnonParams() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doAnonPageEdit( $target, 'Create the page' );
+
+               $resultAnon = $this->doListRecentChangesRequest( [
+                       'rcprop' => 'user',
+                       'rcshow' => WatchedItemQueryService::FILTER_ANON
+               ] );
+               $resultNotAnon = $this->doListRecentChangesRequest( [
+                       'rcprop' => 'user',
+                       'rcshow' => WatchedItemQueryService::FILTER_NOT_ANON
+               ] );
+
+               $items = $this->getItemsFromApiResponse( $resultAnon );
+               $this->assertCount( 1, $items );
+               $this->assertArraySubset( [ 'anon' => true ], $items[0] );
+               $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotAnon ) );
+       }
+
+       public function testNewAndEditTypeParameters() {
+               $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdits(
+                       $this->getLoggedInTestUser(),
+                       [
+                               [
+                                       'target' => $subjectTarget,
+                                       'summary' => 'Create the page',
+                               ],
+                               [
+                                       'target' => $subjectTarget,
+                                       'summary' => 'Change the content',
+                               ],
+                               [
+                                       'target' => $talkTarget,
+                                       'summary' => 'Create Talk page',
+                               ],
+                       ]
+               );
+
+               $resultNew = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rctype' => 'new' ] );
+               $resultEdit = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rctype' => 'edit' ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'ns' => $talkTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $talkTarget ),
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'ns' => $subjectTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $subjectTarget ),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $resultNew )
+               );
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'edit',
+                                       'ns' => $subjectTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $subjectTarget ),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $resultEdit )
+               );
+       }
+
+       public function testLogTypeParameters() {
+               $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->createPageAndDeleteIt( $subjectTarget );
+               $this->doPageEdit( $this->getLoggedInTestUser(), $talkTarget, 'Create Talk page' );
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rctype' => 'log' ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'log',
+                                       'ns' => $subjectTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $subjectTarget ),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       private function getExternalRC( LinkTarget $target ) {
+               $title = Title::newFromLinkTarget( $target );
+
+               $rc = new RecentChange;
+               $rc->mTitle = $title;
+               $rc->mAttribs = [
+                       'rc_timestamp' => wfTimestamp( TS_MW ),
+                       'rc_namespace' => $title->getNamespace(),
+                       'rc_title' => $title->getDBkey(),
+                       'rc_type' => RC_EXTERNAL,
+                       'rc_source' => 'foo',
+                       'rc_minor' => 0,
+                       'rc_cur_id' => $title->getArticleID(),
+                       'rc_user' => 0,
+                       'rc_user_text' => 'External User',
+                       'rc_comment' => '',
+                       'rc_comment_text' => '',
+                       'rc_comment_data' => null,
+                       'rc_this_oldid' => $title->getLatestRevID(),
+                       'rc_last_oldid' => $title->getLatestRevID(),
+                       'rc_bot' => 0,
+                       'rc_ip' => '',
+                       'rc_patrolled' => 0,
+                       'rc_new' => 0,
+                       'rc_old_len' => $title->getLength(),
+                       'rc_new_len' => $title->getLength(),
+                       'rc_deleted' => 0,
+                       'rc_logid' => 0,
+                       'rc_log_type' => null,
+                       'rc_log_action' => '',
+                       'rc_params' => '',
+               ];
+               $rc->mExtra = [
+                       'prefixedDBkey' => $title->getPrefixedDBkey(),
+                       'lastTimestamp' => 0,
+                       'oldSize' => $title->getLength(),
+                       'newSize' => $title->getLength(),
+                       'pageStatus' => 'changed'
+               ];
+
+               return $rc;
+       }
+
+       public function testExternalTypeParameters() {
+               $user = $this->getLoggedInTestUser();
+               $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdit( $user, $subjectTarget, 'Create the page' );
+               $this->doPageEdit( $user, $talkTarget, 'Create Talk page' );
+
+               $rc = $this->getExternalRC( $subjectTarget );
+               $rc->save();
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rctype' => 'external' ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'external',
+                                       'ns' => $subjectTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $subjectTarget ),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       public function testCategorizeTypeParameter() {
+               $user = $this->getLoggedInTestUser();
+               $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $categoryTarget = new TitleValue( NS_CATEGORY, 'ApiQueryRecentChangesIntegrationTestCategory' );
+               $this->doPageEdits(
+                       $user,
+                       [
+                               [
+                                       'target' => $categoryTarget,
+                                       'summary' => 'Create the category',
+                               ],
+                               [
+                                       'target' => $subjectTarget,
+                                       'summary' => 'Create the page and add it to the category',
+                               ],
+                       ]
+               );
+               $title = Title::newFromLinkTarget( $subjectTarget );
+               $revision = Revision::newFromTitle( $title );
+
+               $rc = RecentChange::newForCategorization(
+                       $revision->getTimestamp(),
+                       Title::newFromLinkTarget( $categoryTarget ),
+                       $user,
+                       $revision->getComment(),
+                       $title,
+                       0,
+                       $revision->getId(),
+                       null,
+                       false
+               );
+               $rc->save();
+
+               $result = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rctype' => 'categorize' ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'categorize',
+                                       'ns' => $categoryTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $categoryTarget ),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $result )
+               );
+       }
+
+       public function testLimitParam() {
+               $target1 = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $target2 = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $target3 = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage2' );
+               $this->doPageEdits(
+                       $this->getLoggedInTestUser(),
+                       [
+                               [
+                                       'target' => $target1,
+                                       'summary' => 'Create the page',
+                               ],
+                               [
+                                       'target' => $target2,
+                                       'summary' => 'Create Talk page',
+                               ],
+                               [
+                                       'target' => $target3,
+                                       'summary' => 'Create the page',
+                               ],
+                       ]
+               );
+
+               $resultWithoutLimit = $this->doListRecentChangesRequest( [ 'rcprop' => 'title' ] );
+               $resultWithLimit = $this->doListRecentChangesRequest( [ 'rclimit' => 2, 'rcprop' => 'title' ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target3->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target3 )
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target2->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target2 )
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target1->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target1 )
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $resultWithoutLimit )
+               );
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target3->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target3 )
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target2->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target2 )
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $resultWithLimit )
+               );
+               $this->assertArrayHasKey( 'continue', $resultWithLimit[0] );
+               $this->assertArrayHasKey( 'rccontinue', $resultWithLimit[0]['continue'] );
+       }
+
+       public function testAllRevParam() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdits(
+                       $this->getLoggedInTestUser(),
+                       [
+                               [
+                                       'target' => $target,
+                                       'summary' => 'Create the page',
+                               ],
+                               [
+                                       'target' => $target,
+                                       'summary' => 'Change the content',
+                               ],
+                       ]
+               );
+
+               $resultAllRev = $this->doListRecentChangesRequest( [ 'rcprop' => 'title', 'rcallrev' => '', ] );
+               $resultNoAllRev = $this->doListRecentChangesRequest( [ 'rcprop' => 'title' ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'edit',
+                                       'ns' => $target->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target ),
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target ),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $resultNoAllRev )
+               );
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'edit',
+                                       'ns' => $target->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target ),
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target ),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $resultAllRev )
+               );
+       }
+
+       public function testDirParams() {
+               $subjectTarget = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $talkTarget = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdits(
+                       $this->getLoggedInTestUser(),
+                       [
+                               [
+                                       'target' => $subjectTarget,
+                                       'summary' => 'Create the page',
+                               ],
+                               [
+                                       'target' => $talkTarget,
+                                       'summary' => 'Create Talk page',
+                               ],
+                       ]
+               );
+
+               $resultDirOlder = $this->doListRecentChangesRequest(
+                       [ 'rcdir' => 'older', 'rcprop' => 'title' ]
+               );
+               $resultDirNewer = $this->doListRecentChangesRequest(
+                       [ 'rcdir' => 'newer', 'rcprop' => 'title' ]
+               );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'ns' => $talkTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $talkTarget )
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'ns' => $subjectTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $subjectTarget )
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $resultDirOlder )
+               );
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'ns' => $subjectTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $subjectTarget )
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'ns' => $talkTarget->getNamespace(),
+                                       'title' => $this->getPrefixedText( $talkTarget )
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $resultDirNewer )
+               );
+       }
+
+       public function testStartEndParams() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
+
+               $resultStart = $this->doListRecentChangesRequest( [
+                       'rcstart' => '20010115000000',
+                       'rcdir' => 'newer',
+                       'rcprop' => 'title',
+               ] );
+               $resultEnd = $this->doListRecentChangesRequest( [
+                       'rcend' => '20010115000000',
+                       'rcdir' => 'newer',
+                       'rcprop' => 'title',
+               ] );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target ),
+                               ]
+                       ],
+                       $this->getItemsFromApiResponse( $resultStart )
+               );
+               $this->assertEmpty( $this->getItemsFromApiResponse( $resultEnd ) );
+       }
+
+       public function testContinueParam() {
+               $target1 = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $target2 = new TitleValue( 1, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $target3 = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage2' );
+               $this->doPageEdits(
+                       $this->getLoggedInTestUser(),
+                       [
+                               [
+                                       'target' => $target1,
+                                       'summary' => 'Create the page',
+                               ],
+                               [
+                                       'target' => $target2,
+                                       'summary' => 'Create Talk page',
+                               ],
+                               [
+                                       'target' => $target3,
+                                       'summary' => 'Create the page',
+                               ],
+                       ]
+               );
+
+               $firstResult = $this->doListRecentChangesRequest( [ 'rclimit' => 2, 'rcprop' => 'title' ] );
+               $this->assertArrayHasKey( 'continue', $firstResult[0] );
+               $this->assertArrayHasKey( 'rccontinue', $firstResult[0]['continue'] );
+
+               $continuationParam = $firstResult[0]['continue']['rccontinue'];
+
+               $continuedResult = $this->doListRecentChangesRequest(
+                       [ 'rccontinue' => $continuationParam, 'rcprop' => 'title' ]
+               );
+
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target3->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target3 ),
+                               ],
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target2->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target2 ),
+                               ],
+                       ],
+                       $this->getItemsFromApiResponse( $firstResult )
+               );
+               $this->assertEquals(
+                       [
+                               [
+                                       'type' => 'new',
+                                       'ns' => $target1->getNamespace(),
+                                       'title' => $this->getPrefixedText( $target1 )
+                               ]
+                       ],
+                       $this->getItemsFromApiResponse( $continuedResult )
+               );
+       }
+
+       public function testGeneratorRecentChangesPropInfo_returnsRCPages() {
+               $target = new TitleValue( 0, 'ApiQueryRecentChangesIntegrationTestPage' );
+               $this->doPageEdit( $this->getLoggedInTestUser(), $target, 'Create the page' );
+
+               $result = $this->doGeneratorRecentChangesRequest( [ 'prop' => 'info' ] );
+
+               $this->assertArrayHasKey( 'query', $result[0] );
+               $this->assertArrayHasKey( 'pages', $result[0]['query'] );
+
+               // $result[0]['query']['pages'] uses page ids as keys. Page ids don't matter here, so drop them
+               $pages = array_values( $result[0]['query']['pages'] );
+
+               $this->assertCount( 1, $pages );
+               $this->assertArraySubset(
+                       [
+                               'ns' => $target->getNamespace(),
+                               'title' => $this->getPrefixedText( $target ),
+                               'new' => true,
+                       ],
+                       $pages[0]
+               );
+       }
+
+}
index abef1c9..f1ff947 100644 (file)
@@ -218,6 +218,9 @@ abstract class ApiTestCase extends MediaWikiLangTestCase {
                );
        }
 
+       /**
+        * @coversNothing
+        */
        public function testApiTestGroup() {
                $groups = PHPUnit_Util_Test::getGroups( static::class );
                $constraint = PHPUnit_Framework_Assert::logicalOr(
index 159a0e3..6b60409 100644 (file)
@@ -19,6 +19,8 @@
  * @group Database
  * @group medium
  * @group Broken
+ *
+ * @covers ApiUpload
  */
 class ApiUploadTest extends ApiTestCaseUpload {
        /**
index f901cf2..bb72021 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers ApiUsageException
+ */
 class ApiUsageExceptionTest extends MediaWikiTestCase {
 
        public function testCreateWithStatusValue_CanGetAMessageObject() {
index 7b91094..b663dc7 100644 (file)
@@ -5,6 +5,8 @@
  * @group Database
  * @group medium
  * @todo This test suite is severly broken and need a full review
+ *
+ * @covers ApiWatch
  */
 class ApiWatchTest extends ApiTestCase {
        protected function setUp() {
index 3aa1db3..2d2e29b 100644 (file)
@@ -20,7 +20,7 @@ class ApiFormatPhpTest extends ApiFormatTestBase {
        }
 
        public static function provideGeneralEncoding() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return array_merge(
                        self::addFormatVersion( 1, [
                                // Basic types
@@ -97,7 +97,7 @@ class ApiFormatPhpTest extends ApiFormatTestBase {
                                        'a:1:{s:3:"foo";s:3:"foo";}' ],
                        ] )
                );
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        public function testCrossDomainMangling() {
index 0f8c8ee..915fb5c 100644 (file)
@@ -12,11 +12,11 @@ class ApiFormatXmlTest extends ApiFormatTestBase {
        public static function setUpBeforeClass() {
                parent::setUpBeforeClass();
                $page = WikiPage::factory( Title::newFromText( 'MediaWiki:ApiFormatXmlTest.xsl' ) );
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                $page->doEditContent( new WikitextContent(
                        '<?xml version="1.0"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" />'
                ), 'Summary' );
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
                $page = WikiPage::factory( Title::newFromText( 'MediaWiki:ApiFormatXmlTest' ) );
                $page->doEditContent( new WikitextContent( 'Bogus' ), 'Summary' );
                $page = WikiPage::factory( Title::newFromText( 'ApiFormatXmlTest' ) );
@@ -24,7 +24,7 @@ class ApiFormatXmlTest extends ApiFormatTestBase {
        }
 
        public static function provideGeneralEncoding() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        // Basic types
                        [ [ null, 'a' => null ], '<?xml version="1.0"?><api><_v _idx="0" /></api>' ],
@@ -117,7 +117,7 @@ class ApiFormatXmlTest extends ApiFormatTestBase {
                                        '" type="text/xsl" ?><api />',
                                [ 'xslt' => 'MediaWiki:ApiFormatXmlTest.xsl' ] ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
 }
index 465a9d1..6190516 100644 (file)
@@ -4,12 +4,12 @@
  * @covers ChangesListFilterGroup
  */
 class ChangesListFilterGroupTest extends MediaWikiTestCase {
-       // @codingStandardsIgnoreStart
        /**
+        * phpcs:disable Generic.Files.LineLength
         * @expectedException MWException
         * @expectedExceptionMessage Group names may not contain '_'.  Use the naming convention: 'camelCase'
+        * phpcs:enable
         */
-       // @codingStandardsIgnoreEnd
        public function testReservedCharacter() {
                new MockChangesListFilterGroup(
                        [
index 811c8c2..039658e 100644 (file)
@@ -25,12 +25,12 @@ class ChangesListFilterTest extends MediaWikiTestCase {
                );
        }
 
-       // @codingStandardsIgnoreStart
        /**
+        * phpcs:disable Generic.Files.LineLength
         * @expectedException MWException
         * @expectedExceptionMessage Filter names may not contain '_'.  Use the naming convention: 'lowercase'
+        * phpcs:enable
         */
-       // @codingStandardsIgnoreEnd
        public function testReservedCharacter() {
                $filter = new MockChangesListFilter(
                        [
@@ -41,12 +41,10 @@ class ChangesListFilterTest extends MediaWikiTestCase {
                );
        }
 
-       // @codingStandardsIgnoreStart
        /**
         * @expectedException MWException
         * @expectedExceptionMessage Two filters in a group cannot have the same name: 'somename'
         */
-       // @codingStandardsIgnoreEnd
        public function testDuplicateName() {
                new MockChangesListFilter(
                        [
index 53a4f7b..f745541 100644 (file)
@@ -1,4 +1,8 @@
 <?php
+
+/**
+ * @covers CollationFa
+ */
 class CollationFaTest extends MediaWikiTestCase {
 
        /*
@@ -9,9 +13,7 @@ class CollationFaTest extends MediaWikiTestCase {
 
        public function setUp() {
                parent::setUp();
-               if ( !extension_loaded( 'intl' ) ) {
-                       $this->markTestSkipped( "PHP extension 'intl' is not loaded, skipping." );
-               }
+               $this->checkPHPExtension( 'intl' );
        }
 
        /**
index 5d5317b..d688928 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers CustomUppercaseCollation
+ */
 class CustomUppercaseCollationTest extends MediaWikiTestCase {
 
        public function setUp() {
index 8a2ebaf..a4cc446 100644 (file)
@@ -9,6 +9,8 @@
  */
 class ComposerVersionNormalizerTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @dataProvider nonStringProvider
         */
index 3e70a07..7a4d9d9 100644 (file)
@@ -4,6 +4,8 @@ use Wikimedia\TestingAccessWrapper;
 
 class EtcdConfigTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        private function createConfigMock( array $options = [] ) {
                return $this->getMockBuilder( EtcdConfig::class )
                        ->setConstructorArgs( [ $options + [
index 1bd2eb0..1462c36 100644 (file)
@@ -332,7 +332,9 @@ class ContentHandlerTest extends MediaWikiTestCase {
                }
        }
 
-       /*
+       /**
+        * @covers ContentHandler::getAutosummary
+        *
         * Test if we become a "Created blank page" summary from getAutoSummary if no Content added to
         * page.
         */
@@ -374,11 +376,17 @@ class ContentHandlerTest extends MediaWikiTestCase {
        }
        */
 
+       /**
+        * @covers ContentHandler::supportsCategories
+        */
        public function testSupportsCategories() {
                $handler = new DummyContentHandlerForTesting( CONTENT_MODEL_WIKITEXT );
                $this->assertTrue( $handler->supportsCategories(), 'content model supports categories' );
        }
 
+       /**
+        * @covers ContentHandler::supportsDirectEditing
+        */
        public function testSupportsDirectEditing() {
                $handler = new DummyContentHandlerForTesting( CONTENT_MODEL_JSON );
                $this->assertFalse( $handler->supportsDirectEditing(), 'direct editing is not supported' );
@@ -407,6 +415,7 @@ class ContentHandlerTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers ContentHandler::getForModelID
         * @dataProvider provideGetModelForID
         */
        public function testGetModelForID( $modelId, $handlerClass ) {
@@ -415,6 +424,9 @@ class ContentHandlerTest extends MediaWikiTestCase {
                $this->assertInstanceOf( $handlerClass, $handler );
        }
 
+       /**
+        * @covers ContentHandler::getFieldsForSearchIndex
+        */
        public function testGetFieldsForSearchIndex() {
                $searchEngine = $this->newSearchEngine();
 
index d92fb8f..8f178de 100644 (file)
@@ -21,7 +21,7 @@ class CssContentHandlerTest extends MediaWikiLangTestCase {
         * Keep this in sync with CssContentTest::provideGetRedirectTarget()
         */
        public static function provideMakeRedirectContent() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [
                                'MediaWiki:MonoBook.css',
@@ -36,6 +36,6 @@ class CssContentHandlerTest extends MediaWikiLangTestCase {
                                "/* #REDIRECT */@import url(//example.org/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);"
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 }
index d2078d7..f5cc05e 100644 (file)
@@ -83,6 +83,7 @@ class CssContentTest extends JavaScriptContentTest {
        }
 
        /**
+        * @covers CssContent::getRedirectTarget
         * @dataProvider provideGetRedirectTarget
         */
        public function testGetRedirectTarget( $title, $text ) {
@@ -100,7 +101,7 @@ class CssContentTest extends JavaScriptContentTest {
         * Keep this in sync with CssContentHandlerTest::provideMakeRedirectContent()
         */
        public static function provideGetRedirectTarget() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                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);" ],
@@ -110,7 +111,7 @@ class CssContentTest extends JavaScriptContentTest {
                        # Wrong domain
                        [ null, "/* #REDIRECT */@import url(//example.com/w/index.php?title=Gadget:FooBaz.css&action=raw&ctype=text/css);" ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        public static function dataEquals() {
index 65efcc9..ad9d419 100644 (file)
@@ -2,6 +2,8 @@
 
 /**
  * @group ContentHandler
+ *
+ * @covers FileContentHandler
  */
 class FileContentHandlerTest extends MediaWikiLangTestCase {
        /**
index d229623..080ec96 100644 (file)
@@ -21,7 +21,7 @@ class JavaScriptContentHandlerTest extends MediaWikiLangTestCase {
         * Keep this in sync with JavaScriptContentTest::provideGetRedirectTarget()
         */
        public static function provideMakeRedirectContent() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [
                                'MediaWiki:MonoBook.js',
@@ -36,6 +36,6 @@ class JavaScriptContentHandlerTest extends MediaWikiLangTestCase {
                                '/* #REDIRECT */mw.loader.load("//example.org/w/index.php?title=Gadget:FooBaz.js\u0026action=raw\u0026ctype=text/javascript");'
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 }
index 1c746bc..6656fa4 100644 (file)
@@ -251,19 +251,18 @@ class JavaScriptContentTest extends TextContentTest {
        }
 
        public static function provideUpdateRedirect() {
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [
                                '#REDIRECT [[Someplace]]',
                                '#REDIRECT [[Someplace]]',
                        ],
-
-                       // @codingStandardsIgnoreStart Generic.Files.LineLength
                        [
                                '/* #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
                ];
+               // phpcs:enable
        }
 
        /**
@@ -294,6 +293,7 @@ class JavaScriptContentTest extends TextContentTest {
        }
 
        /**
+        * @covers JavaScriptContent::getRedirectTarget
         * @dataProvider provideGetRedirectTarget
         */
        public function testGetRedirectTarget( $title, $text ) {
@@ -312,7 +312,7 @@ class JavaScriptContentTest extends TextContentTest {
         * Keep this in sync with JavaScriptContentHandlerTest::provideMakeRedirectContent()
         */
        public static function provideGetRedirectTarget() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [
                                'MediaWiki:MonoBook.js',
@@ -337,6 +337,6 @@ class JavaScriptContentTest extends TextContentTest {
                                '/* #REDIRECT */mw.loader.load("//example.com/w/index.php?title=MediaWiki:OtherWiki.js\u0026action=raw\u0026ctype=text/javascript");'
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 }
index 7d9f74e..a85215b 100644 (file)
@@ -4,6 +4,9 @@
  * @group ContentHandler
  */
 class TextContentHandlerTest extends MediaWikiLangTestCase {
+       /**
+        * @covers TextContentHandler::supportsDirectEditing
+        */
        public function testSupportsDirectEditing() {
                $handler = new TextContentHandler();
                $this->assertTrue( $handler->supportsDirectEditing(), 'direct editing is supported' );
index 77cfb92..02f82f4 100644 (file)
@@ -115,6 +115,9 @@ class WikitextContentHandlerTest extends MediaWikiLangTestCase {
                $this->assertEquals( $supported, $this->handler->isSupportedFormat( $format ) );
        }
 
+       /**
+        * @covers WikitextContentHandler::supportsDirectEditing
+        */
        public function testSupportsDirectEditing() {
                $handler = new WikiTextContentHandler();
                $this->assertTrue( $handler->supportsDirectEditing(), 'direct editing is supported' );
@@ -349,6 +352,9 @@ class WikitextContentHandlerTest extends MediaWikiLangTestCase {
        }
        */
 
+       /**
+        * @covers WikitextContentHandler::getDataForSearchIndex
+        */
        public function testDataIndexFieldsFile() {
                $mockEngine = $this->createMock( 'SearchEngine' );
                $title = Title::newFromText( 'Somefile.jpg', NS_FILE );
index f1b54f6..1bdbe01 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers WikiTextStructure
+ */
 class WikitextStructureTest extends MediaWikiLangTestCase {
 
        private function getMockTitle() {
index deaa65a..f0a3606 100644 (file)
@@ -285,6 +285,9 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
                );
        }
 
+       /**
+        * @coversNothing
+        */
        public function testEntireSchema() {
                global $IP;
 
@@ -298,6 +301,7 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
        /**
         * Runs upgrades of older databases and compares results with current schema
         * @todo Currently only checks list of tables
+        * @coversNothing
         */
        public function testUpgrades() {
                global $IP, $wgVersion, $wgProfiler;
@@ -497,6 +501,9 @@ class DatabaseSqliteTest extends MediaWikiTestCase {
                $this->assertTrue( $db->close(), "closing database" );
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\DatabaseSqlite::__toString
+        */
        public function testToString() {
                $db = DatabaseSqlite::newStandaloneInstance( ':memory:' );
 
index 1efeeeb..75d5414 100644 (file)
@@ -1,10 +1,4 @@
 <?php
-
-use Wikimedia\Rdbms\LBFactorySimple;
-use Wikimedia\Rdbms\LBFactoryMulti;
-use Wikimedia\Rdbms\ChronologyProtector;
-use Wikimedia\Rdbms\MySQLMasterPos;
-
 /**
  * Holds tests for LBFactory abstract MediaWiki class.
  *
@@ -23,15 +17,26 @@ use Wikimedia\Rdbms\MySQLMasterPos;
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  * http://www.gnu.org/copyleft/gpl.html
  *
- * @group Database
  * @file
  * @author Antoine Musso
  * @copyright © 2013 Antoine Musso
  * @copyright © 2013 Wikimedia Foundation Inc.
  */
+
+use Wikimedia\Rdbms\LBFactorySimple;
+use Wikimedia\Rdbms\LBFactoryMulti;
+use Wikimedia\Rdbms\ChronologyProtector;
+use Wikimedia\Rdbms\MySQLMasterPos;
+
+/**
+ * @group Database
+ * @covers \Wikimedia\Rdbms\LBFactorySimple
+ * @covers \Wikimedia\Rdbms\LBFactoryMulti
+ */
 class LBFactoryTest extends MediaWikiTestCase {
 
        /**
+        * @covers MWLBFactory::getLBFactoryClass
         * @dataProvider getLBFactoryClassProvider
         */
        public function testGetLBFactoryClass( $expected, $deprecated ) {
@@ -182,6 +187,9 @@ class LBFactoryTest extends MediaWikiTestCase {
                $lb->closeAll();
        }
 
+       /**
+        * @covers \Wikimedia\Rdbms\ChronologyProtector
+        */
        public function testChronologyProtector() {
                // (a) First HTTP request
                $mPos = new MySQLMasterPos( 'db1034-bin.000976', '843431247' );
index a7b0975..5fd33dc 100644 (file)
@@ -24,6 +24,8 @@ use Wikimedia\Rdbms\LoadBalancer;
  *
  * @group Database
  * @file
+ *
+ * @covers \Wikimedia\Rdbms\LoadBalancer
  */
 class LoadBalancerTest extends MediaWikiTestCase {
        public function testWithoutReplica() {
@@ -144,9 +146,9 @@ class LoadBalancerTest extends MediaWikiTestCase {
                        $this->fail( 'Write operation should have failed!' );
                } catch ( DBError $ex ) {
                        // check that the exception message contains "Write operation"
-                       $constriant = new PHPUnit_Framework_Constraint_StringContains( 'Write operation' );
+                       $constraint = new PHPUnit_Framework_Constraint_StringContains( 'Write operation' );
 
-                       if ( !$constriant->evaluate( $ex->getMessage(), '', true ) ) {
+                       if ( !$constraint->evaluate( $ex->getMessage(), '', true ) ) {
                                // re-throw original error, to preserve stack trace
                                throw $ex;
                        }
index 938397a..915a186 100644 (file)
@@ -23,6 +23,9 @@ namespace MediaWiki\Logger\Monolog;
 use MediaWikiTestCase;
 use PHPUnit_Framework_Error_Notice;
 
+/**
+ * @covers \MediaWiki\Logger\Monolog\AvroFormatter
+ */
 class AvroFormatterTest extends MediaWikiTestCase {
 
        protected function setUp() {
index 88cd2dd..a69b0bf 100644 (file)
@@ -24,6 +24,9 @@ use MediaWikiTestCase;
 use Monolog\Logger;
 use Wikimedia\TestingAccessWrapper;
 
+/**
+ * @covers \MediaWiki\Logger\Monolog\KafkaHandler
+ */
 class KafkaHandlerTest extends MediaWikiTestCase {
 
        protected function setUp() {
index 4c0a5fa..ddc0798 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 /**
+ * @covers LinksUpdate
  * @group LinksUpdate
  * @group Database
  * ^--- make sure temporary tables are used.
index 6995bf8..088ab4f 100644 (file)
@@ -5,6 +5,8 @@
  */
 class MWCallableUpdateTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public function testDoUpdate() {
                $ran = 0;
                $update = new MWCallableUpdate( function () use ( &$ran ) {
index e6ad072..1261c24 100644 (file)
@@ -5,6 +5,8 @@
  */
 class TransactionRoundDefiningUpdateTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public function testDoUpdate() {
                $ran = 0;
                $update = new TransactionRoundDefiningUpdate( function () use ( &$ran ) {
diff --git a/tests/phpunit/includes/editpage/TextboxBuilderTest.php b/tests/phpunit/includes/editpage/TextboxBuilderTest.php
new file mode 100644 (file)
index 0000000..668badd
--- /dev/null
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Copyright (C) 2017 Kunal Mehta <legoktm@member.fsf.org>
+ *
+ * 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.
+ *
+ */
+
+namespace MediaWiki\Tests\EditPage;
+
+use Language;
+use MediaWiki\EditPage\TextboxBuilder;
+use MediaWikiTestCase;
+use Title;
+use User;
+
+/**
+ * @covers \MediaWiki\EditPage\TextboxBuilder
+ */
+class TextboxBuilderTest extends MediaWikiTestCase {
+
+       public function provideAddNewLineAtEnd() {
+               return [
+                       [ '', '' ],
+                       [ 'foo', "foo\n" ],
+               ];
+       }
+
+       /**
+        * @dataProvider provideAddNewLineAtEnd
+        */
+       public function testAddNewLineAtEnd( $input, $expected ) {
+               $builder = new TextboxBuilder();
+               $this->assertSame( $expected, $builder->addNewLineAtEnd( $input ) );
+       }
+
+       public function testBuildTextboxAttribs() {
+               $user = new User();
+               $user->setOption( 'editfont', 'monospace' );
+
+               $title = $this->getMockBuilder( Title::class )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+               $title->expects( $this->any() )
+                       ->method( 'getPageLanguage' )
+                       ->will( $this->returnValue( Language::factory( 'en' ) ) );
+
+               $builder = new TextboxBuilder();
+               $attribs = $builder->buildTextboxAttribs(
+                       'mw-textbox1',
+                       [ 'class' => 'foo bar', 'data-foo' => '123', 'rows' => 30 ],
+                       $user,
+                       $title
+               );
+
+               $this->assertInternalType( 'array', $attribs );
+               // custom attrib showed up
+               $this->assertArrayHasKey( 'data-foo', $attribs );
+               // classes merged properly (string)
+               $this->assertSame( 'foo bar mw-editfont-monospace', $attribs['class'] );
+               // overrides in custom attrib worked
+               $this->assertSame( 30, $attribs['rows'] );
+               $this->assertSame( 'en', $attribs['lang'] );
+
+               $attribs2 = $builder->buildTextboxAttribs(
+                       'mw-textbox2', [ 'class' => [ 'foo', 'bar' ] ], $user, $title
+               );
+               // classes merged properly (array)
+               $this->assertSame( [ 'foo', 'bar', 'mw-editfont-monospace' ], $attribs2['class'] );
+
+               $attribs3 = $builder->buildTextboxAttribs(
+                       'mw-textbox3', [], $user, $title
+               );
+               // classes ok when nothing to be merged
+               $this->assertSame( 'mw-editfont-monospace', $attribs3['class'] );
+       }
+}
index 614a1c9..6c5b3b1 100644 (file)
@@ -10,6 +10,7 @@ class MWExceptionTest extends MediaWikiTestCase {
 
        /**
         * @expectedException MWException
+        * @covers MWException
         */
        public function testMwexceptionThrowing() {
                throw new MWException();
index a0bac63..d43e04a 100644 (file)
@@ -5,6 +5,8 @@
  */
 class ExternalStoreFactoryTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public function testExternalStoreFactory_noStores() {
                $factory = new ExternalStoreFactory( [] );
                $this->assertFalse( $factory->getStoreObject( 'ForTesting' ) );
index 800c2fc..205df9c 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers MigrateFileRepoLayout
+ */
 class MigrateFileRepoLayoutTest extends MediaWikiTestCase {
        protected $tmpPrefix;
        protected $migratorMock;
index 82ff12e..6f04c66 100644 (file)
@@ -1,4 +1,8 @@
 <?php
+
+/**
+ * @covers RepoGroup
+ */
 class RepoGroupTest extends MediaWikiTestCase {
 
        function testHasForeignRepoNegative() {
index 5b5f1b0..62e1026 100644 (file)
@@ -6,6 +6,7 @@ class FileTest extends MediaWikiMediaTestCase {
         * @param string $filename
         * @param bool $expected
         * @dataProvider providerCanAnimate
+        * @covers File::canAnimateThumbIfAppropriate
         */
        function testCanAnimateThumbIfAppropriate( $filename, $expected ) {
                $this->setMwGlobals( 'wgMaxAnimatedGifArea', 9000 );
index b7e0053..f74f60a 100644 (file)
@@ -1,21 +1,57 @@
 <?php
 
-
+/**
+ * @covers HTMLForm
+ *
+ * @licence GNU GPL v2+
+ * @author Gergő Tisza
+ * @author Thiemo Mättig
+ */
 class HTMLFormTest extends MediaWikiTestCase {
-       public function testGetHTML_empty() {
+
+       private function newInstance() {
                $form = new HTMLForm( [] );
                $form->setTitle( Title::newFromText( 'Foo' ) );
+               return $form;
+       }
+
+       public function testGetHTML_empty() {
+               $form = $this->newInstance();
                $form->prepareForm();
                $html = $form->getHTML( false );
-               $this->assertRegExp( '/<form\b/', $html );
+               $this->assertStringStartsWith( '<form ', $html );
        }
 
        /**
         * @expectedException LogicException
         */
        public function testGetHTML_noPrepare() {
-               $form = new HTMLForm( [] );
-               $form->setTitle( Title::newFromText( 'Foo' ) );
+               $form = $this->newInstance();
                $form->getHTML( false );
        }
+
+       public function testAutocompleteDefaultsToNull() {
+               $form = $this->newInstance();
+               $this->assertNotContains( 'autocomplete', $form->wrapForm( '' ) );
+       }
+
+       public function testAutocompleteWhenSetToNull() {
+               $form = $this->newInstance();
+               $form->setAutocomplete( null );
+               $this->assertNotContains( 'autocomplete', $form->wrapForm( '' ) );
+       }
+
+       public function testAutocompleteWhenSetToFalse() {
+               $form = $this->newInstance();
+               // Previously false was used instead of null to indicate the attribute should not be set
+               $form->setAutocomplete( false );
+               $this->assertNotContains( 'autocomplete', $form->wrapForm( '' ) );
+       }
+
+       public function testAutocompleteWhenSetToOff() {
+               $form = $this->newInstance();
+               $form->setAutocomplete( 'off' );
+               $this->assertContains( ' autocomplete="off"', $form->wrapForm( '' ) );
+       }
+
 }
index 9ec4f97..75c93be 100644 (file)
@@ -1,6 +1,12 @@
 <?php
 
+/**
+ * @covers HTMLRestrictionsField
+ */
 class HTMLRestrictionsFieldTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        public function testConstruct() {
                $field = new HTMLRestrictionsField( [ 'fieldname' => 'restrictions' ] );
                $this->assertNotEmpty( $field->getLabel(), 'has a default label' );
index 3790e3a..8ca9f6a 100644 (file)
@@ -495,11 +495,10 @@ class HttpTest extends MediaWikiTestCase {
         * where it did not define a cURL constant. T72570
         *
         * @dataProvider provideCurlConstants
+        * @coversNothing
         */
        public function testCurlConstants( $value ) {
-               if ( !extension_loaded( 'curl' ) ) {
-                       $this->markTestSkipped( "PHP extension 'curl' is not loaded, skipping." );
-               }
+               $this->checkPHPExtension( 'curl' );
 
                $this->assertTrue( defined( $value ), $value . ' not defined' );
        }
index 347d0fc..7bb03db 100644 (file)
@@ -37,7 +37,7 @@ class ImportTest extends MediaWikiLangTestCase {
        }
 
        public function getUnknownTagsXML() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [
                                <<< EOF
@@ -71,7 +71,7 @@ EOF
                                'TestImportPage'
                        ]
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
@@ -102,7 +102,7 @@ EOF
        }
 
        public function getRedirectXML() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [
                                <<< EOF
@@ -157,7 +157,7 @@ EOF
                                null
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
@@ -185,7 +185,7 @@ EOF
        }
 
        public function getSiteInfoXML() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [
                                <<< EOF
@@ -217,7 +217,7 @@ EOF
                                ]
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
@@ -248,7 +248,7 @@ EOF
 
                $n = ( $assign ? 1 : 0 ) + ( $create ? 2 : 0 );
 
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                $source = $this->getDataSource( <<<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>
@@ -283,7 +283,7 @@ EOF
 </mediawiki>
 EOF
                );
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
 
                $importer = new WikiImporter( $source, MediaWikiServices::getInstance()->getMainConfig() );
                $importer->setUsernamePrefix( 'Xxx', $assign );
index fe7c506..edba75c 100644 (file)
@@ -10,6 +10,8 @@
  */
 class JobQueueMemoryTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @return JobQueueMemory
         */
index 43d626d..f874f6d 100644 (file)
@@ -16,6 +16,7 @@ class RefreshLinksPartitionTest extends MediaWikiTestCase {
 
        /**
         * @dataProvider provider_backlinks
+        * @covers BacklinkJobUtils::partitionBacklinkJob
         */
        public function testRefreshLinks( $ns, $dbKey, $pages ) {
                $title = Title::makeTitle( $ns, $dbKey );
index 21472d5..76b4ee1 100644 (file)
@@ -6,6 +6,9 @@
  */
 
 class ArrayUtilsTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        private $search;
 
        /**
index b06df97..a6efc85 100644 (file)
@@ -275,7 +275,7 @@ class CSSMinTest extends MediaWikiTestCase {
                        . '%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%228%22 height='
                        . '%228%22%3E%0A%09%3Ccircle cx=%224%22 cy=%224%22 r=%222%22/%3E%0A%3C/svg%3E%0A';
 
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [
                                'Regular file',
@@ -492,7 +492,7 @@ class CSSMinTest extends MediaWikiTestCase {
                                '.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
+               // phpcs:enable
        }
 
        /**
index cba2939..19dc53c 100644 (file)
@@ -1,9 +1,13 @@
 <?php
 
+/**
+ * @covers DeferredStringifier
+ */
 class DeferredStringifierTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
-        * @covers DeferredStringifier
         * @dataProvider provideToString
         */
        public function testToString( $params, $expected ) {
index cfc2d91..264cc00 100644 (file)
@@ -1,8 +1,13 @@
 <?php
 
+/**
+ * @covers DnsSrvDiscoverer
+ */
 class DnsSrvDiscovererTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
-        * @covers DnsSrvDiscoverer
         * @dataProvider provideRecords
         */
        public function testPickServer( $params, $expected ) {
index 12c5787..3e8aaeb 100644 (file)
@@ -28,6 +28,8 @@
  */
 abstract class GenericArrayObjectTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * Returns objects that can serve as elements in the concrete
         * GenericArrayObject deriving class being tested.
index 0822a8a..040bebf 100644 (file)
@@ -4,6 +4,9 @@
  * @group HashRing
  */
 class HashRingTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
         * @covers HashRing
         */
index 5f176e0..eb601e7 100644 (file)
@@ -5,7 +5,24 @@
  */
 class HtmlArmorTest extends PHPUnit_Framework_TestCase {
 
-       public static function provideHtmlArmor() {
+       use MediaWikiCoversValidator;
+
+       public static function provideConstructor() {
+               return [
+                       [ 'test' ],
+                       [ null ],
+                       [ '<em>some html!</em>' ]
+               ];
+       }
+
+       /**
+        * @dataProvider provideConstructor
+        */
+       public function testConstructor( $value ) {
+               $this->assertInstanceOf( HtmlArmor::class, new HtmlArmor( $value ) );
+       }
+
+       public static function provideGetHtml() {
                return [
                        [
                                'foobar',
@@ -19,13 +36,17 @@ class HtmlArmorTest extends PHPUnit_Framework_TestCase {
                                new HtmlArmor( '<script>alert("evil!");</script>' ),
                                '<script>alert("evil!");</script>',
                        ],
+                       [
+                               new HtmlArmor( null ),
+                               null,
+                       ]
                ];
        }
 
        /**
-        * @dataProvider provideHtmlArmor
+        * @dataProvider provideGetHtml
         */
-       public function testHtmlArmor( $input, $expected ) {
+       public function testGetHtml( $input, $expected ) {
                $this->assertEquals(
                        $expected,
                        HtmlArmor::getHtml( $input )
index 57668e5..8192f01 100644 (file)
@@ -6,6 +6,9 @@
  *    ...a dataprovider and test method.
  */
 class IEUrlExtensionTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
         * @covers IEUrlExtension::findIE6Extension
         */
index e47c4ba..8a120ea 100644 (file)
@@ -10,6 +10,9 @@
  */
 
 class IPTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
         * @covers IP::isIPAddress
         * @dataProvider provideInvalidIPs
@@ -561,7 +564,7 @@ class IPTest extends PHPUnit_Framework_TestCase {
        }
 
        /**
-        * Test for IP::splitHostAndPort().
+        * @covers IP::splitHostAndPort()
         * @dataProvider provideSplitHostAndPort
         */
        public function testSplitHostAndPort( $expected, $input, $description ) {
@@ -588,7 +591,7 @@ class IPTest extends PHPUnit_Framework_TestCase {
        }
 
        /**
-        * Test for IP::combineHostAndPort()
+        * @covers IP::combineHostAndPort()
         * @dataProvider provideCombineHostAndPort
         */
        public function testCombineHostAndPort( $expected, $input, $description ) {
@@ -612,7 +615,7 @@ class IPTest extends PHPUnit_Framework_TestCase {
        }
 
        /**
-        * Test for IP::sanitizeRange()
+        * @covers IP::sanitizeRange()
         * @dataProvider provideIPCIDRs
         */
        public function testSanitizeRange( $input, $expected, $description ) {
@@ -636,7 +639,7 @@ class IPTest extends PHPUnit_Framework_TestCase {
        }
 
        /**
-        * Test for IP::prettifyIP()
+        * @covers IP::prettifyIP()
         * @dataProvider provideIPsToPrettify
         */
        public function testPrettifyIP( $ip, $prettified ) {
index ca12f6c..5061e27 100644 (file)
@@ -2,6 +2,8 @@
 
 class JavaScriptMinifierTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public static function provideCases() {
                return [
 
@@ -59,6 +61,20 @@ class JavaScriptMinifierTest extends PHPUnit_Framework_TestCase {
                        [ "0xFF.\nx;", "0xFF.x;" ],
                        [ "5.3.\nx;", "5.3.x;" ],
 
+                       // Cover failure case for incomplete hex literal
+                       [ "0x;", false, false ],
+
+                       // Cover failure case for number with no digits after E
+                       [ "1.4E", false, false ],
+
+                       // Cover failure case for number with several E
+                       [ "1.4EE2", false, false ],
+                       [ "1.4EE", false, false ],
+
+                       // Cover failure case for number with several E (nonconsecutive)
+                       // FIXME: This is invalid, but currently tolerated
+                       [ "1.4E2E3", "1.4E2 E3", false ],
+
                        // Semicolon insertion between an expression having an inline
                        // comment after it, and a statement on the next line (T29046).
                        [
@@ -138,6 +154,7 @@ class JavaScriptMinifierTest extends PHPUnit_Framework_TestCase {
                        [ "var a = 5.;", "var a=5.;" ],
                        [ "5.0.toString();", "5.0.toString();" ],
                        [ "5..toString();", "5..toString();" ],
+                       // Cover failure case for too many decimal points
                        [ "5...toString();", false ],
                        [ "5.\n.toString();", '5..toString();' ],
 
@@ -153,8 +170,9 @@ class JavaScriptMinifierTest extends PHPUnit_Framework_TestCase {
        /**
         * @dataProvider provideCases
         * @covers JavaScriptMinifier::minify
+        * @covers JavaScriptMinifier::parseError
         */
-       public function testJavaScriptMinifierOutput( $code, $expectedOutput, $expectedValid = true ) {
+       public function testMinifyOutput( $code, $expectedOutput, $expectedValid = true ) {
                $minified = JavaScriptMinifier::minify( $code );
 
                // JSMin+'s parser will throw an exception if output is not valid JS.
index 88dc67a..57c9831 100644 (file)
@@ -5,6 +5,8 @@
  */
 class MWMessagePackTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * Provides test cases for MWMessagePackTest::testMessagePack
         *
index 60a5057..363b081 100644 (file)
@@ -3,6 +3,9 @@
  * @group Cache
  */
 class MapCacheLRUTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
         * @covers MapCacheLRU::newFromArray()
         * @covers MapCacheLRU::toArray()
index d99c587..ba8af93 100644 (file)
@@ -26,6 +26,8 @@ class ArrayBackedMemoizedCallable extends MemoizedCallable {
  */
 class MemoizedCallableTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * The memoized callable should relate inputs to outputs in the same
         * way as the original underlying callable.
index 35a7b60..03814da 100644 (file)
@@ -20,6 +20,8 @@
 
 class ObjectFactoryTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @covers ObjectFactory::getObjectFromSpec
         */
index 9c189d1..ddb7bfa 100644 (file)
@@ -11,6 +11,8 @@
  */
 class ProcessCacheLRUTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * Helper to verify emptiness of a cache object.
         * Compare against an array so we get the cache content difference.
@@ -58,6 +60,7 @@ class ProcessCacheLRUTest extends PHPUnit_Framework_TestCase {
 
        /**
         * Highlight diff between assertEquals and assertNotSame
+        * @coversNothing
         */
        public function testPhpUnitArrayEquality() {
                $one = [ 'A' => 1, 'B' => 2 ];
index c5bc03e..d0e404b 100644 (file)
@@ -3,7 +3,13 @@
 use Liuggio\StatsdClient\Entity\StatsdData;
 use Liuggio\StatsdClient\Sender\SenderInterface;
 
+/**
+ * @covers SamplingStatsdClient
+ */
 class SamplingStatsdClientTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
         * @dataProvider samplingDataProvider
         */
index 8075944..3e5ccac 100644 (file)
@@ -2,6 +2,8 @@
 
 class StringUtilsTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @covers StringUtils::isUtf8
         * @dataProvider provideStringsForIsUtf8Check
index 4d71944..7e166f8 100644 (file)
@@ -21,6 +21,8 @@
 
 class TimingTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @covers Timing::clearMarks
         * @covers Timing::getEntries
index 35e9005..d226227 100644 (file)
@@ -26,6 +26,8 @@
  */
 class XhprofDataTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @covers XhprofData::splitKey
         * @dataProvider provideSplitKey
index 6748115..c9123b8 100644 (file)
@@ -19,6 +19,9 @@
  */
 
 class XhprofTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
         * Trying to enable Xhprof when it is already enabled causes an exception
         * to be thrown.
index 5c5eeaa..8a11d87 100644 (file)
@@ -6,11 +6,13 @@
  * @covers XMLTypeCheck
  */
 class XmlTypeCheckTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        const WELL_FORMED_XML = "<root><child /></root>";
        const MAL_FORMED_XML = "<root><child /></error>";
-       // @codingStandardsIgnoreStart Generic.Files.LineLength
+       // phpcs:ignore Generic.Files.LineLength
        const XML_WITH_PIH = '<?xml version="1.0"?><?xml-stylesheet type="text/xsl" href="/w/index.php"?><svg><child /></svg>';
-       // @codingStandardsIgnoreEnd
 
        /**
         * @covers XMLTypeCheck::newFromString
index 742eb95..1f3cae5 100644 (file)
@@ -1,9 +1,12 @@
 <?php
-/*
+/**
  * @group Media
  * @covers MimeAnalyzer
  */
 class MimeAnalyzerTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /** @var MimeAnalyzer */
        private $mimeAnalyzer;
 
index f2fe07d..4320d80 100644 (file)
@@ -163,6 +163,9 @@ class BagOStuffTest extends MediaWikiTestCase {
                $this->assertTrue( $this->cache->add( $key, 'test' ) );
        }
 
+       /**
+        * @covers BagOStuff::get
+        */
        public function testGet() {
                $value = [ 'this' => 'is', 'a' => 'test' ];
 
index 8b9abbc..d71b16c 100644 (file)
@@ -7,6 +7,8 @@ use Wikimedia\TestingAccessWrapper;
  */
 class CachedBagOStuffTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @covers CachedBagOStuff::__construct
         * @covers CachedBagOStuff::doGet
index 53d27c0..9eb3409 100644 (file)
@@ -7,6 +7,8 @@ use Wikimedia\TestingAccessWrapper;
  */
 class HashBagOStuffTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @covers HashBagOStuff::__construct
         */
index e534f92..7053fc1 100644 (file)
@@ -17,6 +17,9 @@ use Wikimedia\TestingAccessWrapper;
  * @covers WANObjectCache::setInterimValue
  */
 class WANObjectCacheTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /** @var TimeAdjustableWANObjectCache */
        private $cache;
        /** @var BagOStuff */
index b6ea426..54706d5 100644 (file)
@@ -3,7 +3,13 @@
 use Wikimedia\Rdbms\TransactionProfiler;
 use Psr\Log\LoggerInterface;
 
+/**
+ * @covers \Wikimedia\Rdbms\TransactionProfiler
+ */
 class TransactionProfilerTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        public function testAffected() {
                $logger = $this->getMockBuilder( LoggerInterface::class )->getMock();
                $logger->expects( $this->exactly( 3 ) )->method( 'info' );
index a8dbdd3..4e5f735 100644 (file)
@@ -6,6 +6,9 @@ use Wikimedia\Rdbms\DatabaseDomain;
  * @covers Wikimedia\Rdbms\DatabaseDomain
  */
 class DatabaseDomainTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        public static function provideConstruct() {
                return [
                        'All strings' =>
index 461ef09..a9f1880 100644 (file)
@@ -106,6 +106,9 @@ class FakeDatabaseMysqlBase extends DatabaseMysqlBase {
 }
 
 class DatabaseMysqlBaseTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
         * @dataProvider provideDiapers
         * @covers Wikimedia\Rdbms\DatabaseMysqlBase::addIdentifierQuotes
index 7b84117..23f7865 100644 (file)
@@ -7,6 +7,9 @@ use Wikimedia\Rdbms\LikeMatch;
  * with creating SQL text.
  */
 class DatabaseSQLTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /** @var DatabaseTestHelper */
        private $database;
 
@@ -843,8 +846,8 @@ class DatabaseSQLTest extends PHPUnit_Framework_TestCase {
        }
 
        public static function provideUnionConditionPermutations() {
+               // phpcs:disable Generic.Files.LineLength
                return [
-                       // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
                        [
                                [
                                        'table' => [ 'table1', 'table2' ],
@@ -986,8 +989,8 @@ class DatabaseSQLTest extends PHPUnit_Framework_TestCase {
                                ],
                                "SELECT  foo_id  FROM foo    WHERE baz IS NULL  ORDER BY foo_id LIMIT 150,25"
                        ],
-                       // @codingStandardsIgnoreEnd
                ];
+               // phpcs:enable
        }
 
        /**
index 7933f19..4a0a7e7 100644 (file)
@@ -7,6 +7,8 @@ use Wikimedia\TestingAccessWrapper;
 
 class DatabaseTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        protected function setUp() {
                $this->db = new DatabaseTestHelper( __CLASS__ . '::' . $this->getName() );
        }
index 514e6cd..7becad2 100644 (file)
@@ -6,6 +6,8 @@
  */
 class XMPTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        protected function setUp() {
                parent::setUp();
                # Requires libxml to do XMP parsing
index 7f7ea93..0785920 100644 (file)
@@ -7,6 +7,8 @@ use Psr\Log\NullLogger;
  */
 class XMPValidateTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @dataProvider provideDates
         * @covers XMPValidate::validateDate
index 4158ea2..03671ac 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers BlockLogFormatter
+ */
 class BlockLogFormatterTest extends LogFormatterTestCase {
 
        /**
index 2337899..0e6855d 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers DeleteLogFormatter
+ */
 class DeleteLogFormatterTest extends LogFormatterTestCase {
 
        /**
index ec12078..80e4c0b 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers ImportLogFormatter
+ */
 class ImportLogFormatterTest extends LogFormatterTestCase {
 
        /**
index 8b9abe4..1978f1b 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers MergeLogFormatter
+ */
 class MergeLogFormatterTest extends LogFormatterTestCase {
 
        /**
index 3433a6a..ebda46b 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers MoveLogFormatter
+ */
 class MoveLogFormatterTest extends LogFormatterTestCase {
 
        /**
index 333fd88..8317e91 100644 (file)
@@ -1,6 +1,7 @@
 <?php
 
 /**
+ * @covers NewUsersLogFormatter
  * @group Database
  */
 class NewUsersLogFormatterTest extends LogFormatterTestCase {
index 2156bdb..0819015 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers PageLangLogFormatter
+ */
 class PageLangLogFormatterTest extends LogFormatterTestCase {
 
        protected function setUp() {
index b680454..0d78ed9 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers PatrolLogFormatter
+ */
 class PatrolLogFormatterTest extends LogFormatterTestCase {
 
        /**
index 1fa7fc2..1c076ca 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers ProtectLogFormatter
+ */
 class ProtectLogFormatterTest extends LogFormatterTestCase {
 
        /**
index f48507d..d081c61 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers RightsLogFormatter
+ */
 class RightsLogFormatterTest extends LogFormatterTestCase {
 
        /**
index 00d93d1..2b4067f 100644 (file)
@@ -1,5 +1,8 @@
 <?php
 
+/**
+ * @covers UploadLogFormatter
+ */
 class UploadLogFormatterTest extends LogFormatterTestCase {
 
        /**
index 3dd7e4c..eb02e7e 100644 (file)
@@ -47,9 +47,8 @@ class ExifBitmapTest extends MediaWikiMediaTestCase {
         * @covers ExifBitmapHandler::isMetadataValid
         */
        public function testGoodMetadata() {
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:ignore Generic.Files.LineLength
                $meta = 'a:16:{s:10:"ImageWidth";i:20;s:11:"ImageLength";i:20;s:13:"BitsPerSample";a:3:{i:0;i:8;i:1;i:8;i:2;i:8;}s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:16:"ImageDescription";s:17:"Created with GIMP";s:12:"StripOffsets";i:8;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:3;s:12:"RowsPerStrip";i:64;s:15:"StripByteCounts";i:238;s:11:"XResolution";s:19:"1207959552/16777216";s:11:"YResolution";s:19:"1207959552/16777216";s:19:"PlanarConfiguration";i:1;s:14:"ResolutionUnit";i:2;s:22:"MEDIAWIKI_EXIF_VERSION";i:2;}';
-               // @codingStandardsIgnoreEnd
                $res = $this->handler->isMetadataValid( null, $meta );
                $this->assertEquals( ExifBitmapHandler::METADATA_GOOD, $res );
        }
@@ -58,9 +57,8 @@ class ExifBitmapTest extends MediaWikiMediaTestCase {
         * @covers ExifBitmapHandler::isMetadataValid
         */
        public function testIsOldGood() {
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:ignore Generic.Files.LineLength
                $meta = 'a:16:{s:10:"ImageWidth";i:20;s:11:"ImageLength";i:20;s:13:"BitsPerSample";a:3:{i:0;i:8;i:1;i:8;i:2;i:8;}s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:16:"ImageDescription";s:17:"Created with GIMP";s:12:"StripOffsets";i:8;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:3;s:12:"RowsPerStrip";i:64;s:15:"StripByteCounts";i:238;s:11:"XResolution";s:19:"1207959552/16777216";s:11:"YResolution";s:19:"1207959552/16777216";s:19:"PlanarConfiguration";i:1;s:14:"ResolutionUnit";i:2;s:22:"MEDIAWIKI_EXIF_VERSION";i:1;}';
-               // @codingStandardsIgnoreEnd
                $res = $this->handler->isMetadataValid( null, $meta );
                $this->assertEquals( ExifBitmapHandler::METADATA_COMPATIBLE, $res );
        }
@@ -70,9 +68,8 @@ class ExifBitmapTest extends MediaWikiMediaTestCase {
         * @covers ExifBitmapHandler::isMetadataValid
         */
        public function testPagedTiffHandledGracefully() {
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:ignore Generic.Files.LineLength
                $meta = 'a:6:{s:9:"page_data";a:1:{i:1;a:5:{s:5:"width";i:643;s:6:"height";i:448;s:5:"alpha";s:4:"true";s:4:"page";i:1;s:6:"pixels";i:288064;}}s:10:"page_count";i:1;s:10:"first_page";i:1;s:9:"last_page";i:1;s:4:"exif";a:9:{s:10:"ImageWidth";i:643;s:11:"ImageLength";i:448;s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:4;s:12:"RowsPerStrip";i:50;s:19:"PlanarConfiguration";i:1;s:22:"MEDIAWIKI_EXIF_VERSION";i:1;}s:21:"TIFF_METADATA_VERSION";s:3:"1.4";}';
-               // @codingStandardsIgnoreEnd
                $res = $this->handler->isMetadataValid( null, $meta );
                $this->assertEquals( ExifBitmapHandler::METADATA_BAD, $res );
        }
index 5ae1763..fff101f 100644 (file)
@@ -5,10 +5,13 @@
  * @group Media
  * @group medium
  *
- * @todo covers tags
+ * @covers BitmapHandler
  */
 class ExifRotationTest extends MediaWikiMediaTestCase {
 
+       /** @var BitmapHandler */
+       private $handler;
+
        protected function setUp() {
                parent::setUp();
                $this->checkPHPExtension( 'exif' );
index aaa3ac4..4dd7443 100644 (file)
@@ -72,18 +72,18 @@ class GIFHandlerTest extends MediaWikiMediaTestCase {
        }
 
        public static function provideIsMetadataValid() {
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [ GIFHandler::BROKEN_FILE, GIFHandler::METADATA_GOOD ],
                        [ '', GIFHandler::METADATA_BAD ],
                        [ null, GIFHandler::METADATA_BAD ],
                        [ 'Something invalid!', GIFHandler::METADATA_BAD ],
-                       // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
                        [
                                '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
                ];
+               // phpcs:enable
        }
 
        /**
@@ -99,8 +99,8 @@ class GIFHandlerTest extends MediaWikiMediaTestCase {
        }
 
        public static function provideGetMetadata() {
+               // phpcs:disable Generic.Files.LineLength
                return [
-                       // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
                        [
                                '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;}}'
@@ -109,8 +109,8 @@ class GIFHandlerTest extends MediaWikiMediaTestCase {
                                '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
                ];
+               // phpcs:enable
        }
 
        /**
@@ -153,6 +153,7 @@ class GIFHandlerTest extends MediaWikiMediaTestCase {
         * @param string $filename
         * @param float $expectedLength
         * @dataProvider provideGetLength
+        * @covers GIFHandler::getLength
         */
        public function testGetLength( $filename, $expectedLength ) {
                $file = $this->dataFile( $filename, 'image/gif' );
index abe0280..13de7ff 100644 (file)
@@ -24,9 +24,8 @@ class JpegTest extends MediaWikiMediaTestCase {
        public function testJpegMetadataExtraction() {
                $file = $this->dataFile( 'test.jpg', 'image/jpeg' );
                $res = $this->handler->getMetadata( $file, $this->filePath . 'test.jpg' );
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:ignore Generic.Files.LineLength
                $expected = 'a:7:{s:16:"ImageDescription";s:9:"Test file";s:11:"XResolution";s:4:"72/1";s:11:"YResolution";s:4:"72/1";s:14:"ResolutionUnit";i:2;s:16:"YCbCrPositioning";i:1;s:15:"JPEGFileComment";a:1:{i:0;s:17:"Created with GIMP";}s:22:"MEDIAWIKI_EXIF_VERSION";i:2;}';
-               // @codingStandardsIgnoreEnd
 
                // Unserialize in case serialization format ever changes.
                $this->assertEquals( unserialize( $expected ), unserialize( $res ) );
index 32d54df..5a66586 100644 (file)
@@ -73,18 +73,18 @@ class PNGHandlerTest extends MediaWikiMediaTestCase {
        }
 
        public static function provideIsMetadataValid() {
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [ PNGHandler::BROKEN_FILE, PNGHandler::METADATA_GOOD ],
                        [ '', PNGHandler::METADATA_BAD ],
                        [ null, PNGHandler::METADATA_BAD ],
                        [ 'Something invalid!', PNGHandler::METADATA_BAD ],
-                       // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
                        [
                                '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
                ];
+               // phpcs:enable
        }
 
        /**
@@ -101,8 +101,8 @@ class PNGHandlerTest extends MediaWikiMediaTestCase {
        }
 
        public static function provideGetMetadata() {
+               // phpcs:disable Generic.Files.LineLength
                return [
-                       // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
                        [
                                '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;}}'
@@ -111,8 +111,8 @@ class PNGHandlerTest extends MediaWikiMediaTestCase {
                                '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
                ];
+               // phpcs:enable
        }
 
        /**
@@ -142,6 +142,7 @@ class PNGHandlerTest extends MediaWikiMediaTestCase {
         * @param string $filename
         * @param float $expectedLength
         * @dataProvider provideGetLength
+        * @covers PNGHandler::getLength
         */
        public function testGetLength( $filename, $expectedLength ) {
                $file = $this->dataFile( $filename, 'image/png' );
index 9bfd5f6..6fbb474 100644 (file)
@@ -128,14 +128,14 @@ class SVGMetadataExtractorTest extends MediaWikiTestCase {
 
        public static function provideSvgFilesWithXMLMetadata() {
                $base = __DIR__ . '/../../data/media';
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:disable Generic.Files.LineLength
                $metadata = '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
       <ns4:Work xmlns:ns4="http://creativecommons.org/ns#" rdf:about="">
         <ns5:format xmlns:ns5="http://purl.org/dc/elements/1.1/">image/svg+xml</ns5:format>
         <ns5:type xmlns:ns5="http://purl.org/dc/elements/1.1/" rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
       </ns4:Work>
     </rdf:RDF>';
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
 
                $metadata = str_replace( "\r", '', $metadata ); // Windows compat
                return [
index d114820..8a69ec5 100644 (file)
@@ -34,9 +34,8 @@ class TiffTest extends MediaWikiTestCase {
        public function testTiffMetadataExtraction() {
                $res = $this->handler->getMetadata( null, $this->filePath . 'test.tiff' );
 
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:ignore Generic.Files.LineLength
                $expected = 'a:16:{s:10:"ImageWidth";i:20;s:11:"ImageLength";i:20;s:13:"BitsPerSample";a:3:{i:0;i:8;i:1;i:8;i:2;i:8;}s:11:"Compression";i:5;s:25:"PhotometricInterpretation";i:2;s:16:"ImageDescription";s:17:"Created with GIMP";s:12:"StripOffsets";i:8;s:11:"Orientation";i:1;s:15:"SamplesPerPixel";i:3;s:12:"RowsPerStrip";i:64;s:15:"StripByteCounts";i:238;s:11:"XResolution";s:19:"1207959552/16777216";s:11:"YResolution";s:19:"1207959552/16777216";s:19:"PlanarConfiguration";i:1;s:14:"ResolutionUnit";i:2;s:22:"MEDIAWIKI_EXIF_VERSION";i:2;}';
-               // @codingStandardsIgnoreEnd
 
                // Re-unserialize in case there are subtle differences between how versions
                // of php serialize stuff.
index b8dadaf..a0a99cc 100644 (file)
@@ -1,4 +1,8 @@
 <?php
+
+/**
+ * @covers WebPHandler
+ */
 class WebPHandlerTest extends MediaWikiTestCase {
        public function setUp() {
                parent::setUp();
@@ -19,7 +23,7 @@ class WebPHandlerTest extends MediaWikiTestCase {
                $this->assertEquals( $expectedResult, WebPHandler::extractMetadata( $this->tempFileName ) );
        }
        public function provideTestExtractMetaData() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        // Files from https://developers.google.com/speed/webp/gallery2
                        [ "\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",
@@ -67,7 +71,7 @@ class WebPHandlerTest extends MediaWikiTestCase {
                        [ 'RIFF1234WEBPVP8                     ', false ],
                        [ 'RIFF1234WEBPVP8L                    ', false ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
index 9cb2f94..7eb5582 100644 (file)
@@ -70,6 +70,7 @@ class MemcachedBagOStuffTest extends MediaWikiTestCase {
 
        /**
         * @dataProvider validKeyProvider
+        * @covers MemcachedBagOStuff::validateKeyEncoding
         */
        public function testValidateKeyEncoding( $key ) {
                $this->assertSame( $key, $this->cache->validateKeyEncoding( $key ) );
@@ -86,6 +87,7 @@ class MemcachedBagOStuffTest extends MediaWikiTestCase {
 
        /**
         * @dataProvider invalidKeyProvider
+        * @covers MemcachedBagOStuff::validateKeyEncoding
         */
        public function testValidateKeyEncodingThrowsException( $key ) {
                $this->setExpectedException( 'Exception' );
index f722fe1..4ef4aab 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 /**
  * @group BagOStuff
+ *
+ * @covers RESTBagOStuff
  */
 class RESTBagOStuffTest extends MediaWikiTestCase {
 
index 34a72ce..ea58e4a 100644 (file)
@@ -6,6 +6,9 @@ use Wikimedia\TestingAccessWrapper;
  * @group BagOStuff
  */
 class RedisBagOStuffTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /** @var RedisBagOStuff */
        private $cache;
 
index 48c4392..4faace2 100644 (file)
@@ -28,6 +28,7 @@ class ImagePage404Test extends MediaWikiMediaTestCase {
        }
 
        /**
+        * @covers ImagePage::getThumbSizes
         * @dataProvider providerGetThumbSizes
         * @param string $filename
         * @param int $expectedNumberThumbs How many thumbnails to show
index 2b30cfa..8e49bf9 100644 (file)
@@ -21,6 +21,7 @@ class ImagePageTest extends MediaWikiMediaTestCase {
        }
 
        /**
+        * @covers ImagePage::getDisplayWidthHeight
         * @dataProvider providerGetDisplayWidthHeight
         * @param array $dim Array [maxWidth, maxHeight, width, height]
         * @param array $expected Array [width, height] The width and height we expect to display at
@@ -65,6 +66,7 @@ class ImagePageTest extends MediaWikiMediaTestCase {
        }
 
        /**
+        * @covers ImagePage::getThumbSizes
         * @dataProvider providerGetThumbSizes
         * @param string $filename
         * @param int $expectedNumberThumbs How many thumbnails to show
index 2b803ae..8e5b183 100644 (file)
@@ -1423,7 +1423,7 @@ more stuff
        }
 
        public function provideTestInsertProtectNullRevision() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                yield [
                        'goat-message-key',
                        [ 'edit' => 'sysop' ],
@@ -1442,7 +1442,7 @@ more stuff
                        true,
                        '(goat-key: WikiPageDbTestBase::testInsertProtectNullRevision, UTSysop)(colon-separator)Goat Goat(word-separator)(parentheses: (protect-summary-desc: (restriction-edit), (protect-level-sysop), (protect-expiring: 04:04, 1 (january) 2020, 1 (january) 2020, 04:04))(word-separator)(protect-summary-desc: (restriction-move), (protect-level-something), (protect-expiring: 05:05, 1 (january) 2021, 1 (january) 2021, 05:05)))'
                ];
-               // @codingStandardsIgnoreEnd Generic.Files.LineLength
+               // phpcs:enable
        }
 
        /**
index 6a2afad..9f5e386 100644 (file)
@@ -9,11 +9,13 @@
  * @author Antoine Musso
  * @copyright Copyright © 2011, Antoine Musso
  * @file
- * @todo covers tags
  *
  * @group Database
  */
 
+/**
+ * @covers Parser::getVariableValue
+ */
 class MagicVariableTest extends MediaWikiTestCase {
        /**
         * @var Parser
index c920982..8d17d21 100644 (file)
@@ -15,6 +15,9 @@ use Wikimedia\ScopedCallback;
  * @todo covers tags
  */
 class ParserIntegrationTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /** @var array */
        private $ptTest;
 
index ad899bd..93ab35c 100644 (file)
@@ -3,6 +3,9 @@
 use Wikimedia\TestingAccessWrapper;
 use Wikimedia\ScopedCallback;
 
+/**
+ * @covers ParserOptions
+ */
 class ParserOptionsTest extends MediaWikiTestCase {
 
        private static function clearCache() {
index 441d60d..9642bbc 100644 (file)
@@ -123,7 +123,7 @@ class ParserOutputTest extends MediaWikiTestCase {
        }
 
        public static function provideGetText() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                $text = <<<EOF
 <p>Test document.
 </p>
@@ -315,7 +315,7 @@ EOF
 EOF
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
 }
index 11a2197..ab13899 100644 (file)
@@ -68,7 +68,7 @@ class PreprocessorTest extends MediaWikiTestCase {
        }
 
        public static function provideCases() {
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:disable Generic.Files.LineLength
                return self::addClassArg( [
                        [ "Foo", "<root>Foo</root>" ],
                        [ "<!-- Foo -->", "<root><comment>&lt;!-- Foo --&gt;</comment></root>" ],
@@ -156,7 +156,7 @@ class PreprocessorTest extends MediaWikiTestCase {
                        [ "{{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
+               // phpcs:enable
        }
 
        /**
@@ -208,7 +208,7 @@ class PreprocessorTest extends MediaWikiTestCase {
         * These are more complex test cases taken out of wiki articles.
         */
        public static function provideFiles() {
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:disable Generic.Files.LineLength
                return self::addClassArg( [
                        [ "QuoteQuran" ], # https://en.wikipedia.org/w/index.php?title=Template:QuoteQuran/sandbox&oldid=237348988 GFDL + CC BY-SA by Striver
                        [ "Factorial" ], # https://en.wikipedia.org/w/index.php?title=Template:Factorial&oldid=98548758 GFDL + CC BY-SA by Polonium
@@ -216,7 +216,7 @@ class PreprocessorTest extends MediaWikiTestCase {
                        [ "Fundraising" ], # https://tl.wiktionary.org/w/index.php?title=MediaWiki:Sitenotice&oldid=5716 GFDL + CC BY-SA, copied there by Sky Harbor.
                        [ "NestedTemplates" ], # T29936
                ] );
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
@@ -242,7 +242,7 @@ class PreprocessorTest extends MediaWikiTestCase {
         * Tests from T30642 · https://phabricator.wikimedia.org/T30642
         */
        public static function provideHeadings() {
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:disable Generic.Files.LineLength
                return self::addClassArg( [
                        /* These should become headings: */
                        [ "== h ==<!--c1-->", "<root><h level=\"2\" i=\"1\">== h ==<comment>&lt;!--c1--&gt;</comment></h></root>" ],
@@ -281,7 +281,7 @@ class PreprocessorTest extends MediaWikiTestCase {
                        [ "== 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
+               // phpcs:enable
        }
 
        /**
index d7e72e1..2cf9553 100644 (file)
@@ -406,6 +406,7 @@ class SanitizerTest extends MediaWikiTestCase {
 
        /**
         * @dataProvider provideIsReservedDataAttribute
+        * @covers Sanitizer::isReservedDataAttribute
         */
        public function testIsReservedDataAttribute( $attr, $expected ) {
                $this->assertSame( $expected, Sanitizer::isReservedDataAttribute( $attr ) );
index 9b8e01e..1673410 100644 (file)
@@ -16,7 +16,7 @@ class BcryptPasswordTest extends PasswordTestCase {
        }
 
        public static function providePasswordTests() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        // Tests from glibc bcrypt implementation
                        [ true, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "U*U" ],
@@ -39,6 +39,6 @@ class BcryptPasswordTest extends PasswordTestCase {
                        [ false, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "UXU" ],
                        [ false, ':bcrypt:5$CCCCCCCCCCCCCCCCCCCCC.$E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW', "" ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 }
index 0c85653..7ed9711 100644 (file)
@@ -4,7 +4,6 @@
  * @covers EncryptedPassword
  * @covers ParameterizedPassword
  * @covers Password
- * @codingStandardsIgnoreStart Generic.Files.LineLength
  */
 class EncryptedPasswordTest extends PasswordTestCase {
        protected function getTypeConfigs() {
@@ -44,6 +43,7 @@ class EncryptedPasswordTest extends PasswordTestCase {
        }
 
        public static function providePasswordTests() {
+               // phpcs:disable Generic.Files.LineLength
                return [
                        // Encrypted with secret1
                        [ true, ':both:aes-256-cbc:0:izBpxujqC1YbzpCB3qAzgg==:ZqHnitT1pL4YJqKqFES2KEevZYSy2LtlibW5+IMi4XKOGKGy6sE638BXyBbLQQsBtTSrt+JyzwOayKtwIfRbaQsBridx/O1JwBSai1TkGkOsYMBXnlu2Bu/EquCBj5QpjYh7p3Uq4rpiop1KQlin1BJMwnAa1PovhxjpxnYhlhkM4X5ALoGi3XM0bapN48vt', 'password' ],
@@ -54,6 +54,7 @@ class EncryptedPasswordTest extends PasswordTestCase {
                        [ true, ':both:aes-256-cbc:1:m1LCnQVIakfYBNlr9KEgQg==:5yPTctqrzsybdgaMEag18AZYbnL37pAtXVBqmWxkjXbnNmiDH+1bHoL8lsEVTH/sJntC82kNVgE7zeiD8xUVLYF2VUnvB5+sU+aysE45/zwsCu7a22TaischMAOWrsHZ/tIgS/TnZY2d+HNyxgsEeeYf/QoL+FhmqHquK02+4SRbA5lLuj9niYy1r5CoM9cQ', 'password' ],
                        [ true, ':secret2:aes-256-cbc:0:m1LCnQVIakfYBNlr9KEgQg==:5yPTctqrzsybdgaMEag18AZYbnL37pAtXVBqmWxkjXbnNmiDH+1bHoL8lsEVTH/sJntC82kNVgE7zeiD8xUVLYF2VUnvB5+sU+aysE45/zwsCu7a22TaischMAOWrsHZ/tIgS/TnZY2d+HNyxgsEeeYf/QoL+FhmqHquK02+4SRbA5lLuj9niYy1r5CoM9cQ', 'password' ],
                ];
+               // phpcs:enable
        }
 
        /**
@@ -61,12 +62,14 @@ class EncryptedPasswordTest extends PasswordTestCase {
         * @expectedException PasswordError
         */
        public function testDecryptionError() {
+               // phpcs:ignore Generic.Files.LineLength
                $hash = ':secret1:aes-256-cbc:0:m1LCnQVIakfYBNlr9KEgQg==:5yPTctqrzsybdgaMEag18AZYbnL37pAtXVBqmWxkjXbnNmiDH+1bHoL8lsEVTH/sJntC82kNVgE7zeiD8xUVLYF2VUnvB5+sU+aysE45/zwsCu7a22TaischMAOWrsHZ/tIgS/TnZY2d+HNyxgsEeeYf/QoL+FhmqHquK02+4SRbA5lLuj9niYy1r5CoM9cQ';
                $password = $this->passwordFactory->newFromCiphertext( $hash );
                $password->crypt( 'password' );
        }
 
        public function testUpdate() {
+               // phpcs:ignore Generic.Files.LineLength
                $hash = ':both:aes-256-cbc:0:izBpxujqC1YbzpCB3qAzgg==:ZqHnitT1pL4YJqKqFES2KEevZYSy2LtlibW5+IMi4XKOGKGy6sE638BXyBbLQQsBtTSrt+JyzwOayKtwIfRbaQsBridx/O1JwBSai1TkGkOsYMBXnlu2Bu/EquCBj5QpjYh7p3Uq4rpiop1KQlin1BJMwnAa1PovhxjpxnYhlhkM4X5ALoGi3XM0bapN48vt';
                $fromHash = $this->passwordFactory->newFromCiphertext( $hash );
                $fromPlaintext = $this->passwordFactory->newFromPlaintext( 'password', $fromHash );
index cf96d06..cee4fbb 100644 (file)
@@ -35,15 +35,15 @@ class LayeredParameterizedPasswordTest extends PasswordTestCase {
        }
 
        public static function providePasswordTests() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
+               // phpcs:disable Generic.Files.LineLength
                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' 
+                               'testPassword123'
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
index d57ad04..6caf3e5 100644 (file)
@@ -9,6 +9,9 @@ abstract class PoolCounterAbstractMock extends PoolCounter {
        }
 }
 
+/**
+ * @covers PoolCounter
+ */
 class PoolCounterTest extends MediaWikiTestCase {
        public function testConstruct() {
                $poolCounterConfig = [
index 5ef30e8..acf4710 100644 (file)
@@ -607,6 +607,11 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
                $this->assertSame( [ 'ext.baz.fizzbuzz' ], $info['attributes']['FizzBuzzMorePlugins'] );
        }
 
+       /**
+        * Verify that extension.schema.json is in sync with ExtensionProcessor
+        *
+        * @coversNothing
+        */
        public function testGlobalSettingsDocumentedInSchema() {
                global $IP;
                $globalSettings = TestingAccessWrapper::newFromClass(
index 9ee5881..15d0c2b 100644 (file)
@@ -4,6 +4,9 @@
  * @covers VersionChecker
  */
 class VersionCheckerTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
         * @dataProvider provideCheck
         */
index 0be04ef..db1fb64 100644 (file)
@@ -6,6 +6,8 @@
  */
 class DerivativeResourceLoaderContextTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        protected static function getContext() {
                $request = new FauxRequest( [
                                'lang' => 'zh',
index 1f2c617..7521e88 100644 (file)
@@ -8,6 +8,8 @@ use Wikimedia\TestingAccessWrapper;
  */
 class MessageBlobStoreTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        protected function setUp() {
                parent::setUp();
                // MediaWiki tests defaults $wgMainWANCache to CACHE_NONE.
index f75d67d..c83f500 100644 (file)
@@ -7,6 +7,8 @@ use Wikimedia\TestingAccessWrapper;
  */
 class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        protected static function expandVariables( $text ) {
                return strtr( $text, [
                        '{blankVer}' => ResourceLoaderTestCase::BLANK_VERSION
@@ -205,7 +207,7 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
                        'test.exempt' => 'ready',
                ] );
 
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                $expected = '<script>document.documentElement.className = document.documentElement.className.replace( /(^|\s)client-nojs(\s|$)/, "$1client-js$2" );</script>' . "\n"
                        . '<script>(window.RLQ=window.RLQ||[]).push(function(){'
                        . 'mw.config.set({"key":"value"});'
@@ -217,7 +219,7 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
                        . '<link rel="stylesheet" href="/w/load.php?debug=false&amp;lang=nl&amp;modules=test.styles.pure&amp;only=styles&amp;skin=fallback"/>' . "\n"
                        . '<style>.private{}</style>' . "\n"
                        . '<script async="" src="/w/load.php?debug=false&amp;lang=nl&amp;modules=startup&amp;only=scripts&amp;skin=fallback"></script>';
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
                $expected = self::expandVariables( $expected );
 
                $this->assertEquals( $expected, $client->getHeadHtml() );
@@ -248,8 +250,8 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
        }
 
        public static function provideMakeLoad() {
+               // phpcs:disable Generic.Files.LineLength
                return [
-                       // @codingStandardsIgnoreStart Generic.Files.LineLength
                        [
                                'context' => [],
                                'modules' => [ 'test.unknown' ],
@@ -347,8 +349,8 @@ class ResourceLoaderClientHtmlTest extends PHPUnit_Framework_TestCase {
                                        . '<style>.orderingC{}.orderingD{}</style>' . "\n"
                                        . '<link rel="stylesheet" href="/w/load.php?debug=false&amp;lang=nl&amp;modules=test.ordering.e&amp;only=styles&amp;skin=fallback"/>'
                        ],
-                       // @codingStandardsIgnoreEnd
                ];
+               // phpcs:enable
        }
 
        /**
index b658efb..f848556 100644 (file)
@@ -9,6 +9,9 @@
  * @covers ResourceLoaderContext
  */
 class ResourceLoaderContextTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        protected static function getResourceLoader() {
                return new EmptyResourceLoader( new HashConfig( [
                        'ResourceLoaderDebug' => false,
index be17a69..0718af6 100644 (file)
@@ -5,8 +5,10 @@
  */
 class ResourceLoaderSkinModuleTest extends PHPUnit_Framework_TestCase {
 
-       // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+       use MediaWikiCoversValidator;
+
        public static function provideGetStyles() {
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [
                                'parent' => [],
@@ -64,8 +66,8 @@ CSS
                                ],
                        ],
                ];
+               // phpcs:enable
        }
-       // @codingStandardsIgnoreEnd
 
        /**
         * @dataProvider provideGetStyles
diff --git a/tests/phpunit/includes/services/ServiceContainerTest.php b/tests/phpunit/includes/services/ServiceContainerTest.php
new file mode 100644 (file)
index 0000000..f4f5650
--- /dev/null
@@ -0,0 +1,413 @@
+<?php
+use MediaWiki\Services\ServiceContainer;
+
+/**
+ * @covers MediaWiki\Services\ServiceContainer
+ *
+ * @group MediaWiki
+ */
+class ServiceContainerTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
+       private function newServiceContainer( $extraArgs = [] ) {
+               return new ServiceContainer( $extraArgs );
+       }
+
+       public function testGetServiceNames() {
+               $services = $this->newServiceContainer();
+               $names = $services->getServiceNames();
+
+               $this->assertInternalType( 'array', $names );
+               $this->assertEmpty( $names );
+
+               $name = 'TestService92834576';
+               $services->defineService( $name, function () {
+                       return null;
+               } );
+
+               $names = $services->getServiceNames();
+               $this->assertContains( $name, $names );
+       }
+
+       public function testHasService() {
+               $services = $this->newServiceContainer();
+
+               $name = 'TestService92834576';
+               $this->assertFalse( $services->hasService( $name ) );
+
+               $services->defineService( $name, function () {
+                       return null;
+               } );
+
+               $this->assertTrue( $services->hasService( $name ) );
+       }
+
+       public function testGetService() {
+               $services = $this->newServiceContainer( [ 'Foo' ] );
+
+               $theService = new stdClass();
+               $name = 'TestService92834576';
+               $count = 0;
+
+               $services->defineService(
+                       $name,
+                       function ( $actualLocator, $extra ) use ( $services, $theService, &$count ) {
+                               $count++;
+                               PHPUnit_Framework_Assert::assertSame( $services, $actualLocator );
+                               PHPUnit_Framework_Assert::assertSame( $extra, 'Foo' );
+                               return $theService;
+                       }
+               );
+
+               $this->assertSame( $theService, $services->getService( $name ) );
+
+               $services->getService( $name );
+               $this->assertSame( 1, $count, 'instantiator should be called exactly once!' );
+       }
+
+       public function testGetService_fail_unknown() {
+               $services = $this->newServiceContainer();
+
+               $name = 'TestService92834576';
+
+               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
+
+               $services->getService( $name );
+       }
+
+       public function testPeekService() {
+               $services = $this->newServiceContainer();
+
+               $services->defineService(
+                       'Foo',
+                       function () {
+                               return new stdClass();
+                       }
+               );
+
+               $services->defineService(
+                       'Bar',
+                       function () {
+                               return new stdClass();
+                       }
+               );
+
+               // trigger instantiation of Foo
+               $services->getService( 'Foo' );
+
+               $this->assertInternalType(
+                       'object',
+                       $services->peekService( 'Foo' ),
+                       'Peek should return the service object if it had been accessed before.'
+               );
+
+               $this->assertNull(
+                       $services->peekService( 'Bar' ),
+                       'Peek should return null if the service was never accessed.'
+               );
+       }
+
+       public function testPeekService_fail_unknown() {
+               $services = $this->newServiceContainer();
+
+               $name = 'TestService92834576';
+
+               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
+
+               $services->peekService( $name );
+       }
+
+       public function testDefineService() {
+               $services = $this->newServiceContainer();
+
+               $theService = new stdClass();
+               $name = 'TestService92834576';
+
+               $services->defineService( $name, function ( $actualLocator ) use ( $services, $theService ) {
+                       PHPUnit_Framework_Assert::assertSame( $services, $actualLocator );
+                       return $theService;
+               } );
+
+               $this->assertTrue( $services->hasService( $name ) );
+               $this->assertSame( $theService, $services->getService( $name ) );
+       }
+
+       public function testDefineService_fail_duplicate() {
+               $services = $this->newServiceContainer();
+
+               $theService = new stdClass();
+               $name = 'TestService92834576';
+
+               $services->defineService( $name, function () use ( $theService ) {
+                       return $theService;
+               } );
+
+               $this->setExpectedException( 'MediaWiki\Services\ServiceAlreadyDefinedException' );
+
+               $services->defineService( $name, function () use ( $theService ) {
+                       return $theService;
+               } );
+       }
+
+       public function testApplyWiring() {
+               $services = $this->newServiceContainer();
+
+               $wiring = [
+                       'Foo' => function () {
+                               return 'Foo!';
+                       },
+                       'Bar' => function () {
+                               return 'Bar!';
+                       },
+               ];
+
+               $services->applyWiring( $wiring );
+
+               $this->assertSame( 'Foo!', $services->getService( 'Foo' ) );
+               $this->assertSame( 'Bar!', $services->getService( 'Bar' ) );
+       }
+
+       public function testImportWiring() {
+               $services = $this->newServiceContainer();
+
+               $wiring = [
+                       'Foo' => function () {
+                               return 'Foo!';
+                       },
+                       'Bar' => function () {
+                               return 'Bar!';
+                       },
+                       'Car' => function () {
+                               return 'FUBAR!';
+                       },
+               ];
+
+               $services->applyWiring( $wiring );
+
+               $newServices = $this->newServiceContainer();
+
+               // define a service before importing, so we can later check that
+               // existing service instances survive importWiring()
+               $newServices->defineService( 'Car', function () {
+                       return 'Car!';
+               } );
+
+               // force instantiation
+               $newServices->getService( 'Car' );
+
+               // Define another service, so we can later check that extra wiring
+               // is not lost.
+               $newServices->defineService( 'Xar', function () {
+                       return 'Xar!';
+               } );
+
+               // import wiring, but skip `Bar`
+               $newServices->importWiring( $services, [ 'Bar' ] );
+
+               $this->assertNotContains( 'Bar', $newServices->getServiceNames(), 'Skip `Bar` service' );
+               $this->assertSame( 'Foo!', $newServices->getService( 'Foo' ) );
+
+               // import all wiring, but preserve existing service instance
+               $newServices->importWiring( $services );
+
+               $this->assertContains( 'Bar', $newServices->getServiceNames(), 'Import all services' );
+               $this->assertSame( 'Bar!', $newServices->getService( 'Bar' ) );
+               $this->assertSame( 'Car!', $newServices->getService( 'Car' ), 'Use existing service instance' );
+               $this->assertSame( 'Xar!', $newServices->getService( 'Xar' ), 'Predefined services are kept' );
+       }
+
+       public function testLoadWiringFiles() {
+               $services = $this->newServiceContainer();
+
+               $wiringFiles = [
+                       __DIR__ . '/TestWiring1.php',
+                       __DIR__ . '/TestWiring2.php',
+               ];
+
+               $services->loadWiringFiles( $wiringFiles );
+
+               $this->assertSame( 'Foo!', $services->getService( 'Foo' ) );
+               $this->assertSame( 'Bar!', $services->getService( 'Bar' ) );
+       }
+
+       public function testLoadWiringFiles_fail_duplicate() {
+               $services = $this->newServiceContainer();
+
+               $wiringFiles = [
+                       __DIR__ . '/TestWiring1.php',
+                       __DIR__ . '/./TestWiring1.php',
+               ];
+
+               // loading the same file twice should fail, because
+               $this->setExpectedException( 'MediaWiki\Services\ServiceAlreadyDefinedException' );
+
+               $services->loadWiringFiles( $wiringFiles );
+       }
+
+       public function testRedefineService() {
+               $services = $this->newServiceContainer( [ 'Foo' ] );
+
+               $theService1 = new stdClass();
+               $name = 'TestService92834576';
+
+               $services->defineService( $name, function () {
+                       PHPUnit_Framework_Assert::fail(
+                               'The original instantiator function should not get called'
+                       );
+               } );
+
+               // redefine before instantiation
+               $services->redefineService(
+                       $name,
+                       function ( $actualLocator, $extra ) use ( $services, $theService1 ) {
+                               PHPUnit_Framework_Assert::assertSame( $services, $actualLocator );
+                               PHPUnit_Framework_Assert::assertSame( 'Foo', $extra );
+                               return $theService1;
+                       }
+               );
+
+               // force instantiation, check result
+               $this->assertSame( $theService1, $services->getService( $name ) );
+       }
+
+       public function testRedefineService_disabled() {
+               $services = $this->newServiceContainer( [ 'Foo' ] );
+
+               $theService1 = new stdClass();
+               $name = 'TestService92834576';
+
+               $services->defineService( $name, function () {
+                       return 'Foo';
+               } );
+
+               // disable the service. we should be able to redefine it anyway.
+               $services->disableService( $name );
+
+               $services->redefineService( $name, function () use ( $theService1 ) {
+                       return $theService1;
+               } );
+
+               // force instantiation, check result
+               $this->assertSame( $theService1, $services->getService( $name ) );
+       }
+
+       public function testRedefineService_fail_undefined() {
+               $services = $this->newServiceContainer();
+
+               $theService = new stdClass();
+               $name = 'TestService92834576';
+
+               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
+
+               $services->redefineService( $name, function () use ( $theService ) {
+                       return $theService;
+               } );
+       }
+
+       public function testRedefineService_fail_in_use() {
+               $services = $this->newServiceContainer( [ 'Foo' ] );
+
+               $theService = new stdClass();
+               $name = 'TestService92834576';
+
+               $services->defineService( $name, function () {
+                       return 'Foo';
+               } );
+
+               // create the service, so it can no longer be redefined
+               $services->getService( $name );
+
+               $this->setExpectedException( 'MediaWiki\Services\CannotReplaceActiveServiceException' );
+
+               $services->redefineService( $name, function () use ( $theService ) {
+                       return $theService;
+               } );
+       }
+
+       public function testDisableService() {
+               $services = $this->newServiceContainer( [ 'Foo' ] );
+
+               $destructible = $this->getMockBuilder( 'MediaWiki\Services\DestructibleService' )
+                       ->getMock();
+               $destructible->expects( $this->once() )
+                       ->method( 'destroy' );
+
+               $services->defineService( 'Foo', function () use ( $destructible ) {
+                       return $destructible;
+               } );
+               $services->defineService( 'Bar', function () {
+                       return new stdClass();
+               } );
+               $services->defineService( 'Qux', function () {
+                       return new stdClass();
+               } );
+
+               // instantiate Foo and Bar services
+               $services->getService( 'Foo' );
+               $services->getService( 'Bar' );
+
+               // disable service, should call destroy() once.
+               $services->disableService( 'Foo' );
+
+               // disabled service should still be listed
+               $this->assertContains( 'Foo', $services->getServiceNames() );
+
+               // getting other services should still work
+               $services->getService( 'Bar' );
+
+               // disable non-destructible service, and not-yet-instantiated service
+               $services->disableService( 'Bar' );
+               $services->disableService( 'Qux' );
+
+               $this->assertNull( $services->peekService( 'Bar' ) );
+               $this->assertNull( $services->peekService( 'Qux' ) );
+
+               // disabled service should still be listed
+               $this->assertContains( 'Bar', $services->getServiceNames() );
+               $this->assertContains( 'Qux', $services->getServiceNames() );
+
+               $this->setExpectedException( 'MediaWiki\Services\ServiceDisabledException' );
+               $services->getService( 'Qux' );
+       }
+
+       public function testDisableService_fail_undefined() {
+               $services = $this->newServiceContainer();
+
+               $theService = new stdClass();
+               $name = 'TestService92834576';
+
+               $this->setExpectedException( 'MediaWiki\Services\NoSuchServiceException' );
+
+               $services->redefineService( $name, function () use ( $theService ) {
+                       return $theService;
+               } );
+       }
+
+       public function testDestroy() {
+               $services = $this->newServiceContainer();
+
+               $destructible = $this->getMockBuilder( 'MediaWiki\Services\DestructibleService' )
+                       ->getMock();
+               $destructible->expects( $this->once() )
+                       ->method( 'destroy' );
+
+               $services->defineService( 'Foo', function () use ( $destructible ) {
+                       return $destructible;
+               } );
+
+               $services->defineService( 'Bar', function () {
+                       return new stdClass();
+               } );
+
+               // create the service
+               $services->getService( 'Foo' );
+
+               // destroy the container
+               $services->destroy();
+
+               $this->setExpectedException( 'MediaWiki\Services\ContainerDisabledException' );
+               $services->getService( 'Bar' );
+       }
+
+}
diff --git a/tests/phpunit/includes/services/TestWiring1.php b/tests/phpunit/includes/services/TestWiring1.php
new file mode 100644 (file)
index 0000000..b6ff4eb
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+/**
+ * Test file for testing ServiceContainer::loadWiringFiles
+ */
+
+return [
+       'Foo' => function () {
+               return 'Foo!';
+       },
+];
diff --git a/tests/phpunit/includes/services/TestWiring2.php b/tests/phpunit/includes/services/TestWiring2.php
new file mode 100644 (file)
index 0000000..dfff64f
--- /dev/null
@@ -0,0 +1,10 @@
+<?php
+/**
+ * Test file for testing ServiceContainer::loadWiringFiles
+ */
+
+return [
+       'Bar' => function () {
+               return 'Bar!';
+       },
+];
index bf0f65b..cb2669f 100644 (file)
@@ -10,6 +10,9 @@ use Wikimedia\TestingAccessWrapper;
  * @group Shell
  */
 class CommandFactoryTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        /**
         * @covers MediaWiki\Shell\CommandFactory::create
         */
index 385dd50..2bafa03 100644 (file)
@@ -8,6 +8,9 @@ use Wikimedia\TestingAccessWrapper;
  * @group Shell
  */
 class CommandTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        private function requirePosix() {
                if ( wfIsWindows() ) {
                        $this->markTestSkipped( 'This test requires a POSIX environment.' );
index c9db74f..1585375 100644 (file)
@@ -24,43 +24,46 @@ use MediaWiki\Shell\Shell;
 use Wikimedia\TestingAccessWrapper;
 
 class FirejailCommandTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        public function provideBuildFinalCommand() {
                global $IP;
-               // @codingStandardsIgnoreStart
+               // phpcs:ignore Generic.Files.LineLength
                $env = "'MW_INCLUDE_STDERR=;MW_CPU_LIMIT=180; MW_CGROUP='\'''\''; MW_MEM_LIMIT=307200; MW_FILE_SIZE_LIMIT=102400; MW_WALL_CLOCK_LIMIT=180; MW_USE_LOG_PIPE=yes'";
-               // @codingStandardsIgnoreEnd
-               $limit = "$IP/includes/shell/limit.sh";
+               $limit = "/bin/bash '$IP/includes/shell/limit.sh'";
                $profile = "--profile=$IP/includes/shell/firejail.profile";
-               $default = '--noroot --seccomp=@default --private-dev';
+               $blacklist = '--blacklist=' . realpath( MW_CONFIG_FILE );
+               $default = "$blacklist --noroot --seccomp=@default --private-dev";
                return [
                        [
                                'No restrictions',
-                               'ls', 0, "/bin/bash '$limit' ''\''ls'\''' $env"
+                               'ls', 0, "$limit ''\''ls'\''' $env"
                        ],
                        [
                                'default restriction',
                                'ls', Shell::RESTRICT_DEFAULT,
-                               "firejail --quiet $profile $default -- /bin/bash '$limit' ''\''ls'\''' $env"
+                               "$limit 'firejail --quiet $profile $default -- '\''ls'\''' $env"
                        ],
                        [
                                'no network',
                                'ls', Shell::NO_NETWORK,
-                               "firejail --quiet $profile --net=none -- /bin/bash '$limit' ''\''ls'\''' $env"
+                               "$limit 'firejail --quiet $profile --net=none -- '\''ls'\''' $env"
                        ],
                        [
                                'default restriction & no network',
                                'ls', Shell::RESTRICT_DEFAULT | Shell::NO_NETWORK,
-                               "firejail --quiet $profile $default --net=none -- /bin/bash '$limit' ''\''ls'\''' $env"
+                               "$limit 'firejail --quiet $profile $default --net=none -- '\''ls'\''' $env"
                        ],
                        [
                                'seccomp',
                                'ls', Shell::SECCOMP,
-                               "firejail --quiet $profile --seccomp=@default -- /bin/bash '$limit' ''\''ls'\''' $env"
+                               "$limit 'firejail --quiet $profile --seccomp=@default -- '\''ls'\''' $env"
                        ],
                        [
                                'seccomp & no execve',
                                'ls', Shell::SECCOMP | Shell::NO_EXECVE,
-                               "firejail --quiet $profile --seccomp=@default,execve -- /bin/bash '$limit' ''\''ls'\''' $env"
+                               "$limit 'firejail --quiet $profile --shell=none --seccomp=@default,execve -- '\''ls'\''' $env"
                        ],
                ];
        }
@@ -75,7 +78,7 @@ class FirejailCommandTest extends PHPUnit_Framework_TestCase {
                        ->params( $params )
                        ->restrict( $flags );
                $wrapper = TestingAccessWrapper::newFromObject( $command );
-               $output = $wrapper->buildFinalCommand();
+               $output = $wrapper->buildFinalCommand( $wrapper->command );
                $this->assertEquals( $expected, $output[0], $desc );
        }
 
index 2f68dbd..986a665 100644 (file)
@@ -7,6 +7,9 @@ use MediaWiki\Shell\Shell;
  * @group Shell
  */
 class ShellTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        public function testIsDisabled() {
                $this->assertInternalType( 'bool', Shell::isDisabled() ); // sanity
        }
index 32dd7f2..ae85f8a 100644 (file)
@@ -90,13 +90,13 @@ class DBSiteStoreTest extends MediaWikiTestCase {
                $site = $store->getSite( 'ertrywuutr' );
                $this->assertInstanceOf( 'Site', $site );
                $this->assertEquals( 'en', $site->getLanguageCode() );
-               $this->assertTrue( is_integer( $site->getInternalId() ) );
+               $this->assertTrue( is_int( $site->getInternalId() ) );
                $this->assertTrue( $site->getInternalId() >= 0 );
 
                $site = $store->getSite( 'sdfhxujgkfpth' );
                $this->assertInstanceOf( 'Site', $site );
                $this->assertEquals( 'nl', $site->getLanguageCode() );
-               $this->assertTrue( is_integer( $site->getInternalId() ) );
+               $this->assertTrue( is_int( $site->getInternalId() ) );
                $this->assertTrue( $site->getInternalId() >= 0 );
        }
 
index 7984795..ed6fbfe 100644 (file)
@@ -29,6 +29,8 @@
  */
 class FileBasedSiteLookupTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        protected function setUp() {
                $this->cacheFile = $this->getCacheFile();
        }
index 64cdbaa..d230550 100644 (file)
@@ -29,6 +29,8 @@ use MediaWiki\Site\MediaWikiPageNameNormalizer;
  */
 class MediaWikiPageNameNormalizerTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @dataProvider normalizePageTitleProvider
         */
index c0d8c00..09cdea7 100644 (file)
@@ -31,6 +31,8 @@
  */
 class SiteExporterTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public function testConstructor_InvalidArgument() {
                $this->setExpectedException( 'InvalidArgumentException' );
 
index ea49429..8a43bf8 100644 (file)
@@ -31,6 +31,8 @@
  */
 class SiteImporterTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        private function newSiteImporter( array $expectedSites, $errorCount ) {
                $store = $this->getMockBuilder( 'SiteStore' )->getMock();
 
index f7d0117..a4a171c 100644 (file)
@@ -99,7 +99,7 @@ class SiteListTest extends MediaWikiTestCase {
                 * @var Site $site
                 */
                foreach ( $sites as $site ) {
-                       if ( is_integer( $site->getInternalId() ) ) {
+                       if ( is_int( $site->getInternalId() ) ) {
                                $this->assertEquals( $site, $sites->getSiteByInternalId( $site->getInternalId() ) );
                        }
                }
@@ -155,7 +155,7 @@ class SiteListTest extends MediaWikiTestCase {
                 * @var Site $site
                 */
                foreach ( $sites as $site ) {
-                       if ( is_integer( $site->getInternalId() ) ) {
+                       if ( is_int( $site->getInternalId() ) ) {
                                $this->assertTrue( $site, $sites->hasInternalId( $site->getInternalId() ) );
                        }
                }
index af94a9d..6514beb 100644 (file)
@@ -29,6 +29,8 @@
  */
 class SitesCacheFileBuilderTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        protected function setUp() {
                $this->cacheFile = $this->getCacheFile();
        }
index 9366282..1147805 100644 (file)
@@ -18,6 +18,7 @@ class ContribsPagerTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers ContribsPager::processDateFilter
         * @dataProvider dateFilterOptionProcessingProvider
         * @param array $inputOpts Input options
         * @param array $expectedOpts Expected options
index ede2791..a845938 100644 (file)
@@ -3,6 +3,9 @@
  * @group Database
  */
 
+/**
+ * @covers MIMEsearchPage
+ */
 class SpecialMIMESearchTest extends MediaWikiTestCase {
 
        /** @var MIMEsearchPage */
index 64e78f2..2ecef79 100644 (file)
@@ -5,6 +5,7 @@
 class UncategorizedCategoriesPageTest extends MediaWikiTestCase {
        /**
         * @dataProvider provideTestGetQueryInfoData
+        * @covers UncategorizedCategoriesPage::getQueryInfo
         */
        public function testGetQueryInfo( $msgContent, $expected ) {
                $msg = new RawMessage( $msgContent );
index f980af0..b20557f 100644 (file)
@@ -200,14 +200,14 @@ class RemexDriverTest extends MediaWikiTestCase {
                        'a<small><i><div>d</div></i>e</small>',
                        '<p>a</p><small><i><div>d</div></i></small><p><small>e</small></p>'
                ],
+               // phpcs:disable Generic.Files.LineLength
                [
                        'Complex pwrap test 6',
                        '<i>a<div>b</div>c<b>d<div>e</div>f</b>g</i>',
-                       // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong
                        // PHP 5 does not allow concatenation in initialisation of a class static variable
                        '<p><i>a</i></p><i><div>b</div></i><p><i>c<b>d</b></i></p><i><b><div>e</div></b></i><p><i><b>f</b>g</i></p>'
-                       // @codingStandardsIgnoreEnd
                ],
+               // phpcs:enable
                /* FIXME the second <b> causes a stack split which clones the <i> even
                 * though no <p> is actually generated
                [
index dd68cdc..3541091 100644 (file)
@@ -103,6 +103,8 @@ class UploadBaseTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers UploadBase::verifyUpload
+        *
         * test uploading a 100 bytes file with $wgMaxUploadSize = 100
         *
         * This method should be abstracted so we can test different settings.
@@ -126,6 +128,7 @@ class UploadBaseTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers UploadBase::checkSvgScriptCallback
         * @dataProvider provideCheckSvgScriptCallback
         */
        public function testCheckSvgScriptCallback( $svg, $wellFormed, $filterMatch, $message ) {
@@ -135,7 +138,7 @@ class UploadBaseTest extends MediaWikiTestCase {
        }
 
        public static function provideCheckSvgScriptCallback() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        // html5sec SVG vectors
                        [
@@ -508,10 +511,11 @@ class UploadBaseTest extends MediaWikiTestCase {
                                'DTD with aliased entities apos (Should be allowed)'
                        ]
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
+        * @covers UploadBase::detectScriptInSvg
         * @dataProvider provideDetectScriptInSvg
         */
        public function testDetectScriptInSvg( $svg, $expected, $message ) {
@@ -552,6 +556,7 @@ class UploadBaseTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers UploadBase::checkXMLEncodingMissmatch
         * @dataProvider provideCheckXMLEncodingMissmatch
         */
        public function testCheckXMLEncodingMissmatch( $fileContents, $evil ) {
index 68b7959..1f578ab 100644 (file)
@@ -3,6 +3,7 @@
 use MediaWiki\Auth\AuthManager;
 
 /**
+ * @covers PasswordReset
  * @group Database
  */
 class PasswordResetTest extends MediaWikiTestCase {
index 2721c18..ea7f715 100644 (file)
@@ -236,6 +236,8 @@ class UserTest extends MediaWikiTestCase {
         * Test, if for all rights a right- message exist,
         * which is used on Special:ListGroupRights as help text
         * Extensions and core
+        *
+        * @coversNothing
         */
        public function testAllRightsWithMessage() {
                // Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
@@ -903,6 +905,9 @@ class UserTest extends MediaWikiTestCase {
                $block->delete();
        }
 
+       /**
+        * @covers User::isPingLimitable
+        */
        public function testIsPingLimitable() {
                $request = new FauxRequest();
                $request->setIP( '1.2.3.4' );
@@ -939,6 +944,7 @@ class UserTest extends MediaWikiTestCase {
        }
 
        /**
+        * @covers User::getExperienceLevel
         * @dataProvider provideExperienceLevel
         */
        public function testExperienceLevel( $editCount, $memberSince, $expLevel ) {
@@ -968,6 +974,9 @@ class UserTest extends MediaWikiTestCase {
                $this->assertEquals( $expLevel, $user->getExperienceLevel() );
        }
 
+       /**
+        * @covers User::getExperienceLevel
+        */
        public function testExperienceLevelAnon() {
                $user = User::newFromName( '10.11.12.13', false );
 
index 7559e22..caeeaab 100644 (file)
@@ -9,7 +9,13 @@
  * dataprovider.
  */
 
+/**
+ * @covers AvroValidator
+ */
 class AvroValidatorTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        public function setUp() {
                if ( !class_exists( 'AvroSchema' ) ) {
                        $this->markTestSkipped( 'Avro is required to run the AvroValidatorTest' );
index 017e97d..d80a61c 100644 (file)
@@ -4,6 +4,10 @@
  * Tests for BatchRowUpdate and its components
  *
  * @group db
+ *
+ * @covers BatchRowUpdate
+ * @covers BatchRowIterator
+ * @covers BatchRowWriter
  */
 class BatchRowUpdateTest extends MediaWikiTestCase {
 
index e8a228e..8e07b5e 100644 (file)
@@ -5,6 +5,8 @@
  */
 class ClassCollectorTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public static function provideCases() {
                return [
                        [
index 0ee4c13..b3885bd 100644 (file)
@@ -5,6 +5,8 @@
  */
 class FileContentsHasherTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public function provideSingleFile() {
                return array_map( function ( $file ) {
                        return [ $file, file_get_contents( $file ) ];
index 86c19ae..c9c1345 100644 (file)
@@ -4,6 +4,10 @@
  * @group HKDF
  */
 
+/**
+ * @covers CryptHKDF
+ * @covers MWCryptHKDF
+ */
 class MWCryptHKDFTest extends MediaWikiTestCase {
 
        protected function setUp() {
@@ -40,7 +44,7 @@ class MWCryptHKDFTest extends MediaWikiTestCase {
         * Test vectors from Appendix A on https://tools.ietf.org/html/rfc5869
         */
        public static function providerRfc5869() {
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:disable Generic.Files.LineLength
                return [
                        // A.1
                        [
@@ -93,6 +97,6 @@ class MWCryptHKDFTest extends MediaWikiTestCase {
                                '0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4' // okm
                        ],
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 }
index 905d14c..66c8d00 100644 (file)
@@ -1,11 +1,14 @@
 <?php
+
 /**
- *
  * @group Hash
+ *
+ * @covers MWCryptHash
  */
-
 class MWCryptHashTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public function testHashLength() {
                if ( MWCryptHash::hashAlgo() !== 'whirlpool' ) {
                        $this->markTestSkipped( 'Hash algorithm isn\'t whirlpool' );
@@ -21,9 +24,8 @@ class MWCryptHashTest extends PHPUnit_Framework_TestCase {
                }
 
                $data = 'foobar';
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:ignore Generic.Files.LineLength
                $hash = '9923afaec3a86f865bb231a588f453f84e8151a2deb4109aebc6de4284be5bebcff4fab82a7e51d920237340a043736e9d13bab196006dcca0fe65314d68eab9';
-               // @codingStandardsIgnoreEnd
 
                $this->assertEquals(
                        hex2bin( $hash ),
@@ -44,9 +46,8 @@ class MWCryptHashTest extends PHPUnit_Framework_TestCase {
 
                $data = 'foobar';
                $key = 'secret';
-               // @codingStandardsIgnoreStart Generic.Files.LineLength
+               // phpcs:ignore Generic.Files.LineLength
                $hash = 'ddc94177b2020e55ce2049199fd9cc6327f416ff6dc621cc34cb43d9bec61d73372b4790c0e24957f565ecaf2d42821e6303619093e99cbe14a3b9250bda5f81';
-               // @codingStandardsIgnoreEnd
 
                $this->assertEquals(
                        hex2bin( $hash ),
index f2ea489..4c05326 100644 (file)
@@ -1,6 +1,8 @@
 <?php
 class MWRestrictionsTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        protected static $restrictionsForChecks;
 
        public static function setUpBeforeClass() {
index 8b54b72..230c935 100644 (file)
@@ -2,6 +2,8 @@
 
 class UIDGeneratorTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        protected function tearDown() {
                // Bug: 44850
                UIDGenerator::unitTestTearDown();
index 7e74d96..09a0676 100644 (file)
@@ -5,6 +5,9 @@
  * NOTE: this test is more like an integration test than a unit test
  */
 class ZipDirectoryReaderTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
        protected $zipDir;
        protected $entries;
 
index 62ba5f6..ef2486d 100644 (file)
@@ -8,6 +8,8 @@ use Wikimedia\TestingAccessWrapper;
  */
 class WatchedItemQueryServiceUnitTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @return PHPUnit_Framework_MockObject_MockObject|Database
         */
index 950d2df..d36f38b 100644 (file)
@@ -10,6 +10,8 @@
  */
 class LanguageCodeTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        public function testConstructor() {
                $instance = new LanguageCode();
 
index fc2ed33..82ab7de 100644 (file)
@@ -160,6 +160,8 @@ class LanguageConverterTest extends MediaWikiLangTestCase {
 
        /**
         * Test exhausting pcre.backtrack_limit
+        *
+        * @covers LanguageConverter::autoConvert
         */
        public function testAutoConvertT124404() {
                $testString = '';
index e39f57e..5cb5602 100644 (file)
@@ -1326,7 +1326,7 @@ class LanguageTest extends LanguageClassesTestCase {
        }
 
        public static function provideCheckTitleEncodingData() {
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:disable Generic.Files.LineLength
                return [
                        [ "" ],
                        [ "United States of America" ], // 7bit ASCII
@@ -1377,7 +1377,7 @@ class LanguageTest extends LanguageClassesTestCase {
                                )
                        ]
                ];
-               // @codingStandardsIgnoreEnd
+               // phpcs:enable
        }
 
        /**
@@ -1630,7 +1630,7 @@ class LanguageTest extends LanguageClassesTestCase {
        }
 
        /**
-        * @dataProvider testFormatNumProvider
+        * @dataProvider provideFormatNum
         * @covers Language::formatNum
         */
        public function testFormatNum(
@@ -1643,7 +1643,7 @@ class LanguageTest extends LanguageClassesTestCase {
                $this->assertEquals( $expected, $formattedNum );
        }
 
-       public function testFormatNumProvider() {
+       public function provideFormatNum() {
                return [
                        [ true, 'en', 100, false, '100' ],
                        [ true, 'en', 101, true, '101' ],
@@ -1657,6 +1657,7 @@ class LanguageTest extends LanguageClassesTestCase {
        }
 
        /**
+        * @covers Language::parseFormattedNumber
         * @dataProvider parseFormattedNumberProvider
         */
        public function testParseFormattedNumber( $langCode, $number ) {
@@ -1795,6 +1796,9 @@ class LanguageTest extends LanguageClassesTestCase {
                ];
        }
 
+       /**
+        * @covers Language::equals
+        */
        public function testEquals() {
                $en1 = new Language();
                $en1->setCode( 'en' );
index 5a66759..f3f5a3f 100644 (file)
@@ -4,7 +4,9 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/LanguageAr.php */
+/**
+ * @covers LanguageAr
+ */
 class LanguageArTest extends LanguageClassesTestCase {
        /**
         * @covers Language::formatNum
index 26db106..4f049cd 100644 (file)
@@ -1,8 +1,11 @@
 <?php
 
-// @codingStandardsIgnoreStart Ignore Squiz.Classes.ValidClassName.NotCamelCaps
+// phpcs:disable Squiz.Classes.ValidClassName.NotCamelCaps
+/**
+ * @covers LanguageBe_tarask
+ */
 class LanguageBe_taraskTest extends LanguageClassesTestCase {
-       // @codingStandardsIgnoreEnd
+       // phpcs:enable
        /**
         * Make sure the language code we are given is indeed
         * be-tarask. This is to ensure LanguageClassesTestCase
index 207f505..29b2ccf 100644 (file)
@@ -5,7 +5,11 @@
  * @file
  */
 
-/** Tests for Croatian (hrvatski) */
+/**
+ * Tests for Croatian (hrvatski)
+ *
+ * @covers LanguageBs
+ */
 class LanguageBsTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providePlural
index f34288c..d99fc26 100644 (file)
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @covers LanguageCrh
+ * @covers CrhConverter
+ */
 class LanguageCrhTest extends LanguageClassesTestCase {
        /**
         * @dataProvider provideAutoConvertToAllVariants
index de65d16..565a885 100644 (file)
@@ -5,7 +5,9 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/LanguageCu.php */
+/**
+ * @covers LanguageCu
+ */
 class LanguageCuTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providePlural
index 949d5db..877a70c 100644 (file)
@@ -5,7 +5,9 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/classes/LanguageDsb.php */
+/**
+ * @covers LanguageDsb
+ */
 class LanguageDsbTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providePlural
index 43eb93e..c5d9e5e 100644 (file)
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @covers LanguageGan
+ * @covers GanConverter
+ */
 class LanguageGanTest extends LanguageClassesTestCase {
        /**
         * @dataProvider provideAutoConvertToAllVariants
index 133cc1c..0841f6f 100644 (file)
@@ -5,7 +5,9 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/classes/LanguageHsb.php */
+/**
+ * @covers LanguageHsb
+ */
 class LanguageHsbTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providePlural
index 7ea63e1..a1925bd 100644 (file)
@@ -5,7 +5,9 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/LanguageHu.php */
+/**
+ * @covers LanguageHu
+ */
 class LanguageHuTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providePlural
index 6453091..b493615 100644 (file)
@@ -5,7 +5,11 @@
  * @file
  */
 
-/** Tests for Armenian (Հայերեն) */
+/**
+ * Tests for Armenian (Հայերեն)
+ *
+ * @covers LanguageHy
+ */
 class LanguageHyTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providePlural
index ff9c4d0..01d97fc 100644 (file)
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @covers LanguageIu
+ * @covers IuConverter
+ */
 class LanguageIuTest extends LanguageClassesTestCase {
        /**
         * @dataProvider provideAutoConvertToAllVariants
index a03eac2..f21950e 100644 (file)
@@ -1,5 +1,10 @@
 <?php
 
+/**
+ * @covers LanguageKk
+ * @covers LanguageKk_cyrl
+ * @covers KkConverter
+ */
 class LanguageKkTest extends LanguageClassesTestCase {
        /**
         * @dataProvider provideAutoConvertToAllVariants
index f77c5b6..6419e28 100644 (file)
@@ -5,7 +5,9 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/classes/LanguageKsh.php */
+/**
+ * @covers LanguageKsh
+ */
 class LanguageKshTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providePlural
index 797ab4a..db69308 100644 (file)
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @covers LanguageKu
+ * @covers KuConverter
+ */
 class LanguageKuTest extends LanguageClassesTestCase {
        /**
         * @dataProvider provideAutoConvertToAllVariants
index 6bac031..673b5c7 100644 (file)
@@ -5,7 +5,9 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/LanguageMl.php */
+/**
+ * @covers LanguageMl
+ */
 class LanguageMlTest extends LanguageClassesTestCase {
 
        /**
index d7a0074..1487729 100644 (file)
@@ -76,7 +76,7 @@ class LanguagePlTest extends LanguageClassesTestCase {
        }
 
        /**
-        * @covers LanguagePl::commafy()
+        * @covers Language::commafy()
         * @dataProvider provideCommafyData
         */
        public function testCommafy( $number, $numbersWithCommas ) {
index a76293c..3e120f4 100644 (file)
@@ -6,7 +6,6 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/classes/LanguageRu.php */
 class LanguageRuTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providePlural
index 207a1b0..1d0f863 100644 (file)
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @covers LanguageShi
+ * @covers ShiConverter
+ */
 class LanguageShiTest extends LanguageClassesTestCase {
        /**
         * @dataProvider provideAutoConvertToAllVariants
index ed138c5..50100ce 100644 (file)
@@ -6,7 +6,9 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/classes/LanguageSl.php */
+/**
+ * @covers LanguageSl
+ */
 class LanguageSlTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providerPlural
index b64fd67..e81d537 100644 (file)
  *  - Tests for LanguageConverter and Language should probably be separate..
  */
 
-/** Tests for MediaWiki languages/LanguageSr.php */
+/**
+ * @covers LanguageSr
+ * @covers SrConverter
+ */
 class LanguageSrTest extends LanguageClassesTestCase {
        /**
         * @covers LanguageConverter::convertTo
index 0ed24ff..8969767 100644 (file)
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @covers LanguageTg
+ * @covers TgConverter
+ */
 class LanguageTgTest extends LanguageClassesTestCase {
        /**
         * @dataProvider provideAutoConvertToAllVariants
index 28d71df..3ddf2d0 100644 (file)
@@ -5,7 +5,9 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/LanguageTr.php */
+/**
+ * @covers LanguageTr
+ */
 class LanguageTrTest extends LanguageClassesTestCase {
 
        /**
index 6b25982..0ccebbe 100644 (file)
@@ -6,7 +6,6 @@
  * @file
  */
 
-/** Tests for Ukrainian */
 class LanguageUkTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providePlural
index 7ef87bf..367226d 100644 (file)
  *  - Tests for LanguageConverter and Language should probably be separate..
  */
 
-/** Tests for MediaWiki languages/LanguageUz.php */
+/**
+ * @covers LanguageUz
+ * @covers UzConverter
+ */
 class LanguageUzTest extends LanguageClassesTestCase {
 
        /**
index 27e57f6..80c9860 100644 (file)
@@ -5,7 +5,9 @@
  * @file
  */
 
-/** Tests for MediaWiki languages/classes/LanguageWa.php */
+/**
+ * @covers LanguageWa
+ */
 class LanguageWaTest extends LanguageClassesTestCase {
        /**
         * @dataProvider providePlural
index 26edc90..2e73ac5 100644 (file)
@@ -1,5 +1,10 @@
 <?php
 
+/**
+ * @covers LanguageZh
+ * @covers LanguageZh_hans
+ * @covers ZhConverter
+ */
 class LanguageZhTest extends LanguageClassesTestCase {
        /**
         * @dataProvider provideAutoConvertToAllVariants
diff --git a/tests/phpunit/maintenance/BenchmarkerTest.php b/tests/phpunit/maintenance/BenchmarkerTest.php
new file mode 100644 (file)
index 0000000..ec570e2
--- /dev/null
@@ -0,0 +1,138 @@
+<?php
+
+use Wikimedia\TestingAccessWrapper;
+
+/**
+ * @covers Benchmarker
+ */
+class BenchmarkerTest extends PHPUnit_Framework_TestCase {
+
+       use MediaWikiCoversValidator;
+
+       public function testBenchSimple() {
+               $bench = $this->getMockBuilder( Benchmarker::class )
+                       ->setMethods( [ 'execute', 'output' ] )
+                       ->getMock();
+               $benchProxy = TestingAccessWrapper::newFromObject( $bench );
+               $benchProxy->defaultCount = 3;
+
+               $count = 0;
+               $bench->bench( [
+                       'test' => function () use ( &$count ) {
+                                       $count++;
+                       }
+               ] );
+
+               $this->assertSame( 3, $count );
+       }
+
+       public function testBenchSetup() {
+               $bench = $this->getMockBuilder( Benchmarker::class )
+                       ->setMethods( [ 'execute', 'output' ] )
+                       ->getMock();
+               $benchProxy = TestingAccessWrapper::newFromObject( $bench );
+               $benchProxy->defaultCount = 2;
+
+               $buffer = [];
+               $bench->bench( [
+                       'test' => [
+                               'setup' => function () use ( &$buffer ) {
+                                               $buffer[] = 'setup';
+                               },
+                               'function' => function () use ( &$buffer ) {
+                                               $buffer[] = 'run';
+                               }
+                       ]
+               ] );
+
+               $this->assertSame( [ 'setup', 'run', 'run' ], $buffer );
+       }
+
+       public function testBenchVerbose() {
+               $bench = $this->getMockBuilder( Benchmarker::class )
+                       ->setMethods( [ 'execute', 'output', 'hasOption', 'verboseRun' ] )
+                       ->getMock();
+               $benchProxy = TestingAccessWrapper::newFromObject( $bench );
+               $benchProxy->defaultCount = 1;
+
+               $bench->expects( $this->exactly( 2 ) )->method( 'hasOption' )
+                       ->will( $this->returnValueMap( [
+                                       [ 'verbose', true ],
+                                       [ 'count', false ],
+                               ] ) );
+
+               $bench->expects( $this->once() )->method( 'verboseRun' )
+                       ->with( 0 )
+                       ->willReturn( null );
+
+               $bench->bench( [
+                       'test' => function () {
+                       }
+               ] );
+       }
+
+       public function noop() {
+       }
+
+       public function testBenchName_method() {
+               $bench = $this->getMockBuilder( Benchmarker::class )
+                       ->setMethods( [ 'execute', 'output', 'addResult' ] )
+                       ->getMock();
+               $benchProxy = TestingAccessWrapper::newFromObject( $bench );
+               $benchProxy->defaultCount = 1;
+
+               $bench->expects( $this->once() )->method( 'addResult' )
+                       ->with( $this->callback( function ( $res ) {
+                               return isset( $res['name'] ) && $res['name'] === __CLASS__ . '::noop()';
+                       } ) );
+
+               $bench->bench( [
+                       [ 'function' => [ $this, 'noop' ] ]
+               ] );
+       }
+
+       public function testBenchName_string() {
+               $bench = $this->getMockBuilder( Benchmarker::class )
+                       ->setMethods( [ 'execute', 'output', 'addResult' ] )
+                       ->getMock();
+               $benchProxy = TestingAccessWrapper::newFromObject( $bench );
+               $benchProxy->defaultCount = 1;
+
+               $bench->expects( $this->once() )->method( 'addResult' )
+                       ->with( $this->callback( function ( $res ) {
+                               return 'strtolower(A)';
+                       } ) );
+
+               $bench->bench( [ [
+                       'function' => 'strtolower',
+                       'args' => [ 'A' ],
+               ] ] );
+       }
+
+       /**
+        * @covers Benchmarker::verboseRun
+        */
+       public function testVerboseRun() {
+               $bench = $this->getMockBuilder( Benchmarker::class )
+                       ->setMethods( [ 'execute', 'output', 'hasOption', 'startBench', 'addResult' ] )
+                       ->getMock();
+               $benchProxy = TestingAccessWrapper::newFromObject( $bench );
+               $benchProxy->defaultCount = 1;
+
+               $bench->expects( $this->exactly( 2 ) )->method( 'hasOption' )
+                       ->will( $this->returnValueMap( [
+                                       [ 'verbose', true ],
+                                       [ 'count', false ],
+                               ] ) );
+
+               $bench->expects( $this->once() )->method( 'output' )
+                       ->with( $this->callback( function ( $out ) {
+                               return preg_match( '/memory.+ peak/', $out ) === 1;
+                       } ) );
+
+               $bench->bench( [
+                       'test' => function () {
+                       }
+               ] );
+       }
+}
index 2c5931d..010bb17 100644 (file)
@@ -151,7 +151,7 @@ class BaseDumpTest extends MediaWikiTestCase {
                $fname = $this->getNewTempFile();
 
                // The header of every prefetch file
-               // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
+               // phpcs:ignore Generic.Files.LineLength
                $header = '<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.7/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.7/ http://www.mediawiki.org/xml/export-0.7.xsd" version="0.7" xml:lang="en">
   <siteinfo>
     <sitename>wikisvn</sitename>
@@ -180,7 +180,6 @@ class BaseDumpTest extends MediaWikiTestCase {
     </namespaces>
   </siteinfo>
 ';
-               // @codingStandardsIgnoreEnd
 
                // An array holding the pages that are available for prefetch
                $available_pages = [];
index ec2746e..b51c14c 100644 (file)
@@ -1,5 +1,9 @@
 <?php
 
+/**
+ * @covers CategoriesRdf
+ * @covers DumpCategoriesAsRdf
+ */
 class CategoriesRdfTest extends MediaWikiLangTestCase {
        public function getCategoryIterator() {
                return [
index af03fe6..dceaf41 100644 (file)
@@ -188,6 +188,7 @@ class SideBarTest extends MediaWikiLangTestCase {
 
        /**
         * Test $wgNoFollowLinks in sidebar
+        * @covers Skin::addToSidebarPlain
         */
        public function testRespectWgnofollowlinks() {
                $this->setMwGlobals( 'wgNoFollowLinks', false );
@@ -201,6 +202,7 @@ class SideBarTest extends MediaWikiLangTestCase {
        /**
         * Test $wgExternaLinkTarget in sidebar
         * @dataProvider dataRespectExternallinktarget
+        * @covers Skin::addToSidebarPlain
         */
        public function testRespectExternallinktarget( $externalLinkTarget ) {
                $this->setMwGlobals( 'wgExternalLinkTarget', $externalLinkTarget );
index 16a9a24..4ab0c2c 100644 (file)
@@ -8,6 +8,8 @@
  */
 class AvailableRightsTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * Returns all rights that should be in $wgAvailableRights + all rights
         * registered via the 'UserGetAllRights' hook + all "core" rights.
index b19376d..0cf4659 100644 (file)
@@ -22,6 +22,8 @@
  */
 class ExtensionJsonValidationTest extends PHPUnit_Framework_TestCase {
 
+       use MediaWikiCoversValidator;
+
        /**
         * @var ExtensionJsonValidator
         */
index b20b68f..6a1b83c 100644 (file)
@@ -12,7 +12,7 @@
                assert.strictEqual( $( '.toc' ).length, 0, 'There is no table of contents on the page at the beginning' );
 
                tocHtml = '<div id="toc" class="toc">' +
-                       '<div class="toctitle">' +
+                       '<div class="toctitle" lang="en" dir="ltr">' +
                        '<h2>Contents</h2>' +
                        '</div>' +
                        '<ul><li></li></ul>' +
index bb27626..1730575 100644 (file)
                assert.equal( href, '/wiki/#Fragment', 'empty title with fragment' );
 
                href = util.getUrl( '#Fragment', { action: 'edit' } );
-               assert.equal( href, '/w/index.php?action=edit#Fragment', 'epmty title with query string and fragment' );
+               assert.equal( href, '/w/index.php?action=edit#Fragment', 'empty title with query string and fragment' );
 
                href = util.getUrl( 'Foo:Sandbox \xC4#Fragment \xC4', { action: 'edit' } );
                assert.equal( href, '/w/index.php?title=Foo:Sandbox_%C3%84&action=edit#Fragment_.C3.84', 'title with query string, fragment, and special characters' );
index 59e1878..26881eb 100644 (file)
@@ -1,5 +1,3 @@
-/* eslint no-undef: "error" */
-/* eslint-env node */
 'use strict';
 const merge = require( 'deepmerge' ),
        password = 'testpass',
index cf9da0c..5eba0e0 100644 (file)
@@ -1,6 +1,3 @@
-/* eslint-env node */
-/* eslint no-undef: "error" */
-/* eslint-disable no-console, comma-dangle */
 'use strict';
 
 const password = 'vagrant',
@@ -51,7 +48,7 @@ exports.config = {
                relPath( './tests/selenium/specs/**/*.js' ),
                relPath( './extensions/*/tests/selenium/specs/**/*.js' ),
                relPath( './extensions/VisualEditor/modules/ve-mw/tests/selenium/specs/**/*.js' ),
-               relPath( './skins/*/tests/selenium/specs/**/*.js' ),
+               relPath( './skins/*/tests/selenium/specs/**/*.js' )
        ],
        // Patterns to exclude.
        exclude: [
@@ -233,7 +230,7 @@ exports.config = {
                // save screenshot
                browser.saveScreenshot( filePath );
                console.log( '\n\tScreenshot location:', filePath, '\n' );
-       },
+       }
        //
        // Hook that gets executed after the suite has ended
        // afterSuite: function (suite) {